Difference between revisions of "OXP howto AI"

From Elite Wiki
(setCoordinatesFromPosition explaination)
m (Fixed & added links, fixed typos)
 
(65 intermediate revisions by 9 users not shown)
Line 1: Line 1:
'''AI Script Format'''
+
'''Notice'''
  
The AI system consists of a [[Stacked AI|stack]] of [[state machine]]s (only the top one of which is active), which respond to game events sent to them as [[Messages|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.
+
This page describes the plist-based method of AI scripting in Oolite. [[OXP standards|Since version 1.80]], the use of plist-based AIs for non-trivial AIs is '''discouraged'''. Javascript AIs are '''recommended'''. Use of the [[Oolite Javascript Reference: PriorityAI Documentation|Priority AI library]] to write AIs, especially the standard conditions and behaviours it provides, is useful to make ships fit in with the core ships and to have future improvements to AI incorporated easily. Alternative AI controller libraries released as OXPs may also be used.
  
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.
+
__TOC__
 +
 
 +
<div style="clear:both"></div>
 +
{{OXPNote|This page was last properly edited by the cognoscenti in 2012-13, before the introduction of the new AI's in the Vanilla game with Oolite v.1.80 & v.1.82}}
 +
 
 +
== AI Script Format ==
 +
 
 +
The AI system consists of a [[Stacked AI|stack]] of [[state machine]]s (only the top one of which is active), which respond to game events sent to them as [[Messages|messages]]. They respond by calling a series of [[methods]] which affect the behaviour of the [[Oolite_JavaScript_Reference:_Entity|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]]. 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.
 
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:
+
In OpenStep property list format a simple (two-state) machine looks like this:
 
  {
 
  {
 
       "STATE_1" = {
 
       "STATE_1" = {
Line 35: Line 44:
 
|-
 
|-
 
|'''dropMessages: (NSString *)messageString'''
 
|'''dropMessages: (NSString *)messageString'''
|Removes the pending massage(s) with this name. (Added in Oolite 1.73)
+
|Removes the pending message(s) with this name.
 
e.g. when attacking a trader there is often both a "FIGHTING" and a "FLEEING" message on update time. When reacting on one while staying in the same state, it might be wise to drop the other possible one.
 
e.g. when attacking a trader there is often both a "FIGHTING" and a "FLEEING" message on update time. When reacting on one while staying in the same state, it might be wise to drop the other possible one.
 
|-
 
|-
Line 42: Line 51:
 
|-
 
|-
 
|'''exitAIWithMessage: (NSString *)messageString'''
 
|'''exitAIWithMessage: (NSString *)messageString'''
|Exits current AI and returns to the same state in the old AI that called this AI with a "setAITo:". It returns: "'''messageString'''" instead of RESTARTED. Useful for something like "exitAIWithMessage: ATTACKED", as the main AI will loose that message with just an "ExitAI". (Added in OOlite 1.73)
+
|Exits current AI and returns to the same state in the old AI that called this AI with a "setAITo:". It returns: "'''messageString'''" instead of RESTARTED. Useful for something like "exitAIWithMessage: ATTACKED", as the main AI will loose that message with just an "ExitAI".
 
|-
 
|-
 
|'''messageSelf: (NSString *)messageString'''
 
|'''messageSelf: (NSString *)messageString'''
|Sends a message to itself to be read in the next UPDATE. Useful to add delays in a reaction on an other message without the need to go to another state. (Added in Oolite 1.73)
+
|Sends a message to itself to be read in the next UPDATE. Useful to add delays in a reaction on an other message without the need to go to another state.
 
e.g.
 
e.g.
 
  INCOMING_MISSILE = ("messageSelf: MISSILE_DETECTED", "pauseAI: 1.5");
 
  INCOMING_MISSILE = ("messageSelf: MISSILE_DETECTED", "pauseAI: 1.5");
Line 55: Line 64:
 
|-
 
|-
 
|'''randomPauseAI: (NSString *)intervalString'''
 
|'''randomPauseAI: (NSString *)intervalString'''
|Sets next AI update time in seconds to a random time between a minimum and a maximum value. This command takes two space separated parameters like in "randomPauseAI: 0.2 2.6". (Added in Oolite 1.73)
+
|Sets next AI update time in seconds to a random time between a minimum and a maximum value. This command takes two space separated parameters like in "randomPauseAI: 0.2 2.6".
 
|-
 
|-
 
|'''setAITo: (NSString *)aiString'''
 
|'''setAITo: (NSString *)aiString'''
Line 77: Line 86:
 
|-
 
|-
 
|'''fightOrFleeMissile'''
 
|'''fightOrFleeMissile'''
|Deals with missiles, uses ECM if available, flees if not, marks as offender if police. Returns: "FLEEING" or nothing.
+
|Deals with missiles by searching a missile heading for itself or one of its escorts. When found it sets the missile as its primary target. Than, it uses ECM if available, or goes into a <code>performFlee</code> mode if no ECM available. It marks the launcher as offender if targeting a police. Returns: "FLEEING" when the ship went into a <code>performFlee</code> mode.
 
|}
 
|}
  
Line 85: Line 94:
 
!width="225"|Method
 
!width="225"|Method
 
!Description
 
!Description
 +
|-
 +
|'''abortAllDockings'''
 +
|Used by stations to send an abort docking message to all ships busy with docking. This allows for immediate launching of ships. This slows down the whole docking process, so only use this command when absolutely needed.
 
|-
 
|-
 
|'''becomeEnergyBlast'''
 
|'''becomeEnergyBlast'''
|Used in the [[Q bomb]].
+
|Used in the [[Q bomb]]. Sends a CASCADE_WEAPON_DETECTED event to every ship in scanner range.
 
|-
 
|-
 
|'''becomeExplosion'''
 
|'''becomeExplosion'''
Line 94: Line 106:
 
|'''becomeLargeExplosion'''
 
|'''becomeLargeExplosion'''
 
|Used at player entity death, not for use in other instances.
 
|Used at player entity death, not for use in other instances.
 +
|-
 +
|'''broadcastEnergyBlastImminent'''<br>(1.77 or later)
 +
|Used in the [[Q bomb]]. Sends a CASCADE_WEAPON_DETECTED event to every ship in scanner range.
 
|-
 
|-
 
|'''dealEnergyDamageWithinDesiredRange'''
 
|'''dealEnergyDamageWithinDesiredRange'''
|Needs desiredRange to be set first, then deals [[weaponEnergy]] ([[Shipdata.plist]]) damage within this sphere.  
+
|Needs desiredRange to be set first, then deals energy damage to ships within this sphere, based on [[Shipdata.plist#weapon_energy|weapon_energy]]:  (weapon_energy * desiredRange) / (6.76 * distance * distance)
 
|-
 
|-
 
|'''decreaseAlertLevel'''
 
|'''decreaseAlertLevel'''
Line 108: Line 123:
 
|-
 
|-
 
|'''dumpCargo'''
 
|'''dumpCargo'''
|Ejects one cargo canister when present. Since Oolite 1.74 this action will send "CARGO_DUMPED" to all ships in range.
+
|Ejects one cargo canister when present. This action will send "CARGO_DUMPED" to all ships in range.
 
|-
 
|-
 
|'''ejectCargo'''
 
|'''ejectCargo'''
|Ejects the complete cargo bay content with 0.75 seconds spacing between cargo canisters. Since Oolite 1.74 this action will send "CARGO_DUMPED" to all ships in range.
+
|Ejects the complete cargo bay content with 0.75 seconds spacing between cargo canisters. This action will send "CARGO_DUMPED" to all ships in range.
 
|-
 
|-
 
|'''enterTargetWormhole'''
 
|'''enterTargetWormhole'''
|Will locate nearest wormhole, and enter it.
+
|Will enter the targeted wormhole, or the nearest wormhole if target is not a wormhole.
 +
|-
 +
|'''enterPlayerWormhole'''
 +
|Will try to enter the players' wormhole if the ship can reach it in time.  Only useful following a "PLAYER WITCHSPACE" message.
 
|-
 
|-
 
|'''escortCheckMother'''
 
|'''escortCheckMother'''
Line 135: Line 153:
 
|-
 
|-
 
|'''Launch..''Some''Ship'''
 
|'''Launch..''Some''Ship'''
|Launches a ship fron a dockable entity, various types of this method exist. See also [[Station Ships]].
+
|Launches a ship from a dockable entity, various types of this method exist. See also [[Station Ships]].
 
* LaunchDefenseShip     
 
* LaunchDefenseShip     
 
* LaunchEscort
 
* LaunchEscort
* LaunchIndependentShipWithRole: <Role> (Added with Oolite 1.73)
+
* LaunchIndependentShipWithRole: <Role>
 
* LaunchMiner
 
* LaunchMiner
 
* LaunchPatrol
 
* LaunchPatrol
Line 144: Line 162:
 
* LaunchPolice
 
* LaunchPolice
 
* LaunchScavenger
 
* LaunchScavenger
* LaunchShipWithRole: <Role>
+
* LaunchShipWithRole: <Role> (sets the station as its mother station.)
 
* LaunchShuttle
 
* LaunchShuttle
 
* LaunchTrader
 
* LaunchTrader
 +
During the launch, there is no AI UPDATE and any active behaviour is ignored. The ship is just flying straight ahead.
 +
When far enough from the station a '''"LAUNCHED OKAY"''' message is generated , the first AI UPDATE happens and the active behaviour is followed.<br>
 +
The launching station will receive a '''"STATION_LAUNCHED_SHIP"''' message.
 
|-
 
|-
 
|'''markTargetForFines'''
 
|'''markTargetForFines'''
 
|Deals out a fine to target. It returns: "TARGET_MARKED". When the target was no ship it returns: "'''TARGET_LOST'''".
 
|Deals out a fine to target. It returns: "TARGET_MARKED". When the target was no ship it returns: "'''TARGET_LOST'''".
Example:
+
Will fine the target on the next docking in the current system. The value of the fine is always 50 or 100, multiplied by the target's [[Oolite_JavaScript_Reference:_Player#legalStatus|legal status]] on docking.
"markTargetForFines: 100"
+
Dealing out multiple fines has no extra effect.  
Will fine the target 10Cr. N.B. for commercial transactions "awardMoney -$" is a more suitable method.
+
On paying the fine, the ships legal status is cleared and the system clock advances a day. The amount to be fined is cleared after the ship enters a new system.  
 
|-
 
|-
 
|'''markTargetForOffence:(NSString*) valueString'''
 
|'''markTargetForOffence:(NSString*) valueString'''
|Has police mark up the criminal record ([[Legal status]]) of target entity.  The value is not added to the criminal record but a bit-wise OR is used between value and criminal record. It returns: "'''TARGET_LOST'''" when the target was no ship. This command can only be used by stations or police ships. With other ships this command is ignored.
+
|Has police mark up the criminal record ([[Oolite_JavaScript_Reference:_Player#legalStatus|Legal status]]) of target entity.  The value is not added to the criminal record but a bit-wise OR is used between value and criminal record. It returns: "'''TARGET_LOST'''" when the target was no ship. This command can only be used by stations or police ships. With other ships this command is ignored.
 
|-
 
|-
 
|'''messageMother:(NSString *)msgString'''
 
|'''messageMother:(NSString *)msgString'''
Line 165: Line 186:
 
|'''performAttack'''
 
|'''performAttack'''
 
|Attacks target.
 
|Attacks target.
 +
|-
 +
|'''performAvoidCollision'''
 +
|This is not an existing AI command but only added here to show its existence that can interfere with other perform actions. Its an automatic feature used by several of the other perform commands to avoid a collision with a very nearby object. The old performance is temporary put on ice, the ships moves away a bit from the obstacle and than continues the old performance. This automatic collision avoidance can be a problem when you want to navigate a ship very close to an existing ship. Therefore none of the non-battle performances will avoid collision with a primary target.
 
|-
 
|-
 
|'''performCollect'''
 
|'''performCollect'''
|Performs 'collection' of target.
+
|Performs 'collection' of target. Generates a "FRUSTRATED" message when not able to come closer to the target and a "TARGET_LOST" when loosing or scooping the cargo. Colliding with cargo in the presence of a scoop, generates the messages "CARGO_SCOOPED" and "HOLD_FULL" independent of the actual behaviour.
 
|-
 
|-
 
|'''performDocking'''
 
|'''performDocking'''
Line 176: Line 200:
 
|-
 
|-
 
|'''performFaceDestination'''
 
|'''performFaceDestination'''
|Has entity face destination. Returns "FACING_DESTINATION" when turn is completed.
+
|Has entity face destination. Sets also the desiredSpeed to zero. Returns "FACING_DESTINATION" when turn is completed.
 
|-
 
|-
 
|'''performFlee'''
 
|'''performFlee'''
Line 186: Line 210:
 
|-
 
|-
 
|'''performHold'''
 
|'''performHold'''
|Performs idleness while tracking a potential target, speed is set to zero. [[frustration]] level is reset.
+
|Performs idleness while tracking a potential target, speed is set to zero. [[frustration]] level is reset. <br>When it has no primary target, or loses the primary target, it will sent a "TARGET_LOST" message and change itself into performIdle.
 
|-
 
|-
 
|'''performHyperSpaceExit'''
 
|'''performHyperSpaceExit'''
|Gets a list of destinations within fuel range, checks if clear of nearby masses, and select one at random. May return "'''WITCHSPACE UNAVAILABLE'''", "'''WITCHSPACE BLOCKED'''" or "'''WITCHSPACE_OKAY'''". It will add a new ship with the same role as the leaving ship at the witchspace entry point.
+
|Gets a list of destinations within fuel range, checks if clear of nearby masses, and select one at random. May return "'''WITCHSPACE UNAVAILABLE'''", "'''WITCHSPACE BLOCKED'''" or "'''WITCHSPACE_OKAY'''". When the ship enters the wormhole, the AI is halted. When the player chooses to enter that system, the AI is restarted in the GLOBAL state with a message "EXITED WITCHSPACE". When the player enters an other system, or when the wormhole collapses without being targeted by the player, the ship is completely removed from memory.
 +
 
 +
This command will also add a new ship with the same role as the leaving ship at the witchspace entry point of the current system. This new ship at the current witchpoint will start with a "EXITED_WITCHSPACE" message so that a script can distinguish between the initial added ship and the replacement ship. (Note the underscore in the message that is not there for the original ship).
  
When the player performs a hyperspace exit or a galactic jump, all NPC ships get the priority message: "'''PLAYER WITCHSPACE'''".
+
When the player performs a hyperspace exit or a galactic jump, all NPC ships get the priority message: "'''PLAYER WITCHSPACE'''".<BR>
 
|-
 
|-
 
|'''performHyperSpaceExitWithoutReplacing'''
 
|'''performHyperSpaceExitWithoutReplacing'''
|Gets a list of destinations within fuel range, checks if clear of nearby masses, and select one at random. May return "'''WITCHSPACE UNAVAILABLE'''", "'''WITCHSPACE BLOCKED'''" or "'''WITCHSPACE_OKAY'''". This command will not add a new ship at the witchspace entry point. (available with version 1.70 and higher)
+
|Gets a list of destinations within fuel range, checks if clear of nearby masses, and select one at random. May return "'''WITCHSPACE UNAVAILABLE'''", "'''WITCHSPACE BLOCKED'''" or "'''WITCHSPACE_OKAY'''". When the player follows the ship to the new system, the AI is restarted in the GLOBAL state with a "EXITED WITCHSPACE" message. This command will not add a new ship at the witchspace entry point.
 
|-
 
|-
 
|'''performIdle'''
 
|'''performIdle'''
Line 201: Line 227:
 
|'''performIntercept'''
 
|'''performIntercept'''
 
|Performs target interception. It needs a range to be set first. When the distance to target becomes less than desired range it returns: "'''DESIRED_RANGE_ACHIEVED'''". When target lost: "'''TARGET_LOST'''". When it hasn't come closer to target for 10 seconds it returns: "'''FRUSTRATED'''"
 
|Performs target interception. It needs a range to be set first. When the distance to target becomes less than desired range it returns: "'''DESIRED_RANGE_ACHIEVED'''". When target lost: "'''TARGET_LOST'''". When it hasn't come closer to target for 10 seconds it returns: "'''FRUSTRATED'''"
 +
|-
 +
|'''performLandOnPlanet'''
 +
|Performs landing. This command can only be used when within 500 meters to the surface. (after the message APPROACHING_SURFACE is send).  When too far away it returns: "NO_PLANET_NEARBY". When landing is complete it returns "'''LANDED_ON_PLANET'''". (will be added with Oolite 1.77)
 
|-
 
|-
 
|'''performMining'''
 
|'''performMining'''
|Performs mining. (Finds, intercepts and shoots asteroids with [[mining]] laser, if fitted.) It returns: "'''TARGET_LOST'''".
+
|Performs mining. (Finds, intercepts and shoots asteroids with a [[Mining Laser|mining laser]], if fitted.) It returns: "'''TARGET_LOST'''".
 +
|-
 +
|'''performScriptedAI'''<br>(added in Oolite 1.77)
 +
|Performs manoeuvres according to a [[OXP_Scripted_AI|custom flight function]] in its ship script
 +
|-
 +
|'''performScriptedAttackAI'''<br>(added in Oolite 1.77)
 +
|Performs manoeuvres according to a [[OXP_Scripted_AI|custom flight function]] in its ship script, and fires at its primary target
 
|-
 
|-
 
|'''performTumble'''
 
|'''performTumble'''
|Performs random pitch and roll, 'evasive maneuvers'.
+
|Performs random pitch and roll, 'evasive manoeuvres'.
 +
|-
 +
|'''setSpeedFactorTo:(NSString *)speedString'''
 +
|Sets the desired speed to a percentage of maxspeed (0->1=0%->100%). If speedfactor is set above 100%, entity will use fuel injectors if available.
 
|-
 
|-
 
|'''setSpeedTo:(NSString *)speedString'''
 
|'''setSpeedTo:(NSString *)speedString'''
 
|Sets desired speed to an absolute value, entity cannot go faster than maxspeed value determined in the [[shipdata.plist]]. If speed is above maxspeed, entity will use fuel injectors if available.  
 
|Sets desired speed to an absolute value, entity cannot go faster than maxspeed value determined in the [[shipdata.plist]]. If speed is above maxspeed, entity will use fuel injectors if available.  
 
|-
 
|-
|'''setSpeedFactorTo:(NSString *)speedString'''
+
|'''setSpeedToCruiseSpeed'''
|Sets the desired speed to a percentage of maxspeed (0->1=0%->100%). If speedfactor is set above 100%, entity will use fuelinjectors if available.
+
|Normally sets desired speed to 80% of max speed. When the ship has slower escorts, speed is adapted to the slowest escort.
 +
|-
 +
|'''setThrustFactorTo:(NSString *)thrustString'''
 +
|Sets the thrust to a percentage of maxThrust (0->1=0%->100%). maxThrust is the thrust value defined in shipdata.
 
|-
 
|-
 
|'''setUpEscorts'''
 
|'''setUpEscorts'''
|Useful to quickly establish (by name and number the [[Shipdata.plist#escorts|shipdata.plist]] prescribed) escorts, when a ship is introduced to a system. See also [[Escort Instructions]].
+
|Unused command in current Oolite versions. Escorts are now automatically added when a mother is created. See also [[Escort Instructions]].
 
|-
 
|-
 
|'''suggestEscort'''
 
|'''suggestEscort'''
|Has an escort seek employment and either gets accepted or rejected by the "mother". See also [[Escort Instructions]].
+
|Has an escort seek employment and either gets accepted or rejected by the "mother". See also [[Escort Instructions]]. It sends "ESCORTING" to the escort when accepted and "ACCEPTED_ESCORT" to the mother ship that accepted the ship. When not accepted it returns "NOT_ESCORTING".
 
|-
 
|-
 
|'''switchLightsOff'''
 
|'''switchLightsOff'''
Line 227: Line 268:
 
|-
 
|-
 
|'''throwSparks'''
 
|'''throwSparks'''
|Will throw a single burst of spark. (added in Oolite 1.73)
+
|Will throw a single burst of spark.
 
|-
 
|-
 
|'''wormholeEntireGroup'''
 
|'''wormholeEntireGroup'''
|Wormholes ships in this group.  Returns '''"ENTER WORMHOLE'''"
+
|Wormholes ships in this group.  Returns '''"ENTER WORMHOLE'''". The primary target must point to the wormhole itself, and that is only the case after the ship received the message "'''WITCHSPACE OKAY"'''.
 
|-
 
|-
 
|'''wormholeEscorts'''
 
|'''wormholeEscorts'''
|Wormholes official escorts. Returns '''"ENTER WORMHOLE'''"
+
|Wormholes official escorts. Returns '''"ENTER WORMHOLE'''". The primary target must point to the wormhole.
 
|-
 
|-
 
|'''wormholeGroup'''
 
|'''wormholeGroup'''
|Wormholes ships in group of which this is a leader.  Returns '''"ENTER WORMHOLE'''"
+
|Wormholes ships in group of which this is a leader.  Returns '''"ENTER WORMHOLE'''". The primary target must point to the wormhole.
 
|}
 
|}
  
Line 247: Line 288:
 
|'''****'''
 
|'''****'''
 
|The aegis check is part of the system update and messages needs no command to generate them. The following messages are '''only generated''' when the status '''changes'''.
 
|The aegis check is part of the system update and messages needs no command to generate them. The following messages are '''only generated''' when the status '''changes'''.
"AEGIS_CLOSE_TO_PLANET":  Within 3x planetary radius of the main planet and not near station.
+
"AEGIS_CLOSE_TO_PLANET":  Within 3x planetary radius of the main planet and not near station.<br>
"AEGIS_IN_DOCKING_RANGE":  Within 2x scanner radius of system station.
+
"AEGIS_IN_DOCKING_RANGE":  Within 2x scanner radius of system station.<br>
"AEGIS_LEAVING_DOCKING_RANGE": Has been in docking range but now only close to planet.
+
"AEGIS_LEAVING_DOCKING_RANGE": Has been in docking range but now only close to planet.<br>
 
"AEGIS_NONE": None of the above three messages is true.<br>
 
"AEGIS_NONE": None of the above three messages is true.<br>
 
+
"AEGIS_CLOSE_TO_MAIN_PLANET":  Within 3x planetary radius of the main planet and not near station.<br>
Starting with Oolite 1.72 new messages are added:<br>
+
"CLOSE_TO_PLANET":  Within 3x planetary radius of any planet and not near station.<br>
"AEGIS_CLOSE_TO_MAIN_PLANET":  Within 3x planetary radius of the main planet and not near station.
 
"CLOSE_TO_PLANET":  Within 3x planetary radius of any planet and not near station.
 
 
"AWAY_FROM_PLANET":  Leaving the area of 3x planetary radius of any planet.<br>
 
"AWAY_FROM_PLANET":  Leaving the area of 3x planetary radius of any planet.<br>
 
+
"CLOSE_TO_SUN":  Within 3x sun radius of the sun .<br>
Starting with Oolite 1.73 new messages are added:<br>
+
"AWAY_FROM_SUN  Leaving the area of 3x sun radius of the sun.<br>
"CLOSE_TO_SUN":  Within 3x sun radius of the sun .
+
"CLOSE_TO_SECONDARY_PLANET":  Within 3x radius of a planet that is not the main-planet.<br>
"AWAY_FROM_SUN  Leaving the area of 3x sun radius of the sun.
+
"CLOSE_TO_MOON":  Within 3x radius of a moon (=planet without atmosphere).<br>
"CLOSE_TO_SECONDARY_PLANET":  Within 3x radius of a planet that is not the main-planet.
 
"CLOSE_TO_MOON":  Within 3x radius of a moon (=planet without atmosphere).
 
  
 
With intersecting aegis of planets the main-planet aegis has priority, even when closer to another planet.  
 
With intersecting aegis of planets the main-planet aegis has priority, even when closer to another planet.  
Line 269: Line 306:
 
"'''APPROACHING_SURFACE'''": passed the border inward.
 
"'''APPROACHING_SURFACE'''": passed the border inward.
 
"'''LEAVING_SURFACE'''":  passed the border outward.
 
"'''LEAVING_SURFACE'''":  passed the border outward.
 +
|-
 +
|'''****'''
 +
|When the ship-key [[Shipdata.plist#track_contacts|track_contacts]] is set to true, the ship will receive a '''"CLOSE_CONTACT"''' message when an other ship enters his collision range. During this message that other ship will be the primary target.
 
|-
 
|-
 
|'''abortDocking'''
 
|'''abortDocking'''
Line 274: Line 314:
 
|-
 
|-
 
|'''checkAegis'''
 
|'''checkAegis'''
|Retransmits the aegis status. Sends: "AEGIS_NONE", "AEGIS_IN_DOCKING_RANGE", "AEGIS_CLOSE_TO_MAIN_PLANET", "AEGIS_CLOSE_TO_PLANET", "CLOSE_TO_PLANET", "CLOSE_TO_SECONDARY_PLANET", "CLOSE_TO_MOON" and/or "CLOSE_TO_SUN". (Added with Oolite 1.74)
+
|Retransmits the aegis status. Sends: "AEGIS_NONE", "AEGIS_IN_DOCKING_RANGE", "AEGIS_CLOSE_TO_MAIN_PLANET", "AEGIS_CLOSE_TO_PLANET", "CLOSE_TO_PLANET", "CLOSE_TO_SECONDARY_PLANET", "CLOSE_TO_MOON" and/or "CLOSE_TO_SUN".
 
|-
 
|-
 
|'''getWitchspaceEntryCoordinates'''
 
|'''getWitchspaceEntryCoordinates'''
Line 289: Line 329:
 
|-
 
|-
 
|'''setCoordinatesFromPosition'''
 
|'''setCoordinatesFromPosition'''
|Sets '''Coordinates''' to the current position. Nothing is done with these coordinates until '''setDestinationFromCoordinates''' is used. Useful for remembering a position for later returning. (''getWitchspaceEntryCoordinates'', ''setPlanetPatrolCoordinates'', ''setSunSkimStartCoordinates'', ''setSunSkimEndCoordinates'', ''setSunSkimExitCoordinates'', s''etCoordinates:'' and ''setDestinationToDockingAbort'' will also set new coordinates and overwrite an existing ''Coordinates'' value with a new one) Added with Oolite 1.74
+
|Sets '''Coordinates''' to the current position. Nothing is done with these coordinates until '''setDestinationFromCoordinates''' is used. Useful for remembering a position for later returning. (''getWitchspaceEntryCoordinates'', ''setPlanetPatrolCoordinates'', ''setSunSkimStartCoordinates'', ''setSunSkimEndCoordinates'', ''setSunSkimExitCoordinates'', ''setCoordinates:'' and ''setDestinationToDockingAbort'' will also set new coordinates and overwrite an existing ''Coordinates'' value with a new one)
 
|-
 
|-
 
|'''setCourseToPlanet'''
 
|'''setCourseToPlanet'''
|Selects the nearest planet it can find, sets the coordinates to a point on the ship's side of the surface with a large random spread to avoid all ships flying to the same point. Then it sets the desired range to 50 m (+ its own collision diameter). This short desired range will probably crash normal fast flying ships on the surface but a collision between the planet and a ship with role "shuttle" is interpreted as landing. (Change with Oolite 1.73: Will exclude moons. Closest planet will be of type: PLANET_TYPE_GREEN)
+
|Selects the nearest planet it can find, sets the coordinates to a point on the ship's side of the surface with a large random spread to avoid all ships flying to the same point. Then it sets the desired range to 50 m (+ its own collision diameter). This short desired range will probably crash normal fast flying ships on the surface but a collision between the planet and a ship with role "shuttle" is interpreted as landing. Will exclude moons. Closest planet will be of type: PLANET_TYPE_GREEN
 
|-
 
|-
 
|'''setCourseToWitchpoint'''
 
|'''setCourseToWitchpoint'''
 
|Sets destination coords to Witchpoint area and sets "DesiredRange" to 10 km.
 
|Sets destination coords to Witchpoint area and sets "DesiredRange" to 10 km.
 +
|-
 +
|'''setDesiredRangeForWaypoint'''
 +
|Sets the desired range to 50 meters, unless the ship has such a slow turn-rate that it needs a longer distance to make its turn. This command is only useful in a 'gotoWaypointAI' construction.
 
|-
 
|-
 
|'''setDesiredRangeTo:(NSString *)rangeString'''
 
|'''setDesiredRangeTo:(NSString *)rangeString'''
Line 327: Line 370:
 
|-
 
|-
 
|'''setSunSkimEndCoordinates'''
 
|'''setSunSkimEndCoordinates'''
|...
+
|Sets the coordinates and returns "APPROACH_COORDINATES". When there is no sun it will return "NO_SUN_FOUND".
 
|-
 
|-
 
|'''setSunSkimExitCoordinates'''
 
|'''setSunSkimExitCoordinates'''
|...
+
|Sets the coordinates and returns "APPROACH_COORDINATES".
 
|-
 
|-
 
|'''setSunSkimStartCoordinates'''
 
|'''setSunSkimStartCoordinates'''
|...
+
|Sets the coordinates and returns "APPROACH_COORDINATES". When there is no sun it will return "NO_SUN_FOUND" or when the sun is not yes initialized it returns "WAIT_FOR_SUN".
 
|-
 
|-
|'''setTargetToSystemStation'''
+
|'''setTargetToLastStation'''
|Sets the system station as the current target.
+
|Sets the last targeted station as the current target. When there is no last station, it will return "NO_STATION_FOUND". (command will be added with Oolite V1.77)
 +
|-
 +
|'''setTargetToNearestStation'''
 +
|Sets the closest station as the current target. When the ship has a mother station, the mother will become the target, even when there is a closer station.
 +
|-
 +
|'''setTargetToNearestFriendlyStation'''
 +
|Sets the closest station as the current target. When the ship has a mother station, the mother will become the target, even when there is a closer station. This command skips stations that target the ship and are in a yellow or red alert state.
 +
|-
 +
|'''setTargetToRandomStation'''
 +
|Sets a random station that is within desiredRange as the current target. This command skips carriers and stations without npc-traffic. It will return "STATION_FOUND" or "NO_STATION_IN_RANGE". (command will be added with Oolite V1.77)
 
|-
 
|-
 
|'''setTargetToStation'''
 
|'''setTargetToStation'''
|Sets the closest station as the current target. When the ship has a mother station, the mother will become the target, even when there is a closer station.
+
|Use setTargetToNearestStation instead because of the more descriptive name, they do the same.
 
|-
 
|-
|'''setTargetToNearestStation'''
+
|'''setTargetToSystemStation'''
|Sets the closest station as the current target. When the ship has a mother station, the mother will become the target, even when there is a closer station. (added with Oolite 1.72?) Exactly the same as '''setTargetToStation''' but preferred above the old name.
+
|Sets the system station as the current target.
 
|-
 
|-
 
|'''setTakeOffFromPlanet'''
 
|'''setTakeOffFromPlanet'''
Line 355: Line 407:
 
|-
 
|-
 
|'''******'''
 
|'''******'''
|Hitting a clean ship automatical sends a "'''OFFENCE_COMMITTED'''" to all nearby ships with scanClass equal CLASS_NEUTRAL, CLASS_STATION, CLASS_BUOY, CLASS_POLICE, CLASS_MILITARY, CLASS_PLAYER. Besides this all the ships flying in a group like pirates, police or escorts get an "'''ATTACKED'''" message as when they were attacked themself.
+
|If a ship is hit by a laser shot it receives the '''ATTACKED''' message. In 1.77 or later, a narrow miss with a laser shot (provided the attacker was targeting the ship missed) will send an '''ATTACKER_MISSED''' message.
 +
|-
 +
|'''******'''
 +
|Hitting a clean ship with scanClass equal to CLASS_NEUTRAL, CLASS_STATION, CLASS_BUOY, CLASS_POLICE, CLASS_MILITARY or CLASS_PLAYER, automatically sends a "'''OFFENCE_COMMITTED'''" to all nearby police ships and the system station. Besides this all the ships flying in a group like pirates, police or escorts get an "'''ATTACKED'''" message as when they were attacked themself.
 +
|-
 +
|-
 +
|'''******'''
 +
|Every time when a thargoid-mothership dies, it sends a "THARGOID_DESTROYED" message to all ships that contain the role "tharglet" in their role list. A thargoid-mothership is a ship with scan_class "CLASS_THARGOID" and having a "thargoid-mothership" role in its role list.
 
|-
 
|-
 
|'''broadcastDistressMessage'''
 
|'''broadcastDistressMessage'''
|Locates all the stations, bounty hunters and police ships in range and tells them that you are under attack. This command resets a previous found target to none at the sending side. It returns: "'''ACCEPT_DISTRESS_MESSAGE'''" in the AI of Stations, Hunters and Police ships and gives them as" Found Target", the "Primary Target" of the sender of the broadcast.
+
|When a primary aggressor exist, this command locates all the stations, bounty hunters and police ships in range and tells them that you are under attack. This command resets a previous found target to none at the sending side. It returns: "'''ACCEPT_DISTRESS_MESSAGE'''" in the AI of Stations, Hunters and Police ships and gives them as" Found Target", the "Primary Target" of the sender of the broadcast.
 
|-
 
|-
 
|'''commsMessage:(NSString *)valueString'''
 
|'''commsMessage:(NSString *)valueString'''
|Broadcasts a general message to player. It will only send a message if the ship has a pilot. (not by rocks, cargo pods etc.)
+
|Broadcasts a general message to 16 nearby ships. It will only send a message if the sending ship has a pilot. (not by rocks, cargo pods etc.). When you want to be sure the player always receives the message, it is better to target the player and use: ''sendTargetCommsMessage''.
 
Example:
 
Example:
  "sendCommsMessage: [thargoid_curses]"
+
  "commsMessage: [thargoid_curses]"
 
|-
 
|-
 
|'''commsMessageByUnpiloted:(NSString *)valueString'''
 
|'''commsMessageByUnpiloted:(NSString *)valueString'''
|Broadcasts a general message to player without check for pilot. (Will be available from 1.72+)
+
|Broadcasts a general message to 16 nearby ships without check for pilot.
 
Example:
 
Example:
 
  "commsMessageByUnpiloted: This is an automated distress signal."
 
  "commsMessageByUnpiloted: This is an automated distress signal."
Line 382: Line 441:
 
== Locating entities ==
 
== Locating entities ==
  
All these methods require a range to be set by setDesiredRange or by <scanner_range> in [[shipdata.plist]], all will return the message TARGET_FOUND or NOTHING_FOUND. The calling entity remembers the found target, but it does not become the current (universal) target. It can be made the current target by responding to the TARGET_FOUND message with a call to setTargetToFoundTarget.
+
For all these methods you can set a maximum scanning range by setting <scanner_range> in [[shipdata.plist]]. Only the first 16 ships in scanner range are evaluated. With more than 16 ships in range, the scanner might miss some ships. So when you want your ship to scan in dense populated areas you might want to set <scanner_range> in [[shipdata.plist]] at a lower value to have less chance to hit the maximum of 16 ships during scanning and do a more accurate scanning in the smaller area.<br>
 +
All scans will return the message TARGET_FOUND or NOTHING_FOUND. The calling entity remembers the found target, but it does not become the current (universal) target. It can be made the current target by responding to the TARGET_FOUND message with a call to setTargetToFoundTarget. All scan commands start with clearing any previous found target, so you can't use two scans in the same line for complex scanning.  
  
 
When you are continuously scanning as in a update event, make sure you add also a pause command. Scanning takes time and in most cases one scan every few seconds is enough. Look also at Oolites internal AI's were this timing is well thought of.
 
When you are continuously scanning as in a update event, make sure you add also a pause command. Scanning takes time and in most cases one scan every few seconds is enough. Look also at Oolites internal AI's were this timing is well thought of.
Line 398: Line 458:
 
|-
 
|-
 
|'''checkGroupOddsVersusTarget'''
 
|'''checkGroupOddsVersusTarget'''
|Will return "ODDS_GOOD", "ODDS_LEVEL" or "ODDS_BAD".
+
|This command compares group sizes after first adding a random number between 0 and 3 to both sides. It will return "ODDS_GOOD", "ODDS_LEVEL" or "ODDS_BAD".
 
|-
 
|-
 
|'''checkForFullHold'''
 
|'''checkForFullHold'''
Line 420: Line 480:
 
|-
 
|-
 
|'''scanForHostiles'''
 
|'''scanForHostiles'''
|Locates all the ships in range targeting the receiver and ships with "CLASS_TARGOID" and chooses the nearest. Returns: "TARGET_FOUND" or "NOTHING_FOUND"
+
|Locates all the ships in range that are in attack mode and are targeting the receiver and ships with "CLASS_TARGOID".  From these ships the nearest is chosen. Returns: "TARGET_FOUND" or "NOTHING_FOUND"
 
|-
 
|-
 
|'''scanForLoot'''
 
|'''scanForLoot'''
 
|Scans for nearest debris in range.
 
|Scans for nearest debris in range.
 
Returns: "HOLD_FULL", "TARGET_FOUND" or "NOTHING_FOUND".
 
Returns: "HOLD_FULL", "TARGET_FOUND" or "NOTHING_FOUND".
If scanning ship is moving station or has no scoop it always return: "NOTHING_FOUND". If scanning ship has scanClass: "CLASS_POLICE", it only finds slaves and lifepods.
+
If scanning ship is moving station or has no scoop it always return: "NOTHING_FOUND". If scanning ship has scanClass: "CLASS_POLICE", it only finds slaves and lifepods.<br>
 +
Loot is everything with scan_class = CLASS_CARGO, except debris that explicit defines: cargo_type = CARGO_NOT_CARGO
 
|-
 
|-
|'''scanForNearestMerchantmen'''
+
|'''scanForNearestMerchantman'''
 
|Scans for ships with role: Trader or Player and selects the nearest. If scanning ship has role Pirate it prefers the player.
 
|Scans for ships with role: Trader or Player and selects the nearest. If scanning ship has role Pirate it prefers the player.
Returns: "TARGET_FOUND" or "NOTHING_FOUND"
+
Returns: "TARGET_FOUND" or "NOTHING_FOUND" (before 1.74 this was called:  scanForNearestMerchantm'''e'''n)
 
|-
 
|-
 
|'''scanForNearestShipWithRole:(NSString*) scanRole'''
 
|'''scanForNearestShipWithRole:(NSString*) scanRole'''
Line 435: Line 496:
 
|-
 
|-
 
|'''scanForNonThargoid'''
 
|'''scanForNonThargoid'''
|Locates all the non thargoid ships in range and chooses the nearest. It finds everything except cargo and ships with a role starting with: "tharg". If it finds the player it prefers the player. Returns: "TARGET_FOUND" or "NOTHING_FOUND"
+
|Locates all the non thargoid ships in range and chooses the nearest. It finds everything except cargo and ships with scanClass "thargoid". If it finds the player it prefers the player. Returns: "TARGET_FOUND" or "NOTHING_FOUND"
 
|-
 
|-
 
|'''scanForOffenders'''
 
|'''scanForOffenders'''
Line 446: Line 507:
 
If scanning ship is station or has no scoop it always return: "NOTHING_FOUND".
 
If scanning ship is station or has no scoop it always return: "NOTHING_FOUND".
 
|-
 
|-
|'''scanForRandomMerchantmen'''
+
|'''scanForRandomMerchantman'''
|Scans for ships with role: Trader or Player and selects one at random. Returns: "TARGET_FOUND" or "NOTHING_FOUND".
+
|Scans for ships with role: Trader or Player and selects one at random. Returns: "TARGET_FOUND" or "NOTHING_FOUND". (In older Oolite versions this was called:  scanForRandomMerchantm'''e'''n)
 
|-
 
|-
 
|'''scanForRocks'''
 
|'''scanForRocks'''
|Scans for nearest boulder in range. When nothing found then scans for nearest asteroid in range. Returns "TARGET_FOUND" or  "NOTING_FOUND".
+
|Scans for nearest boulder in range. When nothing found then scans for nearest asteroid in range. Returns "TARGET_FOUND" or  "NOTING_FOUND". A boulder is anything with 'boulder' in its rolelist and asteroid is anything with 'asteroid' in its rolelist.  
 
|-
 
|-
 
|'''scanForThargoid'''
 
|'''scanForThargoid'''
|Locates all the ships with role "thargoid" in range and chooses the nearest. Returns: "TARGET_FOUND" or "NOTHING_FOUND"
+
|Locates all the ships with primaryRole "thargoid" in range and chooses the nearest. Returns: "TARGET_FOUND" or "NOTHING_FOUND"
 +
|-
 +
|'''thargonCheckMother'''
 +
|Checks if its owner is still alive and in range. When not it scans for a new ship containing the role "thargoid-mothership" in its role list and makes that the new owner. Returns: "TARGET_FOUND" or "NOTHING_FOUND".
 
|}
 
|}
  
Line 461: Line 525:
 
!width="225"|Method
 
!width="225"|Method
 
!Description
 
!Description
 +
|-
 +
|'''****''' (added in 1.77)
 +
|In 1.77 onwards, DEFENSE_TARGET_LOST and DEFENSE_TARGET_DESTROYED messages will be sent if a ship on the point defense target list is lost or destroyed.
 +
|-
 +
|'''addFoundTargetAsDefenseTarget''' (added in 1.77)
 +
|Adds the found target to the point defense target list.
 +
|-
 +
|'''addPrimaryAggressorAsDefenseTarget''' (added in 1.77)
 +
|Adds the primary aggressor to the point defense target list.
 +
|-
 +
|'''clearDefenseTargets''' (added in 1.77)
 +
|Clears the point defense target list
 +
|-
 +
|'''findNewDefenseTarget''' (added in 1.77)
 +
|Looks for the nearest hostile ship not currently on the point defense target list, and adds it.
 
|-
 
|-
 
|'''requestNewTarget'''
 
|'''requestNewTarget'''
Line 469: Line 548:
 
|-
 
|-
 
|'''setTargetToPrimaryAggressor'''
 
|'''setTargetToPrimaryAggressor'''
|This function sets the primary agressor to the primary target. Then in the "performAttack" state, it only has a 25% change of setting the primary agressor to the primary target. The other 75% it will do nothing. This function is designed for used during attack to prevent it will constantly change targets when attacking a group.
+
|This function sets the primary agressor to the primary target. Then in the "performAttack" state, it only has a 25% chance of setting the primary aggressor to the primary target. The other 75% it will do nothing (1.76 or earlier) or set the aggressor as a defense target only (1.77 or later). This function is designed for use during attack to prevent the ship constantly changing targets when attacking a group.
  
primary agressor is set by the system when a ship fires a laser or missile on the other.  
+
Primary aggressor is set by the system when a ship fires a laser or missile at another.  
 
|}
 
|}
  
Line 510: Line 589:
 
|'''checkEnergy'''
 
|'''checkEnergy'''
 
|Checks the energy level and returns: ENERGY_LOW (energy< 25%), ENERGY_MEDIUM (25%<energy<75%), ENERGY_HIGH (75%<energy<100%) or ENERGY_FULL (energy = 100%). Added with Oolite 1.74
 
|Checks the energy level and returns: ENERGY_LOW (energy< 25%), ENERGY_MEDIUM (25%<energy<75%), ENERGY_HIGH (75%<energy<100%) or ENERGY_FULL (energy = 100%). Added with Oolite 1.74
 +
|-
 +
|'''checkHeatInsulation'''
 +
|Checks the heat insulation of a ship and returns: INSULATION_OK or INSULATION_POOR. Added with Oolite 1.75
 
|-
 
|-
 
|'''initialiseTurret'''
 
|'''initialiseTurret'''
|Prepares the turret. As turrets have no statemachine of their own, this function can only be used in the setup_actions of the turrets shipData.
+
|This command itself does nothing. When it is part of the setup_actions of the turrets shipData, it tells Oolite this subEntity has to be treated a turret. It is only needed when using an old style subEntity definition, for the new style definitions, the setup_actions are ignored.
 
|-
 
|-
 
|'''rollD:(NSString*) dice_number'''
 
|'''rollD:(NSString*) dice_number'''
Line 531: Line 613:
 
|-
 
|-
 
|'''safeScriptActionOnTarget:(NSString*) action'''
 
|'''safeScriptActionOnTarget:(NSString*) action'''
|This will do a script action on the target. For NPC ships as target you can use all the AI commands available that will act as if its own AI used the command. (command introduced with version 1.71)
+
|This will do a script action on the target. For NPC ships as target you can use all the AI commands available that will act as if its own AI used the command.
  
It will also execute player script commands, like setting mission variables. For this to work it needs a target being set. It doesn't matter witch one.
+
It will also execute player script commands, like setting mission variables. For this to work it needs a target being set. It doesn't matter which one.
  
 
Example:
 
Example:
Line 545: Line 627:
 
|-
 
|-
 
|'''sendScriptMessage: message'''
 
|'''sendScriptMessage: message'''
|Calls the javaScript function '''message()''' on the ship’s [[Oolite JavaScript Reference: Script|ship script]]. Added in Oolite 1.70. This function opens the whole js power to the AI scripting. e.g. by using:
+
|Calls the javaScript function '''message()''' on the ship’s [[Oolite JavaScript Reference: Script|ship script]]. This function opens the whole js power to the AI scripting. e.g. by using:
 
  "sendScriptMessage: myFunction".
 
  "sendScriptMessage: myFunction".
 
This script message than activates the ship-script function:
 
This script message than activates the ship-script function:
 
  this.myFunction = () { body };
 
  this.myFunction = () { body };
Since Oolite 1.73 one can also transfer space separated parameters by using:
+
One can also transfer space separated parameters by using:
 
  "sendScriptMessage: myFunction param1 param2"
 
  "sendScriptMessage: myFunction param1 param2"
 
These values are transferred as an array and can be read in JavaScript as
 
These values are transferred as an array and can be read in JavaScript as
Line 557: Line 639:
  
 
== Role scanning methods ==
 
== Role scanning methods ==
Starting with version 1.70 next commands will become available. This info is still preliminary until the actual release. These role based methods all skip ships with scanclass: CLASS_CARGO
+
The role based scanning methods all skip ships with scanclass: CLASS_CARGO
  
 
{| border="1" cellpadding="5" style="width:100%
 
{| border="1" cellpadding="5" style="width:100%
Line 593: Line 675:
 
|  
 
|  
 
|}
 
|}
--------------------------------------------------------------------------------
+
----
 +
== Understanding what is happening ==
 +
There are a number of ways of accessing the AI decision-making process:
 +
*Outputting in [[Latest.log]] - see [http://bb.oolite.space/viewtopic.php?p=291162#p291162 here] for how to enable this (several posts - 2023)
 +
*Graphical Output (not for javascript AIs) - see [http://bb.oolite.space/viewtopic.php?f=2&t=21443 here] for more detail (2023)
 +
----
 +
== Links ==
 +
:[[OXP howto]]
 +
=== .plist AI's ===
 +
:[[AI]] (.plist AI's)
 +
::[[Messages]] (sent by Vanilla game machine to AI state machine)
 +
::[[AI_methods]]
 +
=== Javascipt AI's ===
 +
:[[Oolite Javascript Reference: PriorityAI Documentation]]
 +
:[[Oolite PriorityAI Tutorial]] (''Javascript'' AI's)
 +
=== Other relevant pages ===
 +
:[[Role]] - the role of a ship is linked to its AI
 +
:[[Methods]]
 +
=== Bulletin Board snippets ===
 +
* [http://bb.oolite.space/viewtopic.php?f=4&t=13997 Qs about Roles/AIs] - Commander McLane's runs a short tutorial on how to devise an AI
 +
:''Note that this tutorial is from early 2014 - before Oolite v.1.80 debuted - and hence some of the vanilla game AI's are more complex today''
 +
*[http://bb.oolite.space/viewtopic.php?f=6&t=21269 Szaumix's extended critique] of NPC combat AI - see especially his notes from August 2023. (2022-23)
 +
* See [http://bb.oolite.space/viewtopic.php?p=235800#p235800 here] for detail on how "autoweapons" link with roles (cim, 2015)
 +
* [http://bb.oolite.space/viewtopic.php?f=4&t=8479 Preventing witchspace jumps] (2010) - contains notes on how the AIs handle witchspace jumping
 +
* [http://bb.oolite.space/viewtopic.php?p=92907#p92907 Making NPC's more aggressive] - Littlebear (2009)
 +
* [http://bb.oolite.space/viewtopic.php?f=2&t=2619 Explaining bizarre NPC reactions] - see Littlebear's second and third replies (2006)
 +
* [https://bb.oolite.space/viewtopic.php?p=297133#p297133 Thread including pitfalls in designing a new AI] (2024)
 +
 
 
[[Category:Oolite]]
 
[[Category:Oolite]]
 
[[Category:Oolite scripting]]
 
[[Category:Oolite scripting]]

Latest revision as of 13:43, 24 July 2024

Notice

This page describes the plist-based method of AI scripting in Oolite. Since version 1.80, the use of plist-based AIs for non-trivial AIs is discouraged. Javascript AIs are recommended. Use of the Priority AI library to write AIs, especially the standard conditions and behaviours it provides, is useful to make ships fit in with the core ships and to have future improvements to AI incorporated easily. Alternative AI controller libraries released as OXPs may also be used.

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. 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 OpenStep property list 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 = ();
     };
}

The same script in XML.


AI

Messages to the statemachine with a priority are displayed in boldface.

Method Description
dropMessages: (NSString *)messageString Removes the pending message(s) with this name.

e.g. when attacking a trader there is often both a "FIGHTING" and a "FLEEING" message on update time. When reacting on one while staying in the same state, it might be wise to drop the other possible one.

exitAI Exits current AI and returns to the same state in the old AI that called this AI with a "setAITo:". It returns: "RESTARTED".
exitAIWithMessage: (NSString *)messageString Exits current AI and returns to the same state in the old AI that called this AI with a "setAITo:". It returns: "messageString" instead of RESTARTED. Useful for something like "exitAIWithMessage: ATTACKED", as the main AI will loose that message with just an "ExitAI".
messageSelf: (NSString *)messageString Sends a message to itself to be read in the next UPDATE. Useful to add delays in a reaction on an other message without the need to go to another state.

e.g.

INCOMING_MISSILE = ("messageSelf: MISSILE_DETECTED", "pauseAI: 1.5");
MISSILE_DETECTED = (fightOrFleeMissile);

will act delayed on an incoming missile.

pauseAI: (NSString *)intervalString Sets next AI update time in seconds. It does not stop the execution of the remainder of the line. It just sets the next UPDATE time to the current time plus the pause time. The pauseAI commands are non-cumulative.
randomPauseAI: (NSString *)intervalString Sets next AI update time in seconds to a random time between a minimum and a maximum value. This command takes two space separated parameters like in "randomPauseAI: 0.2 2.6".
setAITo: (NSString *)aiString Pauses current AI and switches to anotherAI.plist, this becomes the top AI on the 'AI-stack'.
When anotherAI.plist exits (exitAI or exitAIWithMessage), the previousAI becomes topAI again and AI-state is messaged "RESTARTED" .
(In some older scripts the commands "setStateMachine:" is found. That does the same as "setAITo:" and should be replaced by setAITo:.)
setStateTo: SOMESTATE Changes the AI state to SOMESTATE.
switchAITo: (NSString *)aiString Switches entity AI to another *AI.plist, the previous AI will be exited.

AI choices

Method Description
fightOrFleeHostiles Deploys escorts if he has them. If he has enough missiles left he might fire one. Then decides between issue the FIGHTING or FLEEING message. Returns "FIGHTING", "DEPLOYING_ESCORTS" or "FLEEING".
fightOrFleeMissile Deals with missiles by searching a missile heading for itself or one of its escorts. When found it sets the missile as its primary target. Than, it uses ECM if available, or goes into a performFlee mode if no ECM available. It marks the launcher as offender if targeting a police. Returns: "FLEEING" when the ship went into a performFlee mode.

Perform Action

Method Description
abortAllDockings Used by stations to send an abort docking message to all ships busy with docking. This allows for immediate launching of ships. This slows down the whole docking process, so only use this command when absolutely needed.
becomeEnergyBlast Used in the Q bomb. Sends a CASCADE_WEAPON_DETECTED event to every ship in scanner range.
becomeExplosion The entity model is replaced by an explosion. If player is docked at exploding station it first launches the player.
becomeLargeExplosion Used at player entity death, not for use in other instances.
broadcastEnergyBlastImminent
(1.77 or later)
Used in the Q bomb. Sends a CASCADE_WEAPON_DETECTED event to every ship in scanner range.
dealEnergyDamageWithinDesiredRange Needs desiredRange to be set first, then deals energy damage to ships within this sphere, based on weapon_energy: (weapon_energy * desiredRange) / (6.76 * distance * distance)
decreaseAlertLevel Can only be used on stations. Decreases station alertlevel. Returns: "CONDITION_YELLOW", "CONDITION_GREEN".
deployEscorts Sends the mothers primary target to all escorts and sets the statemachine of all the escorts to: interceptAI.plist.
dockEscorts Gives all existing escorts a dockingAI.plist and sets the state to ABORT so the escorts go to a waiting position for docking.
dumpCargo Ejects one cargo canister when present. This action will send "CARGO_DUMPED" to all ships in range.
ejectCargo Ejects the complete cargo bay content with 0.75 seconds spacing between cargo canisters. This action will send "CARGO_DUMPED" to all ships in range.
enterTargetWormhole Will enter the targeted wormhole, or the nearest wormhole if target is not a wormhole.
enterPlayerWormhole Will try to enter the players' wormhole if the ship can reach it in time. Only useful following a "PLAYER WITCHSPACE" message.
escortCheckMother Returns "ESCORTING" or "NOT_ESCORTING".
fireECM Used by stations and hermits to engage ECM.
fireMissile Fires missiles on selected target. It sends a "INCOMING_MISSILE" message to the target state machine.
groupAttackTarget All ships in group will have their targets set to this entity's current target. It will return "GROUP_ATTACK_TARGET" to the sending ship as well as to all group members.
increaseAlertLevel Can only be used on stations. Increases station alertlevel. Returns: "YELLOW_ALERT", "RED_ALERT".
landOnPlanet Selects the nearest planet it can find, increments the landed shuttles counter for that planet and 'removes' the entity. Returns: "LANDED_ON_PLANET"
Launch..SomeShip Launches a ship from a dockable entity, various types of this method exist. See also Station Ships.
  • LaunchDefenseShip
  • LaunchEscort
  • LaunchIndependentShipWithRole: <Role>
  • LaunchMiner
  • LaunchPatrol
  • LaunchPirateShip
  • LaunchPolice
  • LaunchScavenger
  • LaunchShipWithRole: <Role> (sets the station as its mother station.)
  • LaunchShuttle
  • LaunchTrader

During the launch, there is no AI UPDATE and any active behaviour is ignored. The ship is just flying straight ahead. When far enough from the station a "LAUNCHED OKAY" message is generated , the first AI UPDATE happens and the active behaviour is followed.
The launching station will receive a "STATION_LAUNCHED_SHIP" message.

markTargetForFines Deals out a fine to target. It returns: "TARGET_MARKED". When the target was no ship it returns: "TARGET_LOST".

Will fine the target on the next docking in the current system. The value of the fine is always 50 or 100, multiplied by the target's legal status on docking. Dealing out multiple fines has no extra effect. On paying the fine, the ships legal status is cleared and the system clock advances a day. The amount to be fined is cleared after the ship enters a new system.

markTargetForOffence:(NSString*) valueString Has police mark up the criminal record (Legal status) of target entity. The value is not added to the criminal record but a bit-wise OR is used between value and criminal record. It returns: "TARGET_LOST" when the target was no ship. This command can only be used by stations or police ships. With other ships this command is ignored.
messageMother:(NSString *)msgString Sends a AI priority message to the mothership/leader of a group.

Example:

INCOMING_MISSILE = ("messageMother: INCOMING_MISSILE");

The mothership will then behave as if it was targeted by the missile. But you don't have to use standard message names, you can also send self defined message names were the mother can react on.

performAttack Attacks target.
performAvoidCollision This is not an existing AI command but only added here to show its existence that can interfere with other perform actions. Its an automatic feature used by several of the other perform commands to avoid a collision with a very nearby object. The old performance is temporary put on ice, the ships moves away a bit from the obstacle and than continues the old performance. This automatic collision avoidance can be a problem when you want to navigate a ship very close to an existing ship. Therefore none of the non-battle performances will avoid collision with a primary target.
performCollect Performs 'collection' of target. Generates a "FRUSTRATED" message when not able to come closer to the target and a "TARGET_LOST" when loosing or scooping the cargo. Colliding with cargo in the presence of a scoop, generates the messages "CARGO_SCOOPED" and "HOLD_FULL" independent of the actual behaviour.
performDocking NOT YET IMPLEMENTED.
performEscort Performs escorting. Needs a desired range first. The escorts follow at the desired range. See also Escort Instructions.
performFaceDestination Has entity face destination. Sets also the desiredSpeed to zero. Returns "FACING_DESTINATION" when turn is completed.
performFlee Sets the caller (AI) to flee from it's primary target at maximum speed. If the caller has a cloaking device, it will be activated. It needs a range to be set first. When the ship outruns the attacker by this distance it returns: "REACHED_SAFETY".
performFlyToRangeFromDestination With this command the ship can react in two ways. It first looks at the distance to the target. When it is closer to the target than the previously defined desired range, it will fly away from the target, otherwise it will fly toward the target. It stops the ship at the desired range from the destination and than returns: "DESIRED_RANGE_ACHIEVED".

It will not send a ship on a head-on course to the target, but on a course that intersects with a sphere of desired_range around the target. When flying towards the target it will automatic reduce speed based on ship characteristics so it stops at almost the exactly the desired_range from target. (setting speed in UPDATE could interfere with this). It sends a "FRUSTRATED" message when not progressing for some time.

performHold Performs idleness while tracking a potential target, speed is set to zero. frustration level is reset.
When it has no primary target, or loses the primary target, it will sent a "TARGET_LOST" message and change itself into performIdle.
performHyperSpaceExit Gets a list of destinations within fuel range, checks if clear of nearby masses, and select one at random. May return "WITCHSPACE UNAVAILABLE", "WITCHSPACE BLOCKED" or "WITCHSPACE_OKAY". When the ship enters the wormhole, the AI is halted. When the player chooses to enter that system, the AI is restarted in the GLOBAL state with a message "EXITED WITCHSPACE". When the player enters an other system, or when the wormhole collapses without being targeted by the player, the ship is completely removed from memory.

This command will also add a new ship with the same role as the leaving ship at the witchspace entry point of the current system. This new ship at the current witchpoint will start with a "EXITED_WITCHSPACE" message so that a script can distinguish between the initial added ship and the replacement ship. (Note the underscore in the message that is not there for the original ship).

When the player performs a hyperspace exit or a galactic jump, all NPC ships get the priority message: "PLAYER WITCHSPACE".

performHyperSpaceExitWithoutReplacing Gets a list of destinations within fuel range, checks if clear of nearby masses, and select one at random. May return "WITCHSPACE UNAVAILABLE", "WITCHSPACE BLOCKED" or "WITCHSPACE_OKAY". When the player follows the ship to the new system, the AI is restarted in the GLOBAL state with a "EXITED WITCHSPACE" message. This command will not add a new ship at the witchspace entry point.
performIdle Performs idleness. Ship corrects its roll and pitch to 'horizontal' flight, speed is unaffected. frustration level is reset to zero.
performIntercept Performs target interception. It needs a range to be set first. When the distance to target becomes less than desired range it returns: "DESIRED_RANGE_ACHIEVED". When target lost: "TARGET_LOST". When it hasn't come closer to target for 10 seconds it returns: "FRUSTRATED"
performLandOnPlanet Performs landing. This command can only be used when within 500 meters to the surface. (after the message APPROACHING_SURFACE is send). When too far away it returns: "NO_PLANET_NEARBY". When landing is complete it returns "LANDED_ON_PLANET". (will be added with Oolite 1.77)
performMining Performs mining. (Finds, intercepts and shoots asteroids with a mining laser, if fitted.) It returns: "TARGET_LOST".
performScriptedAI
(added in Oolite 1.77)
Performs manoeuvres according to a custom flight function in its ship script
performScriptedAttackAI
(added in Oolite 1.77)
Performs manoeuvres according to a custom flight function in its ship script, and fires at its primary target
performTumble Performs random pitch and roll, 'evasive manoeuvres'.
setSpeedFactorTo:(NSString *)speedString Sets the desired speed to a percentage of maxspeed (0->1=0%->100%). If speedfactor is set above 100%, entity will use fuel injectors if available.
setSpeedTo:(NSString *)speedString Sets desired speed to an absolute value, entity cannot go faster than maxspeed value determined in the shipdata.plist. If speed is above maxspeed, entity will use fuel injectors if available.
setSpeedToCruiseSpeed Normally sets desired speed to 80% of max speed. When the ship has slower escorts, speed is adapted to the slowest escort.
setThrustFactorTo:(NSString *)thrustString Sets the thrust to a percentage of maxThrust (0->1=0%->100%). maxThrust is the thrust value defined in shipdata.
setUpEscorts Unused command in current Oolite versions. Escorts are now automatically added when a mother is created. See also Escort Instructions.
suggestEscort Has an escort seek employment and either gets accepted or rejected by the "mother". See also Escort Instructions. It sends "ESCORTING" to the escort when accepted and "ACCEPTED_ESCORT" to the mother ship that accepted the ship. When not accepted it returns "NOT_ESCORTING".
switchLightsOff If an entity has lights (or flashers), this command will turn them off. Default state is on. (See shipdata.plist)
switchLightsOn Will turn flashers back on.
throwSparks Will throw a single burst of spark.
wormholeEntireGroup Wormholes ships in this group. Returns "ENTER WORMHOLE". The primary target must point to the wormhole itself, and that is only the case after the ship received the message "WITCHSPACE OKAY".
wormholeEscorts Wormholes official escorts. Returns "ENTER WORMHOLE". The primary target must point to the wormhole.
wormholeGroup Wormholes ships in group of which this is a leader. Returns "ENTER WORMHOLE". The primary target must point to the wormhole.

Navigation

Method Description
**** The aegis check is part of the system update and messages needs no command to generate them. The following messages are only generated when the status changes.

"AEGIS_CLOSE_TO_PLANET": Within 3x planetary radius of the main planet and not near station.
"AEGIS_IN_DOCKING_RANGE": Within 2x scanner radius of system station.
"AEGIS_LEAVING_DOCKING_RANGE": Has been in docking range but now only close to planet.
"AEGIS_NONE": None of the above three messages is true.
"AEGIS_CLOSE_TO_MAIN_PLANET": Within 3x planetary radius of the main planet and not near station.
"CLOSE_TO_PLANET": Within 3x planetary radius of any planet and not near station.
"AWAY_FROM_PLANET": Leaving the area of 3x planetary radius of any planet.
"CLOSE_TO_SUN": Within 3x sun radius of the sun .
"AWAY_FROM_SUN Leaving the area of 3x sun radius of the sun.
"CLOSE_TO_SECONDARY_PLANET": Within 3x radius of a planet that is not the main-planet.
"CLOSE_TO_MOON": Within 3x radius of a moon (=planet without atmosphere).

With intersecting aegis of planets the main-planet aegis has priority, even when closer to another planet.

**** The surface check needs no command. It automatically generates messages when a ship passes a border at approximately 1 meter from the main planet surface.

"APPROACHING_SURFACE": passed the border inward. "LEAVING_SURFACE": passed the border outward.

**** When the ship-key track_contacts is set to true, the ship will receive a "CLOSE_CONTACT" message when an other ship enters his collision range. During this message that other ship will be the primary target.
abortDocking Signal the mother station that the docking is aborted. see Docking Instructions
checkAegis Retransmits the aegis status. Sends: "AEGIS_NONE", "AEGIS_IN_DOCKING_RANGE", "AEGIS_CLOSE_TO_MAIN_PLANET", "AEGIS_CLOSE_TO_PLANET", "CLOSE_TO_PLANET", "CLOSE_TO_SECONDARY_PLANET", "CLOSE_TO_MOON" and/or "CLOSE_TO_SUN".
getWitchspaceEntryCoordinates Calculates coordinates at 10 km from the rotation axis of the nearest station it can find, or just fly 10s forward.
recallDockingInstructions see Docking Instructions
requestDockingCoordinates Requests coordinates from the nearest station it can find (which may be a Rock hermit). Returns: "NO_STATION_FOUND", "TRY_AGAIN_LATER", "HOLD_POSITION", "BACK_OFF" , "APPROACH" or "APPROACH_COORDINATES". see also Docking Instructions
setCoordinates:(NSString *)system_x_y_z Sets destination coords, see addShipsAt. It needs 4 parameters separated with space. When coordinates are set it returns: "APPROACH_COORDINATES". You can even randomize positive coordinates.
setCoordinatesFromPosition Sets Coordinates to the current position. Nothing is done with these coordinates until setDestinationFromCoordinates is used. Useful for remembering a position for later returning. (getWitchspaceEntryCoordinates, setPlanetPatrolCoordinates, setSunSkimStartCoordinates, setSunSkimEndCoordinates, setSunSkimExitCoordinates, setCoordinates: and setDestinationToDockingAbort will also set new coordinates and overwrite an existing Coordinates value with a new one)
setCourseToPlanet Selects the nearest planet it can find, sets the coordinates to a point on the ship's side of the surface with a large random spread to avoid all ships flying to the same point. Then it sets the desired range to 50 m (+ its own collision diameter). This short desired range will probably crash normal fast flying ships on the surface but a collision between the planet and a ship with role "shuttle" is interpreted as landing. Will exclude moons. Closest planet will be of type: PLANET_TYPE_GREEN
setCourseToWitchpoint Sets destination coords to Witchpoint area and sets "DesiredRange" to 10 km.
setDesiredRangeForWaypoint Sets the desired range to 50 meters, unless the ship has such a slow turn-rate that it needs a longer distance to make its turn. This command is only useful in a 'gotoWaypointAI' construction.
setDesiredRangeTo:(NSString *)rangeString 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.

setDestinationFromCoordinates Enables the plotting of manual waypoints.
setDestinationToCurrentLocation 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.
setDestinationToDockingAbort DockingAbort coordinates 8000 meter distance from the docking slit.
setDestinationToStationBeacon Sets destination at 10 km ahead of the docking slid (of the main station). The station beacon itself needs not to be present.
setDestinationToTarget Sets destination to target coords.
setDestinationToWitchpoint Sets destination coordinates to WitchspaceExitPosition.
setDestinationWithinTarget Handy for ramming and racing.
setPlanetPatrolCoordinates Request coordinates for planet control. Read more in setPlanetPatrolCoordinates.
setSunSkimEndCoordinates Sets the coordinates and returns "APPROACH_COORDINATES". When there is no sun it will return "NO_SUN_FOUND".
setSunSkimExitCoordinates Sets the coordinates and returns "APPROACH_COORDINATES".
setSunSkimStartCoordinates Sets the coordinates and returns "APPROACH_COORDINATES". When there is no sun it will return "NO_SUN_FOUND" or when the sun is not yes initialized it returns "WAIT_FOR_SUN".
setTargetToLastStation Sets the last targeted station as the current target. When there is no last station, it will return "NO_STATION_FOUND". (command will be added with Oolite V1.77)
setTargetToNearestStation Sets the closest station as the current target. When the ship has a mother station, the mother will become the target, even when there is a closer station.
setTargetToNearestFriendlyStation Sets the closest station as the current target. When the ship has a mother station, the mother will become the target, even when there is a closer station. This command skips stations that target the ship and are in a yellow or red alert state.
setTargetToRandomStation Sets a random station that is within desiredRange as the current target. This command skips carriers and stations without npc-traffic. It will return "STATION_FOUND" or "NO_STATION_IN_RANGE". (command will be added with Oolite V1.77)
setTargetToStation Use setTargetToNearestStation instead because of the more descriptive name, they do the same.
setTargetToSystemStation Sets the system station as the current target.
setTakeOffFromPlanet Selects the nearest planet it can find and calculates a vector perpendicular to the surface and sets a destination range of 10 km. Does nothing if there is no planet to be found.

Communication

Method Description
****** If a ship is hit by a laser shot it receives the ATTACKED message. In 1.77 or later, a narrow miss with a laser shot (provided the attacker was targeting the ship missed) will send an ATTACKER_MISSED message.
****** Hitting a clean ship with scanClass equal to CLASS_NEUTRAL, CLASS_STATION, CLASS_BUOY, CLASS_POLICE, CLASS_MILITARY or CLASS_PLAYER, automatically sends a "OFFENCE_COMMITTED" to all nearby police ships and the system station. Besides this all the ships flying in a group like pirates, police or escorts get an "ATTACKED" message as when they were attacked themself.
****** Every time when a thargoid-mothership dies, it sends a "THARGOID_DESTROYED" message to all ships that contain the role "tharglet" in their role list. A thargoid-mothership is a ship with scan_class "CLASS_THARGOID" and having a "thargoid-mothership" role in its role list.
broadcastDistressMessage When a primary aggressor exist, this command locates all the stations, bounty hunters and police ships in range and tells them that you are under attack. This command resets a previous found target to none at the sending side. It returns: "ACCEPT_DISTRESS_MESSAGE" in the AI of Stations, Hunters and Police ships and gives them as" Found Target", the "Primary Target" of the sender of the broadcast.
commsMessage:(NSString *)valueString Broadcasts a general message to 16 nearby ships. It will only send a message if the sending ship has a pilot. (not by rocks, cargo pods etc.). When you want to be sure the player always receives the message, it is better to target the player and use: sendTargetCommsMessage.

Example:

"commsMessage: [thargoid_curses]"
commsMessageByUnpiloted:(NSString *)valueString Broadcasts a general message to 16 nearby ships without check for pilot.

Example:

"commsMessageByUnpiloted: This is an automated distress signal."
patrolReportIn This command sets the "last patrol report time" to the current time. Only useful for station patrol.
sendTargetCommsMessage:(NSString*) message Sends any message to the established (found) target. When the target is not a ship it returns: "TARGET_LOST"

Example:

"sendTargetCommsMessage: Listen to me!!"

Locating entities

For all these methods you can set a maximum scanning range by setting <scanner_range> in shipdata.plist. Only the first 16 ships in scanner range are evaluated. With more than 16 ships in range, the scanner might miss some ships. So when you want your ship to scan in dense populated areas you might want to set <scanner_range> in shipdata.plist at a lower value to have less chance to hit the maximum of 16 ships during scanning and do a more accurate scanning in the smaller area.
All scans will return the message TARGET_FOUND or NOTHING_FOUND. The calling entity remembers the found target, but it does not become the current (universal) target. It can be made the current target by responding to the TARGET_FOUND message with a call to setTargetToFoundTarget. All scan commands start with clearing any previous found target, so you can't use two scans in the same line for complex scanning.

When you are continuously scanning as in a update event, make sure you add also a pause command. Scanning takes time and in most cases one scan every few seconds is enough. Look also at Oolites internal AI's were this timing is well thought of.

Method Description
checkCourseToDestination Will return "COURSE_OK" when no obstacles on the direct route, else it calculates a little deviated save vector and returns "WAYPOINT_SET". When there is a small ship in his way it also returns: HAZARD_CAN_BE_DESTROYED

(Since 1.73 not the whole route is examined, but only the part within scanner range for ships and a bit longer range for planets&moons).

checkDistanceTravelled First you must define a range with setDesiredRangeTo:. When the total traveled distance since creation is greater than this value it returns: "GONE_BEYOND_RANGE". Used for missiles.
checkGroupOddsVersusTarget This command compares group sizes after first adding a random number between 0 and 3 to both sides. It will return "ODDS_GOOD", "ODDS_LEVEL" or "ODDS_BAD".
checkForFullHold If entity's cargo capacity is reached, will return "HOLD_FULL".

Since 1.73 it can also return "HOLD_NOT_FULL" or "NO_CARGO_BAY".

checkForMotherStation Will return "STATION_FOUND" or "NOTHING_FOUND".
checkForNormalSpace Will return "NORMAL_SPACE" or "INTERSTELLAR_SPACE".
checkTargetLegalStatus Returns "TARGET_CLEAN, "TARGET_MINOR_OFFENDER", "TARGET_OFFENDER", "TARGET_FUGITIVE" or "NO_TARGET".
findNearestPlanet Will scan for planetentity. Returns nothing. Nearest planet coordinates are placed in destination memory.
scanForFormationLeader Locates the nearest suitable formation leader in range. Returns: "TARGET_FOUND" or "NOTHING_FOUND". See also Escort Instructions.
scanForHostiles Locates all the ships in range that are in attack mode and are targeting the receiver and ships with "CLASS_TARGOID". From these ships the nearest is chosen. Returns: "TARGET_FOUND" or "NOTHING_FOUND"
scanForLoot Scans for nearest debris in range.

Returns: "HOLD_FULL", "TARGET_FOUND" or "NOTHING_FOUND". If scanning ship is moving station or has no scoop it always return: "NOTHING_FOUND". If scanning ship has scanClass: "CLASS_POLICE", it only finds slaves and lifepods.
Loot is everything with scan_class = CLASS_CARGO, except debris that explicit defines: cargo_type = CARGO_NOT_CARGO

scanForNearestMerchantman Scans for ships with role: Trader or Player and selects the nearest. If scanning ship has role Pirate it prefers the player.

Returns: "TARGET_FOUND" or "NOTHING_FOUND" (before 1.74 this was called: scanForNearestMerchantmen)

scanForNearestShipWithRole:(NSString*) scanRole Locates all the ships in range and chooses the nearest. Returns: "TARGET_FOUND" or "NOTHING_FOUND". Anything of CLASS_CARGO is skipped in the search, even if the role matches.
scanForNonThargoid Locates all the non thargoid ships in range and chooses the nearest. It finds everything except cargo and ships with scanClass "thargoid". If it finds the player it prefers the player. Returns: "TARGET_FOUND" or "NOTHING_FOUND"
scanForOffenders Locates all the ships in range, multiplies the legal status with a government factor, subtracts a random value between 0 and 255 from this result and compares the remaining value. It chooses the worst remaining offender. Because of the random value not all ships are found in every scan and the lower the bounty and lower the government, the longer it takes to detect a ship as offender. Returns: "TARGET_FOUND" or "NOTHING_FOUND".

Government factor = 0 in an anarchy and increases with 0.4 for every government till it reaches 2.8 for a corporate state. Result is that it never finds a ship in an anarchy, that is needs 637 points to always find an offender in a feudal state and only needs 91 points to always find a offender in a corporate state.

scanForRandomLoot Scans for debris in range and selects one at random from the first 16 found.

Returns: "TARGET_FOUND" or "NOTHING_FOUND" If scanning ship is station or has no scoop it always return: "NOTHING_FOUND".

scanForRandomMerchantman Scans for ships with role: Trader or Player and selects one at random. Returns: "TARGET_FOUND" or "NOTHING_FOUND". (In older Oolite versions this was called: scanForRandomMerchantmen)
scanForRocks Scans for nearest boulder in range. When nothing found then scans for nearest asteroid in range. Returns "TARGET_FOUND" or "NOTING_FOUND". A boulder is anything with 'boulder' in its rolelist and asteroid is anything with 'asteroid' in its rolelist.
scanForThargoid Locates all the ships with primaryRole "thargoid" in range and chooses the nearest. Returns: "TARGET_FOUND" or "NOTHING_FOUND"
thargonCheckMother Checks if its owner is still alive and in range. When not it scans for a new ship containing the role "thargoid-mothership" in its role list and makes that the new owner. Returns: "TARGET_FOUND" or "NOTHING_FOUND".

Targeting

Method Description
**** (added in 1.77) In 1.77 onwards, DEFENSE_TARGET_LOST and DEFENSE_TARGET_DESTROYED messages will be sent if a ship on the point defense target list is lost or destroyed.
addFoundTargetAsDefenseTarget (added in 1.77) Adds the found target to the point defense target list.
addPrimaryAggressorAsDefenseTarget (added in 1.77) Adds the primary aggressor to the point defense target list.
clearDefenseTargets (added in 1.77) Clears the point defense target list
findNewDefenseTarget (added in 1.77) Looks for the nearest hostile ship not currently on the point defense target list, and adds it.
requestNewTarget Locates all the ships in range targeting the mother ship, and chooses the nearest/biggest. Returns: "MOTHER_LOST", "TARGET_FOUND" or "NOTHING_FOUND".
setTargetToFoundTarget Affirms a TARGET_FOUND by a scanFor- or find-Something-method as the universal target.
setTargetToPrimaryAggressor This function sets the primary agressor to the primary target. Then in the "performAttack" state, it only has a 25% chance of setting the primary aggressor to the primary target. The other 75% it will do nothing (1.76 or earlier) or set the aggressor as a defense target only (1.77 or later). This function is designed for use during attack to prevent the ship constantly changing targets when attacking a group.

Primary aggressor is set by the system when a ship fires a laser or missile at another.

Flying racing points

Method Description
targetFirstBeaconWithCode:(NSString*) beacon code Looks for all beacons in the system that contain the given code, sorts them alphabetical and puts them in a list, and defines the first in the list as the found target. The code-string to search for can be in the middle of the beacon-code itself. (e.g. beacon codes: 1-TBR, 2-TBG, 3-TBR and looking for TB) Returns: "TARGET_FOUND" or "NOTHING_FOUND".
targetNextBeaconWithCode:(NSString*) beacon code Sets the target to the next target in the list that was generated by the command : targetFirstBeaconWithCode. Returns: "NO_CURRENT_BEACON" when the primary target is no beacon, "TARGET_FOUND" when there is a next beacon in the list or "LAST_BEACON" when there is no next beacon in the list. On top of the previous messages it sends a "NOTHING_FOUND" when there is no target found.
setRacepointsFromTarget Sets 3 racing points along the z-axis of the target and sets the destination to the first. Returns: "NOTHING_FOUND" or "RACEPOINTS_SET"
performFlyRacepoints Sets the ship in a mode to fly a path along the 3 points set by setRacepointsFromTarget. Returns: "NAVPOINT_REACHED" when arriving at one of the 3 navpoints and "ENDPOINT_REACHED" when arriving at the last one. It also triggers the eventhandlers: this.shipReachedNavPoint() and this.shipReachedEndPoint() for use in java-script)

Miscellaneous

Method Description
addFuel:(NSString*) fuel_number Changes player's fuel level by fuel_number LY's, max to 7.0 min to 0.0.
becomeUncontrolledThargon Changes ship into cargo with scannClass "CLASS_CARGO" and sets AI to "dumbAI". If also the the cargo type is defined in ShipData.plist it can be picked up like any other cargo.
checkEnergy Checks the energy level and returns: ENERGY_LOW (energy< 25%), ENERGY_MEDIUM (25%<energy<75%), ENERGY_HIGH (75%<energy<100%) or ENERGY_FULL (energy = 100%). Added with Oolite 1.74
checkHeatInsulation Checks the heat insulation of a ship and returns: INSULATION_OK or INSULATION_POOR. Added with Oolite 1.75
initialiseTurret This command itself does nothing. When it is part of the setup_actions of the turrets shipData, it tells Oolite this subEntity has to be treated a turret. It is only needed when using an old style subEntity definition, for the new style definitions, the setup_actions are ignored.
rollD:(NSString*) dice_number Uses "dice" for random situation use. It returns "ROLL_1", "ROLL_2" and so on until dice_number. dice_number is an integer and has no size limit.

Example 1, 3 options in someAI.plist:

GLOBAL = {
  ENTER = ("rollD: 3"); 
  "ROLL_1" = (action1);
  "ROLL_2" = (action2);
  "ROLL_3" = (action3);}

Example 2, 50% chance in script.plist;

conditions = ("d100_number lessthan 50");
do = (action1);
else = (action2);

is similar in function.

safeScriptActionOnTarget:(NSString*) action This will do a script action on the target. For NPC ships as target you can use all the AI commands available that will act as if its own AI used the command.

It will also execute player script commands, like setting mission variables. For this to work it needs a target being set. It doesn't matter which one.

Example:

"scriptActionOnTarget: set: mission_my_missionvariable TRUE",
"scriptActionOnTarget: awardCredits: 100"
scriptActionOnTarget:(NSString*) action This will do the same as safeScriptActionOnTarget, but in addition the legacy script engine is started so all installed player scripts are evaluated immediately. Use of this command is discouraged in favour of safeScriptActionOnTarget as it takes a lot of time to evaluate all scripts and in most situations this is also unnecessary.
sendScriptMessage: message Calls the javaScript function message() on the ship’s ship script. This function opens the whole js power to the AI scripting. e.g. by using:
"sendScriptMessage: myFunction".

This script message than activates the ship-script function:

this.myFunction = () { body };

One can also transfer space separated parameters by using:

"sendScriptMessage: myFunction param1 param2"

These values are transferred as an array and can be read in JavaScript as

this.myFunction = ([param1, param2]) { body };

Note that spaces are read as separation of parameters so you cant transfer message text with spaces.

Role scanning methods

The role based scanning methods all skip ships with scanclass: CLASS_CARGO

Method Description
scanForNearestShipWithPrimaryRole:(NSString*) role new (preferred) name for scanForNearestShipWithRole:.
scanForNearestShipHavingRole:(NSString*) role scan based on entire role set rather than primary role.
scanForNearestShipWithAnyPrimaryRole:(NSString*) role-list takes a list of roles (space-separated) and returns the nearest ship with any of them as primary.
scanForNearestShipHavingAnyRole:(NSString*) role-list takes a list of roles (space-separated) and returns the nearest ship with any of them in its role set.
scanForNearestShipWithScanClass:(NSString*) scanclass searches for a ship by scan class.
scanForNearestShipWithoutPrimaryRole:(NSString*) role
scanForNearestShipNotHavingRole:(NSString*) role
scanForNearestShipWithoutAnyPrimaryRole:(NSString*) role-list
scanForNearestShipNotHavingAnyRole:(NSString*) role-list
scanForNearestShipWithoutScanClass:(NSString*) scanclass

Understanding what is happening

There are a number of ways of accessing the AI decision-making process:

  • Outputting in Latest.log - see here for how to enable this (several posts - 2023)
  • Graphical Output (not for javascript AIs) - see here for more detail (2023)

Links

OXP howto

.plist AI's

AI (.plist AI's)
Messages (sent by Vanilla game machine to AI state machine)
AI_methods

Javascipt AI's

Oolite Javascript Reference: PriorityAI Documentation
Oolite PriorityAI Tutorial (Javascript AI's)

Other relevant pages

Role - the role of a ship is linked to its AI
Methods

Bulletin Board snippets

Note that this tutorial is from early 2014 - before Oolite v.1.80 debuted - and hence some of the vanilla game AI's are more complex today