Difference between revisions of "AiWML"

From The Battle for Wesnoth Wiki
(Continued updating of page to RCA AI specs)
(Filtering Combat with the attacks Aspect: make "See Also" its own section)
 
(132 intermediate revisions by 10 users not shown)
Line 1: Line 1:
 
{{WML Tags}}
 
{{WML Tags}}
  
As of BfW 1.9, the default AI is the RCA AI, which stands for Register Candidate Action AI.  During the AI turn, the RCA AI evaluates a number of potential actions (called candidate actions) for each move.  The candidate action with the highest evaluation score is executed.  Then the next move is evaluated, until no more valid moves are found, which ends the AI turn.
+
== Customizing the Default AI Using WML ==
  
The RCA AI is highly configurable in three different ways (sorted by increasing complexity):
+
This page describes how the behavior of the default (RCA) AI can be customized using simple WML commands.  The descriptions below assume a basic understanding of how the RCA AI evaluates moves, what '''candidate actions''', '''aspects''' and '''goals''' are, and how they interact.  If you do not know these things yet, check out the [[RCA AI]] page.
  
* Changing the parameters/weights by which the AI moves (candidate actions) are evaluated.  This can be done easily in the WML code by setting [[AiWML#Aspects_and_Goals|aspects and goals]] and is the content of this page.
+
This page contains:
 +
* Descriptions of the aspects and goals of the default AI
 +
* Instructions for setting them up at the beginning of the scenario in a [side] tag
  
* Changing the order in which candidate actions are executed (changing their evaluation scores) or deleting candidate actions. See [[Practical Guide to Modifying AI Behavior]] for details.
+
This page does '''not''' contain:
 +
* Instructions for [[LuaAI#Dynamic_Lua_Aspects|setting up aspects dynamically using Lua]].
 +
* Instructions for [[Modifying_AI_Components#Modifying_Standard_Aspects|changing aspects and goals mid scenario]], although for many of them (for example, for all [[Wesnoth_AI_Framework#The_.5Bai.5D_Tag_.E2.80.94_Aspects|standard aspects]]) the methods are almost identical
 +
* Instructions for some of the [[Modifying_AI_Components|more complex AI customization tasks]].
 +
* Anything about [[Micro_AIs|MicroAIs]]
 +
* [[AI_Recruitment|Advanced recruitment details]]
  
* Writing your own candidate actions using [[FormulaAI]] or [[LuaAI]].  See [[Practical Guide to Modifying AI Behavior]] for details.
+
== Defining Aspects and Goals of the RCA AI ==
  
'''Notes on available AIs:'''
+
[[RCA_AI#Use_of_Aspects_in_the_RCA_AI|Aspects]] and [[RCA_AI#Use_of_Goals_and_Targets_in_the_RCA_AI|goals]] of the [[RCA_AI|default (RCA) AI]] can be defined at the beginning of a scenario with [ai] tags inside the [side] tags.  They are used to customize certain aspects of the AI.  The [ai] tag, when used for this purpose, takes the [[#List_of_AI_Aspects|aspects themselves]] as arguments, as well as the following general keys:
* The default AI used through BfW 1.8 was named 'Default AI' (note the capital D)This might cause confusion, as the current default AI (RCA AI) is not the Default AI.
+
* '''time_of_day''': (string) The time(s) of day when the AI should use the parameters given in this [ai] tag. Possible values are listed in [https://github.com/wesnoth/wesnoth/blob/master/data/core/macros/schedules.cfg data/core/macros/schedules.cfg] (see also [[TimeWML]]).  Note that it is the ''id'' (not the ''name'') of the time of day that needs to be used here.  Also note that this aspect did not work for a long time due to a bug (versions 1.7.4 - 1.11.6).  It has been fixed for BfW 1.11.7.
* Besides the RCA AI, the only other AI available in the core distribution is the ''idle_ai'', which does nothing at all (see ''ai_algorithm'' [[AiWML#The_.5Bai.5D_Tag:_Defining_Aspects|below]]).   
 
* The [[General_RCA_AI_Howto#Available_Stages|fallback stage]], which used to fall back to the old Default AI, falls back to the RCA AI now.
 
  
 +
* '''turns''': (string) During which turns the AI should use the parameters given in this [ai] tag. This takes the same syntax of dashes (-) and commas (,) as is described under Filtering Locations in [[FilterWML]], except of course they apply to turns not locations.
  
== Evaluating AI Moves -- Candidate Actions (CAs)  ==
+
* '''ai_algorithm''': (string) Allows an alternate AI algorithm (cannot be created with WML) to be used. Besides the default, the game only comes with ''idle_ai'', which makes the AI do nothing and can be used to create a passive, unmoving side. Cannot be applied only to a set of turns or a given time of day using the keys ''turns'' and ''time_of_day'', but must be given either in an [ai] tag without the aforementioned keys or in the [side] tag outside all [ai] tags. {{DevFeature1.13|5}} In 1.13, the meaning of '''ai_algorithm''' has changed and no longer selects a native AI that's built into the engine, as the RCA AI has now become the core system and no alternatives exist anymore. Instead, it selects a predefined ''[ai]'' definition, such as those defined in ''data/ai/ais''. Since these are defined in WML, you can easily build your own.
 
 
When the AI does its turn, a number of potential actions (called candidate actions, CAs) are evaluated for each move. The CA with the highest evaluation score is executed. Then the next move is evaluated, until no more valid moves are found, which ends the AI turn.  The following candidate actions are evaluated for each move:
 
 
 
*'''Goto''' CA: Move units toward the coordinates set by [[SingleUnitWML|goto_x and goto_y]] in their unit WML.
 
 
 
*'''Recruitment''' CA: Recruit or recall units.
 
 
 
*'''Move leader to goals''' CA: Move the leader to goals set by [[AiWML#the_.5Bai.5D_tag|[leader_goal]]].
 
 
 
*'''Move leader to keep''' CA: Move the leader to the closest available keep.
 
 
 
*'''Combat''' CA: Attack enemy units that are in range.  Note that this CA includes the move to a hex adjacent to the enemy unit as well as the attack itself.
 
 
 
*'''Healing''' CA: Move units onto healing locations (generally villages).
 
 
 
*'''Villages''' CA: Move units onto villages that are unoccupied or owned by an enemy.
 
 
 
*'''Retreat''' CA: Evaluate if any units are in grave danger/hopelessly outnumbered, and if so, retreat them.
 
 
 
*'''Move to targets''' CA: Evaluate potential targets and move units toward those targets.  The evaluation takes into account how valuable the targets are (this is configurable by setting [[AiWML#Aspects_and_Goals|goals]]) and how easily the AI's units can get there.  Targets are enemy units, villages as well as anything defined as a goal. It is important to understand that targets only apply to the move-to-targets CA.  If the AI's unit(s) can get to a target, other CAs, such as Combat, Healing and Villages have a higher evaluation score and are executed first.  Thus, a target is specifically ''not'' an attack target, but only a move target.
 
 
 
*'''Passive leader shares keep''' CA: Move the leader off the keep to let an allied leader recruit.
 
 
 
If several candidate actions are possible for the next move, they are executed in the order given above.  The Goto CA is always the first thing that is done.  If a valid attack is found in the Combat CA, it is ''always'' executed before any healing, village grabbing or move-to-target moves.  One of the effects this has is that attacks always have priority over any goals/targets of the move-to-target phase.
 
 
 
== Aspects and Goals ==
 
 
 
'Aspects' are configurable parameters used in the candidate action score evaluation.  Most commonly, aspects are set using the [[AiWML#the_.5Bai.5D_tag|[ai] tag]] as described below. There are simple aspects which take on an individual value, and composite aspects that might contain several keys or sub-tags.  The sub-tags of aspects are called 'facets'.
 
 
 
'Goals', also called 'targets', are composite aspects that influence the behavior of the AI in the move-to-targets candidate action.  As there a several different goals available, they are given [[AiWML#AI_Targets_and_Goals|their own subsection]] below.
 
 
 
== The [ai] Tag: Defining Aspects ==
 
 
 
The [ai] tag is used inside a [side] or [modify_side] tag.  Its contents are the AI [[AiWML#Aspects_and_Goals|aspects]] and define how the AI controlling that side acts. You can use multiple [ai] tags and have them apply during different turns or times of day, for example to set an undead side's caution higher and aggression lower during the day, or to boost the aggressiveness of a side when they receive reinforcements on a specific turn.
 
 
 
The following key/tags can be used in an '''[ai]''' tag:
 
* '''time_of_day''': (string) The time(s) of day when the AI should use the parameters given in this [ai] tag. Possible values are listed in data/core/macros/schedules.cfg (See [[TimeWML]]).
 
  
* '''turns''': (string) During which turns the AI should use the parameters given in this [ai] tag. This takes the same syntax of dashes (-) and commas (,) as is described under Filtering Locations in [[FilterWML]], except of course they apply to turns not locations.
+
An example of a simple use of the [ai] tag to set AI parameters (aspects) is
  
* '''ai_algorithm''': (string) Allows an alternate AI algorithm (cannot be created with WML) to be used. Besides the default, the game only comes with ''idle_ai'', which makes the AI do nothing and can be used to create a passive, unmoving side. Cannot be applied only to a set of turns or a given time of day using the keys ''turns'' and ''time_of_day'', but must be given either in an [ai] tag without the aforementioned keys or outside [ai] tags inside the [side] tag.
+
<syntaxhighlight lang=wml>
 +
[ai]
 +
    time_of_day=dusk
 +
    aggression=0.99
 +
    caution=0.01
 +
    [avoid]
 +
        [filter]
 +
            side=2,3
 +
        [/filter]
 +
        radius=2
 +
    [/avoid]
 +
[/ai]
 +
</syntaxhighlight>
  
* '''aggression'''=0.4: (double) (value ranging from -infinity to 1.0) This key affects how an AI side fights.  Applies to combat CA only.
 
** In the following formulas of type ''X - Y = Z'', X is always 1 and Z is the value that aggression should be set to: aggression=Z.
 
** It determines how an AI considers the difference between its units and its opponents by taking the value ''1 - AI unit value in proportion to opponent unit value''.  ('Unit value' here means that the AI weights its decision on the chance to kill  a unit or be killed, using a combination of its own units.)  So, to make an AI which considers its units worthless, i.e. only cares about how much damage attacks inflict, set aggression at ''1 - 0 = 1.0''.  This is the highest meaningful value for aggression; although it is insane, it is used on many HttT levels.  If an AI set on this value can inflict 1 damage and take 0, or inflict 2 damage and take 20 himself, he'll take the latter option.  To make an AI which considers its units equally as valuable as its opponent's, i.e. only attacks if he feels he can inflict more damage than he receives, set aggression at ''1 - 1 = 0.0''.
 
** Although an AI which considers its opponent's units worthless is impossible under this scheme, an AI which, for example, considers its units twice as valuable as its opponent's can be represented by aggression ''1 - 2 = -1.0''.
 
** The default is ''1 - 1/2 = 0.5'', which means the AI is content with dealing only half the damage to his opponent of that which he himself takes.
 
** Or to put this whole thing into context, aggression=1.0. means it deals the maximum possible damage, aggression=-10000000000000000.0. means it never attacks unless it will receive no damage in exchange.
 
  
*'''[attacks]'''="": To be added.
+
'''Important Note:''' If you use a different AI engine ([[FormulaAI]] or [[LuaAI]]) for a side, setting aspects in the [side] tag might not work due to a bug in the AI setup mechanism (or it might; there's no general rule that catches all cases).  In that case, you might have to use [modify_side][ai] in a ''prestart'' or ''start'' event instead.  If unsure, you can use <code>:inspect</code> in debug mode to verify whether an aspect was changed successfully.
  
* '''[avoid]'''="": Makes the AI avoid specific locations.  The AI never moves a unit to these locations except for trying to move its leader to a keep or toward [leader_goal]s.  Applies to all CAs that involve moving units, except move-leader-to-goals and move-leader-to-keep.
+
==List of AI Aspects==
** '''[[StandardLocationFilter]]''': The locations for the AI to avoid moving to.  Don't use a [filter_location] tag.
 
  
* '''caution'''=0.25: (double) A number 0.0 or higher that affects how cautious the AI is in various ways. If it is higher, the AI wants to retreat more (especially to a better defensive terrain), it dislikes moving out of a defensive terrain to attack more, and, if grouping is enabled, it forms bigger groups to protect from enemies when going to a target.  Applies to most CAs.
+
'''Note:''' Only one instance of each aspect will be active for a side at any time. Where multiple instances of the same aspect are included in an [ai] tag, the last whose conditions (time of day, turns, etc.) match will be the only one that applies.
** Considering a retreat to be skipped (during the retreat phase) if caution is set to 0 or lower. If caution is greater than 0, there is an evaluation of forces for the map location a unit stands on. This is basically the sum of damage that can be done to that location, reduced by terrain defense and relative hitpoints if attackers don't have full health. A retreat takes place, if<br>caution * their_power > our_power<br>There is also a terrain factor involved if the attacker is not on optimal terrain, but i'll skip this here for simplicity.<br>So let's say the AI has its default caution of 0.25. Then the enemy forces have to be 4 times as strong at least before the unit retreats. For a caution of 1, as soon as the enemy is considered to be stronger, the unit retreats.
 
** Caution is also considered within the attack analysis to evaluate the rating of attacks. The mathematics for that is rather complicated, so let's just state that the caution value directly and proportionally influences a value for reducing the rating of an attack. A caution of 0 has no influence (the rating won't be reduced at all).
 
** If grouping for the AI is enabled and the path to move the group along is considered to be dangerous, caution has an influence, too. &quot;Dangerous&quot; mainly means there is a possibility for the best attacker of a primary target to be severely harmed, for example if he can be killed by enemies if not protected. In that case, the AI compares our group with the enemy and based on the result moves forward or not. &quot;Group&quot;, from what i understood, means every unit of that side, including the leader. So it's not really a coherent group necessarily. Our side is rated which is mainly the sum of maximum damage * defense modifiers for every unit. Then this is compared to the enemy strength by determining a relation of both. A value of 1 means both sides have equal strength. Higher values indicate our side is stronger, lower values likewise. The formula for deciding if a group moves on is:<br>our_strength / their_strength > 0.5 + caution<br>So if caution is 0.5, our side needs to be at least as strong as the enemy. If it is 0, we go on, even if the enemy is up to twice as strong as we are. Setting caution to 1.5 means we need to be at least twice as strong to have the group keep moving.
 
** Caution also influences putting units onto villages. However, i haven't understood the code well enough yet to make backed up statements about it. Probably it's an estimation about how exposed a unit will be on that village, based on how many damage the enemy can do to it.
 
** Caution often won't influence the AI if the leader is involved, because for many actions it is hardcoded with a value of 2.0.  
 
  
* '''[goal]'''="": Defines units or locations as [[AiWML#AI_Targets_and_Goals|targets]] for the AI.  See the dedicated section on the [[AiWML#The_.5Bgoal.5D_Tag|[goal] tag]] below for details.  Applies to move-to-targets CA only.
+
* {{anchor|advancements|'''advancements'''}}: (string) Defines a list of unit types to which AI units can advance. If a unit type is listed here, units that can advance to this type will <u>only</u> advance to this type, even if they have, in principle, several advancement options.  As an example, if this aspect is set to 'Javelineer,Elvish Hero', then all Spearmen advance to Javelineers, and all Elvish Fighters advance to Elvish Heroes.  All other units follow their usual advancement choices as determined by the AI.  '''Important notes:'''
 +
** This is a simplified version of the more complex (and arguably more useful) application of a dynamic Lua ''advancements'' aspect, as described [[LuaAI#The_advancements_Aspect|here]].
 +
** The ''advancements'' aspect only takes effect during the AI turn, that is, on offense only, not on defense.
 +
** Listing more than one advancement unit type for a given unit still results in only one of the types being used (generally the one listed last).
  
* '''grouping'''="offensive": (string) How the AI should try to group unitsApplies to move-to-targets CA only.
+
* {{anchor|aggression|'''aggression'''}}=0.4: (double: ranging from -infinity to 1.0) This key affects how the AI selects its attack targets.  The higher the value, the more likely the AI is to attack even if odds are not in its favorThe description below applies as written to the ''combat'' CA only, but aggression is taken into account by the ''high_xp_attack'' and ''spread_poison'' CAs as well (as of '''Wesnoth 1.13.5''' and '''1.15.3''' respectively).
** '''offensive''': Makes the AI try to group units together before attacking.
+
** '''Important: do not set aggression to values greater than 1''' as this makes the AI ''prefer'' attacks in which it receives more damage (see below) unless that is specifically the effect you want to achieve.
** '''defensive''': Makes the AI group units together very conservatively, only advancing them much beyond its castle if it has overwhelming force.
+
** In the attack evaluation, each attack (this includes attack combinations of several AI units against the same enemy unit) is assigned a score.  The attack with the highest score is done first.  Then the next attack is evaluated, until no attack with a score greater than 0 is found any more.  (Note that this ''attack score'' is different from the ''combat CA score'', which is always 100,000 as long as an individual attack score >0 is found.  The combat CA score is zero if the highest attack score is <=0).
** '''no''': Makes the AI use no grouping behavior.
+
** The attack score is a complex combination of many different aspects of the attacks.  Positive (additive) contributions to the score are things like the value (cost and XP) of the target, the chance to kill the target, whether it is already wounded, how much damage the attack is likely to inflict, etc.  Negative (additive) factors include how much damage the AI's units are likely to take, how valuable they are, how exposed they will be after the attack, etc.  There are also multiplicative factors that are used if the attack target is a threat to the AI's leader etc.
 +
** All the negative contributions to the score are multiplied by '(1-aggression)'.  This means that:
 +
*** If 'aggression=1', no negative contributions are added to the score.  Thus, the AI disregards damage done to its own units and selects attacks based solely on the damage it can do to enemy units.  If the AI can inflict 1 damage and take 0, or inflict 2 damage and take 20, it will take the latter option.
 +
*** The smaller the value of ''aggression'', the more weight is put on value of and potential damage to the AI's units as compared to the attack target.
 +
*** Roughly speaking, 'aggression=0' results in the AI valuing its units approximately as much as the enemy units.  This is not a one-to-one relation, but can be used as an approximate guideline.
 +
*** Very large negative values of ''aggression'' mean that the value of the AI's units is much more important than that of the enemy units.  As a result, the AI never attacks unless it will receive no damage in exchange.
 +
*** The rating for damage received in an attack actually becomes a positive contribution to the score for values of aggression larger than 1.  This usually does not result in sensible behavior and values greater than 1 should therefore not be used.
 +
** Note: ''aggression'' is always set to 1.0 for attacks on units that pose a direct threat to the AI's leader.  Currently this only means units adjacent to the leader.
  
* '''leader_aggression'''="-4.0": Exactly as aggression, but for units which can recruit.  Applies to combat CA only. Note that the move-leader-to-keep CA has a higher score than the combat CA. A leader therefore usually only attacks if he is on his keep at the beginning of the turn, otherwise he moves to the closest keep instead, even with ''leader_aggression=1''.
+
*{{anchor|allow_ally_villages|'''allow_ally_villages'''}}=no (bool) {{DevFeature1.17|6}} Affects ''retreat-injured'' CA only. Normally, the AI is not allowed to take villages from an ally. If this is set to 'yes', the AI may retreat injured units to allied villages (and thereby capture them).
  
* '''[leader_goal]'''="": Makes the AI try to move its leader to a specific location.  Applies to move-leader-to-goals CA only.
+
*{{anchor|attacks|'''[attacks]'''}}: Filters the units considered for combat, both on the AI and the enemy sides.  Applies to the ''combat'', ''high_xp_attacks'' and ''spread_poison'' CAs only.  It cannot be set in the same way as the other aspects and is therefore described in a [[#Filtering_Combat_with_the_attacks_Aspect|separate section]] below.
** '''x''', '''y''': the location for the AI to move its leader to
 
  
* '''leader_value'''=3: (double) A number 0 or higher which determines the value of enemy leaders as [[AiWML#AI_Targets_and_Goals|targets]].  Affects move-to-targets CA only (and therefore specifically does not apply to attacks).
+
* {{anchor|avoid|'''[avoid]'''}}: Makes the AI avoid specific locations.  The AI never moves a unit to these locations except for trying to move its leader to a keep or toward [leader_goal]s, and thus applies to all CAs except ''move-leader-to-goals'' and ''move-leader-to-keep''.
 +
** '''[[StandardLocationFilter]]''': The locations for the AI to avoid.  Do not use a [filter_location] tag.
 +
**'''Note:''' Only one instance of an [avoid] aspect will be active for a side at any time. Where multiple instances are included in an [ai] tag, the last whose conditions (time of day, turns, etc.) match will be the only one that applies.
  
* '''passive_leader'''=no: (bool) If 'yes', the AI leader never moves or attacks (not even to move back to the keep or to attack adjacent units), except to obey [leader_goal]s.  Affects all CAs except recruitment and move-leader-to-goals.
+
* {{anchor|caution|'''caution'''}}=0.25: (double) Defines how cautious the AI is in several ways.  It determines whether the leader should move toward [leader_goal], if attacks are worth moving onto less favorable terrain, whether units should retreat, and whether the AI should move units toward targets individually, as groups or not at all.  Affects several CAs (listed in the order of their [[RCA_AI#The_Candidate_Actions_.28CAs.29_of_the_main_loop_Stage_in_the_RCA_AI|evaluation scores]]):
 +
** ''Move-leader-to-goals CA'': If ''max_risk'' is not set in [leader_goal], its default value is '1-caution'.  This determines whether the leader takes the next step toward his goal.  See description of [leader_goal].
 +
** ''Combat'' CA:
 +
*** During the evaluation of attacks, the AI considers whether the attacking units could get onto more favorable terrain if they didn't attack but moved somewhere else instead.  The difference between the two terrain ratings, together with a number of other factors, determines the "exposure" rating of the units.  This exposure is then subtracted from the 'attack score' as described for ''aggression'' above.
 +
*** The exposure rating also contains a multiplication by ''caution'', meaning that 'caution=0' results in exposure not being taken into account, and that it becomes more and more important for larger values.  In other words, the higher the values of ''caution'', the more reluctant is the AI to attack from unfavorable terrain.  (Note that exposure is one of the negative contributions to the attack score as described for ''aggression'', and therefore is also ignored if 'aggression=1' is set.)
 +
*** If the AI leader is used in an attack, the AI ''always'' uses 'caution=2' for the evaluation of that attack.
 +
** ''Retreat'' CA: {{DevFeature1.15|3}} This CA has been removed.
 +
*** If caution is greater than 0, there is an evaluation of forces for the map location a unit stands on. This is basically the sum of damage that can be done to that location by either side, reduced by terrain defense and relative hitpoints if attackers don't have full health. A retreat takes place, if <tt>caution &times; their_power > our_power</tt>. There is also a terrain factor involved if the attacker is not on optimal terrain, similar to the exposure described above for the combat CA.
 +
*** So let's say the AI has its default caution of 0.25. Then the enemy forces have to be at least 4 times as strong before the unit retreats. For a caution of 1, as soon as the enemy is stronger, the unit retreats.
 +
*** The AI never retreats if caution is set to 0 or lower.
 +
** ''Move-to-targets'' CA:
 +
*** If grouping for the AI is enabled and the path along which to move toward a target is considered to be dangerous, caution has an influence, too. "Dangerous" mainly means that there is a good chance for a unit to be killed if it's by itselfIn that case, the AI compares its units to the enemy units and based on the result moves forward or not. All units that can reach the next location of the move are considered.  The formula for deciding whether to move toward the target as a group is <tt>our_strength / their_strength > 0.5 + caution</tt>. If this condition holds true, units are moved toward the goal as a group, otherwise they try to group together in a location favorable for a attack on the enemy during the next turn.
 +
***So if caution is 0.5, the AI side needs to be at least as strong as the enemy. If it is 0, the AI moves toward the target, even if the enemy is up to twice as strong as the AI. Setting caution to 1.5 means the AI needs to be at least twice as strong as the enemy.
 +
*** The AI also considers retreating units during the move-to-target phase based on criteria similar to those for the retreat CA.
  
* '''passive_leader_shares_keep'''=no: (bool) If 'yes', has most of the effects of ''passive_leader=yes'', but the AI leader moves 1 hex from the keep to share it with allied players (if they can reach it next turn), returns to keep to recruit and attacks adjacent enemy units.
+
* {{anchor|grouping|'''grouping'''}}="offensive": (string) How the AI should try to group units.  Applies to ''move-to-targets'' CA only.  Possible values:
 +
** ''offensive'': Makes the AI try to group units together before attacking.
 +
** ''defensive'': Makes the AI group units together very conservatively, only advancing them much beyond its castle if it has overwhelming force.
 +
** ''no'': Makes the AI use no grouping behavior.
  
*'''recruitment'''="": To be added.
+
* {{anchor|leader_aggression|'''leader_aggression'''}}="-4.0": Exactly as aggression, but for units which can recruit.  Applies to ''combat'' CA only.  Note that the move-leader-to-keep CA has a higher score than the combat CA.  A leader therefore usually only attacks if he is on his keep at the beginning of the turn, otherwise he moves toward the closest keep instead, even with ''leader_aggression=1''.
  
* '''recruitment_ignore_bad_combat'''=no: (bool) If 'yes', the AI does not analyze the enemy units on the map to see if the unit to be recruited is suitable for fighting themAffects recruitment CA only.
+
* {{anchor|leader_goal|'''[leader_goal]'''}}="": Makes the AI try to move its leader to a specific location.  Applies to ''move-leader-to-goals'' CA only.
 +
** '''x''', '''y''': The location toward which the AI should move its leader.
 +
** '''auto_remove'''=no: (bool) If 'no' (default), the AI moves the leader to the goal, after which he stays there until [leader_goal] is [[Modifying_AI_Components#Modifying_Standard_Aspects|removed manually]].  If 'yes', the leader_goal is removed upon the leader getting there.  Important: this ''only'' works if ''id'' is set correctly (see the next bullet).
 +
** '''id'''="": (string)  An internal id key of the [leader_goal] tag.  An id is required for ''auto_remove'' to work.  However, setting this id does not automatically set the id of the [leader_goal] [[Wesnoth_AI_Framework#The_.5Bai.5D_Tag_.E2.80.94_Aspects|facet]].  Thus, in principle for this to work, you need to set the id of the facet as described [[Modifying_AI_Components#Modifying_Standard_Aspects|here]] ''and'' set the ''id'' key in [leader_value] to the same value.  Since you are probably only going to use one [leader_goal] tag at a time, there is a much simpler way: setting 'id=0' (which refers to the first facet) or 'id=*' (which means all facets) in [leader_goal] allows ''auto_remove'' to work without the extra step of setting the facet id. {{DevFeature1.13|5}} Setting this now also sets the id of the [leader_goal] facet, allowing auto_remove to work with multiple leader goals without using the fully-expanded aspect syntax.
 +
**'''max_risk'''=1-caution: (double: meaningful values are >=0)  How much risk the leader may be exposed to by moving toward the goal.  For evaluating this risk, the AI multiplies the leader's hitpoints by this number.  The leader is only moved toward the goal if the resulting value is larger than the expected damage the leader is going to take during the next enemy turnThus, 'max_risk=0' means he will only move if no attack on him is possible at the target hex of the move.  'max_risk=1' (or larger) results in him moving even if he's almost certainly going to die.
  
* '''recruitment_pattern'''="": (string) This key takes a comma separated list containing the usages defined in the recruitable units. Common usages are: 'scout', 'fighter', 'archer', 'healer' and 'mixed fighter'. This tells the AI with what probability it should recruit different types of units. The AI considers all units with the specified usage(s), but only those, so make sure the units you want recruited are really covered by the pattern or use an empty pattern (the default) to have all available units considered. The usage is listed in the unit type config files (see data/core/units/ for mainline units; see also [[UnitTypeWML]]).  Affects recruitment CA only.
+
* {{anchor|leader_ignores_keep|'''leader_ignores_keep'''}}=no: (bool) Set to 'yes' for this aspect to apply to all leaders of a side. {{DevFeature1.15|3}} In addition to 'yes/no', the aspect can now also be set to a comma-separated list of unit ids. The aspect then only applies to leaders with ids matching an id on that list. Setting leader_ignores_keep for some or all leaders means that:
** For example, "recruitment_pattern=fighter,fighter,archer" means, the AI recruits twice as many fighters as archers, and does not recruit scouts (other than scouts for capturing villages, who are recruited independently), healers or mixed fightersIt does ''not'' mean that it recruits two fighters first, then an archer, then two fighters again, etc.
+
** The affected AI leaders do not move to the closest keep at the beginning of the turn. Instead, they participate in the ''move_to_targets'' candidate action (and all other CAs in which they already participated anyway, of course). Thus, these leaders behave in the same way as any other unit of the AI side.
 +
** This also means that these AI leaders do not recruit except on the first turn if they start on a keep, or if they accidentally end up on a keepThus, if a leader is supposed to recruit first and then participate in the action, leader_ignores_keep should be set to 'no' at the beginning of the scenario, and be changed to 'yes' in an event later.
  
* '''scout_village_targeting'''=3: (double) The AI multiplies the value of village [[AiWML#AI_Targets_and_Goals|targets]] for scouts by this value.  Affects move-to-targets CA only.
+
* {{anchor|leader_value|'''leader_value'''}}=3: (double) A number 0 or higher which determines the value of enemy leaders as [[#AI_Targets_and_Goals|targets]].  Affects ''move-to-targets CA'' only (and therefore specifically does not apply to attacks).
  
* '''simple_targeting'''=no: (bool) If 'yes', the AI moves its units toward [[AiWML#AI_Targets_and_Goals|targets]] one by one (sequentially), without considering whether another unit might be better suited for the current move/target.  If 'no' (the default), all units are considered for all targets.  This is slower, but might result in better moves.  Affects move-to-targets CA only.
+
* {{anchor|passive_leader|'''passive_leader'''}}=no: (bool) If 'yes', the AI leader never moves or attacks, not even to move back to the keep (unless 'passive_leader_shares_keep=yes' is set) or to attack adjacent units, except to obey [leader_goal]s.  Affects all CAs except ''recruitment'' and ''move-leader-to-goals''. {{DevFeature1.15|3}} In addition to 'yes/no', the aspect can now also be set to a comma-separated list of unit ids. The aspect then only applies to leaders with ids matching an id on that list.
  
* '''support_villages'''=no: (bool) Trigger a code path that tries to protect those villages that are threatened by the enemy.  This seems to cause the AI to 'sit around' a lot, so it's only used if it's explicitly enabledAffects move-to-targets CA only.
+
* {{anchor|passive_leader_shares_keep|'''passive_leader_shares_keep'''}}=no: (bool) If 'yes', lets the AI leader moves off the keep to share it with allied leaders (if they can reach it next turn) if 'passive_leader=yes' is setHe also returns to keep to recruit when possible and attacks adjacent enemy units. {{DevFeature1.15|3}} In addition to 'yes/no', the aspect can now also be set to a comma-separated list of unit ids. The aspect then only applies to leaders with ids matching an id on that list.
  
* '''village_value'''=1: (double) A number 0 or higher which determines how much the AI tries to go for villages as [[AiWML#AI_Targets_and_Goals|targets]].  Affects move-to-targets CA only.
+
*'''recruitment_diversity''', '''recruitment_instructions''', '''recruitment_more''', '''recruitment_pattern''', '''recruitment_randomness''', '''recruitment_save_gold''': These aspects can be used to customize recruiting with the new recruitment CA introduced in Wesnoth 1.11.  They are described on a [[AI_Recruitment|separate page]].
  
* '''villages_per_scout'''=4: (int) A number 0 or higher which determines how many scouts the AI recruits. If 0, the AI doesn't recruit scouts to capture villages. Affects recruitment CA only.
+
*{{anchor|retreat_factor|'''retreat_factor'''}}=0.25 (double) {{DevFeature1.15|11}} Affects ''retreat-injured'' CA only. Determines how injured AI units have to be before they attempt retreating. This is approximately the fraction of the units' hitpoints, but other factors play a role also, such as the terrain the units are on, and leaders and poisoned units retreat somewhat earlier. Setting this to 0 (or negative values) disables retreating. Note that even setting this to very large values still requires units to be somewhat injured before they start retreating.
  
=== Deprecated AI Targeting Aspects ===
+
*{{anchor|retreat_enemy_weight|'''retreat_enemy_weight'''}}=1.0 (double) {{DevFeature1.15|11}} Affects ''retreat-injured'' CA only. When deciding where to retreat to, the AI considers how much healing a location provides and weighs it against the threat of all the enemies that can get there (balanced by the own units that can get there). In this evaluation, it multiplies the enemy threat rating by ''retreat_enemy_weight'', meaning that the larger its value is, the more a unit tries to move away from enemies.  There are three regimes for this aspect:
 +
** Positive values: Only locations that provide healing (both from terrain and from adjacent healers which have no MP left) are considered. For regenerating units, all hexes are treated as if they provide healing.
 +
** Zero: Enemy threats are ignored
 +
** Negative values: All hexes are considered for retreating. The enemy threat rating is multiplied by the absolute value of the aspect value. Thus, if very negative values are used (e.g. -100), this can be used to make units run away from enemies with little consideration for anything else.
  
The following AI targeting parameters (aspects) currently still work, but have been superseded by the [[AiWML#The_.5Bgoal.5D_Tag|[goal] tag]].  They should not be used any more as they will likely be removed at some pointThese tags specify targets and only apply to the move-to-targets CA.  See notes under [[AiWML#AI_Targets_and_Goals|AI Targets and Goals]].
+
* {{anchor|scout_village_targeting|'''scout_village_targeting'''}}=3: (double) The AI multiplies the value of village [[#AI_Targets_and_Goals|targets]] for scouts by this valueAffects ''move-to-targets'' CA only.
  
* '''[target]'''="": '''Deprecated'''. Any number of [target] tags can be used to set targets for the AI. For anything related to 'values', set them relative to other targets. An AI is willing to dedicate twice as many resources and travel twice as far to get a target worth '2.0' as for a target worth '1.0'.  Applies to move-to-targets CA only.
+
* {{anchor|simple_targeting|'''simple_targeting'''}}=no: (bool) If 'yes', the AI moves its units toward [[#AI_Targets_and_Goals|targets]] one by one (sequentially), without considering whether another unit might be better suited for the current move or target. If 'no' (the default), all units are considered for all targets. This is slower, but might result in better moves. Affects ''move-to-targets'' CA only.
** '''[[StandardUnitFilter]]''': Do not use a [filter] tag.
 
** '''value'''=1: (double)  A number greater than 0 (default=1) which determines how much the AI tries to move toward units which pass the filter.
 
  
* '''[protect_location]'''="": '''Deprecated'''. Gives the AI a location to protect. Note that the AI does ''not'' station any units around the location, it only sends units to attack any enemy units that come within the guarding radius of the targetApplies to move-to-targets CA only.
+
* {{anchor|support_villages|'''support_villages'''}}=no: (bool) Trigger a code path that tries to protect those villages that are threatened by the enemy. This seems to cause the AI to 'sit around' a lot, so it's only used if it's explicitly enabledAffects ''move-to-targets'' CA only.
** '''x''', '''y''': Standard coordinates. These indicate the location the AI is protecting,
 
** '''radius''': Indicates the radius around it to protect (0 indicates a single hex)
 
** '''value''': Indicates the importance of protecting this location
 
  
* '''[protect_unit]'''="": '''Deprecated'''. Gives the AI a set of units to protect. Note once again that the AI does not place units around the protected units if there are no enemies nearbyApplies to move-to-targets CA only.
+
* {{anchor|village_value|'''village_value'''}}=1: (double) A number 0 or higher which determines how much the AI tries to go for villages as [[#AI_Targets_and_Goals|targets]]Affects ''move-to-targets'' CA only.
** '''[[StandardUnitFilter]]''': The unit(s) to protect. Do not use a [filter] tag.
 
** '''radius''': Indicates the radius around it to protect (0 indicates a single hex)
 
** '''value''': Indicates the importance of protecting this unit
 
  
* '''protect_leader'''=2.0 and '''protect_leader_radius'''=10: '''Deprecated'''. The way these parameters work, is to target any enemy units that come within 'protect_leader_radius' of the AI leader with a value of 'protect_leader'.  Applies to move-to-targets phase only.
+
* {{anchor|villages_per_scout|'''villages_per_scout'''}}=4: (int) A number 0 or higher which determines how many scouts the AI recruits. If 0, the AI doesn't recruit scouts to capture villages. Affects ''recruitment'' CA only.
  
 
=== Removed AI Aspects ===
 
=== Removed AI Aspects ===
  
The following AI parameters (aspects) can still be set, their values can be retrieved, and they can be viewed in the inspector, but they do not seem to have an effect in the RCA AI code any more.  Some other parameters will also likely be removed in the future.  We will update this list accordingly.
+
The following AI parameters (aspects) can still be set, their values can be retrieved, and they can be viewed in the gamestate inspector dialog, but they do not have an effect in the RCA AI code any more.  Some other parameters will also likely be removed in the future.  We will update this list accordingly. {{DevFeature1.13|5}} Except for attack_depth, these have now all been removed.  {{DevFeature1.15|0}} attack_depth is now removed as well.
  
 
* '''attack_depth'''=5: (int)
 
* '''attack_depth'''=5: (int)
 
* '''number_of_possible_recruits_to_force_recruit'''=3.1: (double)
 
* '''number_of_possible_recruits_to_force_recruit'''=3.1: (double)
 +
* '''recruitment''': This aspect was used to customize the recruitment of the old default AI (the one used before the RCA AI).  This recruitment code is not used in the RCA AI any more.  Setting recruitment instructions with this aspect is therefore meaningless.  Use the '''recruitment_instructions''' aspect instead.
 +
** It is, in principle, still possible to use this aspect together with the [[Wesnoth_AI_Framework#Recruitment_Stage|recruitment stage]], but this is discouraged for the reasons given at this link.
 +
* '''recruitment_ignore_bad_combat'''=no: (bool)
 
* '''recruitment_ignore_bad_movement'''=no: (bool)
 
* '''recruitment_ignore_bad_movement'''=no: (bool)
  
 
==AI Targets and Goals==
 
==AI Targets and Goals==
  
AI targets are used by the move-to-targets candidate action (CA) to move its units toward selected units or locations.  As such, it is important to understand that these are move targets, not attack targets.  The AI engine automatically selects all enemy units and unowned or enemy-owned villages as targets and assigns them certain base values.  These values are then modified based on the movement cost required to get there, whether they pose a threat to the AI's leader, whether moving toward them would put the units involved in danger, etc.
+
AI targets are used in the ''move-to-targets'' candidate action (CA) to move the AI's units toward selected units or locations.  The AI engine automatically selects all enemy leaders, enemy units that pose a threat to the AI leader and unowned or enemy-owned villages as targets and assigns them certain [[RCA_AI#RCA_AI_Aspect_and_Goal_Configuration|base values]]Additional targets can be defined using the [goal] tag.
  
It is possible to define additional targets or influence the relative ratings of the default targets.  This is done with the [goal] tag, in which we can set criteria for the selection of the targets as well as their base values (which are then modified in the same way as the values of the default targets)As the values of the default targets vary, values set with the [goal] tag should be relative to each other.  The AI is willing to dedicate twice as many resources and travel twice as far to get to a target worth '2.0' as for a target worth '1.0'.
+
It is '''very important''' to realize that these targets apply to the ''move-to-targets'' CA only and have no influence on other CAsIn particular, they have no effect whatsoever on which enemies the AI attacks.  This is often a source of confusion for scenario creatorsMore background information on RCA AI targets and goals can be found [[RCA_AI#Use_of_Goals_and_Targets_in_the_RCA_AI|here]].  The sections below only describe how to set up goals in order to add targets for the ''move-to-targets'' CA.
  
We stress again that it is important to realize that these targets apply to the move-to-targets CA ''only'' and have no influence on other CAs.  This is significant since CAs that deal with, for example, combat or village-grabbing have a higher score than the move-to-targets CA and are therefore always executed first.  In practice that means that targets set with the [goal] tag only affect the AI behavior for targets that it cannot reach during the current turn, and only after combat, village-grabbing etc. are finished.
+
===The [goal] Tag===
  
Five types of targets can be set using the [goal] tag: ''target'' (the default), ''target_location'', ''protect_unit'', ''protect_my_unit'', and ''protect_location''.
+
The [goal] tag defines units or locations as [[#AI_Targets_and_Goals|move targets]] (not attack targets!) for the AI.  '''Applies to ''move-to-targets'' CA only'''. <-- That is '''extremely important''' to understand, in particular the fact that the [goal] tag has '''no influence whatsoever on attacks'''.
  
===The [goal] Tag===
+
The following keys/tags can be used:
 +
* '''name'''="target": (string)  The following values are possible and result in different types of targets, as shown in the examples below:
 +
** ''target'':  The (default) target goal specifies target units (not necessarily enemy units) toward which the AI should move its units. {{DevFeature1.13|5}} target_unit is now a synonym for this.
 +
** ''target_location'': Specifies target locations toward which the AI should move its units.
 +
** ''protect_location'': Specifies locations that the AI should protect. Enemy units within the specified distance (''protect_radius'') of one of these locations are marked as targets with the provided value.  Note that the AI will ''not'' station any units around the protected locations.  It will only send units toward enemy units that come within ''protect_radius'' of them.
 +
** ''protect_unit'': Specifies units (of all sides) that the AI should protect. Enemy units within ''protect_radius'' of one of these units are marked as targets with the provided value.  Note once again that the AI will not place units around the protected units if there are no enemies nearby.
 +
** ''protect_my_unit'': ('''deprecated''') <s>Specifies units from the AI's own side that the AI should protect. (This is basically the ''protect_unit'' goal with an implied ''side='' in the filter, restricting matching units to the AI's side.) Enemy units within ''protect_radius'' of one of these units are marked as targets with the provided value.  Note once again that the AI will not place units around the protected units if there are no enemies nearby.</s>
 +
** ''lua_goal'': A dynamically calculated goal written in Lua. See [[LuaAI#Lua_Goals_and_Targets|here]] for details on how this works.
  
The [goal] tag specifies target units or locations towards which the AI should move its units.  The following keys/tags can be used:
+
* '''[criteria]'''="": Contains a [[StandardUnitFilter]] (for ''target'', ''protect_unit'' or ''protect_my_unit'') or [[StandardLocationFilter]] (for ''target_location'' or ''protect_location'') describing the targets.
* '''name'''="target": (string)  The following values are possible and result in different types of targets:
 
** '''target''':  The (default) target goal specifies target units (not necessarily enemy units) towards which the AI should move its units.
 
** '''target_location''': Specifies target locations towards which the AI should move its units.
 
** '''protect_location''': Specifies locations that the AI should protect. Enemy units within the specified distance (''protect_radius'') of one of these locations are marked as targets with the provided value.  Note that the AI will ''not'' station any units around the location.  It will only send units toward enemy units that come within ''protect_radius'' of the target.
 
** '''protect_unit''': Specifies units (of all sides) that the AI should protect. Enemy units within ''protect_radius'' of one of these units are marked as targets with the provided value.  Note once again that the AI will not place units around the protected units if there are no enemies nearby.
 
** '''protect_my_unit''': Specifies units from the AI's own side that the AI should protect. (This is basically the ''protect_unit'' goal with an implied ''side='' in the filter, restricting matching units to the AI's side.) Enemy units within the specified ''protect_radius'' of one of these units are marked as targets with the provided value.  Note once again that the AI will not place units around the protected units if there are no enemies nearby.
 
  
* '''[criteria]'''="": Contains a [[StandardUnitFilter|SUF]] (for ''target'', ''protect_unit'' or ''protect_my_unit'') or [[StandardLocationFilter|SLF]] (for ''target_location'' or ''protect_location'') describing the targets.
+
* '''value'''=0: (double) The value of the goal.
  
* '''value'''=0: (int) The value of the goal.
+
* '''protect_radius'''=20: (int) The protection radius.  Applies to ''protect_location'', ''protect_unit'' and ''protect_my_unit''.
  
* '''protect_radius'''=20: (int) The protection radius. Applies to ''protect_location'', ''protect_unit'' and ''protect_my_unit''.
+
* '''id'''="": (stringOptional ID used for [[Modifying_AI_Components#Modifying_Goals|modifying the goal]].
  
 
===Examples of [goal] Tag Usage===
 
===Examples of [goal] Tag Usage===
  
 
'''target:'''
 
'''target:'''
[goal]
+
<syntaxhighlight lang='wml'>
    [criteria] #NOTE: this is a SUF, because we're targeting a unit
+
[ai]
        side=3
+
    [goal]
    [/criteria]
+
        [criteria] #NOTE: this is a SUF, because we're targeting a unit
    value=5
+
            side=3
[/goal]
+
        [/criteria]
 +
        value=5
 +
    [/goal]
 +
[/ai]
 +
</syntaxhighlight>
  
 
'''target_location:'''
 
'''target_location:'''
[goal]
+
<syntaxhighlight lang='wml'>
    name=target_location
+
[ai]
    [criteria] #NOTE: this is a SLF, because we're targeting a location
+
    [goal]
        x,y=42,20
+
        name=target_location
    [/criteria]
+
        [criteria] #NOTE: this is a SLF, because we're targeting a location
    value=5
+
            x,y=42,20
[/goal]
+
        [/criteria]
 +
        value=5
 +
    [/goal]
 +
[/ai]
 +
</syntaxhighlight>
  
 
'''protect_location:'''
 
'''protect_location:'''
[goal]
+
<syntaxhighlight lang='wml'>
    name=protect_location
+
[ai]
    [criteria] #NOTE: this is a SLF, because we're protecting a location
+
    [goal]
        x,y=42,20
+
        name=protect_location
    [/criteria]
+
        [criteria] #NOTE: this is a SLF, because we're protecting a location
    protect_radius=16
+
            x,y=42,20
    value=5
+
        [/criteria]
[/goal]
+
        protect_radius=16
 +
        value=5
 +
    [/goal]
 +
[/ai]
 +
</syntaxhighlight>
  
 
'''protect_unit:'''
 
'''protect_unit:'''
[goal]
+
<syntaxhighlight lang='wml'>
    name=protect_unit
+
[ai]
    [criteria] #NOTE: this is a SUF, because we're protecting a unit
+
    [goal]
        side=3
+
        name=protect_unit
    [/criteria]
+
        [criteria] #NOTE: this is a SUF, because we're protecting a unit
    protect_radius=16
+
            side=3
    value=5
+
        [/criteria]
[/goal]
+
        protect_radius=16
 +
        value=5
 +
    [/goal]
 +
[/ai]
 +
</syntaxhighlight>
  
'''protect_my_unit:'''
+
'''How to use protect_unit to protect the own leader''' (We are side 2)
[goal]
+
<syntaxhighlight lang='wml'>
    name=protect_my_unit
+
[ai]
    [criteria] #NOTE: this is a SUF, because we're protecting a unit
+
    [goal]
        canrecruit=yes
+
        name=protect_unit
    [/criteria]
+
        [criteria]
    protect_radius=9
+
            side=2
    value=10
+
            canrecruit=yes
[/goal]
+
        [/criteria]
 +
        protect_radius=8
 +
        value=5
 +
    [/goal]
 +
[/ai]
 +
</syntaxhighlight>
  
To modify goals from WML events, use these helper macros (don't forget to give your [goal]s unique ids):
+
=== Deprecated AI Targeting Aspects ===
  {MODIFY_AI_ADD_GOAL SIDE GOAL_CONFIG}
 
  {MODIFY_AI_DELETE_GOAL SIDE GOAL_ID}
 
  {MODIFY_AI_TRY_DELETE_GOAL SIDE GOAL_ID}
 
  
== Filtering Combat with the 'attacks' Aspect==
+
The following AI targeting parameters currently still work, but have been superseded by the [[#The_.5Bgoal.5D_Tag|[goal] tag]].  They should not be used any more as they will likely be removed at some point.  These tags only apply to the move-to-targets CA.
  
== A Bit More on Simple vs. Composite Aspects ==
+
* '''[target]'''="": '''Deprecated'''. Any number of [target] tags can be used to set targets for the AI. For anything related to 'values', set them relative to other targets. An AI is willing to dedicate twice as many resources and travel twice as far to get to a target worth '2.0' as for a target worth '1.0'.  Applies to move-to-targets CA only.
 +
** '''[[StandardUnitFilter]]''': Do not use a [filter] tag.
 +
** '''value'''=1: (double)  A number greater than 0 (default=1) which determines how much the AI tries to move toward units which pass the filter.
  
We stated [[AiWML#Aspects_and_Goals|above]] that aspects can be either simple or composite, simple aspects being those that take on an single (scalar) value, while composite aspects have a more complex structure containing subtags called 'facets'That is only partially true in that, internally, all aspects are set up as composite aspects. For example, if a simple aspect is defined like this in a [side] or [modify_side] tag:
+
* '''[protect_location]'''="": '''Deprecated'''. Gives the AI a location to protect. Note that the AI does ''not'' station any units around the location, it only sends units to attack any enemy units that come within the guarding radius of the targetApplies to move-to-targets CA only.
[ai]
+
** '''x''', '''y''': Standard coordinates. These indicate the location the AI is protecting.
    aggression=0.765
+
** '''radius''': The radius around it to protect (0 indicates a single hex). {{DevFeature1.13|5}} This key has been changed to protect_radius, though it's preferred to change old code to use the [goal] tag instead.
[/ai]
+
** '''value''': The importance of protecting this location.
the AI engine turns that into:
 
[aspect]
 
    engine=cpp
 
    id=aggression
 
    name=composite_aspect
 
    [facet]
 
        engine=cpp
 
        name=standard_aspect
 
        value=0.765
 
    [/facet]
 
    [default]
 
        engine=cpp
 
        name=standard_aspect
 
        value=0.4
 
    [/default]
 
[/aspect]
 
This can be seen, for example, in savefiles. This shows the aspect id, 'aggression', and the engine for which it is defined, the default 'cpp' engine.  It then shows two facets, the one we just defined with the new value of 0.765, and the facet containing the default settings.
 
  
Taking this one step further, if we look at 'ai config full' for a given side using the gamestate inspector dialog in debug mode, it shows all keys that can be set for this aspect (with their default values for those we did not set specifically):
+
* '''[protect_unit]'''="": '''Deprecated'''. Gives the AI a set of units to protect. Note once again that the AI does not place units around the protected units if there are no enemies nearbyApplies to move-to-targets CA only.
[aspect]
+
** '''[[StandardUnitFilter]]''': The unit(s) to protect. Do not use a [filter] tag.
    engine=cpp
+
** '''radius''': The radius around it to protect (0 indicates a single hex). {{DevFeature1.13|5}} This key has been changed to protect_radius, though it's preferred to change old code to use the [goal] tag instead.
    id=aggression
+
** '''value''': The importance of protecting this unit.
    invalidate_on_gamestate_change=no
 
    invalidate_on_minor_gamestate_change=no
 
    invalidate_on_tod_change_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_change=yes
 
        invalidate_on_turn_start=yes
 
        name=standard_aspect
 
        time_of_day=
 
        turns=
 
        value=0.765
 
    [/facet]
 
    [default]
 
        ...  (omitted for brevity, same as above)
 
        value=0.4
 
    [/default]
 
[/aspect]
 
Thus, we see, that the facet may also contain an id (important if one wants to delete the facet selectively), the time of day and turns for which it is valid, and several invalidate_on_... keys.  The latter ... (need to be explained).
 
 
 
Long story short, the definition of a simple aspect like
 
[ai]
 
    aggression=0.765
 
[/ai]
 
is a syntactical shortcut for
 
[ai]
 
    [aspect]
 
        id=aggression
 
        [facet]
 
            value=0.987
 
        [/facet]
 
    [/aspect]
 
[/ai]
 
This later syntax may just as well be used in the [side] or [modify_side] tags. It is not required for simple aspects without facet ids, but is needed if a facet with an id is required or for the definition of some more complex aspects such as ''attacks''.
 
 
 
Composite aspects can also be set using the [modify_ai] macro (include section below) or with the help of several macros availabe in data/core/macros/ai.cfg.
 
  
==Adding and Deleting Aspects with the [modify_ai] Tag==
+
* '''protect_leader'''=2.0 and '''protect_leader_radius'''=10: '''Deprecated'''. Target any enemy units that come within 'protect_leader_radius' of the AI leader with a value of 'protect_leader'.  Applies to move-to-targets CA only.
  
Aspects can also be changed (defined or deleted) with the [modify_ai] tag, which can be used either in [side][ai] or in an [event].  [modify_ai] has the following keys for modifying aspects:
+
== Filtering which Units Participate in which Actions==
  
* '''side''': If used in an [event] tag, the side of the AI to be modified. Not needed if used in [side][ai].
+
{{DevFeature1.15|3}}
* '''action''': The action to take concerning the aspect.  The following values are allowed:
 
** '''add''': Add the aspect.
 
** '''delete''': Delete the aspect.
 
** '''try_delete''': Delete the aspect if it exists.  This does not produce a warning if [modify_ai] fails to change the AI.
 
* '''path''': Defines the aspect to be modified.  Its values are of form '''aspect[id_of_aspect].facet[facet_identifier]''' and the [facet] subtag needs to be defined:
 
**'''[facet]'''="": Definition of the facet (the details about the aspect and the conditions under which it applies) in the same format as shown [[AiWML#A_Bit_More_on_Simple_vs._Composite_Aspects|above]].
 
  
Here, 'id_of_aspect' is the id/name of the aspect (such as ''aggression'').  The 'facet_identifier' is meaningless for adding an aspect (in fact, it can be empty for that), but needs to be defined when deleting aspects, in which case it can take on the following values:
+
Each [[RCA_AI#The_Candidate_Actions_.28CAs.29_of_the_main_loop_Stage_in_the_RCA_AI|candidate action of the default AI]] can be restricted to apply to only a subset of the AI units. This is done by adding a '''[filter_own]''' tag to the '''[[Wesnoth_AI_Framework#The_.5Bai.5D_Tag_.E2.80.94_Candidate_Actions|[candidate_action]]]''' tag definition.
* *: Deletes all facets of that aspect, except the [default] facet.
 
* A non-negative integer: This identifies the facets in the order in which they are created.
 
* The facet id as defined in the [facet] subtag.
 
  
Let's illustrate all this with a few examples. In order to define aggression in the same way as above, we could use
+
Typical use cases:
[modify_ai]
+
* Restricting an action to certain units so that other units are not used to this. For example, village grabbing could be restricted to scout units only, so that slower units do not take detours on their way toward the enemies. See the example below.
    side=1
+
* Excluding units from a certain action in order to have them available for other actions afterward. For example, one might want to add a custom candidate action which moves healers behind injured units (or use the existing [[Micro_AIs|Micro AI]] for this). Ideally, this should happen after ''all'' other units have moved, specifically also after the move-to-targets candidate action (MtT CA) is done. In the default setting, however, the MtT CA would also move the healers. Thus, we would want to exclude them using a '''[filter_own]''' tag.
    action=add
+
* Adding two instances of the same candidate action with different scores to force the order in which units participate in this action. For example, one could add another instance of the move-leader-to-keep CA with a '''[filter_own]''' tag restricting it to one leader, in order to make this leader move to a keep (and therefore recruit) first.
    path=aspect[aggression].facet[]
 
    [facet]
 
        value=0.765
 
    [/facet]
 
[/modify_ai]
 
This version of the aggression aspect can then be deleted using
 
[modify_ai]
 
    side=1
 
    action=delete
 
    path=aspect[aggression].facet[0]
 
[/modify_ai]
 
if we know that it is the first non-default facet of the ''aggression'' aspect or with
 
[modify_ai]
 
    side=1
 
    action=delete
 
    path=aspect[aggression].facet[*]
 
[/modify_ai]
 
along with all other 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.
 
  
If we want define several facets of the same aspect, don't know the order in which they might be set up, and then only want to delete some of them, we can use the following method. Add a facet with a specific id
+
Note that for the combat AI, using the attacks aspect to filter units as described in the next section '''is slightly more efficient'''. Thus, that should be the preferred method if there are many units on the map.
[modify_ai]
 
    side=1
 
    action=add
 
    path=aspect[aggression].facet[]
 
    [facet]
 
        id=aggression_dusk
 
        time_of_day=dusk
 
        value=0.765
 
    [/facet]
 
[/modify_ai]
 
and delete it by referencing that id
 
[modify_ai]
 
    side=1
 
    action=delete
 
    path=aspect[aggression].facet[aggression_dusk]
 
[/modify_ai]
 
  
It is, of course, unnecessary to add or delete a simple aspect like ''aggression'' in this way, as it can simply be reset by using another 'aggression=value' statement in an [ai] tag.  In fact, this can be done with any aspect.  If several facets are set for the same aspect for the same (or overlapping) turns and times of day, the one set up last is taking effect.  Note, however, that this is not accomplished by modifying the existing facets, but by adding an additional facet to the aspect.  Deleting a facet is, in principle, a cleaner method of dealing with this, although it probably does not make much difference unless the same aspect is changed many times throughout a scenario.  There might also be complex situations of parameter combinations in which deleting facets might be preferable to adding yet another one.
+
Example:
 +
<syntaxhighlight lang='wml'>
 +
[candidate_action]
 +
id=villages
 +
engine=cpp
 +
name=ai_default_rca::get_villages_phase
 +
max_score=60000
 +
score=60000
 +
[filter_own]
 +
type=Wolf Rider
 +
[/filter_own]
 +
[/candidate_action]
 +
</syntaxhighlight>
  
A large number of helper macros for AI modifications are available in [http://www.wesnoth.org/macro-reference.xhtml#file:ai.cfg data/core/macros/ai.cfg].
 
  
===Using [modify_ai] to Change Goals, Candidate Actions and Stages===
+
== Filtering Combat with the ''attacks'' Aspect==
  
For completeness, we mention here that [modify_ai] can also be used to add and delete AI [[AiWML#AI_Targets_and_Goals|goals]], [[General_RCA_AI_Howto#RCA_AI_main_loop_stage_and_Candidate_Actions|candidate actions]] and [[General_RCA_AI_Howto#Available_Stages|stages]] by using the values listed below for the '''path''' key:
+
The ''attacks'' aspect lets us filter the units considered by the ''combat'', ''high_xp_attacks'' and ''spread_poison'' candidate actions.  Units on the AI side can be selected with the '''[filter_own]''' tag and enemy units are filtered via '''[filter_enemy]''', both of which take a [[StandardUnitFilter]].  Only units defined in these tags are considered as attacker/target pairs.  To define, for example, an ''attacks'' aspect in which units from the elvish sorceress line are the only attackers, and undead units are the only targets, use
* '''goal[id_of_goal]''': Goal with specified id
+
<syntaxhighlight lang='wml'>
* '''goal[0]''': Goal 0 (first)
+
[ai]
* '''goal[1]''': Goal 1
+
    [aspect]
* '''goal[*]''': All goals
+
        id=attacks
* '''stage[id_of_stage]''': Stage with specified id
+
        [facet]
* '''stage[0]''': Stage 0 (first)
+
            invalidate_on_gamestate_change=yes
* '''stage[1]''': Stage 1
+
            [filter_own]
* '''stage[*]''': All stages
+
                type=Elvish Sorceress,Elvish Enchantress,Elvish Sylph
*'''stage[id_of_candidate_action_evaluation_loop_stage].candidate_action[id_of_candidate_action]''': Candidate action with specified id of stage with specified id.
+
            [/filter_own]
* '''stage[id_of_candidate_action_evaluation_loop_stage].candidate_action[*]''': All candidate actions of stage with specified id.
+
            [filter_enemy]
 +
                race=undead
 +
            [/filter_enemy]
 +
        [/facet]
 +
    [/aspect]
 +
[/ai]
 +
</syntaxhighlight>
 +
Several important notes:
 +
* The ''attacks'' aspect is a ''composite'' aspect and cannot be defined using the simple syntax of the other ''standard'' aspects.  See [[Wesnoth_AI_Framework#The_.5Bai.5D_Tag_.E2.80.94_Aspects|here]] for a description of the syntax of the example.
 +
* This only works if <code>invalidate_on_gamestate_change=yes</code> is set.  The reason is that the ''attacks'' aspect internally contains information about all available attacker/target pairs.  These need to be recalculated after each move.  This is explained [[Wesnoth_AI_Framework#Some_more_on_the_invalidation_keys|here]].
 +
* If [filter_own] or [filter_enemy] are omitted, the selection defaults to all units of the respective sides.
 +
* '''Most importantly''': The above example results in sorceress-line vs undead attacks being the <u>only</u> attacks done by the AI.  No other attacks are executed, no matter how advantageous their outcomes may be.  There is no simple way around that, but it can be accomplished by one of the following means:
 +
** Setting up the [filter_own] or [filter_enemy] [[StandardUnitFilter]]s to adapt dynamically to the situation on the map.
 +
** Adding a Lua candidate action which dynamically adjusts the aspect depending on the current situation on the map.  An example of dealing with this is given in the [[Micro_AIs#Micro_AI_Test_and_Demo_Scenarios|Micro AI test scenario]] [https://github.com/wesnoth/wesnoth/blob/master/data/ai/micro_ais/scenarios/protect_unit.cfg ''Protect Unit''].
 +
** Using [[LuaAI#Dynamic_Lua_Aspects|dynamic Lua aspects]] is in principle also possible, but far from easy due to the complex tables this aspect returns.
  
Also see the helper macros at [http://www.wesnoth.org/macro-reference.xhtml#file:ai.cfg data/core/macros/ai.cfg].
+
{{DevFeature1.13|5}}
  
Finally note that [modify_ai] in [side][ai] is activated when the AI is first initialized (it's 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.
+
Though the above code still works in 1.13.5 and later (and will continue to work indefinitely), it can also be simplified a little:
 +
<syntaxhighlight lang='wml'>
 +
[ai]
 +
    [attacks]
 +
        invalidate_on_gamestate_change=yes
 +
        [filter_own]
 +
            type=Elvish Sorceress,Elvish Enchantress,Elvish Sylph
 +
        [/filter_own]
 +
        [filter_enemy]
 +
            race=undead
 +
        [/filter_enemy]
 +
    [/attacks]
 +
[/ai]
 +
</syntaxhighlight>
  
 
== See Also ==
 
== See Also ==
* [[AI_Module]]
+
* [[Wesnoth AI]]
 
* [[ReferenceWML]]
 
* [[ReferenceWML]]
* [[Customizing_AI_in_Wesnoth_1.8]]
 
  
 
[[Category: WML Reference]]
 
[[Category: WML Reference]]
 +
[[Category:AI]]

Latest revision as of 06:38, 21 October 2024

[edit]WML Tags

A:

abilities, about, achievement, achievement_group, add_ai_behavior, advanced_preference, advancefrom, advancement, advances, affect_adjacent, ai, allied_with, allow_end_turn, allow_extra_recruit, allow_recruit, allow_undo, and, animate, animate_unit, animation, aspect, attack (replay, weapon), attack_anim, attacks (special, stats), avoid;

B:

base_unit, background_layer, berserk, binary_path, break, brush;

C:

campaign, cancel_action, candidate_action, capture_village, case, chance_to_hit, change_theme, chat, checkbox, choice, choose, clear_global_variable, clear_menu_item, clear_variable, color_adjust, color_palette, color_range, command (action, replay), continue, core, credits_group, criteria;

D:

damage, damage_type, death, deaths, default, defend, defends, defense, delay, deprecated_message, destination, difficulty, disable, disallow_end_turn, disallow_extra_recruit, disallow_recruit, do, do_command, drains, draw_weapon_anim;

E:

editor_group, editor_music, editor_times, effect, else (action, animation), elseif, endlevel, end_turn (action, replay), enemy_of, engine, entry (credits, options), era, event, experimental_filter_ability, experimental_filter_ability_active, experimental_filter_specials, extra_anim;

F:

facet, facing, fake_unit, false, feedback, female, filter (concept, event), filter_adjacent, filter_adjacent_location, filter_attack, filter_attacker, filter_base_value, filter_condition, filter_defender, filter_enemy, filter_location, filter_opponent, filter_own, filter_owner, filter_radius, filter_recall, filter_second, filter_second_attack, filter_self, filter_side, filter_student, filter_vision, filter_weapon, filter_wml, find_path, fire_event, firststrike, floating_text, fonts, for, foreach, found_item, frame;

G:

game_config, get_global_variable, goal, gold, gold_carryover;

H:

harm_unit, has_ally, has_attack, has_unit, has_achievement, have_location, have_unit, heal_on_hit, heal_unit, healed_anim, healing_anim, heals, hide_help, hide_unit, hides;

I:

idle_anim, if (action, animation, intro), illuminates, image (intro, terrain), init_side, insert_tag, inspect, item, item_group;

J:

jamming_costs, join;

K:

kill, killed;

L:

label, language, leader, leader_goal, leadership, leading_anim, levelin_anim, levelout_anim, lift_fog, limit, literal, load_resource, locale, lock_view, lua;

M:

male, menu_item, message, micro_ai, missile_frame, modification, modifications, modify_ai, modify_side, modify_turns, modify_unit, modify_unit_type, move, move_unit, move_unit_fake, move_units_fake, movement_anim, movement costs, movetype, multiplayer, multiplayer_side, music;

N:

not, note;

O:

object, objective, objectives, on_undo, open_help, option, options, or;

P:

part, petrifies, petrify, place_shroud, plague, poison, post_movement_anim, pre_movement_anim, primary_attack, primary_unit, print, progress_achievement, put_to_recall_list;

R:

race, random_placement, recall (action, replay), recalls, recruit, recruit_anim, recruiting_anim, recruits, redraw, regenerate, remove_event, remove_item, remove_object, remove_shroud, remove_sound_source, remove_time_area, remove_trait, remove_unit_overlay, repeat, replace_map, replace_schedule, replay, replay_start, reset_fog, resistance (ability, unit), resistance_defaults, resolution, resource, return, role, rule;

S:

save, scenario, screen_fade, scroll, scroll_to, scroll_to_unit, secondary_attack, secondary_unit, section, select_unit, sequence, set_achievement, set_extra_recruit, set_global_variable, set_menu_item, set_recruit, set_specials, set_variable, set_variables, sheath_weapon_anim, show_if (message, objective, set_menu_item), show_objectives, side, skirmisher, slider, slow, snapshot, sound, sound_source, source (replay, teleport), special_note, specials, split, stage, standing_anim, statistics, status, store_gold, store_items, store_locations, store_map_dimensions, store_reachable_locations, store_relative_direction, store_side, store_starting_location, store_time_of_day, store_turns, store_unit, store_unit_defense, store_unit_defense_on, store_unit_type, store_unit_type_ids, store_villages, story, swarm, sub_achievement, switch, sync_variable;

T:

target, team, teleport (ability, action), teleport_anim, terrain, terrain_defaults, terrain_graphics, terrain_mask, terrain_type, test, test_condition, test_do_attack_by_id, text_input, textdomain, theme, then, tile, time, time_area, topic, toplevel, trait, transform_unit, traveler, true, tunnel;

U:

unhide_unit, unit (action, scenario), unit_overlay, unit_type, unit_worth, units, unlock_view, unpetrify, unstore_unit, unsynced;

V:

value, variable, variables, variant, variation, victory_anim, village, vision_costs, volume;

W:

while, wml_message, wml_schema;

Z:

zoom;

Customizing the Default AI Using WML

This page describes how the behavior of the default (RCA) AI can be customized using simple WML commands. The descriptions below assume a basic understanding of how the RCA AI evaluates moves, what candidate actions, aspects and goals are, and how they interact. If you do not know these things yet, check out the RCA AI page.

This page contains:

  • Descriptions of the aspects and goals of the default AI
  • Instructions for setting them up at the beginning of the scenario in a [side] tag

This page does not contain:

Defining Aspects and Goals of the RCA AI

Aspects and goals of the default (RCA) AI can be defined at the beginning of a scenario with [ai] tags inside the [side] tags. They are used to customize certain aspects of the AI. The [ai] tag, when used for this purpose, takes the aspects themselves as arguments, as well as the following general keys:

  • time_of_day: (string) The time(s) of day when the AI should use the parameters given in this [ai] tag. Possible values are listed in data/core/macros/schedules.cfg (see also TimeWML). Note that it is the id (not the name) of the time of day that needs to be used here. Also note that this aspect did not work for a long time due to a bug (versions 1.7.4 - 1.11.6). It has been fixed for BfW 1.11.7.
  • turns: (string) During which turns the AI should use the parameters given in this [ai] tag. This takes the same syntax of dashes (-) and commas (,) as is described under Filtering Locations in FilterWML, except of course they apply to turns not locations.
  • ai_algorithm: (string) Allows an alternate AI algorithm (cannot be created with WML) to be used. Besides the default, the game only comes with idle_ai, which makes the AI do nothing and can be used to create a passive, unmoving side. Cannot be applied only to a set of turns or a given time of day using the keys turns and time_of_day, but must be given either in an [ai] tag without the aforementioned keys or in the [side] tag outside all [ai] tags. (Version 1.13.5 and later only) In 1.13, the meaning of ai_algorithm has changed and no longer selects a native AI that's built into the engine, as the RCA AI has now become the core system and no alternatives exist anymore. Instead, it selects a predefined [ai] definition, such as those defined in data/ai/ais. Since these are defined in WML, you can easily build your own.

An example of a simple use of the [ai] tag to set AI parameters (aspects) is

[ai]
    time_of_day=dusk
    aggression=0.99
    caution=0.01
    [avoid]
        [filter]
            side=2,3
        [/filter]
        radius=2
    [/avoid]
[/ai]


Important Note: If you use a different AI engine (FormulaAI or LuaAI) for a side, setting aspects in the [side] tag might not work due to a bug in the AI setup mechanism (or it might; there's no general rule that catches all cases). In that case, you might have to use [modify_side][ai] in a prestart or start event instead. If unsure, you can use :inspect in debug mode to verify whether an aspect was changed successfully.

List of AI Aspects

Note: Only one instance of each aspect will be active for a side at any time. Where multiple instances of the same aspect are included in an [ai] tag, the last whose conditions (time of day, turns, etc.) match will be the only one that applies.

  • advancements: (string) Defines a list of unit types to which AI units can advance. If a unit type is listed here, units that can advance to this type will only advance to this type, even if they have, in principle, several advancement options. As an example, if this aspect is set to 'Javelineer,Elvish Hero', then all Spearmen advance to Javelineers, and all Elvish Fighters advance to Elvish Heroes. All other units follow their usual advancement choices as determined by the AI. Important notes:
    • This is a simplified version of the more complex (and arguably more useful) application of a dynamic Lua advancements aspect, as described here.
    • The advancements aspect only takes effect during the AI turn, that is, on offense only, not on defense.
    • Listing more than one advancement unit type for a given unit still results in only one of the types being used (generally the one listed last).
  • aggression=0.4: (double: ranging from -infinity to 1.0) This key affects how the AI selects its attack targets. The higher the value, the more likely the AI is to attack even if odds are not in its favor. The description below applies as written to the combat CA only, but aggression is taken into account by the high_xp_attack and spread_poison CAs as well (as of Wesnoth 1.13.5 and 1.15.3 respectively).
    • Important: do not set aggression to values greater than 1 as this makes the AI prefer attacks in which it receives more damage (see below) unless that is specifically the effect you want to achieve.
    • In the attack evaluation, each attack (this includes attack combinations of several AI units against the same enemy unit) is assigned a score. The attack with the highest score is done first. Then the next attack is evaluated, until no attack with a score greater than 0 is found any more. (Note that this attack score is different from the combat CA score, which is always 100,000 as long as an individual attack score >0 is found. The combat CA score is zero if the highest attack score is <=0).
    • The attack score is a complex combination of many different aspects of the attacks. Positive (additive) contributions to the score are things like the value (cost and XP) of the target, the chance to kill the target, whether it is already wounded, how much damage the attack is likely to inflict, etc. Negative (additive) factors include how much damage the AI's units are likely to take, how valuable they are, how exposed they will be after the attack, etc. There are also multiplicative factors that are used if the attack target is a threat to the AI's leader etc.
    • All the negative contributions to the score are multiplied by '(1-aggression)'. This means that:
      • If 'aggression=1', no negative contributions are added to the score. Thus, the AI disregards damage done to its own units and selects attacks based solely on the damage it can do to enemy units. If the AI can inflict 1 damage and take 0, or inflict 2 damage and take 20, it will take the latter option.
      • The smaller the value of aggression, the more weight is put on value of and potential damage to the AI's units as compared to the attack target.
      • Roughly speaking, 'aggression=0' results in the AI valuing its units approximately as much as the enemy units. This is not a one-to-one relation, but can be used as an approximate guideline.
      • Very large negative values of aggression mean that the value of the AI's units is much more important than that of the enemy units. As a result, the AI never attacks unless it will receive no damage in exchange.
      • The rating for damage received in an attack actually becomes a positive contribution to the score for values of aggression larger than 1. This usually does not result in sensible behavior and values greater than 1 should therefore not be used.
    • Note: aggression is always set to 1.0 for attacks on units that pose a direct threat to the AI's leader. Currently this only means units adjacent to the leader.
  • allow_ally_villages=no (bool) (Version 1.17.6 and later only) Affects retreat-injured CA only. Normally, the AI is not allowed to take villages from an ally. If this is set to 'yes', the AI may retreat injured units to allied villages (and thereby capture them).
  • [attacks]: Filters the units considered for combat, both on the AI and the enemy sides. Applies to the combat, high_xp_attacks and spread_poison CAs only. It cannot be set in the same way as the other aspects and is therefore described in a separate section below.
  • [avoid]: Makes the AI avoid specific locations. The AI never moves a unit to these locations except for trying to move its leader to a keep or toward [leader_goal]s, and thus applies to all CAs except move-leader-to-goals and move-leader-to-keep.
    • StandardLocationFilter: The locations for the AI to avoid. Do not use a [filter_location] tag.
    • Note: Only one instance of an [avoid] aspect will be active for a side at any time. Where multiple instances are included in an [ai] tag, the last whose conditions (time of day, turns, etc.) match will be the only one that applies.
  • caution=0.25: (double) Defines how cautious the AI is in several ways. It determines whether the leader should move toward [leader_goal], if attacks are worth moving onto less favorable terrain, whether units should retreat, and whether the AI should move units toward targets individually, as groups or not at all. Affects several CAs (listed in the order of their evaluation scores):
    • Move-leader-to-goals CA: If max_risk is not set in [leader_goal], its default value is '1-caution'. This determines whether the leader takes the next step toward his goal. See description of [leader_goal].
    • Combat CA:
      • During the evaluation of attacks, the AI considers whether the attacking units could get onto more favorable terrain if they didn't attack but moved somewhere else instead. The difference between the two terrain ratings, together with a number of other factors, determines the "exposure" rating of the units. This exposure is then subtracted from the 'attack score' as described for aggression above.
      • The exposure rating also contains a multiplication by caution, meaning that 'caution=0' results in exposure not being taken into account, and that it becomes more and more important for larger values. In other words, the higher the values of caution, the more reluctant is the AI to attack from unfavorable terrain. (Note that exposure is one of the negative contributions to the attack score as described for aggression, and therefore is also ignored if 'aggression=1' is set.)
      • If the AI leader is used in an attack, the AI always uses 'caution=2' for the evaluation of that attack.
    • Retreat CA: (Version 1.15.3 and later only) This CA has been removed.
      • If caution is greater than 0, there is an evaluation of forces for the map location a unit stands on. This is basically the sum of damage that can be done to that location by either side, reduced by terrain defense and relative hitpoints if attackers don't have full health. A retreat takes place, if caution × their_power > our_power. There is also a terrain factor involved if the attacker is not on optimal terrain, similar to the exposure described above for the combat CA.
      • So let's say the AI has its default caution of 0.25. Then the enemy forces have to be at least 4 times as strong before the unit retreats. For a caution of 1, as soon as the enemy is stronger, the unit retreats.
      • The AI never retreats if caution is set to 0 or lower.
    • Move-to-targets CA:
      • If grouping for the AI is enabled and the path along which to move toward a target is considered to be dangerous, caution has an influence, too. "Dangerous" mainly means that there is a good chance for a unit to be killed if it's by itself. In that case, the AI compares its units to the enemy units and based on the result moves forward or not. All units that can reach the next location of the move are considered. The formula for deciding whether to move toward the target as a group is our_strength / their_strength > 0.5 + caution. If this condition holds true, units are moved toward the goal as a group, otherwise they try to group together in a location favorable for a attack on the enemy during the next turn.
      • So if caution is 0.5, the AI side needs to be at least as strong as the enemy. If it is 0, the AI moves toward the target, even if the enemy is up to twice as strong as the AI. Setting caution to 1.5 means the AI needs to be at least twice as strong as the enemy.
      • The AI also considers retreating units during the move-to-target phase based on criteria similar to those for the retreat CA.
  • grouping="offensive": (string) How the AI should try to group units. Applies to move-to-targets CA only. Possible values:
    • offensive: Makes the AI try to group units together before attacking.
    • defensive: Makes the AI group units together very conservatively, only advancing them much beyond its castle if it has overwhelming force.
    • no: Makes the AI use no grouping behavior.
  • leader_aggression="-4.0": Exactly as aggression, but for units which can recruit. Applies to combat CA only. Note that the move-leader-to-keep CA has a higher score than the combat CA. A leader therefore usually only attacks if he is on his keep at the beginning of the turn, otherwise he moves toward the closest keep instead, even with leader_aggression=1.
  • [leader_goal]="": Makes the AI try to move its leader to a specific location. Applies to move-leader-to-goals CA only.
    • x, y: The location toward which the AI should move its leader.
    • auto_remove=no: (bool) If 'no' (default), the AI moves the leader to the goal, after which he stays there until [leader_goal] is removed manually. If 'yes', the leader_goal is removed upon the leader getting there. Important: this only works if id is set correctly (see the next bullet).
    • id="": (string) An internal id key of the [leader_goal] tag. An id is required for auto_remove to work. However, setting this id does not automatically set the id of the [leader_goal] facet. Thus, in principle for this to work, you need to set the id of the facet as described here and set the id key in [leader_value] to the same value. Since you are probably only going to use one [leader_goal] tag at a time, there is a much simpler way: setting 'id=0' (which refers to the first facet) or 'id=*' (which means all facets) in [leader_goal] allows auto_remove to work without the extra step of setting the facet id. (Version 1.13.5 and later only) Setting this now also sets the id of the [leader_goal] facet, allowing auto_remove to work with multiple leader goals without using the fully-expanded aspect syntax.
    • max_risk=1-caution: (double: meaningful values are >=0) How much risk the leader may be exposed to by moving toward the goal. For evaluating this risk, the AI multiplies the leader's hitpoints by this number. The leader is only moved toward the goal if the resulting value is larger than the expected damage the leader is going to take during the next enemy turn. Thus, 'max_risk=0' means he will only move if no attack on him is possible at the target hex of the move. 'max_risk=1' (or larger) results in him moving even if he's almost certainly going to die.
  • leader_ignores_keep=no: (bool) Set to 'yes' for this aspect to apply to all leaders of a side. (Version 1.15.3 and later only) In addition to 'yes/no', the aspect can now also be set to a comma-separated list of unit ids. The aspect then only applies to leaders with ids matching an id on that list. Setting leader_ignores_keep for some or all leaders means that:
    • The affected AI leaders do not move to the closest keep at the beginning of the turn. Instead, they participate in the move_to_targets candidate action (and all other CAs in which they already participated anyway, of course). Thus, these leaders behave in the same way as any other unit of the AI side.
    • This also means that these AI leaders do not recruit except on the first turn if they start on a keep, or if they accidentally end up on a keep. Thus, if a leader is supposed to recruit first and then participate in the action, leader_ignores_keep should be set to 'no' at the beginning of the scenario, and be changed to 'yes' in an event later.
  • leader_value=3: (double) A number 0 or higher which determines the value of enemy leaders as targets. Affects move-to-targets CA only (and therefore specifically does not apply to attacks).
  • passive_leader=no: (bool) If 'yes', the AI leader never moves or attacks, not even to move back to the keep (unless 'passive_leader_shares_keep=yes' is set) or to attack adjacent units, except to obey [leader_goal]s. Affects all CAs except recruitment and move-leader-to-goals. (Version 1.15.3 and later only) In addition to 'yes/no', the aspect can now also be set to a comma-separated list of unit ids. The aspect then only applies to leaders with ids matching an id on that list.
  • passive_leader_shares_keep=no: (bool) If 'yes', lets the AI leader moves off the keep to share it with allied leaders (if they can reach it next turn) if 'passive_leader=yes' is set. He also returns to keep to recruit when possible and attacks adjacent enemy units. (Version 1.15.3 and later only) In addition to 'yes/no', the aspect can now also be set to a comma-separated list of unit ids. The aspect then only applies to leaders with ids matching an id on that list.
  • recruitment_diversity, recruitment_instructions, recruitment_more, recruitment_pattern, recruitment_randomness, recruitment_save_gold: These aspects can be used to customize recruiting with the new recruitment CA introduced in Wesnoth 1.11. They are described on a separate page.
  • retreat_factor=0.25 (double) (Version 1.15.11 and later only) Affects retreat-injured CA only. Determines how injured AI units have to be before they attempt retreating. This is approximately the fraction of the units' hitpoints, but other factors play a role also, such as the terrain the units are on, and leaders and poisoned units retreat somewhat earlier. Setting this to 0 (or negative values) disables retreating. Note that even setting this to very large values still requires units to be somewhat injured before they start retreating.
  • retreat_enemy_weight=1.0 (double) (Version 1.15.11 and later only) Affects retreat-injured CA only. When deciding where to retreat to, the AI considers how much healing a location provides and weighs it against the threat of all the enemies that can get there (balanced by the own units that can get there). In this evaluation, it multiplies the enemy threat rating by retreat_enemy_weight, meaning that the larger its value is, the more a unit tries to move away from enemies. There are three regimes for this aspect:
    • Positive values: Only locations that provide healing (both from terrain and from adjacent healers which have no MP left) are considered. For regenerating units, all hexes are treated as if they provide healing.
    • Zero: Enemy threats are ignored
    • Negative values: All hexes are considered for retreating. The enemy threat rating is multiplied by the absolute value of the aspect value. Thus, if very negative values are used (e.g. -100), this can be used to make units run away from enemies with little consideration for anything else.
  • scout_village_targeting=3: (double) The AI multiplies the value of village targets for scouts by this value. Affects move-to-targets CA only.
  • simple_targeting=no: (bool) If 'yes', the AI moves its units toward targets one by one (sequentially), without considering whether another unit might be better suited for the current move or target. If 'no' (the default), all units are considered for all targets. This is slower, but might result in better moves. Affects move-to-targets CA only.
  • support_villages=no: (bool) Trigger a code path that tries to protect those villages that are threatened by the enemy. This seems to cause the AI to 'sit around' a lot, so it's only used if it's explicitly enabled. Affects move-to-targets CA only.
  • village_value=1: (double) A number 0 or higher which determines how much the AI tries to go for villages as targets. Affects move-to-targets CA only.
  • villages_per_scout=4: (int) A number 0 or higher which determines how many scouts the AI recruits. If 0, the AI doesn't recruit scouts to capture villages. Affects recruitment CA only.

Removed AI Aspects

The following AI parameters (aspects) can still be set, their values can be retrieved, and they can be viewed in the gamestate inspector dialog, but they do not have an effect in the RCA AI code any more. Some other parameters will also likely be removed in the future. We will update this list accordingly. (Version 1.13.5 and later only) Except for attack_depth, these have now all been removed. (Version 1.15.0 and later only) attack_depth is now removed as well.

  • attack_depth=5: (int)
  • number_of_possible_recruits_to_force_recruit=3.1: (double)
  • recruitment: This aspect was used to customize the recruitment of the old default AI (the one used before the RCA AI). This recruitment code is not used in the RCA AI any more. Setting recruitment instructions with this aspect is therefore meaningless. Use the recruitment_instructions aspect instead.
    • It is, in principle, still possible to use this aspect together with the recruitment stage, but this is discouraged for the reasons given at this link.
  • recruitment_ignore_bad_combat=no: (bool)
  • recruitment_ignore_bad_movement=no: (bool)

AI Targets and Goals

AI targets are used in the move-to-targets candidate action (CA) to move the AI's units toward selected units or locations. The AI engine automatically selects all enemy leaders, enemy units that pose a threat to the AI leader and unowned or enemy-owned villages as targets and assigns them certain base values. Additional targets can be defined using the [goal] tag.

It is very important to realize that these targets apply to the move-to-targets CA only and have no influence on other CAs. In particular, they have no effect whatsoever on which enemies the AI attacks. This is often a source of confusion for scenario creators. More background information on RCA AI targets and goals can be found here. The sections below only describe how to set up goals in order to add targets for the move-to-targets CA.

The [goal] Tag

The [goal] tag defines units or locations as move targets (not attack targets!) for the AI. Applies to move-to-targets CA only. <-- That is extremely important to understand, in particular the fact that the [goal] tag has no influence whatsoever on attacks.

The following keys/tags can be used:
  • name="target": (string) The following values are possible and result in different types of targets, as shown in the examples below:
    • target: The (default) target goal specifies target units (not necessarily enemy units) toward which the AI should move its units. (Version 1.13.5 and later only) target_unit is now a synonym for this.
    • target_location: Specifies target locations toward which the AI should move its units.
    • protect_location: Specifies locations that the AI should protect. Enemy units within the specified distance (protect_radius) of one of these locations are marked as targets with the provided value. Note that the AI will not station any units around the protected locations. It will only send units toward enemy units that come within protect_radius of them.
    • protect_unit: Specifies units (of all sides) that the AI should protect. Enemy units within protect_radius of one of these units are marked as targets with the provided value. Note once again that the AI will not place units around the protected units if there are no enemies nearby.
    • protect_my_unit: (deprecated) Specifies units from the AI's own side that the AI should protect. (This is basically the protect_unit goal with an implied side= in the filter, restricting matching units to the AI's side.) Enemy units within protect_radius of one of these units are marked as targets with the provided value. Note once again that the AI will not place units around the protected units if there are no enemies nearby.
    • lua_goal: A dynamically calculated goal written in Lua. See here for details on how this works.
  • value=0: (double) The value of the goal.
  • protect_radius=20: (int) The protection radius. Applies to protect_location, protect_unit and protect_my_unit.

Examples of [goal] Tag Usage

target:

[ai]
    [goal]
        [criteria] #NOTE: this is a SUF, because we're targeting a unit
            side=3
        [/criteria]
        value=5
    [/goal]
[/ai]

target_location:

[ai]
    [goal]
        name=target_location
        [criteria] #NOTE: this is a SLF, because we're targeting a location
            x,y=42,20
        [/criteria]
        value=5
    [/goal]
[/ai]

protect_location:

[ai]
    [goal]
        name=protect_location
        [criteria] #NOTE: this is a SLF, because we're protecting a location
            x,y=42,20
        [/criteria]
        protect_radius=16
        value=5
    [/goal]
[/ai]

protect_unit:

[ai]
    [goal]
        name=protect_unit
        [criteria] #NOTE: this is a SUF, because we're protecting a unit
            side=3
        [/criteria]
        protect_radius=16
        value=5
    [/goal]
[/ai]

How to use protect_unit to protect the own leader (We are side 2)

[ai]
    [goal]
        name=protect_unit
        [criteria]
            side=2
            canrecruit=yes
        [/criteria]
        protect_radius=8
        value=5
    [/goal]
[/ai]

Deprecated AI Targeting Aspects

The following AI targeting parameters currently still work, but have been superseded by the [goal] tag. They should not be used any more as they will likely be removed at some point. These tags only apply to the move-to-targets CA.

  • [target]="": Deprecated. Any number of [target] tags can be used to set targets for the AI. For anything related to 'values', set them relative to other targets. An AI is willing to dedicate twice as many resources and travel twice as far to get to a target worth '2.0' as for a target worth '1.0'. Applies to move-to-targets CA only.
    • StandardUnitFilter: Do not use a [filter] tag.
    • value=1: (double) A number greater than 0 (default=1) which determines how much the AI tries to move toward units which pass the filter.
  • [protect_location]="": Deprecated. Gives the AI a location to protect. Note that the AI does not station any units around the location, it only sends units to attack any enemy units that come within the guarding radius of the target. Applies to move-to-targets CA only.
    • x, y: Standard coordinates. These indicate the location the AI is protecting.
    • radius: The radius around it to protect (0 indicates a single hex). (Version 1.13.5 and later only) This key has been changed to protect_radius, though it's preferred to change old code to use the [goal] tag instead.
    • value: The importance of protecting this location.
  • [protect_unit]="": Deprecated. Gives the AI a set of units to protect. Note once again that the AI does not place units around the protected units if there are no enemies nearby. Applies to move-to-targets CA only.
    • StandardUnitFilter: The unit(s) to protect. Do not use a [filter] tag.
    • radius: The radius around it to protect (0 indicates a single hex). (Version 1.13.5 and later only) This key has been changed to protect_radius, though it's preferred to change old code to use the [goal] tag instead.
    • value: The importance of protecting this unit.
  • protect_leader=2.0 and protect_leader_radius=10: Deprecated. Target any enemy units that come within 'protect_leader_radius' of the AI leader with a value of 'protect_leader'. Applies to move-to-targets CA only.

Filtering which Units Participate in which Actions

(Version 1.15.3 and later only)

Each candidate action of the default AI can be restricted to apply to only a subset of the AI units. This is done by adding a [filter_own] tag to the [candidate_action] tag definition.

Typical use cases:

  • Restricting an action to certain units so that other units are not used to this. For example, village grabbing could be restricted to scout units only, so that slower units do not take detours on their way toward the enemies. See the example below.
  • Excluding units from a certain action in order to have them available for other actions afterward. For example, one might want to add a custom candidate action which moves healers behind injured units (or use the existing Micro AI for this). Ideally, this should happen after all other units have moved, specifically also after the move-to-targets candidate action (MtT CA) is done. In the default setting, however, the MtT CA would also move the healers. Thus, we would want to exclude them using a [filter_own] tag.
  • Adding two instances of the same candidate action with different scores to force the order in which units participate in this action. For example, one could add another instance of the move-leader-to-keep CA with a [filter_own] tag restricting it to one leader, in order to make this leader move to a keep (and therefore recruit) first.

Note that for the combat AI, using the attacks aspect to filter units as described in the next section is slightly more efficient. Thus, that should be the preferred method if there are many units on the map.

Example:

[candidate_action]
	id=villages
	engine=cpp
	name=ai_default_rca::get_villages_phase
	max_score=60000
	score=60000
	[filter_own]
		type=Wolf Rider
	[/filter_own]
[/candidate_action]


Filtering Combat with the attacks Aspect

The attacks aspect lets us filter the units considered by the combat, high_xp_attacks and spread_poison candidate actions. Units on the AI side can be selected with the [filter_own] tag and enemy units are filtered via [filter_enemy], both of which take a StandardUnitFilter. Only units defined in these tags are considered as attacker/target pairs. To define, for example, an attacks aspect in which units from the elvish sorceress line are the only attackers, and undead units are the only targets, use

[ai]
    [aspect]
        id=attacks
        [facet]
            invalidate_on_gamestate_change=yes
            [filter_own]
                type=Elvish Sorceress,Elvish Enchantress,Elvish Sylph
            [/filter_own]
            [filter_enemy]
                race=undead
            [/filter_enemy]
        [/facet]
    [/aspect]
[/ai]

Several important notes:

  • The attacks aspect is a composite aspect and cannot be defined using the simple syntax of the other standard aspects. See here for a description of the syntax of the example.
  • This only works if invalidate_on_gamestate_change=yes is set. The reason is that the attacks aspect internally contains information about all available attacker/target pairs. These need to be recalculated after each move. This is explained here.
  • If [filter_own] or [filter_enemy] are omitted, the selection defaults to all units of the respective sides.
  • Most importantly: The above example results in sorceress-line vs undead attacks being the only attacks done by the AI. No other attacks are executed, no matter how advantageous their outcomes may be. There is no simple way around that, but it can be accomplished by one of the following means:
    • Setting up the [filter_own] or [filter_enemy] StandardUnitFilters to adapt dynamically to the situation on the map.
    • Adding a Lua candidate action which dynamically adjusts the aspect depending on the current situation on the map. An example of dealing with this is given in the Micro AI test scenario Protect Unit.
    • Using dynamic Lua aspects is in principle also possible, but far from easy due to the complex tables this aspect returns.

(Version 1.13.5 and later only)

Though the above code still works in 1.13.5 and later (and will continue to work indefinitely), it can also be simplified a little:

[ai]
    [attacks]
        invalidate_on_gamestate_change=yes
        [filter_own]
            type=Elvish Sorceress,Elvish Enchantress,Elvish Sylph
        [/filter_own]
        [filter_enemy]
            race=undead
        [/filter_enemy]
    [/attacks]
[/ai]

See Also

This page was last edited on 21 October 2024, at 06:38.