# oolite AI Reference

This page contains reference information regarding the AI system used by oolite. It will be useful for anyone creating an OXP that contains AI elements, or for tinkering with the default AI.

## AI Script Format

The AI system consists of a stack of state machines (only the top one of which is active), which respond to game events sent to them as messages. They respond by calling a series of methods which affect the behaviour of the entity and possibly trigger changes to the AI by changing the state or (more drastically) the state machine.

Each state machine (or AI script) is described in a property list in either ASCII or XML format, which can be edited with a text editor or with Property List Editor. The structure is of a dictionary containing each of the machine's possible states referenced by an identifying state name. Each state comprises a dictionary of responses to messages the AI might receive, referenced by the message itself. Each response is an array of methods that will be called when the AI receives that message.

The AI function calls within a message handler are separated from each other by a comma. If a function takes a parameter the value is separated from the function name by a colon and a space, and both the function name and value are enclosed in double quotes.

In ASCII format a simple (two-state) machine looks like this:

    {
        "STATE_1" = {
            ENTER = ();
            "MESSAGE_A" = ("method1: value", method2, method3);
            "MESSAGE_B" = (method4, "setStateTo: STATE_2");
            EXIT = ();
            UPDATE = ();
        };
        "STATE_2" = {
            ENTER = ();
            "MESSAGE_A" = ("method1: another_value", method5);
            "MESSAGE_B" = (method6, method7, "setStateTo: STATE_1");
            EXIT = ();
            UPDATE = ();
        };
    }

## Game defined states and messages

When an AI state machine is started it is always put into the state GLOBAL, and the ENTER message will be sent.

The following table describes each message the game engine may send to an AI state machine.

These messages may be sent while processing commands executed by the AI state machine, or while the AI's controlled entity is performing it's current task.

`ACCEPT_DISTRESS_CALL` |
`AEGIS_CLOSE_TO_PLANET` |
`AEGIS_IN_DOCKING_RANGE` |
`AEGIS_LEAVING_DOCKING_RANGE` |
`AEGIS_NONE` |
`APPROACH_COORDINATES` |
`APPROACH_START` |
`APPROACH_STATION` |
`ATTACKED` |
`ATTACKED_BY_CLOAKED` | Sent if the ship is attacked by a cloaked ship.
`CARGO_SCOOPED` |
`COLLISION` |
`CONDITION_GREEN` |
`CONDITION_YELLOW` |
`COURSE_OK` |
`DEPLOYING_ESCORTS` |
`DESIRED_RANGE_ACHIEVED` |
`DOCKED` |
`DOCKING_ABORTED` |
`DOCKING_COMPLETE` |
`DOCKING_REFUSED` |
`DOCKING_REQUESTED` |
`ECM` |
`ENERGY_FULL` |
`ENERGY_LOW` |
`ENTER` | Always sent to the new (now current) state of the AI state machine after switching to a new state.
`ENTERED_WITCHSPACE` |
`ESCORTING` |
`EXIT` | Always sent to the current state of the AI state machine before switching to a new state.
`EXITED_WITCHSPACE` | Sent when a ship is added to the system using the `addShips:` script command, or when it is added to replace a ship that witchespaced out; see also `EXITED WITCHSPACE` below.
`EXITED WITCHSPACE` | Sent when a ship is ressurected in a new system after witchspacing out and being followed by the player.
`FACING_DESTINATION` |
`FIGHTING` |
`FLEEING` |
`FRUSTRATED` |
`GONE_BEYOND_RANGE` |
`GROUP_ATTACK_TARGET` |
`HOLD_FULL` |
`HOLD_POSITION` |
`INCOMING_MISSILE` |
`LANDED_ON_PLANET` |
`LAUNCHED` |
`MOTHER_LOST` |
`NO_STATION_FOUND` |
`NO_TARGET` |
`NOT_ESCORTING` |
`NOTHING_FOUND` |
`ODDS_BAD` |
`ODDS_GOOD` |
`ODDS_LEVEL` |
`REACHED_SAFETY` | Sent when the ship controlled by the AI is fleeing it's `primary_target` and is at least `desired_range` kms from it.
`RED_ALERT` |
`RESTARTED` | Sent when an AI state machine is made the current AI state machine by becoming the top of the AI state machine stack for a particular entity.
`STATION_FOUND` |
`TARGET_CLEAN` |
`TARGET_DESTROYED` |
`TARGET_FOUND` | Sent when searching for a target and something suitable is found. The `found_target` can be made the primary target by calling `setTargetToFoundTarget` in response to this message.
`TARGET_FUGITIVE` |
`TARGET_LOST` |
`TARGET_CLOAKED` | Sent before `TARGET_LOST` when the target becomes invisible (starting in Oolite 1.71).
`TARGET_MARKED` |
`TARGET_MINOR_OFFENDER` |
`TARGET_OFFENDER` |
`THARGOID_DESTROYED` |
`TRY_AGAIN_LATER` |
`UPDATE` | This message is sent to the current state each time the AI gets a chance to "think".
`WAIT_FOR_SUN` |
`WAYPOINT_SET` |
`YELLOW_ALERT` |
`CLOSE CONTACT` | This message is sent when the ship comes close to another ship, if it is tracking close contacts.
`POSITIVE X TRAVERSE` | This message is sent when a close contact moves away in the +X direction.
`NEGATIVE X TRAVERSE` | This message is sent when a close contact moves away in the -X direction.
`POSITIVE Y TRAVERSE` | This message is sent when a close contact moves away in the +Y direction.
`NEGATIVE Y TRAVERSE` | This message is sent when a close contact moves away in the -Y direction.
`POSITIVE Z TRAVERSE` | This message is sent when a close contact moves away in the +Z direction.
`NEGATIVE Z TRAVERSE` | This message is sent when a close contact moves away in the -Z direction.
`RACEPOINTS_SET` | Sent by `setRacepointsFromTarget` on success (used for racing AI).
`NAVPOINT_REACHED` | Sent when the ship reaches a navigation point (used for racing AI).
`ENDPOINT_REACHED` | Sent when the ship reaches the last navigation point (used for racing AI).

## AI State Machine Function Reference

`pauseAI`
Parameters | `double interval` | The number of seconds to pause this AI.
This method pauses the calling AI for the number of seconds specified by the `interval` parameter.
`setDestinationToCurrentLocation`
Parameters | none |
This method sets the destination of the current entity to its current location plus a random offset of up to 0.5 metres in the X, Y, and Z coordinates. This can be used to make a ship idle in a small area of space without being completely still.
`setDesiredRangeTo`
Parameters | `double range` | The desired range for some operation, in metres.

Some methods (such as scanForNearestMerchantmen, checkCourseToDestination, checkDistanceTravelled, etc) require a "desired range" parameter to be set before they can be used.

This method is used to set the desired range. There is only one value for desired range within an instance of the AI. The value of desired range is modified internally by AI methods such as fightOrFleeMissile, setCourseToWitchpoint, and setPlanetPatrolCoordinates.

`setSpeedTo`
Parameters | `double speed` | The desired absolute speed for the current entity.
Sets the speed of the current entity to an absolute value. If this value is greater than the current entity's maximum speed the entity will travel at maximum speed.
`setSpeedFactorTo`
Parameters | `double speed` | The fraction of maximum speed to use.
Sets the speed of the current entity to a fraction of its maximum speed. For example, to set an entity to move at 35% of its maximum speed, supply a speed parameter of value "0.35".
`performFlyToRangeFromDestination`
Parameters | none |
Condition on exit | `CONDITION_FLY_RANGE_FROM_DESTINATION` | Always.
Sets the AI's current state to CONDITION_FLY_RANGE_FROM_DESTINATION. While in this state the entity will attempt to fly to its current destination, stopping at the desired range from it.
`performIdle`
Parameters | none |
Condition on exit | `CONDITION_IDLE` | Always.
Sets the AI's current state to CONDITION_IDLE and resets the frustration factor to zero. Unlike performHold the current speed is not modified.
`performHold`
Parameters | none |
Condition on exit | `CONDITION_TRACK_TARGET` | Always.
Sets the entity's speed to zero, sets the AI's current state to CONDITION_TRACK_TARGET and resets the frustration factor to zero.
`setTargetToPrimaryAggressor`
Parameters | none |

If there is no current primary agressor against the caller, or the caller has already targeted the primary agressor, this function does nothing.

If there is a primary agressor and the caller is not currently attacking another target, the primary agressor is targeted.

If the caller is already attacking another entity there is a 75% chance it will continue to attack the current target rather than change its target to the primary agressor.

The game decides which entity, if any, is currently the primary agressor against the caller.

`performAttack`
Parameters | none |
Condition on exit | `CONDITION_ATTACK_TARGET` | Always.
Tells the caller to start attacking its current target.
`scanForNearestMerchantmen`
Parameters | none |
Message | `TARGET_FOUND` | If a suitable merchant vessel is found within scanner range.
Message | `NOTHING_FOUND` | If no suitable vessel is found within scanner range.
Looks for the nearest merchant vessel (including the player's ship) within scanner range. The calling entity remembers the targeted ship, but it does not become the current target. It can be made the current target by responding to the TARGET_FOUND message with a call to `setTargetToFoundTarget`.
`scanForRandomMerchantmen`
Parameters | none |
Message | `TARGET_FOUND` | If at least one merchant vessel is found within scanner range.
Message | `NOTHING_FOUND` | If no merchant vessels are within scanner range.

Randomly selects one of the merchant vessels within scanner range.

The calling entity remembers the targeted ship, but it does not become the current target. It can be made the current target by responding to the TARGET_FOUND message with a call to `setTargetToFoundTarget`.

The player's ship has an equal chance of being selected, if it is within scanner range. The internal game setting of PIRATES_PREFER_PLAYER is ignored in this function.

`scanForLoot`
Parameters | none |
Message | `TARGET_FOUND` | If at least one scoopable item is found within scanner range.
Message | `NOTHING_FOUND` | If there are no scoopable items in scanner range, controlling entity does not have a fuel scoop, or controlling entity is a station.
Selects the nearest scoopable item within scanner range. The calling entity remembers the item, but it does not become the current target. It can be made the current target by responding to the TARGET_FOUND message with a call to `setTargetToFoundTarget`.
`scanForRandomLoot`
Parameters | none |
Message | `TARGET_FOUND` | If at least one scoopable item is found within scanner range.
Message | `NOTHING_FOUND` | If there are no scoopable items in scanner range, controlling entity does not have a fuel scoop, or controlling entity is a station.
Selects a random scoopable item from all those within scanner range. The calling entity remembers the item, but it does not become the current target. It can be made the current target by responding to the TARGET_FOUND message with a call to `setTargetToFoundTarget`.
`setTargetToFoundTarget`
Parameters | none |
Makes most recently found target the current target.
`checkForFullHold`
Parameters | none |
Message | `HOLD_FULL` | If the calling ship's cargo hold is full.
Checks the amount of cargo in the calling ship's hold, and if the hold is full sends the HOLD_FULL message.
`performCollect`
Parameters | none |
Property change | `condition` | CONDITION_COLLECT_TARGET
Property change | `frustration` | 0.0
Sets the caller to collect the primary target, assumed to be a scoopable item. While in the CONDITION_COLLECT_TARGET condition, the TARGET_LOST message will be received if the target is travelling faster than the collecting ship, and the FRUSTRATED message will be sent after 10 seconds, and thereafter every 5 seconds, while the item has not been collected.
`performIntercept`
Parameters | none |
Property change | `condition` | CONDITION_INTERCEPT_TARGET
Property change | `frustration` | 0.0
Sets the caller to intercept the primary target at maximum speed. While in the CONDITION_INTERCEPT_TARGET condition, the DESIRED_RANGE_ACHIEVED message will be received if the target is within the current `desired_range`.
`performFlee`
Parameters | none |
Property change | `condition` | CONDITION_FLEE_TARGET
Property change | `frustration` | 0.0
Sets the caller to flee from the primary target at maximum speed. While in the CONDITION_INTERCEPT_TARGET condition, the REACHED_SAFETY message will be received once the primary target is at least as far away as the current value of `desired_range`. If the caller has a cloaking device, it will be activated.
`requestDockingCoordinates`
Parameters | none |
Property change | `coordinates` | The coordinates of the nearest station, if any.
Message | `NO_STATION_FOUND` | If there are no dockable entities in the current "universe".
Sets the current `coordinates` to the nearest space station or other dockable entity in the current game area. There may be no stations, for example in witchspace, in which case the `NO_STATION_FOUND` message is sent to the current AI state.
`getWitchspaceEntryCoordinates`
Parameters | none |
Property change | `coordinates` | Set to appropriate coordinates to enter witchspace.
Sets the current `coordinates` to an appropriate point to make a witchspace jump. "Appropriate" means either 10kms away from the nearest station, or if no station is found, the distance that can be flown forward in 10 seconds of flying at maximum speed (note that actual speed is not changed).
`setDestinationFromCoordinates`
Parameters | none |
Property change | `destination` | Set to the current value of `coordinates`.
Sets the ship's `destination` to the current value of `coordinates`.
`performDocking`
Parameters | none |
Not implemented yet - does nothing.
`performFaceDestination`
Parameters | none |
Property change | `condition` | CONDITION_FACE_DESTINATION
Requests the ship stop and face the location given by `destination`. The message `FACING_DESTINATION` will be sent when this has been achieved.
`performTumble`
Parameters | none |
Property change | `condition` | CONDITION_TUMBLE
Requests the ship randomly vary it's pitch and roll until taken out of `CONDITION_TUMBLE`. Current speed is not affected.
`fightOrFleeMissile`
Parameters | none |
Property change | `found_target` | Is set to the missile if AI's ship or one of it's group is the target of the missle. The other ships in the group also have their `found_target` changed to the missle.
Property change | `primary_aggressor` | Is set to the missile if AI's ship or one of it's group is the target of the missle. The other ships in the group also have their `found_target` changed to the missle.
Property change | `desired_range` | Is set to 10 kms if the ship decides to flee.
Message | `FLEEING` | If the missile is targeted at the AI's ship or one of it's group, and the AI's ship does not have an ECM.

If a missile is in flight and is targeting the AI's ship or another ship in it's group, all ships in the group have their `found_target` and `primary_aggressor` properties changed to that missle.

The first missle found is dealt with, range and bearing are not taken into account.

If the AI's ship has an ECM it will use it. If not, the AI's ship and any ships in it's group will flee the missle using `performFlee` with a `desired_range` of 10 kms. In this case the `FLEEING` message is sent to the current AI state.

## Ship AI

The following table details the conditions an AI controlled ship may be in. An AI controlled ship is only ever in one of these conditions at a time. The condition is changed during calls to functions during message handlers rather than directly by the AI script.

CONDITION_IDLE | The ship will centre it's roll and pitch controls. It will continue to travel at it's current speed.
CONDITION_TRACK_TARGET |
CONDITION_FLY_TO_TARGET |
CONDITION_HANDS_OFF |
CONDITION_TUMBLE |
CONDITION_ATTACK_TARGET |
CONDITION_ATTACK_FLY_TO_TARGET |
CONDITION_ATTACK_FLY_FROM_TARGET |
CONDITION_RUNNING_DEFENSE |
CONDITION_ATTACK_FLY_TO_TARGET_SIX |
CONDITION_ATTACK_MINING_TARGET |
CONDITION_FLEE_TARGET | The ship will flee from it's primary target at maximum speed.
CONDITION_AVOID_COLLISION |
CONDITION_TRACK_AS_TURRET |
CONDITION_FLY_RANGE_FROM_DESTINATION |
CONDITION_FLY_TO_DESTINATION |
CONDITION_FLY_FROM_DESTINATION |
CONDITION_FACE_DESTINATION |
CONDITION_COLLECT_TARGET |
CONDITION_INTERCEPT_TARGET |
CONDITION_MISSILE_FLY_TO_TARGET |
CONDITION_EXPERIMENTAL |
CONDITION_FORMATION_FORM_UP |
CONDITION_FORMATION_BREAK |
CONDITION_ENERGY_BOMB_COUNTDOWN |