AiWML

From The Battle for Wesnoth Wiki
Revision as of 15:53, 19 February 2016 by Mattsc (talk | contribs) (Adding and Deleting Aspects with the [modify_ai] Tag: delete content that has been moved to other pages)

[edit]WML Tags

A:

abilities, about, add_ai_behavior, advance, 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, attack_anim, attacks, avoid;

B:

base_unit, berserk, binary_path, break, brush;

C:

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

D:

damage, 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, era, event, 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_vision, filter_weapon, filter_wml, find_path, fire_event, firststrike, floating_text, for, foreach, frame, full_heal;

G:

game_config, get_global_variable, goal, gold, gold_carryover;

H:

harm_unit, has_ally, has_attack, has_unit, 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), illuminates, image, 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, portrait, post_movement_anim, pre_movement_anim, primary_attack, primary_unit, print, 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_unit_overlay, repeat, replace_map, replace_schedule, replay, replay_start, reset_fog, resistance (ability, unit), resistance_defaults, resource, return, role, rule;

S:

save, scenario, scroll, scroll_to, scroll_to_unit, secondary_attack, secondary_unit, section, select_unit, sequence, set_extra_recruit, set_global_variable, set_menu_item, set_recruit, set_specials, set_variable, set_variables, sheath_weapon_anim, show_if (message, set_menu_item), show_objectives, side, skirmisher, 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_type, store_unit_type_ids, store_villages, story, swarm, switch, sync_variable;

T:

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

U:

unhide_unit, unit, unit_overlay, unit_type, unit_worth, units, unlock_view, unpetrify, unstore_unit, unsynced;

V:

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

W:

while, wml_message, wml_schema;

Z:

zoom;

Configuring the Default AI Using WML

This page describes how the behavior of the default (RCA) AI can be configured 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 focuses mostly on descriptions of the various AI configuration parameters and how to set them up at the beginning of a scenario, although for many of them (for example, for all simple aspects) the methods for changing them mid-scenario are almost identical. See Modifying AI Components for instructions for some of the more complex AI configuration tasks.

The [ai] Tag: Defining Aspects and Goals

The [ai] tag is used inside a [side] or [modify_side] tag. Its contents are the RCA_AI's aspects and goals that can be used to customize certain aspects of the AI. 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 it receives reinforcements on a specific turn.

Examples of simple uses of the [ai] tag to set AI parameters (aspects) are

[ai]
    aggression=0.99
[/ai]

or

[ai]
    [avoid]
        [filter]
            side=2,3
        [/filter]
        radius=2
    [/avoid]
[/ai]

Important Note: if you use a different AI engine (FormulaAI or LuaAI) or a Micro AI 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] in a prestart or start event instead. If unsure, you can use ':inspect' in debug mode to verify whether an aspect was changed successfully.

The following general keys/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 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.

In addition to these general keys, the aspects themselves make up the remaining keys and tags of the [ai] tag. These are described in the following sections.

List of AI Aspects

  • 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 below.
    • 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. Applies to combat CA only.
    • 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 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.
  • [attacks]: Filters the units considered for combat, both on the AI and the enemy sides. Applies to the combat CA 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.
  • 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 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:
      • 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.
  • [goal]="": Defines units or locations as targets for the AI. See the dedicated section on the [goal] tag below for details. Applies to move-to-targets CA only.
  • 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 below 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.
    • 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) If 'yes', 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). For practical purposes this means that:
    • Leaders participate in all the moves and attacks in the same way as any other unit of the AI side.
    • 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.
  • 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.
  • 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 them. Affects recruitment CA only.
  • recruitment_instruction="": Limits the number of units of a given type that the AI can have on the map simultaneously. Applies to the recruitment CA only. It cannot be set in the same way as the other aspects and is therefore described in a separate section below.
  • recruitment_pattern="": (string) This key takes a comma separated list containing the usages of the units that can be recruited. 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) and 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 it consider all available units. The usage is listed in the unit type config files (see data/core/units/ for mainline units; see also UnitTypeWML). Affects recruitment CA only.
    • For example, "recruitment_pattern=fighter,fighter,archer" means that the AI recruits on average twice as many fighters as archers, and does not recruit scouts (other than scouts for capturing villages, which are recruited independently), healers or mixed fighters. It does not mean that it recruits two fighters first, then an archer, then two fighters again, etc.
  • 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.

Deprecated AI Targeting Aspects

The following AI targeting parameters (aspects) 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 specify targets and 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).
    • 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).
    • 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.

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

  • attack_depth=5: (int)
  • number_of_possible_recruits_to_force_recruit=3.1: (double)
  • 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 and is essential to understand. More background information about AI targets and goals can be found here. The sections below only describe how to modify goals and targets in WML.

The [goal] Tag

The [goal] tag specifies target units or locations toward which the AI should move its units in the move-to-targets CA. 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.
    • 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.
  • 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]

To modify goals from WML events, several helper macros are available in data/core/macros/ai.cfg.

Filtering Combat with the 'attacks' Aspect

The attacks aspect lets us filter the units considered during the combat candidate action. 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 either

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

or

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

Several important notes:

  • See A Bit More on Simple vs. Composite Aspects and Adding and Deleting Aspects with the [modify_ai] Tag below for explanations of the syntax used in these examples.
  • This only works if 'invalidate_on_gamestate_change=yes' is set, so that the available attacker/target pairs are recalculated after each move. This is also explained at A Bit More on Simple vs. Composite Aspects.
  • If [filter_own] or [filter_enemy] are omitted, the selection defaults to all units of the respective sides.
  • Most importantly: The above examples result in the sorceresses-on-undead attacks being the only attacks done by the AI. No other attacks are executed, no matter how advantageous their outcomes might be. There is no simple way to get around that. An example of dealing with this (executing all attacks of a certain kind first, then doing whatever possible attacks are left afterward) by setting up an additional Lua candidate action can be found in Micro AI test scenario 'Protect the Wizard' in /data/ai/micro_ais/.

Limiting Recruiting with the 'recruitment_instruction' Aspect

The number of units that can be recruited by the AI can be limited using the recruitment_instruction aspect. To define, for example, a recruitment_instruction aspect in which only two bowmen and one swordsman can be recruited, use

[ai]
    [aspect]
        id=recruitment
        [facet]
            [value]
                name=ai_default::recruitment
                [limit]
                    type=Swordsman
                    max=1
                [/limit]
                [limit]
                    type=Bowman
                    max=2
                [/limit]
            [/value]
        [/facet]
    [/aspect]
[/ai]

For all the possible keys and syntax, see here.

Several important notes:

  • This aspect may currently result in no recruiting happening at all after the listed units have reached their limit, if those units seem more desirable to the AI than the rest of the recruit list. This is due to a bug and will be fixed soon.
  • See A Bit More on Simple vs. Composite Aspects below for an explanation of the syntax used in this example.
  • The [modify_ai] tag can also be used, equivalently to what is shown above for the attacks aspect.
  • 'name=ai_default::recruitment' needs to be set exactly like this, so that the ai_default::recruitment stage is used.
  • A separate [limit] tag needs to be used for each unit type.
  • The number set by the max key limits the number of units that the side can have simultaneously. Thus, if one of the bowmen dies in the example above, another can be recruited. This is the same behavior as one gets with the LIMIT_CONTEMPORANEOUS_RECRUITS macro.
  • Units for which no [limit] tag is defined can be recruited in arbitrary amounts.

Dynamic Lua Aspects

Aspects can also be defined dynamically using Lua. Here is an example of defining aggression so that it increases slowly from turn to turn:

[aspect]
    id=aggression
    engine=lua
	     
    code=<<
        local value = wesnoth.current.turn / 10.
        return value
    >>      
[/aspect]

Dynamic advancements Aspect

The advancements aspect can be used with a function advance(x, y), where (x, y) is the current location of the unit about to advance. You may use wesnoth.get_unit(x, y) to retrieve the unit object itself. For example, the following code advance the Spearman with id=Bob to a Swordsman, while all other Spearmen are advanced to Javelineers.

[ai]
    [aspect]
        id=advancements
        engine=lua

        code=<<
            function advance(x, y)
                local unit = wesnoth.get_unit(x, y)
                if (unit.id == 'Bob') then
                    return 'Swordsman'
                else
                    return 'Javelineer'
                end
            end
            return advance
        >>
    [/aspect]
[/ai]

Note that the return value of advance(x, y) could also be a list. See above for several important notes on the advancements aspect.

Adding, Deleting or Changing Aspects and Goals Mid Game

The previous sections of this page demonstrate how to set up aspects and goals at the beginning of a scenario using the [ai] tag inside [side] tags. The standard aspects can also be changed while a game is in progress using the [ai] tag inside a [modify_side] tag with the same syntax. However, that does not work for composite aspects and all other AI components. For these, the [modify_ai] tag needs to be used. It has a more complex styntax and is described at Modifying_AI_Components.

See Also