Oolite PriorityAI Tutorial

From Elite Wiki
Jump to: navigation, search

The Priority-based AI is a library for writing Javascript-based AIs in Oolite 1.79 or later, designed to allow sophisticated behaviour in relatively few lines of code, and to ensure that AI behaviour remains sensible after changes in the core game.

You don't need to use Priority-based AI to write Javascript AIs if you don't want to, but for many cases it can be the simplest option. OXPers may of course write their own AIs, or even their own AI construction libraries.

This tutorial goes through the steps to set up a basic player hunting AI that you might use in a mission.

Basic setup

As usual for an AI, the file needs to be in the AIs folder of your OXP, and referenced from shipdata.plist (or set by script or autoAI, but let's assume that's not happening here)

ai_type = "tutorial_playerHunterAI.js";

The Javascript file then contains

// ship script event handler triggered when a new AI is loaded
this.aiStarted = function() {
    // create a new AI controller and assign it this ship
	var ai = new worldScripts["oolite-libPriorityAI"].PriorityAIController(this.ship);
	// set up the priority list
	var priorities = [ /* priorities go here */ ];
	// apply the priority list to the AI
    ai.setPriorities(priorities);
}

That's generally all you need in the file ... except to define the priorities.

Priority 1: survival

The priority list is a list of Javascript objects, each usually containing a condition, and something to do if that condition is true, though more complex options are possible.

The first thing to do, since this ship is going to be fighting, is to make sure it behaves sensibly in the fight.

var priorities = [
	{
		condition: ai.conditionLosingCombat,
		behaviour: ai.behaviourFleeCombat,
		reconsider: 20
	},
	{
		condition: ai.conditionInCombat,
		configuration: ai.configurationAcquireCombatTarget,
		behaviour: ai.behaviourDestroyCurrentTarget,
		reconsider: 5
	}
];

So, firstly the ship checks if it is losing combat. If it is, it starts fleeing combat, and won't check again for another 20 seconds (or until something interrupts it and forces it to reconsider - for example, being shot again)

If it's not losing combat, but it is in combat, then it will acquire a combat target using configurationAcquireCombatTarget, and then it will try to destroy that target (rechecking every five seconds in this case, to make sure it hasn't started losing).

We add the requirement to acquire a combat target because the ship might be fighting multiple targets - this lets it pick up a new one if its current target is destroyed.

So far, so good. The ship will defend itself if attacked. However, it won't attack the player first, so the only way it's going to destroy them is if they make the mistake of shooting it first.

Priority 2: Start a fight with the player

The next thing we add is a search for the player.

var priorities = [
	/* ... as above */
	{
		condition: ai.conditionPlayerNearby,
		configuration: ai.configurationAcquirePlayerAsTarget,
		behaviour: ai.behaviourDestroyCurrentTarget,
		reconsider: 5
	}
];

This now checks if the player is nearby (i.e. in scanner range). If they are, the AI acquires them as a target, and then proceeds to try to destroy that target as above. Assuming the player doesn't flee out of scanner range in the first five seconds, when the AI comes to reconsider, it will now be in combat, and the losing-or-winning priorities added above will be checked first.

If the player has brought friends, the ship might end up fighting them as well, and only go back to fighting the player afterwards. (Or it might need to fight those ships next, but the player probably won't be in a position to notice that)

Priority 3: Hunt the player

So far, so good, but we're still relying on the player actually coming within scanner range of this ship. It would be better if the ship could hunt the player down.

Of course, if the player isn't within scanner range - and we don't cheat - we're going to have to guess where the player is. Sooner or later they're going to be at the system witchpoint, so if the ship can't see the player, send it there.

var priorities = [
	/* ... as above */
	{
		configuration: ai.configurationSetDestinationToWitchpoint,
		behaviour: ai.behaviourApproachDestination,
		reconsider: 20
	}
];

This priority doesn't have a condition, so the AI will always do it if it gets this far down the priority list. The last priority of any AI must always be unconditional.

behaviourApproachDestination is a quite sophisticated behaviour, which will fly to the appropriate destination, avoiding obstacles on the way. The configuration entry sets up the destination, desired range, and desired speed for this trip.

The result

So, the full AI script is

// ship script event handler triggered when a new AI is loaded
this.aiStarted = function() {
    // create a new AI controller and assign it this ship
	var ai = new worldScripts["oolite-libPriorityAI"].PriorityAIController(this.ship);
	// set up the priority list
	var priorities = [ 
	{
		condition: ai.conditionLosingCombat,
		behaviour: ai.behaviourFleeCombat,
		reconsider: 20
	},
	{
		condition: ai.conditionInCombat,
		configuration: ai.configurationAcquireCombatTarget,
		behaviour: ai.behaviourDestroyCurrentTarget,
		reconsider: 5
	},
	{
		condition: ai.conditionPlayerNearby,
		configuration: ai.configurationAcquirePlayerAsTarget,
		behaviour: ai.behaviourDestroyCurrentTarget,
		reconsider: 5
	},
	{		
		configuration: ai.configurationSetDestinationToWitchpoint,
		behaviour: ai.behaviourApproachDestination,
		reconsider: 20
	}
	];
	// apply the priority list to the AI
    ai.setPriorities(priorities);
}

That's it - the ship is ready to hunt down the player!

Obviously there are more sophisticated things the ship could do - it could patrol the spacelane looking for the player, it could only attack the player when there are no witnesses and follow them otherwise, or it could decide that if the player makes it flee, it needs to come back with friends, and go to a nearby station to get some. These are mainly just matters of adding extra priorities to the list.

Have a look through the Priority AI documentation and the AIs in the 1.79 core game for more examples and ideas.