Difference between revisions of "Modifying AI Components"

From The Battle for Wesnoth Wiki
(Modifying AI Component Examples)
m (The [modify_ai] Tag)
 
(43 intermediate revisions by 2 users not shown)
Line 1: Line 1:
{| class="wikitable" style="text-align: center;"
+
== Methods for Modifying the AI Mid Scenario ==
|'''This page is currently under construction (Feb 2016)'''
 
|}
 
  
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.
+
The AI and its parameters are usually set up at the beginning of a scenario and often left unchanged for the entire scenario.  See [[AiWML]] and [[Creating Custom AIs]] for instructions on how to do this, or the complete list of AI resources at [[Wesnoth AI]].
  
== [modify_ai] Tag Overview ==
+
Sometimes it is, however, desirable to modify parts or all of the AI mid-scenario.  Wesnoth provides different tools to accomplish this:
 +
* Standard aspects can be modified mid scenario using the [modify_side] tag
 +
* Composite aspects, goals and all other AI components can be modified mid scenario using the [modify_ai] tag.
 +
** A large number of helper macros are available to facilitate these tasks.
 +
* Micro AIs can be modified mid scenario using the [micro_ai] tag
 +
** The [micro_ai] tag is always used in an event.  There is no difference between using it at the beginning of the scenario, that is, in a ''prestart'' or ''start'' event, or in any other event.  We therefore refer to the [[Micro AIs]] page for this.
  
The [modify_ai] tag provides a method to modfiy [[Wesnoth_AI_Framework#Stages|stages]], [[Wesnoth_AI_Framework#The_Candidate_Actions_of_the_main_loop_Stage|candidate actions]], [[Wesnoth_AI_Framework#Aspects_and_Goals|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]].
+
== Using [modify_side] to Change Aspects Mid Scenario ==
  
Note that the [modify_ai] tag can be used both in [event] tags and in [side][ai] tags.
+
The [modify_side] tag can contain an [ai] tag for modifying aspects while a game is in progress.  This works, however, <u>only</u> for [[Wesnoth_AI_Framework#The_.5Bai.5D_Tag_.E2.80.94_Aspects|standard aspects]].  An example is
 +
<syntaxhighlight lang='wml'>
 +
[modify_side]
 +
    side=2
 +
    [ai]
 +
        aggression=0.765
 +
    [/ai]
 +
[/modify_side]
 +
</syntaxhighlight>
  
 +
[[Wesnoth_AI_Framework#The_.5Bai.5D_Tag_.E2.80.94_Aspects|Composite aspects]] and all other [[Wesnoth_AI_Framework#Types_of_AI_Components|AI components]] cannot be modified in this way.  Use the [modify_ai] tag described below for these tasks.
  
== [modify_ai] Tag Syntax ==
+
Note that modifying an aspect in this fashion does not replace the [[Wesnoth_AI_Framework#The_.5Bai.5D_Tag_.E2.80.94_Aspects|facet]] used to define the aspect in the AI configuration.  It simply adds another facet that then takes precedence over the already existing ones.  In most situations, this does not make a difference, but there might be some cases (for example when facets are only defined for certain times of day or turns), when it might be necessary to replace the existing facet rather than adding a new one.  This can also be done using the [modify_ai] tag as described below.
  
The [modify_ai] tag has the following keys:
+
Note that it is, in principle, also possible to define the aspect using this syntax
 +
<syntaxhighlight lang='wml'>
 +
[modify_side]
 +
    side=2
 +
    [ai]
 +
        [aspect]
 +
            id=aggression
 +
            [facet]
 +
                value=0.765
 +
            [/facet]
 +
        [/aspect]
 +
  [/ai]
 +
[/modify_side]
 +
</syntaxhighlight>
 +
However, as this <u>only</u> works for standard aspects which can also be set with the simpler syntax shown above, there is really no point in doing so.
 +
 
 +
== The [modify_ai] Tag ==
 +
 
 +
The [modify_ai] tag is a tool for modifying [[Wesnoth_AI_Framework#Stages|stages]], [[Wesnoth_AI_Framework#The_Candidate_Actions_of_the_main_loop_Stage|candidate actions]], [[Wesnoth_AI_Framework#Aspects_and_Goals|aspects and goals]] of the active AI on the fly at any time during a scenario.  Since all this functionality is packed into a single tag, its syntax is a bit more complex than that of other tags.  To facilitate this, Wesnoth also provides a large variety of [[#Modifying_AI_Components_Helper_Macros|helper macros]], but even for using those one still needs to understand the general syntax of the [modify_ai] tag.
 +
 
 +
Note that the [modify_ai] tag can be used both in [event] tags and in [side][ai], [era][ai] or [modification][ai] tags, meaning it can also be used to change the AI configuration at game setup time.
 +
 
 +
=== [modify_ai] Tag Syntax ===
 +
 
 +
The [modify_ai] tag takes the following keys:
  
* '''side''': The side of the AI to be modified if used in an event.  Not needed if used in [side][ai].
+
* '''side''': The side of the AI to be modified if used in an event.  This key is not needed if used in [side][ai].  In fact, if given there, it is simply ignored.
 
** More generally, a [[StandardSideFilter]] can be used.
 
** More generally, a [[StandardSideFilter]] can be used.
* '''action''' (string): The action to take concerning the component.  The following values are allowed:
+
* '''action''': (string) The action to take concerning the component.  The following values are allowed:
** ''add'': Add a component.
+
** 'add': Add a component.
** ''change'': Change an existing component.
+
** 'change': Change an existing component.
** ''delete'': Delete 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.
+
** '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.
+
* '''path''': (string) Defines the component of the AI to be modified.  See below.
* '''value''' (key or tag): Defines the new value(s) of the component. See below for details
+
* '''New configuration''' for the component: This depends on the type of component and is shown in the examples below.
  
 
====Possible values for [modify_ai]path ====
 
====Possible values for [modify_ai]path ====
  
Depending on the AI component one wants to modify, the '''path''' key can take on different values:
+
Depending on the AI component one wants to modify, the '''path''' key can take on different values. The general form of a path is a series of elements separated by dots; each element consists of a component type followed by an ID in square brackets. In many cases, the path consists of only a single level (goals or stages) or two levels (aspect/facet and stage/CA), but {{DevFeature1.13|5}} three or even four levels is occasionally possible with aspects. Some examples:
  
* ''aspect[aspect_id].facet[facet_id]''
+
* Select facet 'quark' of the aggression (composite) aspect: <code>aspect[aggression].facet[quark]</code>
* ''goal[goal_id]''
+
* {{DevFeature1.13|5}} Select recruit job 'bobby' of the recruitment_instructions aspect defined as a standard aspect: <code>aspect[recruitment_instructions].recruit[bobby]</code>
* ''stage[stage_id]''
+
* {{DevFeature1.13|5}} Select the default facet of the (composite) village_value aspect: <code>aspect[village_value].facet[default_facet]</code>
* ''stage[CA_avaluation_loop_stage_id].candidate_action[CA_id]''
+
* Select goal 'lighthouse': <code>goal[lighthouse]</code>
 +
* Select the 'main_loop' stage: <code>stage[main_loop]</code>
 +
* Select candidate action 'healer_support' of the 'main_loop' stage: <code>stage[main_loop].candidate_action[healer_support]</code>
  
 
'''Notes on the different ids:'''
 
'''Notes on the different ids:'''
  
* ''aspect_id'': name of the aspect, such as <code>aggression</code>
+
* ''aspect_id'': name of the aspect, such as 'aggression'
* ''CA_avaluation_loop_stage_id'': usually this will be <code>main_loop</code>, although it is in principle possible to assign a different id to this stage
+
* ''CA_evaluation_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]]
+
* ''CA_id'': The id of the candidate action.  See [[RCA_AI#Available_Candidate_Actions|here]] for the ids of the default CAs.
 
* ''facet_id'', ''goal_id'' and ''stage_id'': these can take on a variety of different formats:
 
* ''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.
+
** 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 body of the component configuration.  More on that below.
 
** By contrast, when deleting or changing a component, these ids need to be given.  The following values are possible:
 
** 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
 
*** 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
+
*** An integer, starting at 0, defining the number of the component in the order in which they were defined
 
*** *: All components of this type
 
*** *: All components of this type
  
====Possible values for [modify_ai]value ====
+
If all this seemed a bit theoretical, don't worry.  Below, we provide many examples for how to do this in practice.
 +
 
 +
== 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 [http://www.wesnoth.org/macro-reference.xhtml#file:ai.cfg list] of available macros or the [https://github.com/wesnoth/wesnoth/blob/master/data/core/macros/ai.cfg full definitions].
 +
 
 +
'''Notes on the macros:'''
  
This depends on the type of component and needs to be in the same format as these are added to the AI configurationA summary of these is given [[RCA_AI#Default_AI_Configuration|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'.
+
* We do not describe the individual macros here.  There are way too many of them and, quite frankly, most of them are not really needed as they barely simplify the syntax compared to the full [modify_ai] tagInstead, a variety of examples are given in the following sectionsIf in doubt how to use a macro, or if you want to see all available macros, check out their definitions at the link above.
 +
* There are several macros with ''SIMPLE_ASPECT'' in the name.  Formally, there is no such things as a ''simple'' aspect, only ''standard'' and ''composite'' aspects.  This is just a convention used by the macros for standard aspects which consist of a single scalar value.  Thus, all simple aspects (such as ''aggression'') are standard aspects, but not all standard aspects (such as ''avoid'') are simple aspects.
 +
* There are several macros with ''ALWAYS_ASPECT'' in the name.  These are macros for aspects which apply at all times of day and at all turns.  However, the 'always' used as macro argument is actually the facet id, not the values of either the ''time_of_day'' or ''turns'' keys.  This is done so that the facet ids are standardized should removal of these aspects be desired later.
  
[Todo: not sure yet whether to add examples for all component types here, or simply to go with the examples below.]
+
== Modifying AI Component Examples ==
  
If all this seemed a bit theoretical, don't worry.  We provide many examples how to do this in practice [[below]].
+
=== Modifying Standard Aspects ===
  
 +
As was shown above, standard aspects, and <u>only</u> standard aspects, can be modified using [modify_side].  A simple example is
 +
<syntaxhighlight lang='wml'>
 +
[modify_side]
 +
    side=1
 +
    [ai]
 +
        aggression=0.765
 +
    [/ai]
 +
[/modify_side]
 +
</syntaxhighlight>
 +
This is the simplest syntax for modifying standard aspects (without using macros).  However, as we explain [[Wesnoth_AI_Framework#The_.5Bai.5D_Tag_.E2.80.94_Aspects|here]], internally <u>all</u> aspects are set up as composite aspects.  Thus, [modify_ai] and composite aspect syntax can also be used for simple aspects and we use this example to demonstrate this:
 +
<syntaxhighlight lang='wml'>
 +
[modify_ai]
 +
    side=1
 +
    action=add
 +
    path=aspect[aggression].facet[]
 +
    [facet]
 +
        value=0.765
 +
    [/facet]
 +
[/modify_ai]
 +
</syntaxhighlight>
 +
Finally, using one of the helper macros results in this:
 +
<syntaxhighlight lang='wml'>
 +
{MODIFY_AI_ADD_SIMPLE_ASPECT 1 aggression 0.765}
 +
</syntaxhighlight>
  
== Modifying AI Components Helper Macros ==
+
Removing this setting of the aggression aspect again is done as:
 +
<syntaxhighlight lang='wml'>
 +
[modify_ai]
 +
    side=1
 +
    action=delete  # or try_delete
 +
    path=aspect[aggression].facet[0]
 +
[/modify_ai]
 +
</syntaxhighlight>
 +
Assuming we know that it is the first non-default facet of the ''aggression'' aspect that needs to be removed.  If, instead, we want to remove all custom definitions of aggression, we use
 +
<syntaxhighlight lang='wml'>
 +
[modify_ai]
 +
    side=1
 +
    action=delete  # or try_delete
 +
    path=aspect[aggression].facet[*]
 +
[/modify_ai]
 +
</syntaxhighlight>
  
A large number of helper macros are available to simplify the WML needed for modifying AI components.  These macros are defined in file 'data/core/macros/ai.cfg', see the [http://www.wesnoth.org/macro-reference.xhtml#file:ai.cfg list] of available macros or the [https://github.com/wesnoth/wesnoth/blob/master/data/core/macros/ai.cfg full definitions].
+
Using macros, this is done with
 +
<syntaxhighlight lang='wml'>
 +
{MODIFY_AI_DELETE_ASPECT 1 aggression 0}
 +
</syntaxhighlight>
 +
and
 +
<syntaxhighlight lang='wml'>
 +
{MODIFY_AI_DELETE_ASPECT 1 aggression "*"}
 +
</syntaxhighlight>
  
We do not describe the individual macros here.  Instead, a variety of examples are given in the next sectionIf in doubt how to use a macro, check out its definition at the link aboveThat will also give you a template for the WML code if you do not want to use macros.
+
If we don't know the number of the facet and do not want to remove all of them, we need to assign an id to the facet defining the aspect (the simple syntax of the very first example cannot be used in that case) and use that id for selective removalFor example, the definition could look like this
 +
<syntaxhighlight lang='wml'>
 +
[modify_ai]
 +
    side=1
 +
    action=add
 +
    path=aspect[aggression].facet[]
 +
    [facet]
 +
        id=my_custom_aggression
 +
        value=0.765
 +
    [/facet]
 +
[/modify_ai]
 +
</syntaxhighlight>
 +
and removal like this
 +
<syntaxhighlight lang='wml'>
 +
[modify_ai]
 +
    side=1
 +
    action=delete # or try_delete
 +
    path=aspect[aggression].facet[my_custom_aggression]
 +
[/modify_ai]
 +
</syntaxhighlight>
  
== Modifying AI Component Examples ==
+
The macro versions of these are
 +
<syntaxhighlight lang='wml'>
 +
{MODIFY_AI_ADD_ASPECT 1 aggression (       
 +
    [facet]
 +
        id=my_custom_aggression
 +
        value=0.765
 +
    [/facet]
 +
)}
 +
</syntaxhighlight>
 +
and
 +
<syntaxhighlight lang='wml'>
 +
{MODIFY_AI_DELETE_ASPECT 1 aggression my_custom_aggression}
 +
</syntaxhighlight>
  
'''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.’’’
+
Finally, we stress that a ''standard'' aspect does not need to be restricted to a single, scalar value.  For example, ''avoid'' is a standard aspect and can be defined using both types of syntax, such as
 +
<syntaxhighlight lang='wml'>
 +
[modify_side]
 +
    side=1
 +
    [ai]
 +
        [avoid]
 +
            x,y=20,16
 +
            radius=6
 +
        [/avoid]
 +
    [/ai]
 +
[/modify_side]
 +
</syntaxhighlight>
 +
or
 +
<syntaxhighlight lang='wml'>
 +
[modify_ai]
 +
    side=1
 +
    action=add
 +
    path=aspect[avoid].facet[]
 +
    [facet]
 +
        [value]
 +
            x,y=20,16
 +
            radius=6
 +
        [/value]
 +
    [/facet]
 +
[/modify_ai]
 +
</syntaxhighlight>
 +
Finale note: Any aspect listed at [[AiWML]] which is not specifically pointed out to be a composite aspect (and there are very few of those), is a standard aspect.
  
 +
=== Modifying Composite Aspects ===
  
  {AI_SIMPLE_ALWAYS_ASPECT recruitment_pattern "fighter,fighter,archer,healer"}
+
A small number of the aspects listed at [[AiWML]] are available in ''composite'' aspect syntax only. However, there is really nothing new about modifying them compared to what is shown above for ''standard'' aspects.  The only difference (as far as modifying the aspects is concerned) is that we <u>have to</u> use composite aspect syntax, standard aspect syntax does not work.  Thus, we only show one example of the [[AiWML#Filtering_Combat_with_the_attacks_Aspect|''attacks'' aspect]] here.
{AI_SIMPLE_ALWAYS_ASPECT_VALUE aggression "0.7"}
+
<syntaxhighlight lang='wml'>
 +
[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]
 +
</syntaxhighlight>
  
 +
=== A Few More Notes on Modifying Aspects ===
  
''Example:''
+
* The aspect itself and its [[Wesnoth_AI_Framework#The_.5Bai.5D_Tag_.E2.80.94_Aspects|[default]]] facet cannot be deleted, only the custom facets. {{DevFeature1.13|5}} However, they can be changed, replacing them with a new definition. (The id attribute must match when changing an aspect.) This could change a standard aspect to a composite aspect or vice versa.
  {AI_SIMPLE_ALWAYS_ASPECT_VALUE avoid
+
* For standard aspects, it is generally not necessary to delete custom facets. One can simply overwrite the current value with a new one. The only times when one might have to remove a standard aspect is when it is defined for specific times of day or turns, or when it is defined so many times that it might bloat the AI configuration (and therefore the savefile).
  (
+
* We can also use <code>action=change</code> to delete an existing facet and overwrite it with a new definition.  If <code>*</code> is used as ''facet_id'', this deletes all existing facets of this aspect and replaces them with a single facet with the new definition.
    [not]
+
* Adding a facet with the same ''id'' as an existing facet overwrites the previous occurrence, making this equivalent to changing that facet.
        x,y=20,16
+
* If in doubt about the exact syntax of a given aspect, one can always open the gamestate inspector (by typing <code>:inspect</code> in-game in debug mode) and check out the [default] tag of the respective aspect under 'ai config full' for a given side (team). Note though that it might be necessary to play through at least one partial turn of that side, as the AI config of the side is not necessarily fully initialized until that happens.
        radius=6
 
    [/not]
 
  )}
 
  
{MODIFY_AI_ADD_ASPECT 2 avoid (
+
=== Modifying Goals ===
    [facet]
 
        id="stay_in_own_land"
 
        [value]
 
            [not]
 
                x=20-24,19-30
 
                y=10,11
 
            [/not]
 
        [/value]
 
    [/facet]
 
)}
 
  
 +
Goals can be added and removed using a syntax that is very similar to that for composite aspects
 +
<syntaxhighlight lang='wml'>
 +
[modify_ai]
 +
    side=1
 +
    action=add
 +
    path=goal[]
 +
    [goal]
 +
        id=my_custom_goal
 +
        [criteria]
 +
            side=3
 +
        [/criteria]
 +
        value=5
 +
    [/goal]
 +
[/modify_ai]
 +
</syntaxhighlight>
 +
and
 +
<syntaxhighlight lang='wml'>
 +
[modify_ai]
 +
    side=1
 +
    action=delete
 +
    path=goal[my_custom_goal]
 +
[/modify_ai]
 +
</syntaxhighlight>
 +
Note that we assigned a custom id to the goal here, that was then used for removal.  We could also use the method described above for aspects, using the number of the goal or <code>*</code>.
  
To modify goals from WML events, use these helper macros (don't forget to give your [goal]s unique ids):
+
The macro versions of these examples are
  {MODIFY_AI_ADD_GOAL SIDE GOAL_CONFIG}
+
<syntaxhighlight lang='wml'>
  {MODIFY_AI_DELETE_GOAL SIDE GOAL_ID}
+
{MODIFY_AI_ADD_GOAL 1 (
  {MODIFY_AI_TRY_DELETE_GOAL SIDE GOAL_ID}
+
    [goal]
 +
        id=my_custom_goal
 +
        [criteria]
 +
            side=3
 +
        [/criteria]
 +
        value=5
 +
    [/goal]
 +
)}
 +
</syntaxhighlight>
 +
and
 +
<syntaxhighlight lang='wml'>
 +
{MODIFY_AI_DELETE_GOAL 1 my_custom_goal}
 +
</syntaxhighlight>
  
 +
=== Modifying Candidate Action of the ''main_loop'' Stage ===
  
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.
+
The syntax for modifying candidate actions is entirely equivalent to that for aspects and goals shown above. If one wants to, for example, set up an AI that does not fight, this can be done by removing the ''combat'' CA.  {{DevFeature1.15|3}} There are now additional CAs which also perform attacks. Check out [[RCA_AI#The_Candidate_Actions_.28CAs.29_of_the_main_loop_Stage_in_the_RCA_AI|the candidate actions of the default AI]] to see which CAs need to be remove in order to produce an AI that truly does not attack.
 +
<syntaxhighlight lang='wml'>
 +
[modify_ai]
 +
    side=2
 +
    action=delete
 +
    path=stage[main_loop].candidate_action[combat]
 +
[/modify_ai]
 +
</syntaxhighlight>
 +
or
 +
<syntaxhighlight lang='wml'>
 +
{MODIFY_AI_DELETE_CANDIDATE_ACTION 2 main_loop combat}
 +
</syntaxhighlight>
  
Example: making the AI of side 2, which does not recruit (by removing recruitment-related candidate actions)
+
Adding a [[Creating_Custom_AIs#Creating_Custom_Candidate_Actions|custom Lua candidate action]] is done as follows
 +
<syntaxhighlight lang='wml'>
 +
[modify_ai]
 +
    side=1
 +
    action=add
 +
    path=stage[main_loop].candidate_action[]
 +
    [candidate_action]
 +
        engine=lua
 +
        name=return_guardian_bob
 +
        id=return_guardian_bob
 +
        max_score=100010
 +
        location="~add-ons/my_addon/lua/return_guardian.lua"
 +
        eval_parms="id = 'Bob', return_x = 10, return_y = 15"
 +
        exec_parms="id = 'Bob', return_x = 10, return_y = 15"
 +
    [/candidate_action]
 +
[/modify_ai]
 +
</syntaxhighlight>
  
[side]
+
We'll omit the macro version here as it is almost identical to previous examples.
  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)
+
=== Modifying Stages ===
[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]
 
  
 +
Working with a single stage, the [[Wesnoth_AI_Framework#Stages|''main_loop'' stage]], should be sufficient for essentially all Wesnoth AI projects these days.  It should therefore rarely ever be necessary to add or remove stages any more.  It can, however, be done in the same way as for the other AI components.  The macro definitions linked to above can be used as syntax reference if you ever need to do so.
  
  
 +
'''See also:''' [[Wesnoth AI]]
 
[[Category:AI]]
 
[[Category:AI]]

Latest revision as of 15:59, 13 July 2023

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. See AiWML and Creating Custom AIs for instructions on how to do this, or the complete list of AI resources at Wesnoth AI.

Sometimes it is, however, desirable to modify parts or all of the AI mid-scenario. Wesnoth provides different tools to accomplish this:

  • Standard aspects can be modified mid scenario using the [modify_side] tag
  • Composite aspects, goals and all other AI components can be modified mid scenario using the [modify_ai] tag.
    • A large number of helper macros are available to facilitate these tasks.
  • Micro AIs can be modified mid scenario using the [micro_ai] tag
    • The [micro_ai] tag is always used in an event. There is no difference between using it at the beginning of the scenario, that is, in a prestart or start event, or in any other event. We therefore refer to the Micro AIs page for this.

Using [modify_side] to Change Aspects Mid Scenario

The [modify_side] tag can contain an [ai] tag for modifying aspects while a game is in progress. This works, however, only for standard aspects. An example is

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

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

Note that modifying an aspect in this fashion does not replace the facet used to define the aspect in the AI configuration. It simply adds another facet that then takes precedence over the already existing ones. In most situations, this does not make a difference, but there might be some cases (for example when facets are only defined for certain times of day or turns), when it might be necessary to replace the existing facet rather than adding a new one. This can also be done using the [modify_ai] tag as described below.

Note that it is, in principle, also possible to define the aspect using this syntax

[modify_side]
    side=2
    [ai]
        [aspect]
            id=aggression
            [facet]
                value=0.765
            [/facet]
        [/aspect]
   [/ai]
[/modify_side]

However, as this only works for standard aspects which can also be set with the simpler syntax shown above, there is really no point in doing so.

The [modify_ai] Tag

The [modify_ai] tag is a tool for modifying stages, candidate actions, aspects and goals of the active AI on the fly at any time during a scenario. Since all this functionality is packed into a single tag, its syntax is a bit more complex than that of other tags. To facilitate this, Wesnoth also provides a large variety of helper macros, but even for using those one still needs to understand the general syntax of the [modify_ai] tag.

Note that the [modify_ai] tag can be used both in [event] tags and in [side][ai], [era][ai] or [modification][ai] tags, meaning it can also be used to change the AI configuration at game setup time.

[modify_ai] Tag Syntax

The [modify_ai] tag takes the following keys:

  • side: The side of the AI to be modified if used in an event. This key is not needed if used in [side][ai]. In fact, if given there, it is simply ignored.
  • 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. See below.
  • New configuration for the component: This depends on the type of component and is shown in the examples below.

Possible values for [modify_ai]path

Depending on the AI component one wants to modify, the path key can take on different values. The general form of a path is a series of elements separated by dots; each element consists of a component type followed by an ID in square brackets. In many cases, the path consists of only a single level (goals or stages) or two levels (aspect/facet and stage/CA), but (Version 1.13.5 and later only) three or even four levels is occasionally possible with aspects. Some examples:

  • Select facet 'quark' of the aggression (composite) aspect: aspect[aggression].facet[quark]
  • (Version 1.13.5 and later only) Select recruit job 'bobby' of the recruitment_instructions aspect defined as a standard aspect: aspect[recruitment_instructions].recruit[bobby]
  • (Version 1.13.5 and later only) Select the default facet of the (composite) village_value aspect: aspect[village_value].facet[default_facet]
  • Select goal 'lighthouse': goal[lighthouse]
  • Select the 'main_loop' stage: stage[main_loop]
  • Select candidate action 'healer_support' of the 'main_loop' stage: stage[main_loop].candidate_action[healer_support]

Notes on the different ids:

  • aspect_id: name of the aspect, such as 'aggression'
  • CA_evaluation_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: The id of the candidate action. See here for the ids of the default CAs.
  • 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 body of the component configuration. 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 component in the order in which they were defined
      • *: All components of this type

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

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.

Notes on the macros:

  • We do not describe the individual macros here. There are way too many of them and, quite frankly, most of them are not really needed as they barely simplify the syntax compared to the full [modify_ai] tag. Instead, a variety of examples are given in the following sections. If in doubt how to use a macro, or if you want to see all available macros, check out their definitions at the link above.
  • There are several macros with SIMPLE_ASPECT in the name. Formally, there is no such things as a simple aspect, only standard and composite aspects. This is just a convention used by the macros for standard aspects which consist of a single scalar value. Thus, all simple aspects (such as aggression) are standard aspects, but not all standard aspects (such as avoid) are simple aspects.
  • There are several macros with ALWAYS_ASPECT in the name. These are macros for aspects which apply at all times of day and at all turns. However, the 'always' used as macro argument is actually the facet id, not the values of either the time_of_day or turns keys. This is done so that the facet ids are standardized should removal of these aspects be desired later.

Modifying AI Component Examples

Modifying Standard Aspects

As was shown above, standard aspects, and only standard aspects, can be modified using [modify_side]. A simple example is

[modify_side]
    side=1
    [ai]
        aggression=0.765
    [/ai]
[/modify_side]

This is the simplest syntax for modifying standard aspects (without using macros). However, as we explain here, internally all aspects are set up as composite aspects. Thus, [modify_ai] and composite aspect syntax can also be used for simple aspects and we use this example to demonstrate this:

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

Finally, using one of the helper macros results in this:

{MODIFY_AI_ADD_SIMPLE_ASPECT 1 aggression 0.765}

Removing this setting of the aggression aspect again is done as:

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

Assuming we know that it is the first non-default facet of the aggression aspect that needs to be removed. If, instead, we want to remove all custom definitions of aggression, we use

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

Using macros, this is done with

{MODIFY_AI_DELETE_ASPECT 1 aggression 0}

and

{MODIFY_AI_DELETE_ASPECT 1 aggression "*"}

If we don't know the number of the facet and do not want to remove all of them, we need to assign an id to the facet defining the aspect (the simple syntax of the very first example cannot be used in that case) and use that id for selective removal. For example, the definition could look like this

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

and removal like this

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

The macro versions of these are

{MODIFY_AI_ADD_ASPECT 1 aggression (        
    [facet]
        id=my_custom_aggression
        value=0.765
    [/facet]
)}

and

{MODIFY_AI_DELETE_ASPECT 1 aggression my_custom_aggression}

Finally, we stress that a standard aspect does not need to be restricted to a single, scalar value. For example, avoid is a standard aspect and can be defined using both types of syntax, such as

[modify_side]
    side=1
    [ai]
        [avoid]
            x,y=20,16
            radius=6
        [/avoid]
    [/ai]
[/modify_side]

or

[modify_ai]
    side=1
    action=add
    path=aspect[avoid].facet[]
    [facet]
        [value]
            x,y=20,16
            radius=6
        [/value]
    [/facet]
[/modify_ai]

Finale note: Any aspect listed at AiWML which is not specifically pointed out to be a composite aspect (and there are very few of those), is a standard aspect.

Modifying Composite Aspects

A small number of the aspects listed at AiWML are available in composite aspect syntax only. However, there is really nothing new about modifying them compared to what is shown above for standard aspects. The only difference (as far as modifying the aspects is concerned) is that we have to use composite aspect syntax, standard aspect syntax does not work. Thus, we only show one example of the attacks aspect here.

[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]

A Few More Notes on Modifying Aspects

  • The aspect itself and its [default] facet cannot be deleted, only the custom facets. (Version 1.13.5 and later only) However, they can be changed, replacing them with a new definition. (The id attribute must match when changing an aspect.) This could change a standard aspect to a composite aspect or vice versa.
  • For standard aspects, it is generally not necessary to delete custom facets. One can simply overwrite the current value with a new one. The only times when one might have to remove a standard aspect is when it is defined for specific times of day or turns, or when it is defined so many times that it might bloat the AI configuration (and therefore the savefile).
  • We can also use action=change to delete an existing facet and overwrite it with a new definition. If * is used as facet_id, this deletes all existing facets of this aspect and replaces them with a single facet with the new definition.
  • Adding a facet with the same id as an existing facet overwrites the previous occurrence, making this equivalent to changing that facet.
  • If in doubt about the exact syntax of a given aspect, one can always open the gamestate inspector (by typing :inspect in-game in debug mode) and check out the [default] tag of the respective aspect under 'ai config full' for a given side (team). Note though that it might be necessary to play through at least one partial turn of that side, as the AI config of the side is not necessarily fully initialized until that happens.

Modifying Goals

Goals can be added and removed using a syntax that is very similar to that for composite aspects

[modify_ai]
    side=1
    action=add
    path=goal[]
    [goal]
        id=my_custom_goal
        [criteria]
            side=3
        [/criteria]
        value=5
    [/goal]
[/modify_ai]

and

[modify_ai]
    side=1
    action=delete
    path=goal[my_custom_goal]
[/modify_ai]

Note that we assigned a custom id to the goal here, that was then used for removal. We could also use the method described above for aspects, using the number of the goal or *.

The macro versions of these examples are

{MODIFY_AI_ADD_GOAL 1 (
    [goal]
        id=my_custom_goal
        [criteria]
            side=3
        [/criteria]
        value=5
    [/goal]
)}

and

{MODIFY_AI_DELETE_GOAL 1 my_custom_goal}

Modifying Candidate Action of the main_loop Stage

The syntax for modifying candidate actions is entirely equivalent to that for aspects and goals shown above. If one wants to, for example, set up an AI that does not fight, this can be done by removing the combat CA. (Version 1.15.3 and later only) There are now additional CAs which also perform attacks. Check out the candidate actions of the default AI to see which CAs need to be remove in order to produce an AI that truly does not attack.

[modify_ai]
    side=2
    action=delete
    path=stage[main_loop].candidate_action[combat]
[/modify_ai]

or

{MODIFY_AI_DELETE_CANDIDATE_ACTION 2 main_loop combat}

Adding a custom Lua candidate action is done as follows

[modify_ai]
    side=1
    action=add
    path=stage[main_loop].candidate_action[]
    [candidate_action]
        engine=lua
        name=return_guardian_bob
        id=return_guardian_bob
        max_score=100010
        location="~add-ons/my_addon/lua/return_guardian.lua"
        eval_parms="id = 'Bob', return_x = 10, return_y = 15"
        exec_parms="id = 'Bob', return_x = 10, return_y = 15"
    [/candidate_action]
[/modify_ai]

We'll omit the macro version here as it is almost identical to previous examples.

Modifying Stages

Working with a single stage, the main_loop stage, should be sufficient for essentially all Wesnoth AI projects these days. It should therefore rarely ever be necessary to add or remove stages any more. It can, however, be done in the same way as for the other AI components. The macro definitions linked to above can be used as syntax reference if you ever need to do so.


See also: Wesnoth AI

This page was last edited on 13 July 2023, at 15:59.