oolite/Resources/AIReference.html
2005-05-25 10:26:48 +00:00

711 lines
20 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<html>
<head><title>oolite AI Reference</title></head>
<body>
<h1>oolite AI Reference</h1>
<p>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.</p>
<h2>AI Script Format</h2>
<p>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.</p>
<p>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.</p>
<p>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.</p>
<p>In ASCII format a simple (two-state) machine looks like this:</p>
<pre><code>
{
     "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 = ();
     };
}
</code></pre>
<h2>Game defined states and messages</h2>
<p>When an AI state machine is started it is always put into the state GLOBAL, and the ENTER message will be sent.</p>
<p>The following table describes each message the game engine may send to an
AI state machine.</p>
<p>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.</p>
<table border="1" width="100%">
<tr><td><code>ACCEPT_DISTRESS_CALL</code></td>
<td>
</td></tr>
<tr><td><code>AEGIS_CLOSE_TO_PLANET</code></td>
<td>
</td></tr>
<tr><td><code>AEGIS_IN_DOCKING_RANGE</code></td>
<td>
</td></tr>
<tr><td><code>AEGIS_LEAVING_DOCKING_RANGE</code></td>
<td>
</td></tr>
<tr><td><code>AEGIS_NONE</code></td>
<td>
</td></tr>
<tr><td><code>APPROACH_COORDINATES</code></td>
<td>
</td></tr>
<tr><td><code>APPROACH_START</code></td>
<td>
</td></tr>
<tr><td><code>APPROACH_STATION</code></td>
<td>
</td></tr>
<tr><td><code>ATTACKED</code></td>
<td>
</td></tr>
<tr><td><code>CARGO_SCOOPED</code></td>
<td>
</td></tr>
<tr><td><code>COLLISION</code></td>
<td>
</td></tr>
<tr><td><code>CONDITION_GREEN</code></td>
<td>
</td></tr>
<tr><td><code>CONDITION_YELLOW</code></td>
<td>
</td></tr>
<tr><td><code>COURSE_OK</code></td>
<td>
</td></tr>
<tr><td><code>DEPLOYING_ESCORTS</code></td>
<td>
</td></tr>
<tr><td><code>DESIRED_RANGE_ACHIEVED</code></td>
<td>
</td></tr>
<tr><td><code>DOCKED</code></td>
<td>
</td></tr>
<tr><td><code>DOCKING_ABORTED</code></td>
<td>
</td></tr>
<tr><td><code>DOCKING_COMPLETE</code></td>
<td>
</td></tr>
<tr><td><code>DOCKING_REFUSED</code></td>
<td>
</td></tr>
<tr><td><code>DOCKING_REQUESTED</code></td>
<td>
</td></tr>
<tr><td><code>ECM</code></td>
<td>
</td></tr>
<tr><td><code>ENERGY_FULL</code></td>
<td>
</td></tr>
<tr><td><code>ENERGY_LOW</code></td>
<td>
</td></tr>
<tr><td><code>ENTER</code></td>
<td>
<p>Always sent to the new (now current) state of the AI state machine after switching to a new state.</p>
</td></tr>
<tr><td><code>ENTERED_WITCHSPACE</code></td>
<td>
</td></tr>
<tr><td><code>ESCORTING</code></td>
<td>
</td></tr>
<tr><td><code>EXIT</code></td>
<td>
<p>Always sent to the current state of the AI state machine before switching to a new state.</p>
</td></tr>
<tr><td><code>EXITED_WITCHSPACE</code></td>
<td>
</td></tr>
<tr><td><code>FACING_DESTINATION</code></td>
<td>
</td></tr>
<tr><td><code>FIGHTING</code></td>
<td>
</td></tr>
<tr><td><code>FLEEING</code></td>
<td>
</td></tr>
<tr><td><code>FRUSTRATED</code></td>
<td>
</td></tr>
<tr><td><code>GONE_BEYOND_RANGE</code></td>
<td>
</td></tr>
<tr><td><code>GROUP_ATTACK_TARGET</code></td>
<td>
</td></tr>
<tr><td><code>HOLD_FULL</code></td>
<td>
</td></tr>
<tr><td><code>HOLD_POSITION</code></td>
<td>
</td></tr>
<tr><td><code>INCOMING_MISSILE</code></td>
<td>
</td></tr>
<tr><td><code>LANDED_ON_PLANET</code></td>
<td>
</td></tr>
<tr><td><code>LAUNCHED</code></td>
<td>
</td></tr>
<tr><td><code>MOTHER_LOST</code></td>
<td>
</td></tr>
<tr><td><code>NO_STATION_FOUND</code></td>
<td>
</td></tr>
<tr><td><code>NO_TARGET</code></td>
<td>
</td></tr>
<tr><td><code>NOT_ESCORTING</code></td>
<td>
</td></tr>
<tr><td><code>NOTHING_FOUND</code></td>
<td>
</td></tr>
<tr><td><code>ODDS_BAD</code></td>
<td>
</td></tr>
<tr><td><code>ODDS_GOOD</code></td>
<td>
</td></tr>
<tr><td><code>ODDS_LEVEL</code></td>
<td>
</td></tr>
<tr><td><code>REACHED_SAFETY</code></td>
<td>
<p>Sent when the ship controlled by the AI is fleeing it's <code class="prop">primary_target</code> and is at least
<code class="prop">desired_range</code> kms from it.
</td></tr>
<tr><td><code>RED_ALERT</code></td>
<td>
</td></tr>
<tr><td><code>RESTARTED</code></td>
<td>
<p>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.</p>
</td></tr>
<tr><td><code>STATION_FOUND</code></td>
<td>
</td></tr>
<tr><td><code>TARGET_CLEAN</code></td>
<td>
</td></tr>
<tr><td><code>TARGET_DESTROYED</code></td>
<td>
</td></tr>
<tr><td><code>TARGET_FOUND</code></td>
<td>
<p>Sent when searching for a target and something suitable is found. The <code class="prop">found_target</code> can be made the
primary target by calling <code class="func">setTargetToFoundTarget</code> in response to this message.</p>
</td></tr>
<tr><td><code>TARGET_FUGITIVE</code></td>
<td>
</td></tr>
<tr><td><code>TARGET_LOST</code></td>
<td>
</td></tr>
<tr><td><code>TARGET_MARKED</code></td>
<td>
</td></tr>
<tr><td><code>TARGET_MINOR_OFFENDER</code></td>
<td>
</td></tr>
<tr><td><code>TARGET_OFFENDER</code></td>
<td>
</td></tr>
<tr><td><code>THARGOID_DESTROYED</code></td>
<td>
</td></tr>
<tr><td><code>TRY_AGAIN_LATER</code></td>
<td>
</td></tr>
<tr><td><code>UPDATE</code></td>
<td>
<p>This message is sent to the current state each time the AI gets a chance to "think".</p>
</td></tr>
<tr><td><code>WAIT_FOR_SUN</code></td>
<td>
</td></tr>
<tr><td><code>WAYPOINT_SET</code></td>
<td>
</td></tr>
<tr><td><code>YELLOW_ALERT</code></td>
<td>
</td></tr>
</table>
<h2>AI State Machine Function Reference</h2>
<table border="1">
<tr style="background: #CCCCCC">
<td colspan="3"><code>pauseAI</code></td>
</tr>
<tr>
<td>Parameters</td><td><code>double interval</code></td><td>The number of seconds to pause this AI.</td>
</tr>
<tr>
<td colspan="3">This method pauses the calling AI for the number of seconds specified by the <code>interval</code> parameter.</td>
</tr>
<tr><td colspan="3">&nbsp;</td></tr>
<tr style="background: #CCCCCC">
<td colspan="3"><code>setDestinationToCurrentLocation</code></td>
</tr>
<tr>
<td>Parameters</td><td>none</td><td>&nbsp;</td>
</tr>
<tr>
<td colspan="3">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.</td>
</tr>
<tr><td colspan="3">&nbsp;</td></tr>
<tr style="background: #CCCCCC">
<td colspan="3"><code>setDesiredRangeTo</code></td>
</tr>
<tr>
<td>Parameters</td><td><code>double range</code></td><td>The desired range for some operation, in metres.</td>
</tr>
<tr>
<td colspan="3"><p>Some methods (such as scanForNearestMerchantmen, checkCourseToDestination, checkDistanceTravelled, etc) require a "desired range" parameter
to be set before they can be used.</p>
<p>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.</p></td>
</tr>
<tr><td colspan="3">&nbsp;</td></tr>
<tr style="background: #CCCCCC">
<td colspan="3"><code>setSpeedTo</code></td>
</tr>
<tr>
<td>Parameters</td><td><code>double speed</code></td><td>The desired absolute speed for the current entity.</td>
</tr>
<tr>
<td colspan="3"><p>Sets the speed of the current entity to an absolute value.</p>
<p>If this value is greater than the current entity's maximum speed the entity
will travel at maximum speed.</p></td>
</tr>
<tr><td colspan="3">&nbsp;</td></tr>
<tr style="background: #CCCCCC">
<td colspan="3"><code>setSpeedFactorTo</code></td>
</tr>
<tr>
<td>Parameters</td><td><code>double speed</code></td><td>The fraction of maximum speed to use.</td>
</tr>
<tr>
<td colspan="3"><p>Sets the speed of the current entity to a fraction of its maximum speed.</p>
<p>For example, to set an entity to move at 35% of its maximum speed, supply a speed parameter of value "0.35".</p></td>
</tr>
<tr><td colspan="3">&nbsp;</td></tr>
<tr style="background: #CCCCCC">
<td colspan="3"><code>performFlyToRangeFromDestination</code></td>
</tr>
<tr>
<td>Parameters</td><td>none</td><td>&nbsp;</td>
</tr>
<tr>
<td>Condition on exit</td><td><code>CONDITION_FLY_RANGE_FROM_DESTINATION</code></td><td>Always.</td>
</tr>
<tr>
<td colspan="3"><p>Sets the AI's current state to CONDITION_FLY_RANGE_FROM_DESTINATION.</p>
<p>While in this state the entity will attempt to fly to its current destination, stopping at the desired range from it.</p></td>
</tr>
<tr><td colspan="3">&nbsp;</td></tr>
<tr style="background: #CCCCCC">
<td colspan="3"><code>performIdle</code></td>
</tr>
<tr>
<td>Parameters</td><td>none</td><td>&nbsp;</td>
</tr>
<tr>
<td>Condition on exit</td><td><code>CONDITION_IDLE</code></td><td>Always.</td>
</tr>
<tr>
<td colspan="3"><p>Sets the AI's current state to CONDITION_IDLE and resets the frustration factor to zero.</p>
<p>Unlike performHold the current speed is not modified.</p></td>
</tr>
<tr><td colspan="3">&nbsp;</td></tr>
<tr style="background: #CCCCCC">
<td colspan="3"><code>performHold</code></td>
</tr>
<tr>
<td>Parameters</td><td>none</td><td>&nbsp;</td>
</tr>
<tr>
<td>Condition on exit</td><td><code>CONDITION_TRACK_TARGET</code></td><td>Always.</td>
</tr>
<tr>
<td colspan="3"><p>Sets the entity's speed to zero, sets the AI's current state to CONDITION_TRACK_TARGET and resets the frustration factor to zero.</p>
</tr>
<tr><td colspan="3">&nbsp;</td></tr>
<tr style="background: #CCCCCC">
<td colspan="3"><code>setTargetToPrimaryAggressor</code></td>
</tr>
<tr>
<td>Parameters</td><td>none</td><td>&nbsp;</td>
</tr>
<tr>
<td colspan="3"><p>If there is no current primary agressor against the caller, or the caller has already targeted
the primary agressor, this function does nothing.</p>
<p>If there is a primary agressor and the caller is not currently attacking another target, the primary agressor
is targeted.</p>
<p>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.</p>
<p>The game decides which entity, if any, is currently the primary agressor against the caller.</p>
</tr>
<tr><td colspan="3">&nbsp;</td></tr>
<tr style="background: #CCCCCC">
<td colspan="3"><code>performAttack</code></td>
</tr>
<tr>
<td>Parameters</td><td>none</td><td>&nbsp;</td>
</tr>
<tr>
<td>Condition on exit</td><td><code>CONDITION_ATTACK_TARGET</code></td><td>Always.</td>
</tr>
<tr>
<td colspan="3"><p>Tells the caller to start attacking its current target.</p>
</tr>
<tr><td colspan="3">&nbsp;</td></tr>
<tr style="background: #CCCCCC">
<td colspan="3"><code>scanForNearestMerchantmen</code></td>
</tr>
<tr>
<td>Parameters</td><td>none</td><td>&nbsp;</td>
</tr>
<tr>
<td>Message</td><td><code>TARGET_FOUND</code></td><td>If a suitable merchant vessel is found within scanner range.</td>
</tr>
<tr>
<td>Message</td><td><code>NOTHING_FOUND</code></td><td>If no suitable vessel is found within scanner range.</td>
</tr>
<tr>
<td colspan="3"><p>Looks for the nearest merchant vessel (including the player's ship) within scanner range.</p>
<p> 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 <code>setTargetToFoundTarget</code>.</p>
</tr>
<tr><td colspan="3">&nbsp;</td></tr>
<tr style="background: #CCCCCC">
<td colspan="3"><code>scanForRandomMerchantmen</code></td>
</tr>
<tr>
<td>Parameters</td><td>none</td><td>&nbsp;</td>
</tr>
<tr>
<td>Message</td><td><code>TARGET_FOUND</code></td><td>If at least one merchant vessel is found within scanner range.</td>
</tr>
<tr>
<td>Message</td><td><code>NOTHING_FOUND</code></td><td>If no merchant vessels are within scanner range.</td>
</tr>
<tr>
<td colspan="3"><p>Randomly selects one of the merchant vessels within scanner range.</p>
<p>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 <code>setTargetToFoundTarget</code>.</p>
<p>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.</p>
</tr>
<tr><td colspan="3">&nbsp;</td></tr>
<tr style="background: #CCCCCC">
<td colspan="3"><code>scanForLoot</code></td>
</tr>
<tr>
<td>Parameters</td><td>none</td><td>&nbsp;</td>
</tr>
<tr>
<td>Message</td><td><code>TARGET_FOUND</code></td><td>If at least one scoopable item is found within scanner range.</td>
</tr>
<tr>
<td>Message</td><td><code>NOTHING_FOUND</code></td><td>If there are no scoopable items in scanner range,
controlling entity does not have a fuel scoop, or controlling entity is a station.</td>
</tr>
<tr>
<td colspan="3"><p>Selects the nearest scoopable item within scanner range.</p>
<p>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 <code>setTargetToFoundTarget</code>.</p>
</tr>
<tr><td colspan="3">&nbsp;</td></tr>
<tr style="background: #CCCCCC">
<td colspan="3"><code>scanForRandomLoot</code></td>
</tr>
<tr>
<td>Parameters</td><td>none</td><td>&nbsp;</td>
</tr>
<tr>
<td>Message</td><td><code>TARGET_FOUND</code></td><td>If at least one scoopable item is found within scanner range.</td>
</tr>
<tr>
<td>Message</td><td><code>NOTHING_FOUND</code></td><td>If there are no scoopable items in scanner range,
controlling entity does not have a fuel scoop, or controlling entity is a station.</td>
</tr>
<tr>
<td colspan="3"><p>Selects a random scoopable item from all those within scanner range.</p>
<p>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 <code>setTargetToFoundTarget</code>.</p>
</tr>
<tr><td colspan="3">&nbsp;</td></tr>
<tr style="background: #CCCCCC">
<td colspan="3"><code>setTargetToFoundTarget</code></td>
</tr>
<tr>
<td>Parameters</td><td>none</td><td>&nbsp;</td>
</tr>
<tr>
<td colspan="3"><p>Makes most recently found target the current target.</p>
</tr>
<tr><td colspan="3">&nbsp;</td></tr>
<tr style="background: #CCCCCC">
<td colspan="3"><code>checkForFullHold</code></td>
</tr>
<tr>
<td>Parameters</td><td>none</td><td>&nbsp;</td>
</tr>
<tr>
<td>Message</td><td><code>HOLD_FULL</code></td><td>If the calling ship's cargo hold is full.</td>
</tr>
<tr>
<td colspan="3"><p>Checks the amount of cargo in the calling ship's hold, and
if the hold is full sends the HOLD_FULL message.</p>
</tr>
<tr><td colspan="3">&nbsp;</td></tr>
<tr style="background: #CCCCCC">
<td colspan="3"><code>performCollect</code></td>
</tr>
<tr>
<td>Parameters</td><td>none</td><td>&nbsp;</td>
</tr>
<tr>
<td>Property change</td><td><code>condition</code></td><td>CONDITION_COLLECT_TARGET</td>
</tr>
<tr>
<td>Property change</td><td><code>frustration</code></td><td>0.0</td>
</tr>
<tr>
<td colspan="3"><p>Sets the caller to collect the primary target, assumed to be a scoopable item.</p>
<p>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.</p>
</tr>
<tr><td colspan="3">&nbsp;</td></tr>
<tr style="background: #CCCCCC">
<td colspan="3"><code>performIntercept</code></td>
</tr>
<tr>
<td>Parameters</td><td>none</td><td>&nbsp;</td>
</tr>
<tr>
<td>Property change</td><td><code>condition</code></td><td>CONDITION_INTERCEPT_TARGET</td>
</tr>
<tr>
<td>Property change</td><td><code>frustration</code></td><td>0.0</td>
</tr>
<tr>
<td colspan="3"><p>Sets the caller to intercept the primary target at maximum speed.</p>
<p>While in the CONDITION_INTERCEPT_TARGET condition, the DESIRED_RANGE_ACHIEVED message will
be received if the target is within the current <code>desired_range</code>.</p>
</tr>
<tr><td colspan="3">&nbsp;</td></tr>
<tr style="background: #CCCCCC">
<td colspan="3"><code>performFlee</code></td>
</tr>
<tr>
<td>Parameters</td><td>none</td><td>&nbsp;</td>
</tr>
<tr>
<td>Property change</td><td><code>condition</code></td><td>CONDITION_FLEE_TARGET</td>
</tr>
<tr>
<td>Property change</td><td><code>frustration</code></td><td>0.0</td>
</tr>
<tr>
<td colspan="3"><p>Sets the caller to flee from the primary target at maximum speed.</p>
<p>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
<code>desired_range</code>.</p>
<p>If the caller has a cloaking device, it will be activated.</p>
</tr>
</table>
<h2>Ship AI</h2>
<p>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.</p>
<table border="1" width="100%">
<tr><td>CONDITION_IDLE</td>
<td>The ship will centre it's roll and pitch controls. It will continue to travel at it's
current speed.</td></tr>
<tr><td>CONDITION_TRACK_TARGET</td><td></td></tr>
<tr><td>CONDITION_FLY_TO_TARGET</td><td></td></tr>
<tr><td>CONDITION_HANDS_OFF</td><td></td></tr>
<tr><td>CONDITION_TUMBLE</td><td></td></tr>
<tr><td>CONDITION_ATTACK_TARGET</td><td></td></tr>
<tr><td>CONDITION_ATTACK_FLY_TO_TARGET</td><td></td></tr>
<tr><td>CONDITION_ATTACK_FLY_FROM_TARGET</td><td></td></tr>
<tr><td>CONDITION_RUNNING_DEFENSE</td><td></td></tr>
<tr><td>CONDITION_ATTACK_FLY_TO_TARGET_SIX</td><td></td></tr>
<tr><td>CONDITION_ATTACK_MINING_TARGET</td><td></td></tr>
<tr><td>CONDITION_FLEE_TARGET</td>
<td>The ship will flee from it's primary target at maximum speed.</td></tr>
<tr><td>CONDITION_AVOID_COLLISION</td><td></td></tr>
<tr><td>CONDITION_TRACK_AS_TURRET</td><td></td></tr>
<tr><td>CONDITION_FLY_RANGE_FROM_DESTINATION</td><td></td></tr>
<tr><td>CONDITION_FLY_TO_DESTINATION</td><td></td></tr>
<tr><td>CONDITION_FLY_FROM_DESTINATION</td><td></td></tr>
<tr><td>CONDITION_FACE_DESTINATION</td><td></td></tr>
<tr><td>CONDITION_COLLECT_TARGET</td><td></td></tr>
<tr><td>CONDITION_INTERCEPT_TARGET</td><td></td></tr>
<tr><td>CONDITION_MISSILE_FLY_TO_TARGET</td><td></td></tr>
<tr><td>CONDITION_EXPERIMENTAL</td><td></td></tr>
<tr><td>CONDITION_FORMATION_FORM_UP</td><td></td></tr>
<tr><td>CONDITION_FORMATION_BREAK</td><td></td></tr>
<tr><td>CONDITION_ENERGY_BOMB_COUNTDOWN</td><td></td></tr>
</table>
</html>
</body>