Modifying AI Components

From The Battle for Wesnoth Wiki
Revision as of 16:44, 22 February 2016 by Mattsc (talk | contribs)
This page is currently under construction (Feb 2016)

Methods for Modifying the AI Mid Scenario

The AI and its parameters are usually set up at the beginning of a scenario and often left unchanged for the entire scenario. Sometimes it is, however, desirable to modify parts or all of the AI mid-scenario. For this purpose, Wesnoth provides the [modify_ai] tag and a large number of helper macros.

Using [modify_side] to Change Aspects Mid Scenario

The [modify_side] tag can contain [ai] tags to modify aspects while a game is in progress. This works, however, only for standard aspects, not composite aspects, and goals (is that true?). An example is

[modify_side]
    side=2
    [ai]
        aggression=0.999
    [/ai]
[/modify_side]

Composite aspects and all other AI components cannot be modified in this way. Use the [modify_ai] tag for these.

Note that modifying an aspect in this fashion does not replace the facet used to define the aspect in the aspect configuration. It simply adds another facet that then takes preference over the already existing ones. For most cases, this does not make a difference, but there might be some cases (for example when aspects are only defined at 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.


Using the [micro_ai] Tag to Add or Modify Micro AIs Mid Scenario

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. See Micro_AIs for details.


[modify_ai] Tag Overview

The [modify_ai] tag provides a method to modfiy stages, candidate actions, ascpects 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, but it is well worth spending a little time trying to understand how it works. If you do not want to bother with that, Wesnoth also provides a large variety of helper macros. These are described further below on this page.

Note that the [modify_ai] tag can be used both in [event] tags and in [side][ai] tags.

[modify_ai] Tag Syntax

The [modify_ai] tag has the following keys:

  • side: The side of the AI to be modified if used in an event. Not needed if used in [side][ai].
  • action (string): The action to take concerning the component. The following values are allowed:
    • add: Add a component.
    • change: Change an existing component.
    • delete: Delete an existing component.
    • try_delete: Delete a component if it exists. This does not produce a warning if [modify_ai] fails to change the AI.
  • path (string): Defines the component of the AI to be modified. More on this below.
  • value (key or tag): Defines the new value(s) of the component. See below for details

Possible values for [modify_ai]path

Depending on the AI component one wants to modify, the path key can take on different values:

  • aspect[aspect_id].facet[facet_id]
  • goal[goal_id]
  • stage[stage_id]
  • stage[CA_avaluation_loop_stage_id].candidate_action[CA_id]

Notes on the different ids:

  • aspect_id: name of the aspect, such as aggression
  • CA_avaluation_loop_stage_id: usually this will be main_loop, although it is in principle possible to assign a different id to this stage
  • CA_id: takes on the value described here
  • facet_id, goal_id and stage_id: these can take on a variety of different formats:
    • When adding one of these components, these ids are meaningless. In fact, they do not define the actual ids and can therefore simply be left empty. Instead, the ids are either assigned automatically or can be defined in the value key/tag of [modify_ai]. More on that below.
    • By contrast, when deleting or changing a component, these ids need to be given. The following values are possible:
      • A string identifying the id used when defining the component
      • An integer, starting at 0, defining the number of the aspect in the order in which they were set up
      • *: All components of this type

Possible values for [modify_ai]value

This depends on the type of component and needs to be in the same format as these are added to the AI configuration. A summary of these is given here. The syntax can also be seen using the in-game gamestate inspector dialog, by typing ':inspect' in debug mode and selecting 'ai config full'.

[Todo: not sure yet whether to add examples for all component types here, or simply to go with the examples below.]

If all this seemed a bit theoretical, don't worry. We provide many examples how to do this in practice below.


Modifying AI Components Helper Macros

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 list of available macros or the full definitions.

We do not describe the individual macros here. Instead, a variety of examples are given in the next section. If in doubt how to use a macro, check out its definition at the link above. That will also give you a template for the WML code if you do not want to use macros.

Modifying AI Component Examples

WARNING: Currently this is just a collection of code snippets from all over the place, so that they don't get lost. This will be organized and cleaned up shortly.’’’

In order to define aggression in the same way as above, we could use

[modify_ai]
    side=1
    action=add
    path=aspect[aggression].facet[]
    [facet]
        value=0.765
    [/facet]
[/modify_ai]

A large number of macros exist to facilitate the changing of aspects. For simple aspects such as the above, the following can be used instead:

{MODIFY_AI_ADD_SIMPLE_ASPECT 1 aggression 0.765}

This version of the aggression aspect can then be deleted using

[modify_ai]
    side=1
    action=delete  # or try_delete
    path=aspect[aggression].facet[0]
[/modify_ai]

or

{MODIFY_AI_DELETE_ASPECT 1 aggression 0}

if we know that it is the first non-default facet of the aggression aspect.

[modify_ai]
    side=1
    action=delete  # or try_delete
    path=aspect[aggression].facet[*]
[/modify_ai]

or

{MODIFY_AI_DELETE_ASPECT 1 aggression "*"}

deletes all user-defined aggression facets that might have been added. (Note that the aspect itself and its default facet cannot be deleted.) These two methods of deleting the facet also work if the value of aggression was simply set by using 'aggression=0.765' in the [ai] tag.

We can also use 'action=change' to delete an existing facet and overwrite it with a new definition. If '*' is used for facet_identifier, this deletes all existing facets of this aspect and replace them by a single facet with the new definition. [Note that adding a facet with the same id as an existing facet overwrites the previous occurrence, making that equivalent to changing the facet.]

[modify_ai]
    side=2
    action=add
    path=aspect[attacks].facet[]
    [facet]
        invalidate_on_gamestate_change=yes
        [filter_own]
            type=Elvish Sorceress,Elvish Enchantress,Elvish Sylph
        [/filter_own]
        [filter_enemy]
            race=undead
        [/filter_enemy]
    [/facet]
[/modify_ai]

Sometimes we might want to define several facets of the same aspect, but don't know in advance in which order they will be created. If we then only want to delete some of them selectively, we need to use facets with specific id's, such as

[modify_ai]
    side=1
    action=add
    path=aspect[aggression].facet[]
    [facet]
        id=aggression_dusk
        time_of_day=dusk
        value=0.765
    [/facet]
[/modify_ai]

This can also be done using macros

{MODIFY_AI_ADD_ASPECT 1 aggression (        
    [facet]
        id=aggression_dusk
        time_of_day=dusk
        value=0.765
    [/facet]
)}

This can be deleted by referencing that id

[modify_ai]
    side=1
    action=delete  # or try_delete
    path=aspect[aggression].facet[aggression_dusk]
[/modify_ai]

or

{MODIFY_AI_DELETE_ASPECT 1 aggression aggression_dusk}

A large number of other helper macros for AI modifications is available in data/core/macros/ai.cfg. An example of setting/changing a complex aspect using these macros is:

{MODIFY_AI_ADD_ASPECT 1 recruitment_instructions (
    [facet]
        [value]
            [recruit]
                type=2
                number=2
                total=yes
                importance=1
            [/recruit]
            [recruit]
                type=1
                importance=0
            [/recruit]
        [/value]
    [/facet]
)}

Note that here [value] is a tag not a key (value=) as in the examples used for 'aggression' above, since the content of the tag is more than a single number. If in doubt what syntax to use, go into the gamestate inspector but typing :inspect in-game and check out the [default] tag for the respective aspect under 'ai config full'.

{AI_SIMPLE_ALWAYS_ASPECT recruitment_pattern "fighter,fighter,archer,healer"}
{AI_SIMPLE_ALWAYS_ASPECT_VALUE aggression "0.7"}


Example:

{AI_SIMPLE_ALWAYS_ASPECT_VALUE avoid
(
    [not]
        x,y=20,16
        radius=6
    [/not]
)}
{MODIFY_AI_ADD_ASPECT 2 avoid (
    [facet]
        id="stay_in_own_land"
        [value]
            [not]
                x=20-24,19-30
                y=10,11
            [/not]
        [/value]
    [/facet]
)}


To modify goals from WML events, use these helper macros (don't forget to give your [goal]s unique ids):

 {MODIFY_AI_ADD_GOAL SIDE GOAL_CONFIG}
 {MODIFY_AI_DELETE_GOAL SIDE GOAL_ID}
 {MODIFY_AI_TRY_DELETE_GOAL SIDE GOAL_ID}


To work with this stage, we can either add or delete candidate actions. To do this, there are macroses, {MODIFY_AI_ADD_CANDIDATE_ACTION SIDE STAGE_ID CANDIDATE_ACTION} and {MODIFY_AI_DELETE_CANDIDATE_ACTION SIDE STAGE_ID CANDIDATE_ACTION_ID}. Internally, these are simple macroses which use the [modify_ai] tag. Those macroses can be used either in [side][ai] or in [event] - so, it is possible to modify the AI at any moment of the game, from a WML event handler.

Example: making the AI of side 2, which does not recruit (by removing recruitment-related candidate actions)

[side]
  side=2
  {ai/aliases/stable_singleplayer.cfg}
  [ai]
     {MODIFY_AI_DELETE_CANDIDATE_ACTION 2 main_loop recruitment}
     {MODIFY_AI_DELETE_CANDIDATE_ACTION 2 main_loop move_leader_to_keep}
  [/ai]
[/side]

Example: same things as above, but from an arbitrary [event] (this is recommended way to do things, since it's easier to test if it's in standalone event handler)

[side]
  side=2
  {ai/aliases/stable_singleplayer.cfg}
[/side]
[event]
  name=ai_2_stop_recruiting
  {MODIFY_AI_DELETE_CANDIDATE_ACTION 2 main_loop recruitment}
  {MODIFY_AI_DELETE_CANDIDATE_ACTION 2 main_loop move_leader_to_keep}
[/event]

Finally note that [modify_ai] in [side][ai] is activated when the AI is first initialized. It is guaranteed to happen before the AI acts for the first time, but otherwise it can happen at any time, for example, when the game is saved. So, for example, you might see the uninitialized version of the config (with unapplied [modify_ai] tags) if using ':inspect' right after the scenario start.