Bounty hunter AI in JS
This commit is contained in:
parent
b036000ef4
commit
3cdd7af7b1
108
Resources/AIs/bountyHunterAI.js
Normal file
108
Resources/AIs/bountyHunterAI.js
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
bountyHunterAI.js
|
||||||
|
|
||||||
|
Priority-based AI for bounty hunters
|
||||||
|
|
||||||
|
Oolite
|
||||||
|
Copyright © 2004-2013 Giles C Williams and contributors
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||||
|
MA 02110-1301, USA.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
this.name = "Oolite Bounty Hunter AI";
|
||||||
|
this.version = "1.79";
|
||||||
|
|
||||||
|
this.aiStarted = function() {
|
||||||
|
this.ai = new worldScripts["oolite-libPriorityAI"].AILib(this.ship);
|
||||||
|
|
||||||
|
ai.setParameter("oolite_flag_listenForDistressCall",true);
|
||||||
|
|
||||||
|
/* Communications currently for debugging purposes. Need to either
|
||||||
|
* be removed or given a much bigger set of phrases to choose from
|
||||||
|
* before 1.79 */
|
||||||
|
ai.setCommunication("oolite_spacelanePatrol","Setting course for the [p1]");
|
||||||
|
ai.setCommunication("oolite_distressResponseSender","Hold on, [p1]!");
|
||||||
|
ai.setCommunication("oolite_distressResponseAggressor","[p1]. Cease your attack or be destroyed!");
|
||||||
|
ai.setCommunication("oolite_beginningAttack","Scan confirms criminal status of [p1]. Commencing attack run");
|
||||||
|
ai.setCommunication("oolite_quiriumCascade","%N! Q-bomb!");
|
||||||
|
ai.setCommunication("oolite_friendlyFire","Hey! Watch where you're shooting, [p1].");
|
||||||
|
|
||||||
|
ai.setPriorities([
|
||||||
|
/* Fight */
|
||||||
|
{
|
||||||
|
condition: ai.conditionLosingCombat,
|
||||||
|
behaviour: ai.behaviourFleeCombat,
|
||||||
|
reconsider: 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
condition: ai.conditionInCombat,
|
||||||
|
configuration: ai.configurationAcquireCombatTarget,
|
||||||
|
behaviour: ai.behaviourDestroyCurrentTarget,
|
||||||
|
reconsider: 5
|
||||||
|
},
|
||||||
|
/* Check for distress calls */
|
||||||
|
{
|
||||||
|
condition: ai.conditionHasReceivedDistressCall,
|
||||||
|
behaviour: ai.behaviourRespondToDistressCall,
|
||||||
|
reconsider: 20
|
||||||
|
},
|
||||||
|
/* Check for profitable targets */
|
||||||
|
{
|
||||||
|
preconfiguration: ai.configurationCheckScanner,
|
||||||
|
condition: ai.conditionScannerContainsFugitive,
|
||||||
|
configuration: ai.configurationAcquireScannedTarget,
|
||||||
|
behaviour: ai.behaviourDestroyCurrentTarget,
|
||||||
|
reconsider: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
condition: ai.conditionScannerContainsHuntableOffender,
|
||||||
|
configuration: ai.configurationAcquireScannedTarget,
|
||||||
|
behaviour: ai.behaviourDestroyCurrentTarget,
|
||||||
|
reconsider: 1
|
||||||
|
},
|
||||||
|
/* What about loot? */
|
||||||
|
{
|
||||||
|
condition: ai.conditionScannerContainsSalvage,
|
||||||
|
configuration: ai.configurationAcquireScannedTarget,
|
||||||
|
behaviour: ai.behaviourCollectSalvage,
|
||||||
|
reconsider: 20
|
||||||
|
},
|
||||||
|
/* Check we're in a real system */
|
||||||
|
{
|
||||||
|
condition: ai.conditionInInterstellarSpace,
|
||||||
|
configuration: ai.configurationSelectWitchspaceDestination,
|
||||||
|
behaviour: ai.behaviourEnterWitchspace,
|
||||||
|
reconsider: 20
|
||||||
|
},
|
||||||
|
/* Nothing interesting here. Patrol for a bit */
|
||||||
|
{
|
||||||
|
condition: ai.conditionHasPatrolRoute,
|
||||||
|
configuration: ai.configurationSetDestinationFromPatrolRoute,
|
||||||
|
behaviour: ai.behaviourApproachDestination,
|
||||||
|
reconsider: 30
|
||||||
|
},
|
||||||
|
/* No patrol route set up. Make one */
|
||||||
|
{
|
||||||
|
configuration: ai.configurationMakeSpacelanePatrolRoute,
|
||||||
|
behaviour: ai.behaviourApproachDestination,
|
||||||
|
reconsider: 30
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
}
|
@ -43,6 +43,7 @@ this.AILib = function(ship)
|
|||||||
var priorityList = null;
|
var priorityList = null;
|
||||||
var reconsiderationTimer = null;
|
var reconsiderationTimer = null;
|
||||||
var parameters = {};
|
var parameters = {};
|
||||||
|
var communications = {};
|
||||||
|
|
||||||
/* Private utility functions */
|
/* Private utility functions */
|
||||||
|
|
||||||
@ -56,7 +57,7 @@ this.AILib = function(ship)
|
|||||||
// to set up condition parameters
|
// to set up condition parameters
|
||||||
if (priority.preconfiguration)
|
if (priority.preconfiguration)
|
||||||
{
|
{
|
||||||
priority.preconfiguration.call(this.ship.AIScript);
|
priority.preconfiguration.call(this);
|
||||||
}
|
}
|
||||||
// absent condition is always true
|
// absent condition is always true
|
||||||
if (!priority.condition || priority.condition.call(this))
|
if (!priority.condition || priority.condition.call(this))
|
||||||
@ -64,7 +65,7 @@ this.AILib = function(ship)
|
|||||||
// always call the configuration function at this point
|
// always call the configuration function at this point
|
||||||
if (priority.configuration)
|
if (priority.configuration)
|
||||||
{
|
{
|
||||||
priority.configuration.call(this.ship.AIScript);
|
priority.configuration.call(this);
|
||||||
}
|
}
|
||||||
// this is what we're doing
|
// this is what we're doing
|
||||||
if (priority.behaviour)
|
if (priority.behaviour)
|
||||||
@ -102,44 +103,8 @@ this.AILib = function(ship)
|
|||||||
return null; // nothing in the list is usable, so return
|
return null; // nothing in the list is usable, so return
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Resets the reconsideration timer. */
|
/* Only call this from the timer to avoid loops */
|
||||||
function _resetReconsideration(delay)
|
function _reconsider() {
|
||||||
{
|
|
||||||
if (reconsiderationTimer != null)
|
|
||||||
{
|
|
||||||
reconsiderationTimer.stop();
|
|
||||||
reconsiderationTimer = null;
|
|
||||||
}
|
|
||||||
reconsiderationTimer = new Timer(this, this.reconsider, delay);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/* ****************** General AI functions ************** */
|
|
||||||
|
|
||||||
|
|
||||||
this.setPriorities = function(prioritylist)
|
|
||||||
{
|
|
||||||
priorityList = prioritylist;
|
|
||||||
this.reconsider();
|
|
||||||
}
|
|
||||||
|
|
||||||
// parameters created by Oolite must always be prefixed oolite-
|
|
||||||
this.setParameter = function(key, value)
|
|
||||||
{
|
|
||||||
parameters[key] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.getParameter = function(key)
|
|
||||||
{
|
|
||||||
if (key in parameters)
|
|
||||||
{
|
|
||||||
return parameters[key];
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
this.reconsider = function() {
|
|
||||||
if (reconsiderationTimer != null)
|
if (reconsiderationTimer != null)
|
||||||
{
|
{
|
||||||
reconsiderationTimer.stop();
|
reconsiderationTimer.stop();
|
||||||
@ -157,8 +122,59 @@ this.AILib = function(ship)
|
|||||||
|
|
||||||
newBehaviour.call(this);
|
newBehaviour.call(this);
|
||||||
return true;
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* Resets the reconsideration timer. */
|
||||||
|
function _resetReconsideration(delay)
|
||||||
|
{
|
||||||
|
if (reconsiderationTimer != null)
|
||||||
|
{
|
||||||
|
reconsiderationTimer.stop();
|
||||||
|
reconsiderationTimer = null;
|
||||||
|
}
|
||||||
|
reconsiderationTimer = new Timer(this, _reconsider.bind(this), delay);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* ****************** General AI functions ************** */
|
||||||
|
|
||||||
|
|
||||||
|
this.setPriorities = function(prioritylist)
|
||||||
|
{
|
||||||
|
priorityList = prioritylist;
|
||||||
|
this.reconsiderNow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// parameters created by Oolite must always be prefixed oolite-
|
||||||
|
this.setCommunication = function(key, value)
|
||||||
|
{
|
||||||
|
communications[key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// parameters created by Oolite must always be prefixed oolite-
|
||||||
|
this.setParameter = function(key, value)
|
||||||
|
{
|
||||||
|
parameters[key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.getParameter = function(key)
|
||||||
|
{
|
||||||
|
if (key in parameters)
|
||||||
|
{
|
||||||
|
return parameters[key];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Requests reconsideration of behaviour ahead of schedule. */
|
||||||
|
this.reconsiderNow = function() {
|
||||||
|
_resetReconsideration.call(this,0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
this.setUpHandlers = function(handlers)
|
this.setUpHandlers = function(handlers)
|
||||||
{
|
{
|
||||||
// step 1: go through activeHandlers, and delete those
|
// step 1: go through activeHandlers, and delete those
|
||||||
@ -168,10 +184,6 @@ this.AILib = function(ship)
|
|||||||
delete this.ship.AIScript[activeHandlers[i]];
|
delete this.ship.AIScript[activeHandlers[i]];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (handlers.entityDestroyed)
|
|
||||||
{
|
|
||||||
handlers.oolite_entityDestroyedAux = handlers.entityDestroyed;
|
|
||||||
}
|
|
||||||
handlers.entityDestroyed = function()
|
handlers.entityDestroyed = function()
|
||||||
{
|
{
|
||||||
if (reconsiderationTimer != null)
|
if (reconsiderationTimer != null)
|
||||||
@ -179,7 +191,6 @@ this.AILib = function(ship)
|
|||||||
reconsiderationTimer.stop();
|
reconsiderationTimer.stop();
|
||||||
reconsiderationTimer = null;
|
reconsiderationTimer = null;
|
||||||
}
|
}
|
||||||
this.ship.AIScript.oolite_entityDestroyedAux();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// step 2: go through the keys in handlers and put those handlers
|
// step 2: go through the keys in handlers and put those handlers
|
||||||
@ -192,6 +203,34 @@ this.AILib = function(ship)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.checkScannerWithPredicate = function(predicate)
|
||||||
|
{
|
||||||
|
var scan = this.getParameter("oolite_scanResults");
|
||||||
|
if (scan == null || predicate == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (var i = 0 ; i < scan.length ; i++)
|
||||||
|
{
|
||||||
|
if (predicate(scan[i]))
|
||||||
|
{
|
||||||
|
this.setParameter("oolite_scanResultSpecific",scan[i]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
this.communicate = function(key,parameter)
|
||||||
|
{
|
||||||
|
if (key in communications)
|
||||||
|
{
|
||||||
|
this.ship.commsMessage(expandDescription(communications[key],{"p1":parameter}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ****************** Condition functions ************** */
|
/* ****************** Condition functions ************** */
|
||||||
|
|
||||||
/* Conditions. Any function which returns true or false can be used as
|
/* Conditions. Any function which returns true or false can be used as
|
||||||
@ -250,7 +289,7 @@ this.AILib = function(ship)
|
|||||||
|
|
||||||
this.conditionInCombat = function()
|
this.conditionInCombat = function()
|
||||||
{
|
{
|
||||||
if (this.ship.target && this.ship.target.target == this.ship && this.ship.target.hasHostileTarget)
|
if (this.ship.hasHostileTarget)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -292,6 +331,56 @@ this.AILib = function(ship)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
this.conditionScannerContainsFugitive = function()
|
||||||
|
{
|
||||||
|
return this.checkScannerWithPredicate(function(s) {
|
||||||
|
return s.isInSpace && s.bounty > 50;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.conditionScannerContainsHuntableOffender = function()
|
||||||
|
{
|
||||||
|
return this.checkScannerWithPredicate(function(s) {
|
||||||
|
var threshold = 50 - (system.info.government * 7);
|
||||||
|
return s.isInSpace && s.bounty > threshold;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.conditionScannerContainsSalvage = function()
|
||||||
|
{
|
||||||
|
if (this.ship.cargoSpaceAvailable == 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return this.checkScannerWithPredicate(function(s) {
|
||||||
|
return s.isInSpace && s.scanClass == "CLASS_CARGO";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.conditionHasReceivedDistressCall = function()
|
||||||
|
{
|
||||||
|
var aggressor = this.getParameter("oolite_distressAggressor");
|
||||||
|
var sender = this.getParameter("oolite_distressSender");
|
||||||
|
if (aggressor == null || !aggressor.isInSpace || sender == null || !sender.isInSpace || sender.position.distanceTo(this.ship) > this.ship.scannerRange)
|
||||||
|
{
|
||||||
|
// no, or it has expired
|
||||||
|
this.setParameter("oolite_distressAggressor",null);
|
||||||
|
this.setParameter("oolite_distressSender",null);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.conditionHasPatrolRoute = function()
|
||||||
|
{
|
||||||
|
return this.getParameter("oolite_patrolRoute") != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.conditionInInterstellarSpace = function()
|
||||||
|
{
|
||||||
|
return system.isInterstellarSpace;
|
||||||
|
}
|
||||||
|
|
||||||
/* ****************** Behaviour functions ************** */
|
/* ****************** Behaviour functions ************** */
|
||||||
|
|
||||||
/* Behaviours. Behaviours are effectively a state definition,
|
/* Behaviours. Behaviours are effectively a state definition,
|
||||||
@ -310,6 +399,10 @@ this.AILib = function(ship)
|
|||||||
{
|
{
|
||||||
if (cascade.distanceTo(this.ship) < 25600)
|
if (cascade.distanceTo(this.ship) < 25600)
|
||||||
{
|
{
|
||||||
|
if (this.ship.destination != cascade)
|
||||||
|
{
|
||||||
|
this.communication("oolite_quiriumCascade");
|
||||||
|
}
|
||||||
this.ship.destination = cascade;
|
this.ship.destination = cascade;
|
||||||
this.ship.desiredRange = 30000;
|
this.ship.desiredRange = 30000;
|
||||||
this.ship.desiredSpeed = 10*this.ship.maxSpeed;
|
this.ship.desiredSpeed = 10*this.ship.maxSpeed;
|
||||||
@ -322,7 +415,7 @@ this.AILib = function(ship)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.ship.target = this.ship.AIPrimaryAggressor;
|
this.ship.target = this.ship.AIPrimaryAggressor;
|
||||||
if (this.ship.position.distanceTo(this.ship.target) > 25600)
|
if (!this.ship.target || this.ship.position.distanceTo(this.ship.target) > 25600)
|
||||||
{
|
{
|
||||||
var dts = this.ship.defenseTargets;
|
var dts = this.ship.defenseTargets;
|
||||||
for (var i = 0 ; i < dts.length ; i++)
|
for (var i = 0 ; i < dts.length ; i++)
|
||||||
@ -342,10 +435,28 @@ this.AILib = function(ship)
|
|||||||
var handlers = {};
|
var handlers = {};
|
||||||
this.responsesAddStandard(handlers);
|
this.responsesAddStandard(handlers);
|
||||||
this.setUpHandlers(handlers);
|
this.setUpHandlers(handlers);
|
||||||
|
if (!this.ship.hasHostileTarget)
|
||||||
|
{
|
||||||
|
// entering attack mode
|
||||||
|
this.communicate("oolite_beginningAttack",this.ship.target.displayName);
|
||||||
|
}
|
||||||
this.ship.performAttack();
|
this.ship.performAttack();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
this.behaviourCollectSalvage = function()
|
||||||
|
{
|
||||||
|
var handlers = {};
|
||||||
|
this.responsesAddStandard(handlers);
|
||||||
|
handlers.shipScoopedOther = function(other)
|
||||||
|
{
|
||||||
|
this.reconsiderNow();
|
||||||
|
}
|
||||||
|
this.setUpHandlers(handlers);
|
||||||
|
this.ship.performCollect();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
this.behaviourApproachDestination = function()
|
this.behaviourApproachDestination = function()
|
||||||
{
|
{
|
||||||
var handlers = {};
|
var handlers = {};
|
||||||
@ -354,13 +465,11 @@ this.AILib = function(ship)
|
|||||||
handlers.shipAchievedDesiredRange = function()
|
handlers.shipAchievedDesiredRange = function()
|
||||||
{
|
{
|
||||||
var waypoints = this.getParameter("oolite_waypoints");
|
var waypoints = this.getParameter("oolite_waypoints");
|
||||||
log(this.name,"Reached desired range");
|
|
||||||
if (waypoints != null)
|
if (waypoints != null)
|
||||||
{
|
{
|
||||||
if (waypoints.length > 0)
|
if (waypoints.length > 0)
|
||||||
{
|
{
|
||||||
waypoints.pop();
|
waypoints.pop();
|
||||||
log(this.name,"Reached waypoint");
|
|
||||||
if (waypoints.length == 0)
|
if (waypoints.length == 0)
|
||||||
{
|
{
|
||||||
waypoints = null;
|
waypoints = null;
|
||||||
@ -368,7 +477,18 @@ this.AILib = function(ship)
|
|||||||
this.setParameter("oolite_waypoints",waypoints);
|
this.setParameter("oolite_waypoints",waypoints);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.reconsider();
|
else
|
||||||
|
{
|
||||||
|
var patrol = this.getParameter("oolite_patrolRoute");
|
||||||
|
if (patrol != null && this.ship.destination.distanceTo(patrol) < 1000)
|
||||||
|
{
|
||||||
|
// finished patrol to waypoint
|
||||||
|
// clear route
|
||||||
|
this.communicate("oolite_waypointReached");
|
||||||
|
this.setParameter("oolite_patrolRoute",null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.reconsiderNow();
|
||||||
};
|
};
|
||||||
|
|
||||||
var waypoints = this.getParameter("oolite_waypoints");
|
var waypoints = this.getParameter("oolite_waypoints");
|
||||||
@ -389,7 +509,6 @@ this.AILib = function(ship)
|
|||||||
waypoints = [];
|
waypoints = [];
|
||||||
}
|
}
|
||||||
waypoints.push(this.ship.getSafeCourseToDestination());
|
waypoints.push(this.ship.getSafeCourseToDestination());
|
||||||
log(this.name,"Set new waypoint "+waypoints[waypoints.length-1]);
|
|
||||||
this.ship.destination = waypoints[waypoints.length-1];
|
this.ship.destination = waypoints[waypoints.length-1];
|
||||||
this.ship.desiredRange = 1000;
|
this.ship.desiredRange = 1000;
|
||||||
}
|
}
|
||||||
@ -428,7 +547,7 @@ this.AILib = function(ship)
|
|||||||
case "DOCKING_REFUSED":
|
case "DOCKING_REFUSED":
|
||||||
this.ship.setParameter("oolite_dockingStation",null);
|
this.ship.setParameter("oolite_dockingStation",null);
|
||||||
this.ship.target = null;
|
this.ship.target = null;
|
||||||
this.reconsider();
|
this.reconsiderNow();
|
||||||
break;
|
break;
|
||||||
case "HOLD_POSITION":
|
case "HOLD_POSITION":
|
||||||
case "TRY_AGAIN_LATER":
|
case "TRY_AGAIN_LATER":
|
||||||
@ -445,6 +564,103 @@ this.AILib = function(ship)
|
|||||||
this.setUpHandlers(handlers);
|
this.setUpHandlers(handlers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Standard "help the innocent" distress call response. Perhaps
|
||||||
|
* there should be a 'blood in the water' response available
|
||||||
|
* too... */
|
||||||
|
this.behaviourRespondToDistressCall = function()
|
||||||
|
{
|
||||||
|
var aggressor = this.getParameter("oolite_distressAggressor");
|
||||||
|
var sender = this.getParameter("oolite_distressSender");
|
||||||
|
if (sender.bounty > aggressor.bounty)
|
||||||
|
{
|
||||||
|
var tmp = sender;
|
||||||
|
sender = aggressor;
|
||||||
|
aggressor = tmp;
|
||||||
|
}
|
||||||
|
if (aggressor.position.distanceTo(this.ship) < this.ship.scannerRange)
|
||||||
|
{
|
||||||
|
this.ship.target = aggressor;
|
||||||
|
this.ship.performAttack();
|
||||||
|
this.reconsiderNow();
|
||||||
|
this.communicate("oolite_distressResponseAggressor",aggressor.displayName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ // we can't actually see what's attacking the sender yet
|
||||||
|
this.ship.destination = sender.position;
|
||||||
|
this.ship.desiredRange = 1000+sender.collisionRadius+this.ship.collisionRadius;
|
||||||
|
this.ship.desiredSpeed = 7 * this.ship.maxSpeed; // use injectors if possible
|
||||||
|
this.ship.performFlyToRangeFromDestination();
|
||||||
|
// and when we next reconsider, hopefully the aggressor will be on the scanner
|
||||||
|
this.communicate("oolite_distressResponseSender",sender.displayName);
|
||||||
|
}
|
||||||
|
var handlers = {};
|
||||||
|
this.responsesAddStandard(handlers);
|
||||||
|
this.setUpHandlers(handlers);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
this.behaviourEnterWitchspace = function()
|
||||||
|
{
|
||||||
|
var handlers = {};
|
||||||
|
this.responsesAddStandard(handlers);
|
||||||
|
var wormhole = this.getParameter("oolite_witchspaceWormhole");
|
||||||
|
if (wormhole && wormhole.expiryTime < clock.adjustedSeconds)
|
||||||
|
{
|
||||||
|
// the wormhole we were trying for has expired
|
||||||
|
this.setParameter("oolite_witchspaceWormhole",null);
|
||||||
|
}
|
||||||
|
|
||||||
|
var destID = this.getParameter("oolite_witchspaceDestination");
|
||||||
|
if (destID == null)
|
||||||
|
{
|
||||||
|
// look for wormholes out of here
|
||||||
|
// no systems in range
|
||||||
|
handlers.wormholeSuggested = function(hole)
|
||||||
|
{
|
||||||
|
this.ship.destination = hole.position;
|
||||||
|
this.ship.desiredRange = 0;
|
||||||
|
this.ship.desiredSpeed = this.ship.maxSpeed;
|
||||||
|
this.ship.performFlyToRangeFromDestination();
|
||||||
|
this.setParameter("oolite_witchspaceWormhole",hole);
|
||||||
|
// don't reconsider
|
||||||
|
}
|
||||||
|
handlers.playerWillEnterWitchspace = function()
|
||||||
|
{
|
||||||
|
var wormhole = this.getParameter("oolite_witchspaceWormhole");
|
||||||
|
if (wormhole != null)
|
||||||
|
{
|
||||||
|
this.ship.enterWormhole(wormhole);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.ship.enterWormhole();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.setUpHandlers(handlers);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
handlers.shipWitchspaceBlocked = function(blocker)
|
||||||
|
{
|
||||||
|
this.ship.setDestination = blocker.position;
|
||||||
|
this.ship.setDesiredRange = 30000;
|
||||||
|
this.ship.setDesiredSpeed = this.ship.maxSpeed;
|
||||||
|
this.ship.performFlyToRangeFromDestination();
|
||||||
|
// no reconsidering yet
|
||||||
|
}
|
||||||
|
// set up the handlers before trying it
|
||||||
|
this.setUpHandlers(handlers);
|
||||||
|
|
||||||
|
// this should work
|
||||||
|
var result = this.ship.exitSystem(destID);
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
this.reconsiderNow(); // reconsider AI on arrival
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* ****************** Configuration functions ************** */
|
/* ****************** Configuration functions ************** */
|
||||||
|
|
||||||
/* Configurations. Configurations are set up actions for a behaviour
|
/* Configurations. Configurations are set up actions for a behaviour
|
||||||
@ -495,6 +711,139 @@ this.AILib = function(ship)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.configurationCheckScanner = function()
|
||||||
|
{
|
||||||
|
this.setParameter("oolite_scanResults",this.ship.checkScanner());
|
||||||
|
this.setParameter("oolite_scanResultSpecific",null);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.configurationAcquireScannedTarget = function()
|
||||||
|
{
|
||||||
|
this.ship.target = this.getParameter("oolite_scanResultSpecific");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.configurationSetDestinationFromPatrolRoute = function()
|
||||||
|
{
|
||||||
|
this.ship.destination = this.getParameter("oolite_patrolRoute");
|
||||||
|
this.ship.desiredRange = this.getParameter("oolite_patrolRouteRange");
|
||||||
|
this.ship.desiredSpeed = this.ship.maxSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.configurationMakeSpacelanePatrolRoute = function()
|
||||||
|
{
|
||||||
|
var p = this.ship.position;
|
||||||
|
var choice = "";
|
||||||
|
if (p.magnitude() < 10000)
|
||||||
|
{
|
||||||
|
// near witchpoint
|
||||||
|
if (Math.random() < 0.9)
|
||||||
|
{
|
||||||
|
// mostly return to planet
|
||||||
|
choice = "PLANET";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
choice = "SUN";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (p.distanceTo(system.mainPlanet) < system.mainPlanet.radius * 2)
|
||||||
|
{
|
||||||
|
// near planet
|
||||||
|
if (Math.random() < 0.75)
|
||||||
|
{
|
||||||
|
// mostly go to witchpoint
|
||||||
|
choice = "WITCHPOINT";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
choice = "SUN";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (p.distanceTo(system.sun) < system.sun.radius * 3)
|
||||||
|
{
|
||||||
|
// near sun
|
||||||
|
if (Math.random() < 0.9)
|
||||||
|
{
|
||||||
|
// mostly return to planet
|
||||||
|
choice = "PLANET";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
choice = "SUN";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (p.z < system.mainPlanet.position.z && ((p.x * p.x) + (p.y * p.y)) < system.mainPlanet.radius * 3)
|
||||||
|
{
|
||||||
|
// on lane 1
|
||||||
|
if (Math.random() < 0.5)
|
||||||
|
{
|
||||||
|
choice = "PLANET";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
choice = "WITCHPOINT";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (p.subtract(system.mainPlanet).dot(p.subtract(system.sun)) < -0.9)
|
||||||
|
{
|
||||||
|
// on lane 2
|
||||||
|
if (Math.random() < 0.5)
|
||||||
|
{
|
||||||
|
choice = "PLANET";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
choice = "SUN";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (p.dot(system.sun.position) > 0.9)
|
||||||
|
{
|
||||||
|
// on lane 3
|
||||||
|
if (Math.random() < 0.5)
|
||||||
|
{
|
||||||
|
choice = "WITCHPOINT";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
choice = "SUN";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// we're not on any lane. Return to the planet
|
||||||
|
choice = "PLANET";
|
||||||
|
}
|
||||||
|
// having chosen, now set up the next stop on the patrol
|
||||||
|
switch (choice) {
|
||||||
|
case "WITCHPOINT":
|
||||||
|
this.setParameter("oolite_patrolRoute",new Vector3D(0,0,0));
|
||||||
|
this.setParameter("oolite_patrolRouteRange",7500);
|
||||||
|
break;
|
||||||
|
case "PLANET":
|
||||||
|
this.setParameter("oolite_patrolRoute",system.mainPlanet.position);
|
||||||
|
this.setParameter("oolite_patrolRouteRange",system.mainPlanet.radius*2);
|
||||||
|
break;
|
||||||
|
case "SUN":
|
||||||
|
this.setParameter("oolite_patrolRoute",system.sun.position);
|
||||||
|
this.setParameter("oolite_patrolRouteRange",system.sun.radius*2.5);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this.communicate("oolite_spacelanePatrol",choice.toLowerCase());
|
||||||
|
|
||||||
|
this.configurationSetDestinationFromPatrolRoute();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
this.configurationSelectWitchspaceDestination = function()
|
||||||
|
{
|
||||||
|
if (!this.ship.hasHyperspaceMotor)
|
||||||
|
{
|
||||||
|
this.setParameter("oolite_witchspaceDestination",null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var possible = system.info.systemsInRange(this.ship.fuel);
|
||||||
|
this.setParameter("oolite_witchspaceDestination",possible[Math.floor(Math.random()*possible.length)].systemID);
|
||||||
|
}
|
||||||
|
|
||||||
/* ****************** Response definition functions ************** */
|
/* ****************** Response definition functions ************** */
|
||||||
|
|
||||||
@ -512,7 +861,7 @@ this.AILib = function(ship)
|
|||||||
this.setParameter("oolite_cascadeDetected",weapon.position);
|
this.setParameter("oolite_cascadeDetected",weapon.position);
|
||||||
this.ship.target = weapon;
|
this.ship.target = weapon;
|
||||||
this.ship.performFlee();
|
this.ship.performFlee();
|
||||||
this.reconsider();
|
this.reconsiderNow();
|
||||||
};
|
};
|
||||||
|
|
||||||
handlers.shipAttackedWithMissile = function(missile,whom)
|
handlers.shipAttackedWithMissile = function(missile,whom)
|
||||||
@ -532,16 +881,31 @@ this.AILib = function(ship)
|
|||||||
this.ship.target = whom;
|
this.ship.target = whom;
|
||||||
this.ship.requestHelpFromGroup();
|
this.ship.requestHelpFromGroup();
|
||||||
this.ship.target = tmp;
|
this.ship.target = tmp;
|
||||||
this.reconsider();
|
this.reconsiderNow();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
handlers.shipBeingAttacked = function(whom)
|
handlers.shipBeingAttacked = function(whom)
|
||||||
{
|
{
|
||||||
|
if (whom.target != this.ship && whom != player.ship)
|
||||||
|
{
|
||||||
|
// was accidental
|
||||||
|
if (whom.group != null && whom.group == this.ship.group)
|
||||||
|
{
|
||||||
|
this.communicate("oolite_friendlyFire",whom.displayName);
|
||||||
|
// ignore it
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (Math.random() > 0.1)
|
||||||
|
{
|
||||||
|
// usually ignore it anyway
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (this.ship.defenseTargets.indexOf(whom) < 0)
|
if (this.ship.defenseTargets.indexOf(whom) < 0)
|
||||||
{
|
{
|
||||||
this.ship.addDefenseTarget(whom);
|
this.ship.addDefenseTarget(whom);
|
||||||
this.reconsider();
|
this.reconsiderNow();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -549,7 +913,7 @@ this.AILib = function(ship)
|
|||||||
if (this.ship.energy * 4 < this.ship.maxEnergy)
|
if (this.ship.energy * 4 < this.ship.maxEnergy)
|
||||||
{
|
{
|
||||||
// but at low energy still reconsider
|
// but at low energy still reconsider
|
||||||
this.reconsider();
|
this.reconsiderNow();
|
||||||
this.ship.requestHelpFromGroup();
|
this.ship.requestHelpFromGroup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -563,12 +927,12 @@ this.AILib = function(ship)
|
|||||||
if (this.ship.defenseTargets.indexOf(whom) < 0)
|
if (this.ship.defenseTargets.indexOf(whom) < 0)
|
||||||
{
|
{
|
||||||
this.ship.addDefenseTarget(whom);
|
this.ship.addDefenseTarget(whom);
|
||||||
this.reconsider();
|
this.reconsiderNow();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
handlers.shipTargetLost = function(target)
|
handlers.shipTargetLost = function(target)
|
||||||
{
|
{
|
||||||
this.reconsider();
|
this.reconsiderNow();
|
||||||
};
|
};
|
||||||
// TODO: this one needs overriding for escorts
|
// TODO: this one needs overriding for escorts
|
||||||
handlers.helpRequestReceived = function(ally, enemy)
|
handlers.helpRequestReceived = function(ally, enemy)
|
||||||
@ -585,13 +949,23 @@ this.AILib = function(ship)
|
|||||||
{
|
{
|
||||||
// not already helping, go for it...
|
// not already helping, go for it...
|
||||||
this.ship.target = enemy;
|
this.ship.target = enemy;
|
||||||
this.reconsider();
|
this.reconsiderNow();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
handlers.approachingPlanetSurface = function()
|
handlers.approachingPlanetSurface = function()
|
||||||
{
|
{
|
||||||
this.reconsider();
|
this.reconsiderNow();
|
||||||
|
}
|
||||||
|
handlers.distressMessageReceived = function(aggressor, sender)
|
||||||
|
{
|
||||||
|
if (this.getParameter("oolite_flag_listenForDistressCall") != true)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.setParameter("oolite_distressAggressor",aggressor);
|
||||||
|
this.setParameter("oolite_distressSender",sender);
|
||||||
|
this.reconsiderNow();
|
||||||
}
|
}
|
||||||
// TODO: more event handlers
|
// TODO: more event handlers
|
||||||
}
|
}
|
||||||
@ -600,7 +974,7 @@ this.AILib = function(ship)
|
|||||||
handlers.stationWithdrewDockingClearance = function()
|
handlers.stationWithdrewDockingClearance = function()
|
||||||
{
|
{
|
||||||
this.setParameter("oolite_dockingStation",null);
|
this.setParameter("oolite_dockingStation",null);
|
||||||
this.reconsider();
|
this.reconsiderNow();
|
||||||
};
|
};
|
||||||
|
|
||||||
handlers.shipAchievedDesiredRange = function()
|
handlers.shipAchievedDesiredRange = function()
|
||||||
@ -608,7 +982,7 @@ this.AILib = function(ship)
|
|||||||
var message = this.ship.dockingInstructions.ai_message;
|
var message = this.ship.dockingInstructions.ai_message;
|
||||||
if (message == "APPROACH" || message == "BACK_OFF" || message == "APPROACH_COORDINATES")
|
if (message == "APPROACH" || message == "BACK_OFF" || message == "APPROACH_COORDINATES")
|
||||||
{
|
{
|
||||||
this.reconsider();
|
this.reconsiderNow();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user