Difference between revisions of "Wesnoth AI Framework"

From The Battle for Wesnoth Wiki
(The [ai] Tag — Aspects: Wow, how long has that type been there!?)
(Dynamic Lua Aspects: Clarify that this can just as well go in [facet])
Line 399: Line 399:
 
[/aspect]
 
[/aspect]
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
 +
It's also possible to put all of that ''in'' a [facet] tag, rather than in an [aspect] tag – this would allow the Lua aspect to take effect only at certain times of day, for example.
  
 
== The [ai] Tag — Goals ==  
 
== The [ai] Tag — Goals ==  

Revision as of 23:25, 9 April 2024

Wesnoth AI Framework: A Composite AI

The Wesnoth AI framework is that of a composite AI. In other words, rather than the AI being one huge monolithic block, it is composed of a variety of different components which can be combined in a modular fashion (almost) at will.

In its default configuration, Wesnoth provides a predefined combination of these components in the RCA AI. This configuration can be modified in a multitude of different ways. Due to the modular setup, it is not only possible to add new AI behavior to before or after the default AI moves, or replace the default AI entirely, but also to insert new behavior routines in between existing components. This can be done either in addition to or as substitutions for existing components.

This page describes the AI components and their configuration in a general sense. Check out RCA AI for a description of how these are assembled into the default AI and Wesnoth AI for a collection of links to pages explaining how to customize and modify the existing AI or write a completely new AI.

Types of AI Components

The Wesnoth AI framework consists of the following types of components:

Stages

These are the fundamental building blocks of the AI. The AI is set up as a series of stages which are executed in the order in which they are put into the AI configuration. In other words, all actions of the first stage are executed first, then all actions of the second stage, etc.

While there are six different types of stages, only one of them, called the main_loop stage, is used in the default AI. In fact, this stage is sufficient for the vast majority of custom AI applications as well. We therefore only describe the main_loop stage and its sub-components in detail.

The Candidate Actions of the main_loop Stage

The main_loop stage consists of a number of candidate actions (CAs), each of which contains an evaluation and an execution function. For each AI move, the evaluation functions of all CAs are called, with each of them returning a score. The execution function of the CA with the highest score is then called, which results in an AI move (or in some cases, several moves) to be done. Then all CAs are evaluated again (including the one that was just executed) and the highest scoring CA is executed, until no CA returns a valid (non-zero) score any more.

Combining candidate actions designed for specific tasks such as attacks or village grabbing, it is possible to create entire AIs in a modular fashion. The CAs can be put together in whatever order and combination best suits the needs of a scenario. They do not need to be sorted in order of their evaluation scores and can even return variable scores which adapt to the situation on the map.

For a summary of the candidate actions of the default AI, click here.

Aspects and Goals

Aspects are configurable input parameters used to customize a candidate action's behavior. They are implemented as the the return values of functions that are called by the CAs of the RCA AI. They can also be called and taken into account by custom CAs, but that is not necessarily always the case. For example, some of the Micro AIs respect some of the RCA AI aspects (such as avoid), but not all do.

The return values of the aspect functions can be defined and/or customized using both WML or Lua.

Goals are used similarly to aspects in that they also affect the behavior of the default AI. They can be used to customize the directions into which the default AI moves its units. However, both their syntax and their internal implementation (see below) are different from those of the aspects.

Check out the RCA AI page for details on which aspects and goals exist and how they are used by the default AI.

Engines

Engines assemble the configurations provided for the individual components of the AI into usable code and execute this code. In recent Wesnoth versions, you do not need to worry about the engines any more, they are always defined and active by default. It is sufficient to know that the components can be written in three different languages, C++, Lua and Formula AI (FAI). Information on how to do this is provided in the links of the Wesnoth AI page.

It is worth noting that some stages are only set up for specific engines (see below), while the candidate actions, aspects and goals of the main_loop stage can be written in any of the three languages and can be combined arbitrarily.

AI Configuration

The Wesnoth AIs are assembled from configurations provided in several different places:

  • The default AI parameters in a variety of configuration files in the 'data/ai/' directory
  • Optional [ai] or [modify_ai] tags in era configurations
  • Optional [ai] or [modify_ai] tags in multiplayer faction configurations
  • Optional [ai] or [modify_ai] tags in scenario configurations
  • Optional [ai] tags in individual unit definitions (ie in the [unit] tag) - note that this option may be removed or drastically changed in the future

When the game is created, all these config snippets are merged into a single configuration stored in form of an [ai] tag. Then, aspects with the same ids are merged. During the game, whenever a [modify_ai] tag is acted upon (for example in an event), it is added into the existing AI configuration in the same way.

In the following, we describe the syntax of the [ai] tag. We first show the top-level keys and tags that can be used. Details on the use of the tags for the individual components follow after that, together with examples and links to more information for each component.

The [ai] Tag — Top-level Elements

AI configurations are set up and stored using the [ai] tag. It has the following top-level elements, which are described in more detail in the remaining sections of this page.

  • description="": (translatable string) This is the text displayed in the MP setup menu when choosing an AI for a computer player. It is only relevant for reusable AI configurations, for example in EraWML.
  • id="": (string) The id of the [ai] config snippet. This was originally meant to make it possible to remove [ai] configurations selectively during a game. However, due to the merging process described above, this information is lost. The id is therefore meaningless in the current implementation of the AI. (Version 1.13.5 and later only) This id can now be referenced by ai_algorithm in order to set the base AI algorithm to build on. It is only relevant for reusable AI configurations, for example in EraWML.
  • ai_algorithm: (string) This used to instruct Wesnoth to load a different AI engine instead of the composite AI. (Version 1.13.5 and later only) It now specifies a default AI configuration to load; any AI available at the multiplayer select screen can be chosen, or AIs defined in other addons. It must reference the id attribute of another [ai] tag. It defaults to ai_default_rca; other possible values include experimental_ai and idle_ai. Specifying the ID of an AI defined in data/ai/ais/ or /data/ai/dev/ is roughly equivalent to macro-including that file in your side configuration just above the opening [ai] tag, except that the AI configuration will be loaded on the fly (similar to using [modify_side]switch_ai) rather than included in the preprocessed WML. Additional aspects, stages, and so on can still be added to the [ai] tag as normal.
  • mp_rank: (integer) (Version 1.15.0 and later only) A value that determines in which order available AIs are displayed in the multiplayer selection menu. AIs are listed in ascending order of mp_rank (smallest values first). The mainline default (RCA) AI and Experimental AI have values of 1000 and 1010, respectively, meaning that custom AIs with mp_rank less than 1000 will be listed before any of the default AIs. AIs that do not contain an mp_rank line are shown at the end of the list. It is only relevant for reusable AI configurations, for example in EraWML.
  • version="": (string) This key is currently still needed to distinguish whether aspects are defined using standard or composite syntax in the [ai] tag. If it is omitted, standard syntax is used. If set to '10703' or '10710', the engine uses composite syntax. However, we are in the process of removing this distinction. When that is done, both types of syntax can be used without needing the version key, even mixed together inside the same [ai] tag. We will also deprecate this key when that happens. (Version 1.13.5 and later only) The version key is no longer recognized and will be mistaken as an attempt to set a non-existent "version" aspect. The key should not normally be required even prior to 1.13.5, however.
  • [stage]: Configuration of the stage(s) used in the AI. Several [stage] tags can be used, even several stages of the same type. They are executed in the order in which they are put into the [ai] tag.
  • [aspect]: Configuration of the aspects to be used by the AI. These are in composite aspect format.
    • Most aspects can also be provided using the simpler syntax explained at AiWML.
  • [goal]: Configuration of the goals to be used by the AI.
  • [engine]: This tag used to be needed for the Lua AI engine. It is not required any more, the Lua engine is created automatically now, just as the two other engines. If you need information on how this works, check out the Lua AI legacy documentation. Note that this tag is still used internally, so it will almost certainly not be removed in the future.
  • [modify_ai]: The [modify_ai] tag can specify modifications to be applied to the AI immediately. This is the preferred way to add a candidate action to the RCA AI, but can also be used for any other type of modification that modify_ai supports.
  • [micro_ai]: Add a [micro_ai] at initialization time. See Micro AIs for details. This is equivalent to adding the micro AI at prestart. The side and action keys are not supported here.
  • formula="": (string) Formula AI code to be executed by the AI. We recommend not using this any more, and it is not guaranteed to continue working. See the Formula AI legacy documentation for more information. (Version 1.13.5 and later only) As of version 1.13.5 this key is definitely not recognized at this level. It has likely not been recognized for some time prior to this, as well.
  • time_of_day, turns, engine: (Version 1.13.5 and later only) Specifies default values for aspects given as attributes or simple tags. (Simple tags are tags that do not contain either a value= attribute or a [value] subtag, with the exception that [attacks] is never a simple tag.) This is available prior to 1.13.5, but more limited; the engine attribute is probably more limited, and there might be problems mixing this syntax with fully-specified composite aspects in the same [ai] tag. (That can easily be worked around in a side configuration by splitting the [ai] tag in two.)
  • Other tags and attributes: (Version 1.13.5 and later only) Any other tag or attribute found is assumed to be a simplified aspect. More details about this syntax is given in the section on aspects later on this page. Some of this syntax is available prior to 1.13.5, but it has been generalized in 1.13.5 to automatically work for any compatible aspect. See AIWML for a list of these tags and attributes.

If no ai_algorithm is specified, normally the game will automatically load in the default AI, as if you had specified ai_algorithm=ai_default_rca. However, if there is a [stage] tag, then this behaviour is disabled and the AI will be built from a blank slate. This special behaviour only comes into play if ai_algorithm is omitted entirely.

The [ai] Tag — Stages

The [ai] tag can contain one or several stages defined in [stage] tags. If the AI configuration contains several stages, they are executed in the order in which they are put into the [ai] tag.

While there are six different types of stages available, all AI functionality possible in Wesnoth can be achieved using only a single one, the candidate action evaluation loop stage. In the default setup, this stage has id 'main_loop' and we generally simply refer to it as the main_loop stage.

Other stages exist mostly for legacy reasons from the times in the AI development when the main_loop stage did not exist yet. They are currently still functional and kept for backward compatibility reasons, but they are not maintained any more and might be removed in a future Wesnoth release cycle. We therefore recommend that all custom AI development is done using the main_loop stage only.

All stages support the id and engine tags. The latter defaults to cpp, and can be omitted in this case; the former is a unique identifier which is required if you want to later remove or modify the stage with [modify_ai]. If engine=cpp, an additional name tag is required, which tells the game which C++ AI algorithm to use. Currently the only valid values are 'ai_default_rca::candidate_action_evaluation_loop' and 'empty'. The 'empty' stage does nothing at all and should generally not be required.

main_loop Stage Configuration

For the main_loop stage, the [ai] tag contains the following elements:

  • name: This must be set to 'ai_default_rca::candidate_action_evaluation_loop', so that the AI knows that this is the main_loop stage.
  • id: (string) This is the identifier of the AI. It is usually set to 'main_loop', but can take on any value. It only matters if you are planning to remove or modify the stage during a scenario. Note that adding or removing a candidate action counts as a modification.
  • engine=cpp: (string) This must be set to 'cpp', which is also the default value. It can therefore be omitted.
  • [candidate_action]: Candidate action configuration tags. See below for details.
  • [args]: (Version 1.13.5 and later only) Lua engine only; specifies arguments to pass to the stage's execution function. This works similarly to the [args] in candidate actions.

Notes:

  • As an example, the configuration of the main_loop stage of the default AI is shown here.
  • Candidate actions can use any of the three available engines. Just because the stage uses the cpp engine does not mean that the CAs need to do so as well. See below for an example.
  • While that should rarely ever be necessary, it is possible to include several main_loop stage definitions in the same [ai] tag.
    • This is done by putting several [stage] tags into the same [ai] tag
    • The AI engine then evaluates the CAs of the first stage in the usual way, until no CA returns a valid score any more.
    • After the first stage is finished, it moves on to the second stage and repeats the process, until all stages have finished. This ends the AI turn.
    • Obviously, this only makes sense if the sets of CAs of the different stages are not identical (although individual CAs might appear in several stages).

Recruitment Stage

There is a specialized configurable recruitment stage. However, this stage uses the recruitment functions of the old Default AI (the one used before the RCA AI existed). Anything that can be done with this stage, and more, can now also be done with the recruitment candidate action using the recruitment_instruction aspect. It should therefore never be necessary to use this stage and we do not describe it here.

(Version 1.13.5 and later only) This stage has now been removed. Any use of this stage within the old recruitment aspect should still continue to work, as the syntax of this stage is compatible with the recruitment_instructions aspect and recruitment is now considered a synonym of that newer aspect. Straight uses of this stage, however, will no longer function.

Legacy Stages

Four other stages are also available. They do, however, not provide any functionality that is not also possible with the main_loop stage, only different ways of achieving the same functionality. We therefore only list them here for completeness, with brief examples and links to legacy documentation.

Note that both this documentation and the stages themselves might be removed at some point.

Lua stage

Executes Lua code by calling a function created inside a Lua engine. Whatever element is returned by the code in the Lua [engine] tag is accessible here as an upvalue. So, for example, (...):execute() calls whatever_is_returned_by_lua_engine:execute().

[stage]
    engine="lua"
    code= "(...):execute()"
[/stage]

See the Lua AI legacy documentation.

Formula AI Side Formulas Stage

This stage executes a given Formula AI side formula. Example:

[stage]
    engine=fai
    name=side_formulas
    move="write_your_formula_here"
[/stage]

See the Formula AI legacy documentation.

Formula AI Unit Formulas Stage

This stage takes no parameters and executes all Formula AI formulas which are attached to units. Example:

[stage]
    engine=fai
    name=unit_formulas
[/stage]

See the Formula AI legacy documentation.

Fallback stage

Fall back to another AI. Example:

[stage] 
    id=fallback
    name=testing_ai_default::fallback
    [ai]
       ai_algorithm=default_ai
    [/ai]
[/stage]

This example shows how to set up a stage to fall back to the old Default AI. This was useful when it was not clear yet how well the RCA AI would work and whether it would suddenly stop in the middle of the CA evaluation loop. There is really no reason to use a fallback stage any more these days, especially since it is also possible to simply add another stage to the AI configuration (without that having to be a fallback stage).

(Version 1.13.5 and later only) This stage has now been removed since the RCA AI is now the only algorithm and thus there's nothing else to fallback to.

The [ai] Tag — Candidate Actions

The main_loop stage (and only this stage) can contain an assortment of candidate actions. They are evaluated and executed in the manner explained above. This section explains how to configure the [candidate_action] tag that goes into the [stage] tag of the main_loop stage.

All three engines can, in principle, be used to write custom CAs. However, only the use of Lua CAs is recommended for this purpose. Using the cpp engine has the obvious problem of requiring changes to the Wesnoth source code. Formula AI CAs are discouraged for the same reasons why we do not recommend using Formula AI stages any more.

The [candidate_action] Tag

The [candidate_action] tag can contain the following keys:

  • engine: This key is required for Wesnoth to know which engine the CA should be processed with. Possible values are 'cpp', 'lua' and 'fai'.
  • id: The id of the CA is, in principle, optional. However, it is needed if you want to remove or change the CA after its initial definition.
  • name: The CAs of the default AI are identified by their name, making this a required key for the cpp engine. Check here for the names of the available default CAs. The key is optional for other engines.
  • max_score: The maximum score the CA evaluation function might return. This parameter is optional, but it is useful to reduce the AI move evaluation time. During each iteration through the evaluation loop, the main_loop stage only evaluates CAs with max_score larger than that of the highest-scoring CA found so far during this iteration. For that same reason, it also makes sense to order CAs by decreasing max_score in the [stage] tag, even though that is not technically necessary.
  • score: (cpp engine only) The score returned by the CA. Note that this means that cpp engine CAs always have fixed scores.
  • [filter_own]: (Version 1.15.3 and later only) The AI units participating in this candidate action can be restricted to only the units defined in this tag. See the AiWML page for more information and an example. The content of this tag is available to both the evaluation and execution function as a WML table. This tag is optional. If it is omitted, all AI units are used. (cpp and lua CAs only; fai CAs have a different mechanism.)

In addition, Lua CAs also contain the following keys:

  • location: File name, including path, of the AI code for the CA.
  • eval_parms, exec_parms: (deprecated) The parameters to be passed to the evaluation and execution functions of the AI. These need to be in form of a Lua table, without the outer curly brackets. They are passed to these functions as the second argument, cfg.
  • sticky, unit_x, unit_y: Specifies that this is a behavioral candidate action that is automatically removed once the unit on the given location dies.
  • [args]: (Version 1.13.5 and later only) This replaces eval_parms and exec_parms, which are now deprecated and will be removed in a later version. The content of this tag is available to both the evaluation and execution function as a WML table. Details at the link above.

Notes:

  • The syntax for Lua CAs has evolved a fair bit, and some of the older syntaxes are still supported. They are deprecated, however, and may be removed in a future version.
  • The current syntax was originally called external Lua CAs. However, as this has now become the standard, we drop the external and simply call them Lua CAs.
  • Formula AI CAs contain some additional keys. As we do not recommend using the fai engine any more, we do not describe this syntax here and refer to the Formula AI legacy documentation instead.

Here are examples of [candidate_action] tag uses:

Combat CA of the default AI:

[candidate_action]
    id=combat
    engine=cpp
    name=ai_default_rca::combat_phase
    max_score=100000
    score=100000
[/candidate_action]

Lua AI CA:

[candidate_action]
    engine=lua
    name=return_guardian_bob
    id=return_guardian_bob
    max_score=100010
    location="~add-ons/my_addon/lua/return_guardian.lua"
    [args]
        id=Bob
        return_x=10
        return_y=15
    [/args]
[/candidate_action]

Available Candidate Actions

  • cpp engine: The available CAs of the default AI are given here.
  • lua engine: The Micro AIs are written using Lua CAs, which can be used either as they are or as templates for creating your own CAs. They can be found here.
  • fai engine: As we said above, we do not recommend using the fai engine any more for creating custom CAs. However, if you want to do so, a few simple Formula AI CA examples can be found in the Formula AI legacy documentation.

The [ai] Tag — Aspects

The values of aspects are used by the candidate actions of the default AI as parameters influencing the AI behavior. Thus, for the most part, they only apply to the CAs of the default AI. It is, however, possible to write Lua CAs which query certain aspects and take them into account. For example, some of the Micro AIs respect some of the default aspects.

A huge number of aspects are available for the default AI. They are therefore given their own page. Only the syntax and internal structure of the aspect configuration is shown here.

There are two types of syntax for defining aspects. In the following, we slowly walk you through these using increasingly complex examples, with the full definition of all the possible key and tags listed at the end of this section.

The vast majority of aspects can be defined using a straight-forward syntax of simply defining their values using keys or tags. These are sometimes referred to as simple aspects, though the simplicity is in the syntax rather than a feature of the aspect. (In actual fact, this syntax defines facets of a composite aspect.) Examples are

[ai]
    time_of_day=dawn
    aggression=0.765
[/ai]

or

[ai]
    [avoid]
        terrain=W*
    [/avoid]
[ai]

For simple aspect syntax, several additional keys are available in addition to the aspect names themselves, time_of_day (as shown in the example above), turns and (Version 1.13.5 and later only) engine. These are also explained at AiWML, but these keys basically affect all aspects defined in this simple syntax. (Version 1.13.5 and later only) Currently, every aspect except the attacks aspect can be defined in this way. Prior to 1.13.5, there were also a few other aspects that could not be defined in this way.

(Version 1.13.5 and later only) Occasionally, a more complex structure is required. Any aspect name can be used as a tag which contains the contents of a [facet] tag. Thus, the above two examples could also be implemented like this:

[ai]
    [aggression]
        time_of_day=dawn
        value=0.765
    [/aggression]
    [avoid]
        [value]
            terrain=W*
        [/value]
    [/avoid]
[/ai]

This syntax has the advantage of allowing you to set the facet ID as well as the invalidate keys, if desired. They are not affected by toplevel turns, time_of_day, and engine keys. However, they expand in a very similar way to the simpler syntax - that is, they define a facet of a composite aspect. In the case of aspects that require a tag in both syntaxes (such as avoid), it's the presence of [value] that disambiguates them.

The third way of defining an aspect is to use the full syntax, which is sometimes called complex aspects, though this is merely a feature of the syntax and not something inherent to any given aspect. All simple aspects expand to equivalent complex aspects, after all. A complex aspect uses the following keys:

  • engine=cpp: The engine to use for this tag. This can usually be omitted.
  • id: A unique identifier for the aspect. This is mainly used for [modify_ai].
  • name: Only required for the cpp engine. Possible values are standard_aspect, composite_aspect, lua_aspect, and ai_default_rca::aspect_attacks. Most of these values are only valid with the cpp engine, while lua_aspect is only valid with the Lua engine. A sensible default is normally chosen, allowing this to be omitted. (Version 1.13.5 and later only) Prior to 1.13.5, some of these values would not work in certain contexts, but in 1.13.5, any valid value may be used here in any aspect context.
  • invalidate_on_* keys: These four keys are primarily for advanced usage. They are described in more detail below.

A complex aspect contains additional keys and tags based on the value of its name attribute. Standard aspects contain either a value attribute or a [value] tag which specifies the attribute's value. The attack aspect contains the [filter_own] and [filter_enemy] tags, as described here. Lua aspects contain additional keys as defined here. And composite aspects contain the following additional tags:

  • [facet]: A sub-aspect which will be taken as the value of the aspect, unless its turns and time_of_day keys do not match. (Version 1.13.5 and later only) Formerly this had to be a standard aspect, but as of 1.13.5 it can be any type of aspect, such as a composite aspect or a Lua aspect.
  • [default]: A sub-aspect which will specifies the default value of the aspect, which is used if there are no facets or if all facets are inactive. (Version 1.13.5 and later only) Formerly this had to be a standard aspect, but as of 1.13.5 it can be any type of aspect, such as a composite aspect or a Lua aspect. Note: Overriding the default aspect is generally not recommended. It's just as easy to simply add an unconditional facet instead.

At the toplevel within the [ai] tag, complex aspects are defined by an [aspect] tag containing the various keys and tags that define the aspect. Typically, these toplevel aspects are composite aspects, meaning that they contain facets to specify the actual value of the aspect (though they can easily be changed to Lua aspects (Version 1.13.5 and later only) or standard aspects). The id attribute in an [aspect] tag must be a valid aspect name, otherwise it will give an error and be ignored.

Let's try to explain this using the aggression example from above. If we wanted to define that using the complex aspect syntax, it would look like this:

[ai]
    [aspect]
        id=aggression
        [facet]
            id=custom_aggression # Can be used to remove this facet later
            time_of_day=dawn
            value=0.765
        [/facet]
    [/aspect]
[/ai]

The most important part is that the composite aspect structure uses so-called facets, which contain the value of the aspect. If the aspect is a single scalar value, such as in this example, that value is assigned using the value key. If it is a tag, such as [avoid], the content of the tag is added inside a [value] tag. For example:

[facet]
    engine=cpp
    id=custom_avoid
    name=standard_aspect
    [value]
        terrain=W*
    [/value]
[/facet]

That’s it for the most practical purposes, although there a few more parameters in the full aspect configuration:

[aspect]
    engine=cpp
    id=aggression
    invalidate_on_gamestate_change=no
    invalidate_on_minor_gamestate_change=no
    invalidate_on_tod_change=yes
    invalidate_on_turn_start=yes
    name=composite_aspect
    [facet]
        engine=cpp
        id=
        invalidate_on_gamestate_change=no
        invalidate_on_minor_gamestate_change=no
        invalidate_on_tod_change=yes
        invalidate_on_turn_start=yes
        name=standard_aspect
        time_of_day=dawn
        turns=
        value=0.765
    [/facet]
    [default]
        engine=cpp
        id=custom_aggression
        invalidate_on_gamestate_change=no
        invalidate_on_minor_gamestate_change=no
        invalidate_on_tod_change=yes
        invalidate_on_turn_start=yes
        name=standard_aspect
        time_of_day=dawn
        turns=
        value=0.4
    [/default]
[/aspect]

Thus, the full list of keys and tags inside the [aspect] tag is as follows:

  • engine=cpp: The engine processing the aspect. Most often this is 'cpp', which is also the default and can therefore be omitted, but it is also possible to define dynamic Lua aspects. These have the syntax shown below. (Note: engine=fai is not supported for aspects.)
  • id: This must be set to the aspect name (yes, name) shown at AiWML.
  • name=composite_aspect: As described above.
  • invalidate_on_turn_start="yes": (boolean) If "yes", the value of this aspect is invalidated at the start of each AI turn.
  • invalidate_on_tod_change="yes": (boolean) If "yes", the value of this aspect is invalidated when the absolute time of day bonus changes anywhere on the map. This implies invalidate_on_turn_start. (Version 1.13.5 and later only) Before 1.13.5, this was not implemented.
  • invalidate_on_gamestate_change="no": (boolean) If "yes", the value of this aspect is invalidated on each game state change (on turn start, move, attack, recruit, etc.). This implies invalidate_on_turn_start.
  • invalidate_on_minor_gamestate_change="no": (boolean) If "yes", the value of this aspect is invalidated on each minor game state change (on set unit variable, etc). This implies invalidate_on_gamestate_change. (Currently this is not implemented.)
  • code: (Lua engine only) If the aspect is defined dynamically in Lua, this key contains the Lua code to be executed. See below.
  • [facet] or [default]: These tags define the aspect values. [default] contains the default value assigned to the aspect at the start of the game. It cannot be modified or deleted. [facet] tags contain the custom values for the aspect and override the value from [default]. If there are several [facet] tags, the most recent one active at the current time of day and turn number is applied. The tags contain the following keys:
    • engine: Same as above, overrides the key with same name in the [aspect] tag
    • id: This has a different meaning from the [aspect] tag id key. It can be freely chosen and is only needed if you plan to modify or remove the aspect at a later time. If not, the id can be omitted. Not used in the [default] tag.
    • The different invalidation keys: They have the same meaning as those under the [aspect] tag, but apply only to this facet.
    • name: Possible values include 'standard_aspect' and 'composite_aspect', as described above. The engine chooses the correct value automatically, so you never have to worry about this unless you're doing something unusual.
    • time_of_day and turns: Define when the aspect is active. See here for details. Not valid in [default].
    • value or [value]: This, finally, is the actual value the facet returns. See the examples above for syntax.

All of this is admittedly a bit complex. This is done because there are a couple aspects which require all these keys and customization functionality. In the vast majority of cases, you do not have to worry about this and can simply use the standard aspect syntax of the first two examples.

Note: If unsure, the easiest way to see the full configuration for any given aspect (or any other AI component, in fact) is either in savefiles, or in-game by typing :inspect in debug mode and choosing 'ai config full' for a team.

Some more on the invalidation keys

A few of the aspects return a significant amount of information, as opposed to only a single value (such as aggression) or an array of locations (such as avoid). For example, the attacks aspect returns a list of possible attacks of the filtered attacker/target unit pairs, together with ratings for many different aspects of these attacks. This list, originally established at the beginning of the AI turn, is not valid any more after the first attack has been performed and needs to be reset. The AI does this by "invalidating" the aspect, after which the aspect information is calculated anew the next time the aspect is queried by a candidate action.

If you check out the default values of the invalidation keys, you see that, in the default configuration, information stored about aspects is reevaluated only at the beginning of each AI turn and when the time of day changes. It is not reevaluated by default after the game state changes (such as after an attack) during the AI turn. This works for most aspects, but not for the attacks aspect (and it might not be sufficient for all custom aspects either). This is the reason why invalidate_on_gamestate_change=yes needs to be set explicitly for the attacks aspect as shown here.

As a final comment, you can see at that link that the attacks aspect is also an exception in that its configuration and definition do not contain a value key or [value] tag, but [filter_own] and [filter_enemy] tags. If you look at the configuration in the inspector, you will also see that it has name=ai_default_rca::aspect_attacks instead of standard_aspect. In other words, the attacks aspect is never a standard aspect (though it can be a composite or (Version 1.13.5 and later only) Lua aspect).

Dynamic Lua Aspects

It is also possible to define aspects dynamically in Lua. In that case, no [default] and [facet] tags are added to the configuration. They are replaced by the code key used to define the aspect. For the second example given at the link above, the configuration looks like this:

[aspect]
    code=<<
        local value = wesnoth.current.turn / 10.
        return value
    >>
    engine=lua
    id=aggression
    invalidate_on_gamestate_change=no
    invalidate_on_minor_gamestate_change=no
    invalidate_on_tod_change=yes
    invalidate_on_turn_start=yes
    name=lua_aspect
[/aspect]

It's also possible to put all of that in a [facet] tag, rather than in an [aspect] tag – this would allow the Lua aspect to take effect only at certain times of day, for example.

The [ai] Tag — Goals

Goals are essentially a special type of aspect, in that they are used to customize the behavior of the default (RCA) AI. However as described here, the default goals are not stored in configuration files. Similarly, custom goals are stored in a different format in the AI configuration than the aspects. Fortunately, this format is the same as that used for defining custom goals. See the examples given there for syntax.

The [ai] Tag — Engines

As stated above, it is not necessary to define engines any more these days. Just for reference, we list the possible attributes of the [engine] tag here nevertheless.

  • id: (string) Optional id of the engine.
  • engine=cpp: (string) The type of engine used to parse this [engine] config snippet. This will always be cpp, since the lua and fai engines are not equipped for parsing [engine] tags.
  • name=cpp: (string) Name of the [engine]. Must be a valid engine name (cpp, lua, or fai).
  • code: If name=lua only. The Lua code to add to the engine. See the old method for setting up custom Lua CAs for details. It should generally return ... or similar - if it doesn't, other components using the Lua engine may not be able to function correctly.


See also: Wesnoth AI