ReferencePythonAPI
From Wesnoth
The Python AI works by executing a python script at each turn, allowing to move and attack units. This document explains how to enable that AI and describes the objects a Python script can access as well as their properties and methods.
All properties are read-only, unless specified otherwise.
All objects except wesnoth.gamemap support the == operator. They actually support comparisons as well, but the result is only meaningful for equality test.
Contents |
Building and specifying options for the Python AI
Python support will be built if HAVE_PYTHON is defined during the build process. Under Unix, this is disabled with the --disable-python configure switch.
There are three ways to use a Python AI once Python support is enabled. In all three cases, the .py file must be in the data/ais path relative to the Wesnoth data dir or userdata dir. E.g. under Unix, these scripts would be found: ~/.wesnoth/data/ais/my_ai.py, /usr/share/wesnoth/data/ais/my_ai.py. Or in Windows, wesnoth/userdata/data/ais/my_ai.py and wesnoth/data/ais/my_ai.py.
- Method 1: Start a multiplayer game, and select the python AI to use. It must be present for all players. For this to work, the main .py file of the AI needs to have this comment as first line:
#!WPY
- Method 2: Start a game from the commandline, using the --multiplayer option, for example (in one line):
wesnoth --multiplayer --scenario=multiplayer_Fallenstar_Lake --controller2=ai --controller3=ai --algorithm2=python_ai --parm2=python_script:test.py --side2="Knalgan Alliance" --side3="Rebels"
The above will start the scenario with the given id, with player 2 playing as python AI and using the script "test.py".
- Method 3: Specify a python AI directly inside a map. In the
[side]tag, put the following lines:controller=ai [ai] ai_algorithm=python_ai python_script=path to script [/ai]
In this case, the script should reside in a directory "data/ais" below the campaign path.
Python availability
Wesnoth can be compiled without Python support, in which case Python AIs are not loaded. You can use the PYTHON preprocessor symbol in WML to check for that case (and then for example display a message about it to the user). See PreprocessorRef. Also see the next section.
Implementation details of the Python AI
There are a few details of the implementation that should be kept in mind when writing an AI. There is one Python interpreter, which is used by all AI's and initialized once, in the game. This Python interpreter will run the AI script every turn.
This has the following consequences:
- The AI script is reloaded every turn, so it's not possible to store a global variable in the main script to cache data. See get_variable() and set_variable() for how to store data between turns (and also over saving/reloading a game).
wesnoth module reference
This is an automatically generated reference, but feel free to edit it - changes will not be overwritten but instead reviewed and included in the next version. This is the wesnoth AI module. The python script will be executed once for each turn of the side with the python AI using the script.
Functions
| attack_unit() | attack_unit(location attacker, location defender, int weapon = -1)
Unit at position 'attacker' attacks unit at position 'defender' with weapon 'weapon'. The weapon parameter is optional, and the same weapon which would be highlighted for a human player is used if it is omitted. |
| get_adjacent_tiles() | positions = get_adjacent_tiles(location)
Returns a list of wesnoth.location representing tiles adjacent to the specified location. |
| get_current_team() | team = get_current_team()
Returns a wesnoth.team object representing the current team. |
| get_destinations_by_unit() | moves = get_destinations_by_unit()
Returns a dictionary. Keys are wesnoth.location objects pointing to player's units, values are lists of possible destinations for this unit. |
| get_enemy_destinations_by_unit() | moves = get_enemy_destinations_by_unit()
Returns a dictionary. Keys are wesnoth.location objects pointing to player's units, values are lists of possible destinations for this unit. |
| get_enemy_units_by_destination() | moves = get_enemy_units_by_destination()
Returns a dictionary. Keys are wesnoth.location objects pointing to positions the enemie's units can reach, values are lists of locations where units that can reach this position are. |
| get_gamestatus() | status = get_gamestatus()
Returns a wesnoth.gamestatus object representing the current game status. |
| get_location() | location = get_location(x, y)
Returns a wesnoth.location object pointing to position (x, y) on the map. |
| get_map() | map = get_map()
Returns a wesnoth.gamemap object representing the current map. |
| get_teams() | teams = get_teams()
Returns a list containing wesnoth.team objects, representing the current teams in the game. |
| get_units() | units = get_units()
Returns a dictionary containing (location, unit) pairs. |
| get_units_by_destination() | moves = get_units_by_destination()
Returns a dictionary. Keys are wesnoth.location objects pointing to positions the player's units can reach, values are lists of locations where units that can reach this position are. |
| get_variable() | value = get_variable(variable)
Retrieves a persistent variable 'variable' from the AI, which has previously been set with set_variable - or None if it can't be found. |
| get_version() | get_version()
Returns a string containing current Wesnoth version |
| log_message() | log_message(string)
Logs a message, displayed as a chat message, if debug is enabled. |
| move_unit() | new_position = move_unit(location from, location to)
Moves the unit on 'from' to the location specified by 'to', and returns a wesnoth.location object representing the position the unit was moved to. |
| raise_user_interact() | raise_user_interact()
Function which should be called frequently to allow the user to interact with the interface. This function will make sure that interaction doesn't occur too often, so there is no problem with calling it very regularly. |
| recruit_unit() | result = recruit_unit(string name, location where)
Recruits the unit of type 'name', at the location 'where'. Returns 1 on success, 0 on failure. |
| set_variable() | set_variable(variable, value)
Sets a persistent variable 'variable' to 'value'. This can be used to make the AI save strings (and other python values which can be marshalled) over multiple turns. |
| test_move() | (enemy_destinations_by_unit, enemy_units_by_destination) or None = test_move(from location, to location (optional))
Returns two dictionaries, representing the possible enemy moves if the unit were to move from 'from location' to 'test location'. If 'to location' is not given, it returns the possible enemy moves ignoring this unit. The results will be the same as if wesnoth.get_enemy_destinations_by_unit() and wesnoth.get_enemy_units_by_destination() were called after actually performing the move. Returns None if there is no unit at 'from location'. |
attacktype
Describes an attack type.
| attack_weight | AI setting, floating point number. |
| backstab | This attack has backstab. |
| berserk | This attack uses berserk. |
| charge | This attack has the 'charge' special. |
| damage | Attack damage. |
| defense_weight | AI setting, floating point number. |
| drains | This attack has the 'drains' special. |
| magical | This attack is magical. |
| marksman | This attack has 'marksman' special. |
| name | Name of the attack. |
| num_attacks | Number of hits. |
| plague | This attack has 'plague' special. |
| poison | This attack has the 'poison' special. |
| range | String with the name of the attack range. |
| slow | This attack causes slow. |
| stones | This attack has 'stones' special. |
gamemap
Represents the current map.
| is_castle() | result = is_castle(location)
Returns True if the given location is a castle tile (where units are recruited to), False otherwise. |
| is_keep() | result = is_keep(location)
Returns True if a keep (where a leader must stand to recruit) is at the given location, False otherwise. |
| is_village() | result = is_village(location)
Returns True if a village is at the given location, False otherwise. |
| x | Width of the map in hexes. |
| y | Height of the map in hexes. |
gamestatus
This class has information about the game status.
| lawful_bonus | The bonus for lawful units in the current turn. This is the percentage to add to the attack damage of lawful units (alignment = 0), and to subtract from chaotic units (alignment = 2). Neutral units (alignment = 1) are not affected. |
| number_of_turns | The maximum number of turns of the whole game. |
| previous_lawful_bonus | The value of lawful_bonus in the previous turn. |
| turn | The current turn. |
location
Represents a single location on the map.
| adjacent_to() | result = adjacent_to(location)
Returns True if the location is adjacent to this one, False otherwise. |
| distance_to() | int distance = distance_to(location)
Returns the distance in hexes to the other location. |
| x | X position, starting with 0 for leftmost column. |
| y | Y position, starting with 0 for topmost row. |
team
Represents one team/player/side.
| gold | The current amount of gold this team has. |
| income | The current per-turn income if this team. |
| is_enemy | Whether this team is an enemy. |
| name | The name of this team. |
| owns_village() | result = owns_village(location)
True if the team owns a village at the given location. |
| recruits() | recruits = recruits()
Returns a list of wesnoth.unittype objects of all possible recruits for this team. |
| side | Side number of this team, starting with 1. |
| targets() | targets = targets()
Returns a dictionary containing all WML targets for the team, mapping their locations to the scores in WML. |
unit
Represents a single unit. Trying to use a method or access a property, with the exception of is_valid, will result in an exception if the unit is invalid (was destroyed last move, and so on).
| attack_statistics() | own_hp, enemy_hp = attack_statistics(location from, location to, int attack = -1)
Returns two dictionaries with the expected battle results when the unit attacks from 'from' to the unit at 'to', optionally using the attack with index 'attack', or if no attack is given the attack which would be presented to the player in the attack dialog. The dictionaries contain the expected hitpoints after the fight, as a mapping from hitpoints to percent, where percent are specified as floating point value from 0 to 1. For example, a return of: {0:1}, {50:0.5, 40:0.5} would mean, the attacking unit is certain to die (probability for 0 hitpoints is 1), and the enemy unit will either remain at 50 or 40 HP after the fight, with equal probability of 0.5. |
| attacks() | attacktype[] = attacks()
Returns list of possible attack types.
|
| can_attack | If the unit can still attack. |
| can_recruit | If the unit can recruit. |
| damage_from() | percent = damage_from(attacktype)
Returns the damage in percent the unit receives when attacked with the given attack type. (0 means no damage at all, 100 means full damage, 200 means double damage.) |
| defense_modifier() | percent = defense_modifier(location)
Returns the defense modifier in % (probability the unit will be hit) on the given location. |
| experience | Current experience of the unit. |
| find_path() | location[] path = find_path(location from, location to, float max_cost = unit.movement_left)
Finds a path from 'from' to 'to' costing less than 'max_cost' movement points to reach and returns it as a list of locations. path[0] will be 'from', path[-1] will be 'to'. If no path can be found (for example, if the target is not reachable, or it would cost more than max_cost), an empty list is returned. |
| hitpoints | Current hitpoints of the unit. |
| is_enemy | True if this is an enemy unit, False if it is allied. |
| is_valid | Indicates if the unit is still valid in the game. This is the only accessible field of an invalid unit, all others trigger an exception. |
| max_experience | Maximum experience of the unit. |
| max_hitpoints | Maximum hitpoints of the unit. |
| max_movement | Maximum movement points of the unit. |
| movement_cost() | cost = movement_cost(location)
Returns the cost of moving over the given location. |
| movement_left | How many movement points the unit has left. |
| name | Name of the unit (description from WML). |
| poisoned | If the unit is poisoned. |
| side | The side of the unit, starting with 1. |
| slowed | If the unit is slowed. |
| stoned | If the unit is stoned. |
| type() | unittype = type()
Returns the type of the unit. |
unittype
Describes a unit type.
| advances_to() | unittype[] = advances_to()
Returns a list of wesnoth.unittype of possible advancements. |
| alignment | Alignment of the type: 0=lawful, 1=neutral, 2=chaotic. |
| attacks() | attacktype[] = attacks()
Returns list of possible attack types.
|
| can_advance | If type can advance. |
| cost | Cost of the type. |
| curing | If type has curing ability (remove poison from others). |
| damage_from() | percent = damage_from(attacktype)
Returns the damage in percent a unit of this type receives when attacked with the given attack type. (0 means no damage at all, 100 means full damage, 200 means double damage.) |
| defense_modifier() | percent = defense_modifier(location)
Returns the defense modifier in % (probability the unit will be hit) on the given location. |
| has_zoc | If type has a ZOC. |
| heals | If type can heal others (either healing or curing ability). |
| hitpoints | Hitpoints of the type. |
| illuminates | If type has illuminates ability. |
| leadership | If type has leadership ability. |
| level | Level of the type. |
| movement | Movement points of the type. |
| movement_cost() | cost = movement_cost(location)
Returns the cost of moving over the given location. |
| name | Name of the unit type. |
| not_living | If type has not-living ability. |
| regenerate | If type has regenerate ability. |
| skirmisher | If type has skirmisher ability. |
| steadfast | If type has steadfast ability. |
| teleport | If type has teleport ability. |
| usage | AI's usage hint of the type, one of: 'archer', 'fighter', 'healer', 'mixed fighter', 'scout'. |
