2013-07-13 11:36:28 +01:00
/ *
2013-07-26 18:52:11 +01:00
oolite - ailib . js
2013-07-13 11:36:28 +01:00
2013-07-26 18:52:11 +01:00
Priority - based Javascript AI library
2013-07-13 11:36:28 +01:00
2013-07-26 18:52:11 +01:00
Oolite
Copyright © 2004 - 2013 Giles C Williams and contributors
2013-07-13 11:36:28 +01:00
2013-07-26 18:52:11 +01:00
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 .
2013-07-13 11:36:28 +01:00
2013-07-26 18:52:11 +01:00
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 .
2013-07-13 11:36:28 +01:00
2013-07-26 18:52:11 +01:00
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 .
2013-07-13 11:36:28 +01:00
* /
"use strict" ;
2013-07-12 19:44:14 +01:00
/* AI Library */
this . name = "oolite-libPriorityAI" ;
this . version = "1.79" ;
2013-07-13 11:36:28 +01:00
this . copyright = "© 2008-2013 the Oolite team." ;
this . author = "cim" ;
2013-07-12 19:44:14 +01:00
/* Constructor */
this . AILib = function ( ship )
{
2013-07-27 12:29:59 +01:00
// the ship property must be read-only
Object . defineProperty ( this , "ship" , {
value : ship ,
writable : false ,
enumerable : true ,
configurable : false
} ) ;
2013-07-14 19:02:16 +01:00
this . ship . AIScript . oolite _intership = { } ;
2013-07-15 23:14:47 +01:00
this . ship . AIScript . oolite _priorityai = this ;
2013-07-12 19:44:14 +01:00
var activeHandlers = [ ] ;
var priorityList = null ;
var parameters = { } ;
2013-07-13 19:13:30 +01:00
var communications = { } ;
2013-07-19 20:18:53 +01:00
var waypointgenerator = null ;
2013-07-12 19:44:14 +01:00
2013-07-26 18:52:11 +01:00
/* Private utility functions. Cannot be called from external code */
2013-07-12 19:44:14 +01:00
2013-07-13 11:36:28 +01:00
/* Considers a priority list, potentially recursively */
2013-07-26 18:52:11 +01:00
function _reconsiderList ( priorities ) {
2013-07-12 19:44:14 +01:00
var l = priorities . length ;
for ( var i = 0 ; i < l ; i ++ )
{
var priority = priorities [ i ] ;
2013-07-17 22:44:26 +01:00
if ( this . getParameter ( "oolite_flag_behaviourLogging" ) )
{
if ( priority . label )
2013-07-18 23:00:23 +01:00
{ log ( this . ship . name , "Considering: " + priority . label ) ;
2013-07-17 22:44:26 +01:00
}
else
{
log ( this . ship . name , "Considering: entry " + i ) ;
}
}
2013-07-12 19:44:14 +01:00
// always call the preconfiguration function at this point
// to set up condition parameters
if ( priority . preconfiguration )
{
2013-07-13 19:13:30 +01:00
priority . preconfiguration . call ( this ) ;
2013-07-12 19:44:14 +01:00
}
2013-07-14 19:02:16 +01:00
// allow inverted conditions
2013-07-17 22:44:26 +01:00
var condmet = true ;
2013-07-14 19:02:16 +01:00
if ( priority . notcondition )
{
2013-07-17 22:44:26 +01:00
condmet = ! priority . notcondition . call ( this ) ;
}
else if ( priority . condition )
{
condmet = priority . condition . call ( this ) ;
2013-07-14 19:02:16 +01:00
}
2013-07-12 19:44:14 +01:00
// absent condition is always true
2013-07-17 22:44:26 +01:00
if ( condmet )
2013-07-12 19:44:14 +01:00
{
2013-07-17 22:44:26 +01:00
if ( this . getParameter ( "oolite_flag_behaviourLogging" ) )
{
log ( this . ship . name , "Conditions met" ) ;
}
2013-07-12 19:44:14 +01:00
// always call the configuration function at this point
if ( priority . configuration )
{
2013-07-13 19:13:30 +01:00
priority . configuration . call ( this ) ;
2013-07-12 19:44:14 +01:00
}
// this is what we're doing
if ( priority . behaviour )
{
2013-07-17 22:44:26 +01:00
if ( this . getParameter ( "oolite_flag_behaviourLogging" ) )
{
log ( this . ship . name , "Executing behaviour" ) ;
}
2013-07-12 19:44:14 +01:00
if ( priority . reconsider )
{
2013-07-26 18:52:11 +01:00
_resetReconsideration . call ( this , priority . reconsider ) ;
2013-07-12 19:44:14 +01:00
}
return priority . behaviour ;
}
// otherwise this is what we might be doing
if ( priority . truebranch )
{
2013-07-17 22:44:26 +01:00
if ( this . getParameter ( "oolite_flag_behaviourLogging" ) )
{
log ( this . ship . name , "Entering truebranch" ) ;
}
2013-07-26 18:52:11 +01:00
var branch = _reconsiderList . call ( this , priority . truebranch ) ;
2013-07-12 19:44:14 +01:00
if ( branch != null )
{
return branch ;
}
// otherwise nothing in the branch was usable, so move on
}
}
else
{
if ( priority . falsebranch )
{
2013-07-17 22:44:26 +01:00
if ( this . getParameter ( "oolite_flag_behaviourLogging" ) )
{
log ( this . ship . name , "Entering falsebranch" ) ;
}
2013-07-26 18:52:11 +01:00
var branch = _reconsiderList . call ( this , priority . falsebranch ) ;
2013-07-12 19:44:14 +01:00
if ( branch != null )
{
return branch ;
}
// otherwise nothing in the branch was usable, so move on
}
}
}
2013-07-17 22:44:26 +01:00
if ( this . getParameter ( "oolite_flag_behaviourLogging" ) )
{
log ( this . ship . name , "Exiting branch" ) ;
}
2013-07-12 19:44:14 +01:00
return null ; // nothing in the list is usable, so return
} ;
2013-07-20 12:20:41 +01:00
/* Only call this from aiAwoken to avoid loops */
2013-07-26 18:52:11 +01:00
function _reconsider ( ) {
2013-07-13 19:13:30 +01:00
if ( ! this . ship || ! this . ship . isValid || ! this . ship . isInSpace )
{
return ;
}
2013-07-26 18:52:11 +01:00
var newBehaviour = _reconsiderList . call ( this , priorityList ) ;
2013-07-13 19:13:30 +01:00
if ( newBehaviour == null ) {
log ( this . name , "AI '" + this . ship . AIScript . name + "' for ship " + this . ship + " had all priorities fail. All priority based AIs should end with an unconditional entry." ) ;
return false ;
}
2013-07-16 22:33:42 +01:00
if ( this . getParameter ( "oolite_flag_behaviourLogging" ) )
{
log ( this . ship . name , newBehaviour ) ;
}
2013-07-13 19:13:30 +01:00
newBehaviour . call ( this ) ;
return true ;
} ;
2013-07-12 19:44:14 +01:00
/* Resets the reconsideration timer. */
2013-07-26 18:52:11 +01:00
function _resetReconsideration ( delay )
2013-07-12 19:44:14 +01:00
{
2013-07-20 12:20:41 +01:00
this . ship . AIScriptWakeTime = clock . adjustedSeconds + delay ;
2013-07-12 19:44:14 +01:00
} ;
2013-07-26 18:52:11 +01:00
/* ****************** General AI functions. ************** */
2013-07-27 12:29:59 +01:00
/ * T h e s e p r i v i l e g e d f u n c t i o n s i n t e r f a c e w i t h t h e p r i v a t e f u n c t i o n s
* and variables . Do not override them . * /
2013-07-12 19:44:14 +01:00
2013-07-27 12:29:59 +01:00
this . applyHandlers = function ( handlers )
2013-07-12 19:44:14 +01:00
{
2013-07-27 12:29:59 +01:00
// step 1: go through activeHandlers, and delete those
// functions from this.ship.AIScript
for ( var i = 0 ; i < activeHandlers . length ; i ++ )
{
delete this . ship . AIScript [ activeHandlers [ i ] ] ;
}
/ * T h i s h a n d l e r m u s t a l w a y s e x i s t f o r a p r i o r i t y A I , a n d m u s t
* be set here . * /
handlers . aiAwoken = function ( )
{
_reconsider . call ( this ) ;
}
2013-07-13 19:13:30 +01:00
2013-07-27 12:29:59 +01:00
// step 2: go through the keys in handlers and put those handlers
// into this.ship.AIScript and the keys into activeHandlers
activeHandlers = Object . keys ( handlers ) ;
for ( var i = 0 ; i < activeHandlers . length ; i ++ )
{
this . ship . AIScript [ activeHandlers [ i ] ] = handlers [ [ activeHandlers [ i ] ] ] . bind ( this ) ;
}
2013-07-13 19:13:30 +01:00
2013-07-12 19:44:14 +01:00
}
2013-07-27 12:29:59 +01:00
this . communicate = function ( key , parameter1 , parameter2 )
2013-07-12 19:44:14 +01:00
{
2013-07-27 12:29:59 +01:00
if ( key in communications )
{
this . ship . commsMessage ( expandDescription ( communications [ key ] , { "p1" : parameter1 , "p2" : parameter2 } ) ) ;
}
2013-07-12 19:44:14 +01:00
}
2013-07-27 12:29:59 +01:00
2013-07-12 19:44:14 +01:00
this . getParameter = function ( key )
{
if ( key in parameters )
{
return parameters [ key ] ;
}
return null ;
}
2013-07-19 20:18:53 +01:00
this . getWaypointGenerator = function ( )
{
return waypointgenerator ;
}
2013-07-13 19:13:30 +01:00
/* Requests reconsideration of behaviour ahead of schedule. */
2013-07-14 21:28:19 +01:00
this . reconsiderNow = function ( )
{
2013-07-27 12:29:59 +01:00
_resetReconsideration . call ( this , 0.05 ) ;
2013-07-12 19:44:14 +01:00
}
2013-07-13 19:13:30 +01:00
2013-07-27 12:29:59 +01:00
// parameters created by Oolite must always be prefixed oolite_
this . setCommunication = function ( key , value )
2013-07-12 19:44:14 +01:00
{
2013-07-27 12:29:59 +01:00
communications [ key ] = value ;
}
2013-07-12 19:44:14 +01:00
2013-07-15 23:14:47 +01:00
2013-07-27 12:29:59 +01:00
// parameters created by Oolite must always be prefixed oolite_
this . setParameter = function ( key , value )
{
parameters [ key ] = value ;
}
2013-07-12 19:44:14 +01:00
2013-07-27 12:29:59 +01:00
this . setPriorities = function ( priorities )
{
priorityList = priorities ;
this . applyHandlers ( { } ) ;
this . reconsiderNow ( ) ;
2013-07-12 19:44:14 +01:00
}
2013-07-27 12:29:59 +01:00
// set the waypoint generator function
this . setWaypointGenerator = function ( value )
2013-07-13 19:13:30 +01:00
{
2013-07-27 12:29:59 +01:00
waypointgenerator = value ;
2013-07-13 19:13:30 +01:00
}
2013-07-27 12:29:59 +01:00
2013-07-26 18:52:11 +01:00
} ; // end object constructor
2013-07-13 19:13:30 +01:00
2013-07-26 18:52:11 +01:00
/* Object prototype */
AILib . prototype . constructor = AILib ;
AILib . prototype . name = this . name ;
/* ****************** AI utility functions. ************** */
/ * T h e s e f u n c t i o n s p r o v i d e s t a n d a r d c h e c k s f o r c o n s i s t e n c y i n
* conditions and other functions . * /
AILib . prototype . allied = function ( ship1 , ship2 )
{
// ships in same group
if ( ship1 . group && ship1 . group . containsShip ( ship2 ) )
2013-07-13 19:13:30 +01:00
{
2013-07-26 18:52:11 +01:00
return true ;
}
if ( ship1 . group && ship1 . group . leader )
{
// ship1 is escort of ship in same group as ship2
if ( ship1 . group . leader . group && ship1 . group . leader . group . containsShip ( ship2 ) )
2013-07-13 19:13:30 +01:00
{
2013-07-26 18:52:11 +01:00
return true ;
2013-07-13 19:13:30 +01:00
}
}
2013-07-26 18:52:11 +01:00
// or in reverse, ship2 is the escort
if ( ship2 . group && ship2 . group . leader )
2013-07-13 23:18:05 +01:00
{
2013-07-26 18:52:11 +01:00
// ship2 is escort of ship in same group as ship1
if ( ship2 . group . leader . group && ship2 . group . leader . group . containsShip ( ship1 ) )
2013-07-14 19:02:16 +01:00
{
2013-07-26 18:52:11 +01:00
return true ;
2013-07-14 19:02:16 +01:00
}
2013-07-13 23:18:05 +01:00
}
2013-07-26 18:52:11 +01:00
// ship1 is escort of a ship, ship2 is escort of a ship, both
// those ships are in the same group
if ( ship1 . group && ship1 . group . leader && ship2 . group && ship2 . group . leader && ship1 . group . leader . group && ship1 . group . leader . group . containsShip ( ship2 . group . leader ) )
{
return true ;
}
// Okay, these ships really do have nothing to do with each other...
return false ;
}
2013-07-13 23:18:05 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . checkScannerWithPredicate = function ( predicate )
{
var scan = this . getParameter ( "oolite_scanResults" ) ;
if ( scan == null || predicate == null )
{
return false ;
}
for ( var i = 0 ; i < scan . length ; i ++ )
2013-07-22 21:24:27 +01:00
{
2013-07-26 18:52:11 +01:00
if ( predicate . call ( this , scan [ i ] ) )
2013-07-22 21:24:27 +01:00
{
2013-07-26 18:52:11 +01:00
this . setParameter ( "oolite_scanResultSpecific" , scan [ i ] ) ;
return true ;
2013-07-22 21:24:27 +01:00
}
2013-07-26 18:52:11 +01:00
}
return false ;
}
AILib . prototype . cruiseSpeed = function ( )
{
var cruise = this . ship . maxSpeed * 0.8 ;
if ( this . ship . group )
{
for ( var i = 0 ; i < this . ship . group . ships . length ; i ++ )
2013-07-22 21:24:27 +01:00
{
2013-07-26 18:52:11 +01:00
if ( this . ship . group . ships [ i ] . maxSpeed >= this . ship . maxSpeed / 4 )
2013-07-22 21:24:27 +01:00
{
2013-07-26 18:52:11 +01:00
if ( cruise > this . ship . group . ships [ i ] . maxSpeed )
2013-07-22 21:24:27 +01:00
{
2013-07-26 18:52:11 +01:00
cruise = this . ship . group . ships [ i ] . maxSpeed ;
2013-07-22 21:24:27 +01:00
}
}
}
}
2013-07-26 18:52:11 +01:00
if ( this . ship . escortGroup )
2013-07-13 23:18:05 +01:00
{
2013-07-26 18:52:11 +01:00
for ( var i = 0 ; i < this . ship . escortGroup . ships . length ; i ++ )
2013-07-13 23:18:05 +01:00
{
2013-07-26 18:52:11 +01:00
if ( this . ship . escortGroup . ships [ i ] . maxSpeed >= this . ship . maxSpeed / 4 )
2013-07-13 23:18:05 +01:00
{
2013-07-26 18:52:11 +01:00
if ( cruise > this . ship . escortGroup . ships [ i ] . maxSpeed )
2013-07-13 23:18:05 +01:00
{
2013-07-26 18:52:11 +01:00
cruise = this . ship . escortGroup . ships [ i ] . maxSpeed ;
2013-07-13 23:18:05 +01:00
}
}
}
2013-07-26 18:52:11 +01:00
}
return cruise ;
}
2013-07-27 12:29:59 +01:00
AILib . prototype . fineThreshold = function ( )
{
return 50 - ( system . info . government * 7 ) ;
}
2013-07-26 18:52:11 +01:00
AILib . prototype . friendlyStation = function ( station )
{
2013-07-27 12:29:59 +01:00
if ( station . isMainStation && this . ship . bounty > this . fineThreshold ( ) )
2013-07-26 18:52:11 +01:00
{
return false ;
}
return ( station . target != this . ship || ! station . hasHostileTarget ) ;
}
AILib . prototype . homeStation = function ( )
{
// home station might be the owner of the ship, or might just
// be a group member
if ( this . ship . owner && this . ship . owner . isStation && this . friendlyStation ( this . ship . owner ) )
{
return this . ship . owner ;
}
if ( this . ship . group )
{
for ( var i = 0 ; i < this . ship . group . ships . length ; i ++ )
2013-07-13 23:18:05 +01:00
{
2013-07-26 18:52:11 +01:00
if ( this . ship . group . ships [ i ] != this . ship && this . ship . group . ships [ i ] . isStation && this . friendlyStation ( this . ship . group . ships [ i ] . isStation ) )
2013-07-13 23:18:05 +01:00
{
2013-07-26 18:52:11 +01:00
return this . ship . group . ships [ i ] ;
2013-07-13 23:18:05 +01:00
}
}
}
2013-07-26 18:52:11 +01:00
return null ;
}
AILib . prototype . isAggressive = function ( ship )
{
if ( ship && ship . isPlayer )
{
return ! ship . isFleeing ;
}
return ship && ship . hasHostileTarget && ! ship . isFleeing && ! ship . isDerelict ;
}
AILib . prototype . isFighting = function ( ship )
{
if ( ship . isStation )
{
return ship . alertCondition == 3 && ship . target ;
}
return ship && ship . hasHostileTarget ;
}
/* ****************** Condition functions ************** */
/ * C o n d i t i o n s . A n y f u n c t i o n w h i c h r e t u r n s t r u e o r f a l s e c a n b e u s e d a s
* a condition . They do not have to be part of the AI library , but
* several common conditions are provided here . * /
/*** Combat-related conditions ***/
2013-07-27 15:39:23 +01:00
AILib . prototype . conditionCascadeDetected = function ( )
{
var cpos = this . getParameter ( "oolite_cascadeDetected" ) ;
if ( cpos != null )
{
if ( cpos . distanceTo ( this . ship ) < this . ship . scannerRange )
{
return true ;
}
this . setParameter ( "oolite_cascadeDetected" , null ) ;
}
return false ;
}
2013-07-26 18:52:11 +01:00
AILib . prototype . conditionCombatOddsGood = function ( )
{
// TODO: this should consider what the ships are, somehow
var us = 1 ;
if ( this . ship . group )
{
us += this . ship . group . count - 1 ;
}
if ( this . ship . escortGroup )
{
us += this . ship . escortGroup . count - 1 ;
}
var them = 1 ;
if ( ! this . ship . target )
{
return false ;
}
else
{
if ( this . ship . target . group )
{
them += this . ship . target . group . count - 1 ;
}
if ( this . ship . target . escortGroup )
{
them += this . ship . target . escortGroup . count - 1 ;
}
}
return us >= them ;
}
2013-07-13 23:18:05 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . conditionInCombat = function ( )
{
if ( this . isFighting ( this . ship ) )
{
return true ;
}
var dts = this . ship . defenseTargets ;
for ( var i = 0 ; i < dts . length ; i ++ )
2013-07-15 23:14:47 +01:00
{
2013-07-26 18:52:11 +01:00
if ( dts [ i ] . position . squaredDistanceTo ( this . ship ) < this . ship . scannerRange * this . ship . scannerRange )
2013-07-15 23:14:47 +01:00
{
return true ;
}
2013-07-26 18:52:11 +01:00
}
if ( this . ship . group != null )
{
for ( var i = 0 ; i < this . ship . group . length ; i ++ )
2013-07-15 23:14:47 +01:00
{
2013-07-26 18:52:11 +01:00
if ( this . isFighting ( this . ship . group . ships [ i ] ) )
2013-07-15 23:14:47 +01:00
{
return true ;
}
}
2013-07-26 18:52:11 +01:00
}
if ( this . ship . escortGroup != null )
{
for ( var i = 0 ; i < this . ship . escortGroup . length ; i ++ )
2013-07-15 23:14:47 +01:00
{
2013-07-26 18:52:11 +01:00
if ( this . isFighting ( this . ship . escortGroup . ships [ i ] ) )
2013-07-15 23:14:47 +01:00
{
return true ;
}
}
}
2013-07-26 18:52:11 +01:00
delete this . ship . AIScript . oolite _intership . cargodemandpaid ;
return false ;
}
2013-07-15 23:14:47 +01:00
2013-07-26 18:52:11 +01:00
/* Ships being attacked are firing back */
AILib . prototype . conditionInCombatWithHostiles = function ( )
{
if ( this . isFighting ( ship ) && this . isAggressive ( this . ship . target ) )
2013-07-15 23:14:47 +01:00
{
2013-07-26 18:52:11 +01:00
return true ;
2013-07-15 23:14:47 +01:00
}
2013-07-26 18:52:11 +01:00
var dts = this . ship . defenseTargets ;
for ( var i = 0 ; i < dts . length ; i ++ )
2013-07-20 09:14:58 +01:00
{
2013-07-26 18:52:11 +01:00
if ( this . isAggressive ( dts [ i ] ) && dts [ i ] . position . squaredDistanceTo ( this . ship ) < this . ship . scannerRange * this . ship . scannerRange )
2013-07-23 21:21:49 +01:00
{
2013-07-26 18:52:11 +01:00
return true ;
2013-07-23 21:21:49 +01:00
}
2013-07-20 09:14:58 +01:00
}
2013-07-26 18:52:11 +01:00
if ( this . ship . group != null )
2013-07-12 19:44:14 +01:00
{
2013-07-26 18:52:11 +01:00
for ( var i = 0 ; i < this . ship . group . length ; i ++ )
2013-07-13 11:36:28 +01:00
{
2013-07-26 18:52:11 +01:00
if ( this . isFighting ( this . ship . group . ships [ i ] ) && this . isAggressive ( this . ship . group . ships [ i ] . target ) )
2013-07-13 11:36:28 +01:00
{
return true ;
}
2013-07-17 22:44:26 +01:00
}
2013-07-26 18:52:11 +01:00
}
if ( this . ship . escortGroup != null )
{
for ( var i = 0 ; i < this . ship . escortGroup . length ; i ++ )
2013-07-17 22:44:26 +01:00
{
2013-07-26 18:52:11 +01:00
if ( this . isFighting ( this . ship . escortGroup . ships [ i ] ) && this . isAggressive ( this . ship . escortGroup . ships [ i ] . target ) )
{
return true ;
}
2013-07-17 22:44:26 +01:00
}
2013-07-26 18:52:11 +01:00
}
delete this . ship . AIScript . oolite _intership . cargodemandpaid ;
return false ;
}
AILib . prototype . conditionLosingCombat = function ( )
{
var cascade = this . getParameter ( "oolite_cascadeDetected" ) ;
if ( cascade != null )
{
if ( cascade . distanceTo ( this . ship ) < 25600 )
2013-07-13 11:36:28 +01:00
{
return true ;
}
2013-07-26 18:52:11 +01:00
else
2013-07-13 11:36:28 +01:00
{
2013-07-26 18:52:11 +01:00
this . setParameter ( "oolite_cascadeDetected" , null ) ;
2013-07-13 11:36:28 +01:00
}
2013-07-26 18:52:11 +01:00
}
if ( this . ship . energy == this . ship . maxEnergy )
{
// forget previous defeats
this . setParameter ( "oolite_lastFleeing" , null ) ;
}
if ( ! this . conditionInCombat ( ) )
{
return false ;
}
var lastThreat = this . getParameter ( "oolite_lastFleeing" ) ;
if ( lastThreat != null && this . ship . position . distanceTo ( lastThreat ) < 25600 )
{
// the thing that attacked us is still nearby
return true ;
}
if ( this . ship . energy * 4 < this . ship . maxEnergy )
{
// TODO: adjust threshold based on group odds
return true ; // losing if less than 1/4 energy
}
var dts = this . ship . defenseTargets ;
for ( var i = 0 ; i < dts . length ; i ++ )
{
if ( dts [ i ] . scanClass == "CLASS_MISSILE" && dts [ i ] . target == this . ship )
2013-07-14 19:02:16 +01:00
{
return true ;
}
2013-07-26 18:52:11 +01:00
if ( dts [ i ] . scanClass == "CLASS_MINE" )
2013-07-14 19:02:16 +01:00
{
return true ;
}
2013-07-12 19:44:14 +01:00
}
2013-07-26 18:52:11 +01:00
// if we've dumped cargo or the group leader has, then we're losing
if ( this . ship . AIScript . oolite _intership . cargodemandpaid )
{
return true ;
}
if ( this . ship . group && this . ship . group . leader && this . ship . group . leader . AIScript . oolite _intership && this . ship . group . leader . AIScript . oolite _intership . cargodemandpaid )
{
return true ;
}
// TODO: add some reassessment of odds based on group size
return false ; // not losing yet
}
2013-07-12 19:44:14 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . conditionMothershipInCombat = function ( )
{
if ( this . ship . group && this . ship . group . leader && this . ship . group . leader != this . ship )
2013-07-12 19:44:14 +01:00
{
2013-07-26 18:52:11 +01:00
var leader = this . ship . group . leader ;
if ( leader . position . distanceTo ( this . ship ) > this . ship . scannerRange )
2013-07-12 19:44:14 +01:00
{
2013-07-26 18:52:11 +01:00
return false ; // can't tell
2013-07-12 19:44:14 +01:00
}
2013-07-26 18:52:11 +01:00
if ( this . isFighting ( leader ) )
2013-07-12 19:44:14 +01:00
{
2013-07-26 18:52:11 +01:00
return true ;
2013-07-12 19:44:14 +01:00
}
2013-07-26 18:52:11 +01:00
if ( leader . target && leader . target . target == leader && leader . target . hasHostileTarget )
2013-07-13 11:36:28 +01:00
{
2013-07-26 18:52:11 +01:00
return true ;
2013-07-13 11:36:28 +01:00
}
2013-07-26 18:52:11 +01:00
var dts = leader . defenseTargets ;
for ( var i = 0 ; i < dts . length ; i ++ )
2013-07-13 11:36:28 +01:00
{
2013-07-26 18:52:11 +01:00
if ( dts [ i ] . target == leader && dts [ i ] . hasHostileTarget )
2013-07-13 11:36:28 +01:00
{
2013-07-26 18:52:11 +01:00
return true ;
2013-07-13 11:36:28 +01:00
}
}
2013-07-12 19:44:14 +01:00
return false ;
}
2013-07-26 18:52:11 +01:00
else
{
// no mothership
return false ;
}
}
2013-07-12 19:44:14 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . conditionMothershipIsAttacking = function ( )
{
if ( this . ship . group && this . ship . group . leader != this . ship )
2013-07-17 22:44:26 +01:00
{
2013-07-26 18:52:11 +01:00
var leader = this . ship . group . leader ;
if ( leader . target && this . isFighting ( leader ) && leader . target . position . distanceTo ( this . ship ) < this . ship . scannerRange )
2013-07-17 22:44:26 +01:00
{
return true ;
}
2013-07-26 18:52:11 +01:00
}
return false ;
}
// as MothershipIsAttacking, but leader.target must be aggressive
AILib . prototype . conditionMothershipIsAttackingHostileTarget = function ( )
{
if ( this . ship . group && this . ship . group . leader != this . ship )
{
var leader = this . ship . group . leader ;
if ( leader . target && this . isFighting ( leader ) && this . isAggressive ( leader . target ) && leader . target . position . distanceTo ( this . ship ) < this . ship . scannerRange )
2013-07-17 22:44:26 +01:00
{
2013-07-26 18:52:11 +01:00
return true ;
2013-07-17 22:44:26 +01:00
}
2013-07-26 18:52:11 +01:00
}
return false ;
}
AILib . prototype . conditionMothershipUnderAttack = function ( )
{
if ( this . ship . group && this . ship . group . leader != this . ship )
{
var leader = this . ship . group . leader ;
if ( leader . target && leader . target . target == leader && leader . target . hasHostileTarget && leader . target . position . distanceTo ( this . ship ) < this . ship . scannerRange )
2013-07-17 22:44:26 +01:00
{
2013-07-26 18:52:11 +01:00
return true ;
2013-07-17 22:44:26 +01:00
}
2013-07-26 18:52:11 +01:00
var dts = leader . defenseTargets ;
for ( var i = 0 ; i < dts . length ; i ++ )
2013-07-17 22:44:26 +01:00
{
2013-07-26 18:52:11 +01:00
if ( dts [ i ] . target == leader && dts [ i ] . hasHostileTarget && dts [ i ] . position . distanceTo ( this . ship ) < this . ship . scannerRange )
2013-07-17 22:44:26 +01:00
{
2013-07-26 18:52:11 +01:00
return true ;
2013-07-17 22:44:26 +01:00
}
}
return false ;
}
2013-07-26 18:52:11 +01:00
else
2013-07-24 21:56:50 +01:00
{
2013-07-26 18:52:11 +01:00
return false ;
2013-07-24 21:56:50 +01:00
}
2013-07-26 18:52:11 +01:00
}
2013-07-24 21:56:50 +01:00
2013-07-26 18:52:11 +01:00
/*** Navigation-related conditions ***/
AILib . prototype . conditionCanWitchspaceOut = function ( )
{
if ( ! this . ship . hasHyperspaceMotor )
2013-07-24 21:56:50 +01:00
{
2013-07-26 18:52:11 +01:00
return false ;
2013-07-24 21:56:50 +01:00
}
2013-07-26 18:52:11 +01:00
return ( system . info . systemsInRange ( this . ship . fuel ) . length > 0 ) ;
}
2013-07-24 21:56:50 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . conditionFriendlyStationExists = function ( )
{
var stations = system . stations ;
for ( var i = 0 ; i < stations . length ; i ++ )
2013-07-13 23:18:05 +01:00
{
2013-07-26 18:52:11 +01:00
var station = stations [ i ] ;
if ( this . friendlyStation ( station ) )
{
// this is not a very good check for friendliness, but
// it will have to do for now
return true ;
}
2013-07-13 23:18:05 +01:00
}
2013-07-26 18:52:11 +01:00
return false ;
}
2013-07-13 23:18:05 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . conditionFriendlyStationNearby = function ( )
{
var stations = system . stations ;
for ( var i = 0 ; i < stations . length ; i ++ )
2013-07-13 23:18:05 +01:00
{
2013-07-26 18:52:11 +01:00
var station = stations [ i ] ;
if ( this . friendlyStation ( station ) )
2013-07-13 23:18:05 +01:00
{
2013-07-26 18:52:11 +01:00
// this is not a very good check for friendliness, but
// it will have to do for now
if ( station . position . distanceTo ( this . ship ) < this . ship . scannerRange )
2013-07-13 23:18:05 +01:00
{
return true ;
}
}
}
2013-07-26 18:52:11 +01:00
return false ;
}
2013-07-13 23:18:05 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . conditionGroupIsSeparated = function ( )
{
if ( ! this . ship . group || ! this . ship . group . leader )
2013-07-13 23:18:05 +01:00
{
2013-07-26 18:52:11 +01:00
return false ;
2013-07-13 23:18:05 +01:00
}
2013-07-26 18:52:11 +01:00
if ( this . ship . group . leader . isStation )
2013-07-13 23:18:05 +01:00
{
2013-07-26 18:52:11 +01:00
// can get 2x as far from station
return ( this . ship . position . distanceTo ( this . ship . group . leader ) > this . ship . scannerRange * 2 ) ;
2013-07-13 23:18:05 +01:00
}
2013-07-26 18:52:11 +01:00
else
2013-07-22 23:15:17 +01:00
{
2013-07-26 18:52:11 +01:00
return ( this . ship . position . distanceTo ( this . ship . group . leader ) > this . ship . scannerRange ) ;
2013-07-22 23:15:17 +01:00
}
2013-07-26 18:52:11 +01:00
}
2013-07-22 23:15:17 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . conditionHasSelectedPlanet = function ( )
{
var planet = this . getParameter ( "oolite_selectedPlanet" ) ;
if ( planet && ( ! planet . isValid || ! planet . isPlanet ) )
2013-07-12 19:44:14 +01:00
{
2013-07-26 18:52:11 +01:00
this . setParameter ( "oolite_selectedPlanet" , null ) ;
return false ;
2013-07-12 19:44:14 +01:00
}
2013-07-26 18:52:11 +01:00
return planet != null ;
}
2013-07-12 19:44:14 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . conditionHasSelectedStation = function ( )
{
var station = this . getParameter ( "oolite_selectedStation" ) ;
if ( station && ( ! station . isValid || ! station . isStation ) )
2013-07-13 19:13:30 +01:00
{
2013-07-26 18:52:11 +01:00
this . setParameter ( "oolite_selectedStation" , null ) ;
return false ;
2013-07-13 19:13:30 +01:00
}
2013-07-26 18:52:11 +01:00
return station != null ;
}
2013-07-13 19:13:30 +01:00
2013-07-14 23:11:25 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . conditionHomeStationExists = function ( )
{
return ( this . homeStation ( ) != null ) ;
}
AILib . prototype . conditionHomeStationNearby = function ( )
{
var home = this . homeStation ( ) ;
if ( home == null )
2013-07-13 19:13:30 +01:00
{
2013-07-26 18:52:11 +01:00
return false ;
2013-07-13 19:13:30 +01:00
}
2013-07-26 18:52:11 +01:00
return this . ship . position . distanceTo ( home ) < this . ship . scannerRange ;
}
AILib . prototype . conditionInInterstellarSpace = function ( )
{
return system . isInterstellarSpace ;
}
2013-07-18 23:00:23 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . conditionMainPlanetNearby = function ( )
{
if ( ! system . mainPlanet )
2013-07-18 23:00:23 +01:00
{
2013-07-26 18:52:11 +01:00
return false ;
2013-07-18 23:00:23 +01:00
}
2013-07-26 18:52:11 +01:00
if ( this . ship . position . distanceTo ( system . mainPlanet ) < system . mainPlanet . radius * 4 )
2013-07-21 11:10:47 +01:00
{
2013-07-26 18:52:11 +01:00
return true ;
2013-07-21 11:10:47 +01:00
}
2013-07-26 18:52:11 +01:00
return false ;
}
2013-07-21 11:10:47 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . conditionNearDestination = function ( )
{
return ( this . ship . destination . squaredDistanceTo ( this . ship ) < this . ship . desiredRange * this . ship . desiredRange ) ;
}
AILib . prototype . conditionPlayerNearby = function ( )
{
return this . ship . position . distanceTo ( player . ship ) < this . ship . scannerRange ;
}
AILib . prototype . conditionReadyToSunskim = function ( )
{
return ( system . sun && this . ship . position . distanceTo ( system . sun ) < system . sun . radius * 1.15 ) ;
}
AILib . prototype . conditionSelectedStationNearby = function ( )
{
var station = this . getParameter ( "oolite_selectedStation" ) ;
if ( station && station . position . distanceTo ( this . ship ) < this . ship . scannerRange )
2013-07-15 23:14:47 +01:00
{
2013-07-26 18:52:11 +01:00
return true ;
2013-07-15 23:14:47 +01:00
}
2013-07-26 18:52:11 +01:00
return false ;
}
2013-07-13 19:13:30 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . conditionSelectedStationNearMainPlanet = function ( )
{
if ( ! system . mainPlanet )
2013-07-22 21:24:27 +01:00
{
2013-07-26 18:52:11 +01:00
return false ;
2013-07-23 22:37:07 +01:00
}
2013-07-26 18:52:11 +01:00
var station = this . getParameter ( "oolite_selectedStation" ) ;
if ( station && station . position . distanceTo ( system . mainPlanet ) < system . mainPlanet . radius * 4 )
2013-07-23 22:37:07 +01:00
{
2013-07-26 18:52:11 +01:00
return true ;
2013-07-22 21:24:27 +01:00
}
2013-07-26 18:52:11 +01:00
return false ;
}
AILib . prototype . conditionSunskimPossible = function ( )
{
return ( system . sun &&
! system . sun . hasGoneNova &&
! system . sun . isGoingNova &&
this . ship . fuel < 7 &&
this . ship . equipmentStatus ( "EQ_FUEL_SCOOPS" ) == "EQUIPMENT_OK" &&
( this . ship . heatInsulation > 1000 / this . ship . maxSpeed || this . ship . heatInsulation >= 12 ) ) ;
}
/*** Pirate conditions ***/
2013-07-22 21:24:27 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . conditionCargoDemandsMet = function ( )
{
if ( ! this . getParameter ( "oolite_flag_watchForCargo" ) )
2013-07-18 23:00:23 +01:00
{
2013-07-26 18:52:11 +01:00
log ( this . name , "AI '" + this . ship . AIScript . name + "' for ship " + this . ship + " is asking if cargo demands are met but has not set 'oolite_flag_watchForCargo'" ) ;
return true ;
2013-07-18 23:00:23 +01:00
}
2013-07-26 18:52:11 +01:00
var seen = this . getParameter ( "oolite_cargoDropped" ) ;
if ( seen != null )
2013-07-13 19:13:30 +01:00
{
2013-07-26 18:52:11 +01:00
var recorder = null ;
var demand = 0 ;
if ( this . ship . group )
2013-07-13 19:13:30 +01:00
{
2013-07-26 18:52:11 +01:00
if ( this . ship . group . leader && this . ship . group . leader . AIScript . oolite _intership && this . ship . group . leader . AIScript . oolite _intership . cargodemanded > 0 )
{
if ( this . ship . group . leader . AIScript . oolite _intership . cargodemandmet )
{
return true ;
}
recorder = this . ship . group . leader ;
demand = this . ship . group . leader . AIScript . oolite _intership . cargodemanded ;
}
else if ( this . ship . group . ships [ 0 ] . AIScript . oolite _intership && this . ship . group . ships [ 0 ] . AIScript . oolite _intership . cargodemanded > 0 )
{
demand = this . ship . group . ships [ 0 ] . AIScript . oolite _intership . cargodemanded ;
if ( this . ship . group . ships [ 0 ] . AIScript . oolite _intership . cargodemandmet )
{
return true ;
}
recorder = this . ship . group . ships [ 0 ] ;
}
2013-07-15 23:14:47 +01:00
}
2013-07-26 18:52:11 +01:00
else
2013-07-15 23:14:47 +01:00
{
2013-07-26 18:52:11 +01:00
if ( this . ship . AIScript . oolite _intership . cargodemanded > 0 )
2013-07-15 23:14:47 +01:00
{
2013-07-26 18:52:11 +01:00
if ( this . ship . AIScript . oolite _intership . cargodemandmet )
2013-07-15 23:14:47 +01:00
{
2013-07-26 18:52:11 +01:00
return true ;
2013-07-15 23:14:47 +01:00
}
2013-07-26 18:52:11 +01:00
demand = this . ship . AIScript . oolite _intership . cargodemanded ;
recorder = this . ship ;
2013-07-15 23:14:47 +01:00
}
2013-07-13 19:13:30 +01:00
}
2013-07-26 18:52:11 +01:00
if ( demand == 0 )
2013-07-23 21:21:49 +01:00
{
2013-07-26 18:52:11 +01:00
return false ; // no demand made, so it can't have been met
2013-07-23 21:21:49 +01:00
}
2013-07-26 18:52:11 +01:00
if ( demand <= seen )
2013-07-13 19:13:30 +01:00
{
2013-07-26 18:52:11 +01:00
recorder . AIScript . oolite _intership . cargodemandmet = true ;
return true ;
2013-07-13 19:13:30 +01:00
}
}
2013-07-26 18:52:11 +01:00
return false ;
}
2013-07-13 19:13:30 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . conditionGroupHasEnoughLoot = function ( )
{
var used = 0 ;
var available = 0 ;
if ( ! this . ship . group )
2013-07-14 19:02:16 +01:00
{
2013-07-26 18:52:11 +01:00
used = this . ship . cargoSpaceUsed ;
if ( this . ship . equipmentStatus ( "EQ_FUEL_SCOOPS" ) == "EQUIPMENT_OK" )
2013-07-14 19:02:16 +01:00
{
2013-07-26 18:52:11 +01:00
available = this . ship . cargoSpaceAvailable ;
2013-07-14 19:02:16 +01:00
}
}
2013-07-26 18:52:11 +01:00
else
2013-07-21 23:25:41 +01:00
{
2013-07-26 18:52:11 +01:00
for ( var i = 0 ; i < this . ship . group . ships . length ; i ++ )
2013-07-21 23:25:41 +01:00
{
2013-07-26 18:52:11 +01:00
used += this . ship . group . ships [ i ] . cargoSpaceUsed ;
if ( this . ship . equipmentStatus ( "EQ_FUEL_SCOOPS" ) == "EQUIPMENT_OK" )
{
available += this . ship . group . ships [ i ] . cargoSpaceAvailable ;
}
2013-07-21 23:25:41 +01:00
}
}
2013-07-26 18:52:11 +01:00
if ( available < used || available == 0 )
{
/ * O v e r h a l f - f u l l . T h i s w i l l d o f o r n o w . T O D O : c u t t i n g
* losses if group is taking damage , losing ships , running
* low on consumables , etc . * /
return true ;
}
return false ;
}
2013-07-21 23:25:41 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . conditionPiratesCanBePaidOff = function ( )
{
if ( this . ship . AIScript . oolite _intership . cargodemandpaid )
2013-07-13 19:13:30 +01:00
{
2013-07-26 18:52:11 +01:00
return false ;
2013-07-13 19:13:30 +01:00
}
2013-07-26 18:52:11 +01:00
// TODO: need some way for the player to set this
if ( ! this . ship . AIScript . oolite _intership . cargodemand )
2013-07-13 23:18:05 +01:00
{
2013-07-26 18:52:11 +01:00
return false ;
2013-07-13 23:18:05 +01:00
}
2013-07-26 18:52:11 +01:00
if ( this . ship . cargoSpaceUsed < this . ship . AIScript . oolite _intership . cargodemand )
2013-07-14 19:02:16 +01:00
{
return false ;
}
2013-07-26 18:52:11 +01:00
return true ;
}
/*** Scanner conditions ***/
AILib . prototype . conditionScannerContainsEscapePods = function ( )
{
return this . checkScannerWithPredicate ( function ( s ) {
return s . primaryRole == "escape-capsule" && s . isInSpace && s . scanClass == "CLASS_CARGO" && s . velocity . magnitude ( ) < this . ship . maxSpeed && this . conditionCanScoopCargo ( ) ;
} ) ;
}
2013-07-14 19:02:16 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . conditionScannerContainsFineableOffender = function ( )
{
return this . checkScannerWithPredicate ( function ( s ) {
2013-07-27 12:29:59 +01:00
var threshold = this . fineThreshold ( ) ;
2013-07-26 18:52:11 +01:00
return s . isInSpace && s . bounty <= threshold && s . bounty > 0 && ! s . markedForFines && ( s . scanClass == "CLASS_NEUTRAL" || s . isPlayer ) && ! s . isDerelict ;
} ) ;
}
AILib . prototype . conditionScannerContainsFugitive = function ( )
{
return this . checkScannerWithPredicate ( function ( s ) {
2013-07-27 18:09:24 +01:00
return s . isInSpace && s . bounty > 50 && s . scanClass != "CLASS_CARGO" && s . scanClass != "CLASS_ROCK" ;
2013-07-26 18:52:11 +01:00
} ) ;
}
AILib . prototype . conditionScannerContainsHuntableOffender = function ( )
{
return this . checkScannerWithPredicate ( function ( s ) {
2013-07-27 12:29:59 +01:00
var threshold = this . fineThreshold ( ) ;
2013-07-27 18:09:24 +01:00
return s . isInSpace && s . bounty > threshold && s . scanClass != "CLASS_CARGO" && s . scanClass != "CLASS_ROCK" ;
2013-07-26 18:52:11 +01:00
} ) ;
}
AILib . prototype . conditionScannerContainsHunters = function ( )
{
return this . checkScannerWithPredicate ( function ( s ) {
return s . primaryRole == "hunter" || s . scanClass == "CLASS_POLICE" || ( s . isStation && s . isMainStation ) ;
} ) ;
}
AILib . prototype . conditionScannerContainsMiningOpportunity = function ( )
{
// if hold full, no
if ( ! this . conditionCanScoopCargo ( ) )
2013-07-14 19:02:16 +01:00
{
return false ;
}
2013-07-26 18:52:11 +01:00
// need a mining laser, and for now a forward one
if ( ! this . ship . forwardWeapon == "EQ_WEAPON_MINING_LASER" )
2013-07-14 19:02:16 +01:00
{
return false ;
}
2013-07-26 18:52:11 +01:00
return this . conditionScannerContainsRocks ( ) ;
}
2013-07-14 19:02:16 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . conditionScannerContainsNonThargoid = function ( )
{
var prioritytargets = this . checkScannerWithPredicate ( function ( s ) {
return s . scanClass != "CLASS_THARGOID" && s . scanClass != "CLASS_ROCK" && s . scanClass != "CLASS_CARGO" ;
} ) ;
if ( prioritytargets )
2013-07-22 21:24:27 +01:00
{
2013-07-26 18:52:11 +01:00
return true ;
2013-07-22 21:24:27 +01:00
}
2013-07-26 18:52:11 +01:00
return this . checkScannerWithPredicate ( function ( s ) {
return s . scanClass != "CLASS_THARGOID" ;
} ) ;
}
2013-07-22 21:24:27 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . conditionScannerContainsPirateVictims = function ( )
{
return this . checkScannerWithPredicate ( function ( s ) {
// is a pirate victim
// has some cargo on board
// hasn't already paid up
return s . isPirateVictim && s . cargoSpaceUsed > 0 && ( ! s . AIScript || ! s . AIScript . oolite _intership || ! s . AIScript . oolite _intership . cargodemandpaid ) ;
} ) ;
}
AILib . prototype . conditionScannerContainsReadyThargoidMothership = function ( )
{
return this . checkScannerWithPredicate ( function ( s ) {
return s . hasRole ( "thargoid-mothership" ) && ( ! s . escortGroup || s . escortGroup . count <= 16 ) ;
} ) ;
}
2013-07-22 21:24:27 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . conditionScannerContainsRocks = function ( )
{
var scan1 = this . checkScannerWithPredicate ( function ( s ) {
return s . isInSpace && s . isBoulder ;
} ) ;
if ( scan1 )
2013-07-25 20:09:53 +01:00
{
2013-07-26 18:52:11 +01:00
return true ;
2013-07-25 20:09:53 +01:00
}
2013-07-26 18:52:11 +01:00
// no boulders, what about asteroids?
return this . checkScannerWithPredicate ( function ( s ) {
return s . isInSpace && s . hasRole ( "asteroid" ) ;
} ) ;
}
AILib . prototype . conditionScannerContainsSalvage = function ( )
{
return this . checkScannerWithPredicate ( function ( s ) {
return s . isInSpace && s . scanClass == "CLASS_CARGO" ;
} ) ;
}
2013-07-25 20:09:53 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . conditionScannerContainsSalvageForGroup = function ( )
{
var maxspeed = 0 ;
if ( this . conditionCanScoopCargo ( ) )
{
maxspeed = this . ship . maxSpeed ;
}
if ( this . ship . group )
2013-07-13 23:18:05 +01:00
{
2013-07-26 18:52:11 +01:00
for ( var i = 0 ; i < this . ship . group . ships . length ; i ++ )
2013-07-13 23:18:05 +01:00
{
2013-07-26 18:52:11 +01:00
var ship = this . ship . group . ships [ i ] ;
if ( ship . cargoSpaceAvailable > 0 && ship . equipmentStatus ( "EQ_FUEL_SCOOPS" ) == "EQUIPMENT_OK" && ship . maxSpeed > maxspeed )
2013-07-13 23:18:05 +01:00
{
2013-07-26 18:52:11 +01:00
maxspeed = ship . maxSpeed ;
2013-07-13 23:18:05 +01:00
}
}
}
2013-07-26 18:52:11 +01:00
return this . checkScannerWithPredicate ( function ( s ) {
return s . isInSpace && s . scanClass == "CLASS_CARGO" && s . velocity . magnitude ( ) < maxspeed ;
} ) ;
}
2013-07-13 23:18:05 +01:00
2013-07-22 21:24:27 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . conditionScannerContainsSalvageForMe = function ( )
{
if ( ! this . conditionCanScoopCargo ( ) )
2013-07-13 23:18:05 +01:00
{
return false ;
}
2013-07-26 18:52:11 +01:00
return this . checkScannerWithPredicate ( function ( s ) {
return s . isInSpace && s . scanClass == "CLASS_CARGO" && s . velocity . magnitude ( ) < this . ship . maxSpeed ;
} ) ;
}
2013-07-13 23:18:05 +01:00
2013-07-21 11:10:47 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . conditionScannerContainsShipNeedingEscort = function ( )
{
if ( this . ship . bounty == 0 )
2013-07-21 11:10:47 +01:00
{
return this . checkScannerWithPredicate ( function ( s ) {
2013-07-26 18:52:11 +01:00
return s . scanClass == this . ship . scanClass && s . bounty == 0 && ( ! s . escortGroup || s . escortGroup . count <= s . maxEscorts ) ;
2013-07-21 11:10:47 +01:00
} ) ;
}
2013-07-26 18:52:11 +01:00
else
2013-07-21 11:10:47 +01:00
{
return this . checkScannerWithPredicate ( function ( s ) {
2013-07-26 18:52:11 +01:00
return s . scanClass == this . ship . scanClass && s . bounty > 0 && ( ! s . escortGroup || s . escortGroup . count <= s . maxEscorts ) ;
2013-07-21 11:10:47 +01:00
} ) ;
}
2013-07-26 18:52:11 +01:00
}
AILib . prototype . conditionScannerContainsThargoidMothership = function ( )
{
return this . checkScannerWithPredicate ( function ( s ) {
return s . hasRole ( "thargoid-mothership" ) ;
} ) ;
}
2013-07-21 11:10:47 +01:00
2013-07-26 18:52:11 +01:00
/*** State conditions ***/
AILib . prototype . conditionAllEscortsInFlight = function ( )
{
if ( ! this . ship . escortGroup )
2013-07-13 23:18:05 +01:00
{
2013-07-26 18:52:11 +01:00
return true ; // there are no escorts not in flight
2013-07-13 23:18:05 +01:00
}
2013-07-26 18:52:11 +01:00
for ( var i = 0 ; i < this . ship . escortGroup . ships . length ; i ++ )
2013-07-13 23:18:05 +01:00
{
2013-07-26 18:52:11 +01:00
if ( this . ship . escortGroup . ships [ i ] . status != "STATUS_IN_FLIGHT" )
2013-07-13 23:18:05 +01:00
{
return false ;
}
}
2013-07-26 18:52:11 +01:00
return true ;
}
2013-07-13 23:18:05 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . conditionCanScoopCargo = function ( )
{
if ( this . ship . cargoSpaceAvailable == 0 || this . ship . equipmentStatus ( "EQ_FUEL_SCOOPS" ) != "EQUIPMENT_OK" )
2013-07-14 19:02:16 +01:00
{
2013-07-26 18:52:11 +01:00
return false ;
2013-07-14 19:02:16 +01:00
}
2013-07-26 18:52:11 +01:00
return true ;
}
2013-07-14 19:02:16 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . conditionCargoIsProfitableHere = function ( )
{
if ( ! system . mainStation )
2013-07-14 19:02:16 +01:00
{
2013-07-26 18:52:11 +01:00
return false ;
2013-07-14 19:02:16 +01:00
}
2013-07-26 18:52:11 +01:00
if ( this . ship . cargoSpaceUsed == 0 )
2013-07-14 19:02:16 +01:00
{
2013-07-26 18:52:11 +01:00
return false ;
2013-07-14 19:02:16 +01:00
}
2013-07-26 18:52:11 +01:00
var cargo = this . ship . cargoList ;
var profit = 0 ;
var multiplier = ( system . info . economy <= 3 ) ? - 1 : 1 ;
for ( var i = 0 ; i < cargo . length ; i ++ )
2013-07-14 19:02:16 +01:00
{
2013-07-26 18:52:11 +01:00
var commodity = cargo [ i ] . commodity ;
var quantity = cargo [ i ] . quantity ;
var adjust = system . mainStation . market [ commodity ] . marketEcoAdjustPrice * multiplier * quantity / system . mainStation . market [ commodity ] . marketMaskPrice ;
profit += adjust ;
2013-07-14 19:02:16 +01:00
}
2013-07-26 18:52:11 +01:00
return ( profit >= 0 ) ;
}
AILib . prototype . conditionGroupLeaderIsStation = function ( )
{
return ( this . ship . group && this . ship . group . leader && this . ship . group . leader . isStation ) ;
}
AILib . prototype . conditionHasInterceptCoordinates = function ( )
{
return ( this . getParameter ( "oolite_interceptCoordinates" ) != null ) ;
}
AILib . prototype . conditionHasMothership = function ( )
{
return ( this . ship . group && this . ship . group . leader && this . ship . group . leader != this . ship ) ;
}
AILib . prototype . conditionHasNonThargoidTarget = function ( )
{
return ( this . ship . target && this . ship . target . scanClass != "CLASS_THARGOID" ) ;
}
2013-07-14 19:02:16 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . conditionHasReceivedDistressCall = function ( )
{
var aggressor = this . getParameter ( "oolite_distressAggressor" ) ;
var sender = this . getParameter ( "oolite_distressSender" ) ;
var ts = this . getParameter ( "oolite_distressTimestamp" ) ;
if ( aggressor == null || ! aggressor . isInSpace || sender == null || ! sender . isInSpace || sender . position . distanceTo ( this . ship ) > this . ship . scannerRange || ts + 30 < clock . adjustedSeconds )
2013-07-15 23:14:47 +01:00
{
2013-07-26 18:52:11 +01:00
// no, or it has expired
this . setParameter ( "oolite_distressAggressor" , null ) ;
this . setParameter ( "oolite_distressSender" , null ) ;
this . setParameter ( "oolite_distressTimestamp" , null ) ;
return false ;
2013-07-15 23:14:47 +01:00
}
2013-07-26 18:52:11 +01:00
return true ;
}
AILib . prototype . conditionHasTarget = function ( )
{
return this . ship . target != null ;
}
AILib . prototype . conditionHasWaypoint = function ( )
{
return this . getParameter ( "oolite_waypoint" ) != null ;
}
AILib . prototype . conditionIsActiveThargon = function ( )
{
return this . ship . scanClass == "CLASS_THARGOID" && this . ship . hasRole ( "EQ_THARGON" ) ;
}
2013-07-15 23:14:47 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . conditionIsEscorting = function ( )
{
if ( ! this . ship . group || ! this . ship . group . leader || this . ship . group . leader == this . ship )
2013-07-18 23:00:23 +01:00
{
return false ;
}
2013-07-26 18:52:11 +01:00
if ( this . ship . group . leader . escortGroup && this . ship . group . leader . escortGroup . containsShip ( this . ship ) )
2013-07-14 19:02:16 +01:00
{
return true ;
}
2013-07-26 18:52:11 +01:00
return false ;
}
2013-07-14 19:02:16 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . conditionIsGroupLeader = function ( )
{
if ( ! this . ship . group )
2013-07-15 23:14:47 +01:00
{
return true ;
}
2013-07-26 18:52:11 +01:00
return ( this . ship . group . leader == this . ship ) ;
}
AILib . prototype . conditionMissileOutOfFuel = function ( )
{
var range = 30000 ; // 30 km default
if ( this . ship . scriptInfo . oolite _missile _range )
{
range = this . ship . scriptInfo . oolite _missile _range ;
}
return range < this . ship . distanceTravelled ;
}
AILib . prototype . conditionWitchspaceEntryRequested = function ( )
{
return ( this . getParameter ( "oolite_witchspaceWormhole" ) != null ) ;
}
2013-07-15 23:14:47 +01:00
2013-07-26 18:52:11 +01:00
/* ****************** Behaviour functions ************** */
/ * B e h a v i o u r s . B e h a v i o u r s a r e e f f e c t i v e l y a s t a t e d e f i n i t i o n ,
* defining a set of events and responses . They are aided in this
* by the 'responses' , which mean that the event handlers for the
* behaviour within the definition can itself be templated . * /
AILib . prototype . behaviourApproachDestination = function ( )
{
var handlers = { } ;
this . responsesAddStandard ( handlers ) ;
handlers . shipAchievedDesiredRange = function ( )
2013-07-14 23:11:25 +01:00
{
2013-07-26 18:52:11 +01:00
var waypoints = this . getParameter ( "oolite_waypoints" ) ;
if ( waypoints != null )
2013-07-14 23:11:25 +01:00
{
2013-07-26 18:52:11 +01:00
if ( waypoints . length > 0 )
{
waypoints . pop ( ) ;
if ( waypoints . length == 0 )
{
waypoints = null ;
}
this . setParameter ( "oolite_waypoints" , waypoints ) ;
}
2013-07-14 23:11:25 +01:00
}
2013-07-26 18:52:11 +01:00
else
2013-07-14 23:11:25 +01:00
{
2013-07-26 18:52:11 +01:00
var patrol = this . getParameter ( "oolite_waypoint" ) ;
if ( patrol != null && this . ship . destination . distanceTo ( patrol ) < 1000 + this . getParameter ( "oolite_waypointRange" ) )
2013-07-14 23:11:25 +01:00
{
2013-07-26 18:52:11 +01:00
// finished patrol to waypoint
// clear route
this . communicate ( "oolite_waypointReached" ) ;
this . setParameter ( "oolite_waypoint" , null ) ;
this . setParameter ( "oolite_waypointRange" , null ) ;
if ( this . getParameter ( "oolite_flag_patrolStation" ) )
2013-07-14 23:11:25 +01:00
{
2013-07-26 18:52:11 +01:00
if ( this . ship . group )
2013-07-17 22:44:26 +01:00
{
2013-07-26 18:52:11 +01:00
var station = this . ship . group . leader ;
if ( station != null && station . isStation )
{
this . communicate ( "oolite_patrolReportIn" , station . displayName ) ;
this . ship . patrolReportIn ( station ) ;
}
2013-07-17 22:44:26 +01:00
}
2013-07-14 23:11:25 +01:00
}
2013-07-26 18:52:11 +01:00
}
}
this . reconsiderNow ( ) ;
} ;
2013-07-14 23:11:25 +01:00
2013-07-26 18:52:11 +01:00
var waypoints = this . getParameter ( "oolite_waypoints" ) ;
if ( waypoints != null )
{
this . ship . destination = waypoints [ waypoints . length - 1 ] ;
this . ship . desiredRange = 1000 ;
}
var blocker = this . ship . checkCourseToDestination ( ) ;
if ( blocker )
{
if ( blocker . isPlanet || blocker . isSun )
{
// the selected planet can't block
if ( blocker . isSun || this . getParameter ( "oolite_selectedPlanet" ) != blocker )
{
if ( this . ship . position . distanceTo ( blocker ) < blocker . radius * 3 )
2013-07-14 23:11:25 +01:00
{
2013-07-26 18:52:11 +01:00
if ( waypoints == null )
2013-07-17 22:44:26 +01:00
{
2013-07-26 18:52:11 +01:00
waypoints = [ ] ;
2013-07-17 22:44:26 +01:00
}
2013-07-26 18:52:11 +01:00
waypoints . push ( this . ship . getSafeCourseToDestination ( ) ) ;
this . ship . destination = waypoints [ waypoints . length - 1 ] ;
this . ship . desiredRange = 1000 ;
2013-07-14 23:11:25 +01:00
}
}
2013-07-26 18:52:11 +01:00
}
else if ( blocker . isShip )
{
if ( this . ship . position . distanceTo ( blocker ) < 25600 )
2013-07-14 23:11:25 +01:00
{
2013-07-26 18:52:11 +01:00
if ( ! blocker . group || ! blocker . group . leader == this . ship )
2013-07-14 23:11:25 +01:00
{
2013-07-26 18:52:11 +01:00
// our own escorts are not a blocker!
if ( waypoints == null )
2013-07-17 22:44:26 +01:00
{
2013-07-26 18:52:11 +01:00
waypoints = [ ] ;
2013-07-17 22:44:26 +01:00
}
2013-07-26 18:52:11 +01:00
waypoints . push ( this . ship . getSafeCourseToDestination ( ) ) ;
this . ship . destination = waypoints [ waypoints . length - 1 ] ;
this . ship . desiredRange = 1000 ;
2013-07-14 23:11:25 +01:00
}
}
}
}
2013-07-26 18:52:11 +01:00
this . setParameter ( "oolite_waypoints" , waypoints ) ;
2013-07-27 12:29:59 +01:00
this . applyHandlers ( handlers ) ;
2013-07-26 18:52:11 +01:00
this . ship . performFlyToRangeFromDestination ( ) ;
}
2013-07-14 23:11:25 +01:00
2013-07-26 18:52:11 +01:00
2013-07-27 15:39:23 +01:00
AILib . prototype . behaviourAvoidCascadeExplosion = function ( )
{
var handlers = { } ;
this . responsesAddStandard ( handlers ) ;
this . applyHandlers ( handlers ) ;
var cascade = this . getParameter ( "oolite_cascadeDetected" ) ;
if ( cascade != null )
{
if ( cascade . distanceTo ( this . ship ) < 25600 )
{
if ( this . ship . defenseTargets . length > 0 && this . ship . defenseTargets [ 0 ] . scanClass == "CLASS_MINE" )
{
// if the mine is still visible, conventional fleeing works
this . ship . target = this . ship . defenseTargets [ 0 ] ;
this . ship . desiredRange = 30000 ;
this . ship . performFlee ( ) ;
return ;
}
else
{
if ( this . ship . destination != cascade )
{
this . communicate ( "oolite_quiriumCascade" ) ;
}
this . ship . destination = cascade ;
this . ship . desiredRange = 30000 ;
this . ship . desiredSpeed = 10 * this . ship . maxSpeed ;
this . ship . performFlyToRangeFromDestination ( ) ;
return ;
}
}
else
{
this . setParameter ( "oolite_cascadeDetected" , null ) ;
}
}
}
2013-07-26 18:52:11 +01:00
AILib . prototype . behaviourBecomeInactiveThargon = function ( )
{
2013-07-27 12:29:59 +01:00
this . applyHandlers ( { } ) ;
2013-07-26 18:52:11 +01:00
this . ship . scanClass = "CLASS_CARGO" ;
this . ship . target = null ;
this . ship . clearDefenseTargets ( ) ;
if ( this . ship . group )
2013-07-20 09:14:58 +01:00
{
2013-07-26 18:52:11 +01:00
this . ship . group . removeShip ( this . ship ) ;
this . ship . group = null ;
2013-07-20 09:14:58 +01:00
}
2013-07-26 18:52:11 +01:00
if ( this . ship . escortGroup )
2013-07-14 23:11:25 +01:00
{
2013-07-26 18:52:11 +01:00
this . ship . escortGroup . removeShip ( this . ship ) ;
}
this . ship . desiredSpeed = 0 ;
this . ship . performStop ( ) ;
var nearby = this . ship . checkScanner ( ) ;
for ( var i = 0 ; i < nearby . length ; i ++ )
{
var ship = nearby [ i ] ;
if ( ship . target == this . ship && ! ship . isPlayer && ship . hasHostileTarget )
2013-07-20 09:14:58 +01:00
{
2013-07-26 18:52:11 +01:00
ship . target = null ;
2013-07-20 09:14:58 +01:00
}
2013-07-26 18:52:11 +01:00
ship . removeDefenseTarget ( this . ship ) ;
}
}
AILib . prototype . behaviourCollectSalvage = function ( )
{
var handlers = { } ;
this . responsesAddStandard ( handlers ) ;
handlers . shipScoopedOther = function ( other )
{
this . setParameter ( "oolite_cargoDropped" , null ) ;
this . reconsiderNow ( ) ;
2013-07-14 23:11:25 +01:00
}
2013-07-27 12:29:59 +01:00
this . applyHandlers ( handlers ) ;
2013-07-26 18:52:11 +01:00
this . ship . performCollect ( ) ;
}
AILib . prototype . behaviourDestroyCurrentTarget = function ( )
{
this . setParameter ( "oolite_witchspaceEntry" , null ) ;
2013-07-14 23:11:25 +01:00
2013-07-26 18:52:11 +01:00
var handlers = { } ;
this . responsesAddStandard ( handlers ) ;
2013-07-27 12:29:59 +01:00
this . applyHandlers ( handlers ) ;
2013-07-26 18:52:11 +01:00
if ( this . ship . target && ! this . ship . hasHostileTarget )
2013-07-14 23:11:25 +01:00
{
2013-07-26 18:52:11 +01:00
// entering attack mode
this . communicate ( "oolite_beginningAttack" , this . ship . target . displayName ) ;
}
this . ship . performAttack ( ) ;
}
AILib . prototype . behaviourDockWithStation = function ( )
{
// may need to release escorts
if ( this . ship . escortGroup && this . ship . escortGroup . count > 1 )
{
this . ship . dockEscorts ( ) ;
}
var station = this . getParameter ( "oolite_dockingStation" ) ;
this . ship . target = station ;
var handlers = { } ;
this . responsesAddStandard ( handlers ) ;
this . responsesAddDocking ( handlers ) ;
this . ship . requestDockingInstructions ( ) ;
if ( ! this . ship . dockingInstructions )
{
this . ship . performIdle ( ) ;
this . reconsiderNow ( ) ;
return ;
}
switch ( this . ship . dockingInstructions . ai _message )
{
case "TOO_BIG_TO_DOCK" :
case "DOCKING_REFUSED" :
this . ship . setParameter ( "oolite_dockingStation" , null ) ;
this . ship . target = null ;
this . reconsiderNow ( ) ;
break ;
case "TRY_AGAIN_LATER" :
if ( this . ship . target . position . distanceTo ( this . ship ) < 10000 )
2013-07-14 23:11:25 +01:00
{
2013-07-26 18:52:11 +01:00
this . ship . destination = this . ship . target . position ;
this . ship . desiredRange = 12500 ;
this . ship . desiredSpeed = this . cruiseSpeed ( ) ;
this . ship . performFlyToRangeFromDestination ( ) ;
break ;
2013-07-14 23:11:25 +01:00
}
2013-07-26 18:52:11 +01:00
// else fall through
case "HOLD_POSITION" :
this . ship . destination = this . ship . target . position ;
this . ship . performFaceDestination ( ) ;
// and will reconsider in a little bit
break ;
case "APPROACH" :
case "APPROACH_COORDINATES" :
case "BACK_OFF" :
this . ship . performFlyToRangeFromDestination ( ) ;
break ;
}
2013-07-27 12:29:59 +01:00
this . applyHandlers ( handlers ) ;
2013-07-26 18:52:11 +01:00
}
2013-07-14 23:11:25 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . 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 ) ;
}
else if ( wormhole )
{
this . ship . destination = wormhole . position ;
this . ship . desiredRange = 0 ;
this . ship . desiredSpeed = this . ship . maxSpeed ;
this . ship . performFlyToRangeFromDestination ( ) ;
2013-07-27 12:29:59 +01:00
this . applyHandlers ( handlers ) ;
2013-07-26 18:52:11 +01:00
return ;
}
var destID = this . getParameter ( "oolite_witchspaceDestination" ) ;
if ( destID == null )
{
// look for wormholes out of here
// no systems in range
handlers . wormholeSuggested = function ( hole )
2013-07-14 23:11:25 +01:00
{
2013-07-26 18:52:11 +01:00
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
2013-07-14 23:11:25 +01:00
}
2013-07-26 18:52:11 +01:00
handlers . playerWillEnterWitchspace = function ( )
2013-07-14 23:11:25 +01:00
{
2013-07-26 18:52:11 +01:00
var wormhole = this . getParameter ( "oolite_witchspaceWormhole" ) ;
if ( wormhole != null )
2013-07-16 22:33:42 +01:00
{
2013-07-26 18:52:11 +01:00
this . ship . enterWormhole ( wormhole ) ;
}
else
2013-07-16 22:33:42 +01:00
{
2013-07-26 18:52:11 +01:00
this . ship . enterWormhole ( ) ;
2013-07-16 22:33:42 +01:00
}
2013-07-14 23:11:25 +01:00
}
2013-07-27 12:29:59 +01:00
this . applyHandlers ( handlers ) ;
2013-07-26 18:52:11 +01:00
return ;
2013-07-14 23:11:25 +01:00
}
2013-07-26 18:52:11 +01:00
else
2013-07-14 23:11:25 +01:00
{
2013-07-26 18:52:11 +01:00
handlers . shipWitchspaceBlocked = function ( blocker )
2013-07-14 23:11:25 +01:00
{
2013-07-26 18:52:11 +01:00
this . ship . setDestination = blocker . position ;
this . ship . setDesiredRange = 30000 ;
this . ship . setDesiredSpeed = this . cruiseSpeed ( ) ;
this . ship . performFlyToRangeFromDestination ( ) ;
this . setParameter ( "oolite_witchspaceEntry" , null ) ;
// no reconsidering yet
}
// set up the handlers before trying it
2013-07-27 12:29:59 +01:00
this . applyHandlers ( handlers ) ;
2013-07-26 18:52:11 +01:00
var entry = this . getParameter ( "oolite_witchspaceEntry" ) ;
// wait for escorts to launch
if ( ! this . conditionAllEscortsInFlight ( ) )
{
this . ship . destination = this . ship . position ;
this . ship . desiredRange = 10000 ;
this . ship . desiredSpeed = this . cruiseSpeed ( ) ;
if ( this . ship . checkCourseToDestination ( ) )
2013-07-15 23:14:47 +01:00
{
2013-07-26 18:52:11 +01:00
this . ship . destination = this . ship . getSafeCourseToDestination ( ) ;
2013-07-15 23:14:47 +01:00
}
2013-07-26 18:52:11 +01:00
this . ship . performFlyToRangeFromDestination ( ) ;
2013-07-14 23:11:25 +01:00
}
2013-07-26 18:52:11 +01:00
else if ( entry != null && entry < clock . seconds )
2013-07-14 23:11:25 +01:00
{
2013-07-26 18:52:11 +01:00
// this should work
var result = this . ship . exitSystem ( destID ) ;
// if it doesn't, we'll get blocked
if ( result )
2013-07-14 23:11:25 +01:00
{
2013-07-26 18:52:11 +01:00
this . setParameter ( "oolite_witchspaceEntry" , null ) ;
2013-07-14 23:11:25 +01:00
}
}
2013-07-26 18:52:11 +01:00
else
2013-07-14 23:11:25 +01:00
{
2013-07-26 18:52:11 +01:00
if ( entry == null )
{
this . communicate ( "oolite_engageWitchspaceDrive" ) ;
this . setParameter ( "oolite_witchspaceEntry" , clock . seconds + 15 ) ;
}
this . ship . destination = this . ship . position ;
this . ship . desiredRange = 10000 ;
this . ship . desiredSpeed = this . cruiseSpeed ( ) ;
if ( this . ship . checkCourseToDestination ( ) )
{
this . ship . destination = this . ship . getSafeCourseToDestination ( ) ;
}
this . ship . performFlyToRangeFromDestination ( ) ;
2013-07-14 23:11:25 +01:00
}
}
2013-07-26 18:52:11 +01:00
}
AILib . prototype . behaviourEscortMothership = function ( )
{
var handlers = { } ;
this . responsesAddStandard ( handlers ) ;
this . responsesAddEscort ( handlers ) ;
2013-07-27 12:29:59 +01:00
this . applyHandlers ( handlers ) ;
2013-07-26 18:52:11 +01:00
this . ship . desiredRange = 0 ;
this . ship . performEscort ( ) ;
}
2013-07-14 23:11:25 +01:00
2013-07-21 11:10:47 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . behaviourFineCurrentTarget = function ( )
{
var handlers = { } ;
this . responsesAddStandard ( handlers ) ;
2013-07-27 12:29:59 +01:00
this . applyHandlers ( handlers ) ;
2013-07-26 18:52:11 +01:00
if ( this . ship . scanClass == "CLASS_POLICE" && this . ship . target )
2013-07-24 21:56:50 +01:00
{
2013-07-26 18:52:11 +01:00
this . communicate ( "oolite_markForFines" , this . ship . target . displayName ) ;
this . ship . markTargetForFines ( ) ;
2013-07-24 21:56:50 +01:00
}
2013-07-26 18:52:11 +01:00
this . ship . performIdle ( ) ;
}
2013-07-12 19:44:14 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . behaviourFleeCombat = function ( )
{
var handlers = { } ;
this . responsesAddStandard ( handlers ) ;
2013-07-27 12:29:59 +01:00
this . applyHandlers ( handlers ) ;
2013-07-13 11:36:28 +01:00
2013-07-26 18:52:11 +01:00
var cascade = this . getParameter ( "oolite_cascadeDetected" ) ;
if ( cascade != null )
{
if ( cascade . distanceTo ( this . ship ) < 25600 )
2013-07-13 11:36:28 +01:00
{
2013-07-27 12:29:59 +01:00
if ( this . ship . defenseTargets . length > 0 && this . ship . defenseTargets [ 0 ] . scanClass == "CLASS_MINE" )
2013-07-13 11:36:28 +01:00
{
2013-07-27 12:29:59 +01:00
// if the mine is still visible, conventional fleeing works
this . ship . target = this . ship . defenseTargets [ 0 ] ;
this . ship . desiredRange = 30000 ;
this . ship . performFlee ( ) ;
return ;
}
else
{
if ( this . ship . destination != cascade )
{
this . communicate ( "oolite_quiriumCascade" ) ;
}
this . ship . destination = cascade ;
this . ship . desiredRange = 30000 ;
this . ship . desiredSpeed = 10 * this . ship . maxSpeed ;
this . ship . performFlyToRangeFromDestination ( ) ;
return ;
2013-07-13 11:36:28 +01:00
}
}
2013-07-26 18:52:11 +01:00
else
2013-07-13 11:36:28 +01:00
{
2013-07-26 18:52:11 +01:00
this . setParameter ( "oolite_cascadeDetected" , null ) ;
2013-07-13 11:36:28 +01:00
}
2013-07-12 19:44:14 +01:00
}
2013-07-26 18:52:11 +01:00
this . ship . target = this . ship . AIPrimaryAggressor ;
if ( ! this . ship . target || this . ship . position . distanceTo ( this . ship . target ) > 25600 )
2013-07-12 19:44:14 +01:00
{
2013-07-26 18:52:11 +01:00
var dts = this . ship . defenseTargets ;
for ( var i = 0 ; i < dts . length ; i ++ )
2013-07-13 19:13:30 +01:00
{
2013-07-26 18:52:11 +01:00
this . ship . position . distanceTo ( dts [ i ] ) < 25600 ;
this . ship . target = dts [ i ] ;
break ;
2013-07-13 19:13:30 +01:00
}
2013-07-12 19:44:14 +01:00
}
2013-07-26 18:52:11 +01:00
this . setParameter ( "oolite_lastFleeing" , this . ship . target ) ;
this . ship . desiredRange = this . ship . scannerRange ;
this . ship . performFlee ( ) ;
}
2013-07-12 19:44:14 +01:00
2013-07-26 18:52:11 +01:00
/* Follow the group leader in a less organised way than escorting them */
AILib . prototype . behaviourFollowGroupLeader = function ( )
{
var handlers = { } ;
this . responsesAddStandard ( handlers ) ;
2013-07-27 12:29:59 +01:00
this . applyHandlers ( handlers ) ;
2013-07-26 18:52:11 +01:00
if ( ! this . ship . group || ! this . ship . group . leader )
2013-07-13 23:18:05 +01:00
{
2013-07-26 18:52:11 +01:00
this . ship . performIdle ( ) ;
}
else
{
this . ship . destination = this . ship . group . leader . position ;
this . ship . desiredRange = 2000 + Math . random ( ) * 2000 ;
this . ship . desiredSpeed = this . ship . maxSpeed ;
this . ship . performFlyToRangeFromDestination ( ) ;
2013-07-13 23:18:05 +01:00
}
2013-07-26 18:52:11 +01:00
}
2013-07-13 23:18:05 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . behaviourGuardTarget = function ( )
{
if ( ! this . ship . target )
2013-07-18 23:00:23 +01:00
{
2013-07-26 18:52:11 +01:00
this . ship . destination = this . ship . position ;
2013-07-18 23:00:23 +01:00
}
2013-07-26 18:52:11 +01:00
else
{
this . ship . destination = this . ship . target . position ;
}
this . ship . desiredSpeed = this . cruiseSpeed ( ) ;
this . ship . desiredRange = 2500 ;
var handlers = { } ;
this . responsesAddStandard ( handlers ) ;
2013-07-27 12:29:59 +01:00
this . applyHandlers ( handlers ) ;
2013-07-26 18:52:11 +01:00
this . ship . performFlyToRangeFromDestination ( ) ;
}
2013-07-18 23:00:23 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . behaviourLandOnPlanet = function ( )
{
this . ship . desiredSpeed = this . ship . maxSpeed / 4 ;
this . ship . performLandOnPlanet ( ) ;
this . ship . AIScriptWakeTime = 0 ; // cancel reconsiderations
2013-07-27 12:29:59 +01:00
this . applyHandlers ( { } ) ; // cancel interruptions
2013-07-26 18:52:11 +01:00
this . communicate ( "oolite_landingOnPlanet" ) ;
}
AILib . prototype . behaviourLeaveVicinityOfTarget = function ( )
{
if ( ! this . ship . target )
2013-07-22 21:24:27 +01:00
{
2013-07-26 18:52:11 +01:00
this . reconsiderNow ( ) ;
return ;
2013-07-22 21:24:27 +01:00
}
2013-07-26 18:52:11 +01:00
this . ship . destination = this . ship . target . position ;
this . ship . desiredRange = 27500 ;
this . ship . desiredSpeed = this . ship . maxSpeed ;
var handlers = { } ;
this . responsesAddStandard ( handlers ) ;
2013-07-27 12:29:59 +01:00
this . applyHandlers ( handlers ) ;
2013-07-26 18:52:11 +01:00
this . ship . performFlyToRangeFromDestination ( ) ;
}
2013-07-22 21:24:27 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . behaviourMineTarget = function ( )
{
var handlers = { } ;
this . responsesAddStandard ( handlers ) ;
2013-07-27 12:29:59 +01:00
this . applyHandlers ( handlers ) ;
2013-07-26 18:52:11 +01:00
this . ship . performMining ( ) ;
}
AILib . prototype . behaviourOfferToEscort = function ( )
{
var handlers = { } ;
this . responsesAddStandard ( handlers ) ;
2013-07-27 12:29:59 +01:00
this . applyHandlers ( handlers ) ;
2013-07-26 18:52:11 +01:00
var possible = this . getParameter ( "oolite_scanResultSpecific" ) ;
if ( possible == null )
2013-07-13 19:13:30 +01:00
{
2013-07-26 18:52:11 +01:00
this . reconsiderNow ( ) ;
}
else
{
if ( this . ship . offerToEscort ( possible ) )
2013-07-13 19:13:30 +01:00
{
2013-07-26 18:52:11 +01:00
// accepted
2013-07-13 19:13:30 +01:00
this . reconsiderNow ( ) ;
}
2013-07-26 18:52:11 +01:00
// if rejected, wait for next scheduled reconsideration
2013-07-13 19:13:30 +01:00
}
2013-07-26 18:52:11 +01:00
}
2013-07-13 19:13:30 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . behaviourPayOffPirates = function ( )
{
this . ship . dumpCargo ( this . ship . AIScript . oolite _intership . cargodemand ) ;
this . communicate ( "oolite_agreeingToDumpCargo" ) ;
delete this . ship . AIScript . oolite _intership . cargodemand ;
this . ship . AIScript . oolite _intership . cargodemandpaid = true ;
this . behaviourFleeCombat ( ) ;
}
2013-07-13 09:53:53 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . behaviourReconsider = function ( )
{
var handlers = { } ;
this . responsesAddStandard ( handlers ) ;
2013-07-27 12:29:59 +01:00
this . applyHandlers ( handlers ) ;
2013-07-26 18:52:11 +01:00
this . reconsiderNow ( ) ;
}
// Separate behaviour to EscortMothership in case we want to change it later
// This is the one to catch up with a distant mothership
AILib . prototype . behaviourRejoinMothership = function ( )
{
var handlers = { } ;
this . responsesAddStandard ( handlers ) ;
this . responsesAddEscort ( handlers ) ;
2013-07-27 12:29:59 +01:00
this . applyHandlers ( handlers ) ;
2013-07-26 18:52:11 +01:00
// to consider: should this behaviour use injectors if
// possible? so few escorts have them that it's probably not
// worth it.
this . ship . desiredRange = 0 ;
this . ship . performEscort ( ) ;
}
AILib . prototype . behaviourRepelCurrentTarget = function ( )
{
this . setParameter ( "oolite_witchspaceEntry" , null ) ;
var handlers = { } ;
this . responsesAddStandard ( handlers ) ;
2013-07-27 12:29:59 +01:00
this . applyHandlers ( handlers ) ;
2013-07-26 18:52:11 +01:00
if ( ! this . ship . target || ! this . ship . target . isValid || ! this . ship . target . isShip )
{
this . reconsiderNow ( ) ;
return ;
}
if ( ! this . isAggressive ( this . ship . target ) )
{
var target = this . ship . target ;
// repelling succeeded
if ( this . ship . escortGroup )
2013-07-13 09:53:53 +01:00
{
2013-07-26 18:52:11 +01:00
// also tell escorts to stop attacking it
for ( var i = 0 ; i < this . ship . escortGroup . ships . length ; i ++ )
2013-07-13 09:53:53 +01:00
{
2013-07-26 18:52:11 +01:00
this . ship . escortGroup . ships [ i ] . removeDefenseTarget ( target ) ;
if ( this . ship . escortGroup . ships [ i ] . target == target )
2013-07-13 09:53:53 +01:00
{
2013-07-26 18:52:11 +01:00
this . ship . escortGroup . ships [ i ] . target = null ;
2013-07-13 09:53:53 +01:00
}
}
}
2013-07-26 18:52:11 +01:00
this . ship . removeDefenseTarget ( target ) ;
this . ship . target = null ;
2013-07-12 19:44:14 +01:00
}
2013-07-26 18:52:11 +01:00
else
2013-07-12 23:00:39 +01:00
{
2013-07-26 18:52:11 +01:00
if ( ! this . ship . hasHostileTarget )
2013-07-14 19:02:16 +01:00
{
2013-07-26 18:52:11 +01:00
// entering attack mode
this . communicate ( "oolite_beginningAttack" , this . ship . target . displayName ) ;
2013-07-12 23:00:39 +01:00
}
2013-07-26 18:52:11 +01:00
this . ship . performAttack ( ) ;
2013-07-12 23:00:39 +01:00
}
2013-07-26 18:52:11 +01:00
}
2013-07-12 19:44:14 +01:00
2013-07-26 18:52:11 +01:00
/ * S t a n d a r d " h e l p t h e i n n o c e n t " d i s t r e s s c a l l r e s p o n s e . P e r h a p s
* there should be a 'blood in the water' response available
* too ... * /
AILib . prototype . behaviourRespondToDistressCall = function ( )
{
var aggressor = this . getParameter ( "oolite_distressAggressor" ) ;
var sender = this . getParameter ( "oolite_distressSender" ) ;
if ( aggressor && aggressor . isShip && sender && sender . isShip )
2013-07-13 19:13:30 +01:00
{
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 ) ;
}
}
2013-07-26 18:52:11 +01:00
var handlers = { } ;
this . responsesAddStandard ( handlers ) ;
2013-07-27 12:29:59 +01:00
this . applyHandlers ( handlers ) ;
2013-07-26 18:52:11 +01:00
}
2013-07-13 19:13:30 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . behaviourRobTarget = function ( )
{
var demand = null ;
if ( this . ship . group && this . ship . group . leader )
{
if ( this . ship . group . leader . AIScript . oolite _intership && this . ship . group . leader . AIScript . oolite _intership . cargodemanded )
2013-07-13 19:13:30 +01:00
{
2013-07-26 18:52:11 +01:00
demand = this . ship . group . leader . AIScript . oolite _intership . cargodemanded ;
2013-07-13 19:13:30 +01:00
}
}
2013-07-26 18:52:11 +01:00
else
2013-07-13 23:18:05 +01:00
{
2013-07-26 18:52:11 +01:00
if ( this . ship . AIScript . oolite _intership . cargodemanded )
{
demand = this . ship . AIScript . oolite _intership . cargodemanded ;
}
2013-07-13 23:18:05 +01:00
}
2013-07-26 18:52:11 +01:00
if ( demand == null )
2013-07-13 23:18:05 +01:00
{
2013-07-26 18:52:11 +01:00
var hascargo = this . ship . target . cargoSpaceUsed ;
// blowing them up probably gets ~10%, so how much we feel
// confident in demanding depends on how likely patrols
// are to come along and interfere.
demand = ( hascargo / 20 ) * ( 8 - system . info . government ) * ( 1 + Math . random ( ) ) ;
// between 5% and 80% of cargo
demand = Math . ceil ( demand ) ; // round it up so there's always at least 1
demand = 2 + ( demand % 10 ) ; //
/ *
// since cargo dumping detection uses checkScanner, this doesn't work
// for any substantial volume of cargo. Consider reinstating if
// increasing the max-count on checkScanner doesn't break things
2013-07-13 23:18:05 +01:00
2013-07-26 18:52:11 +01:00
var maxdemand = 0 ;
var gc = 1 ;
if ( ! this . ship . group )
2013-07-15 23:14:47 +01:00
{
2013-07-26 18:52:11 +01:00
if ( this . ship . equipmentStatus ( "EQ_FUEL_SCOOPS" ) == "EQUIPMENT_OK" )
2013-07-15 23:14:47 +01:00
{
2013-07-26 18:52:11 +01:00
maxdemand = this . ship . cargoSpaceAvailable ;
2013-07-15 23:14:47 +01:00
}
2013-07-13 23:18:05 +01:00
}
else
{
2013-07-26 18:52:11 +01:00
gc = this . ship . group . ships . length ;
for ( var i = 0 ; i < gc ; i ++ )
2013-07-14 23:11:25 +01:00
{
2013-07-26 18:52:11 +01:00
var ship = this . ship . group . ships [ i ] ;
if ( ship . equipmentStatus ( "EQ_FUEL_SCOOPS" ) == "EQUIPMENT_OK" )
2013-07-14 23:11:25 +01:00
{
2013-07-26 18:52:11 +01:00
maxdemand += ship . cargoSpaceAvailable ;
}
2013-07-14 23:11:25 +01:00
}
}
2013-07-26 18:52:11 +01:00
if ( demand > maxdemand )
2013-07-14 23:11:25 +01:00
{
2013-07-26 18:52:11 +01:00
demand = maxdemand ; // don't ask for more than we can carry
2013-07-14 23:11:25 +01:00
}
2013-07-26 18:52:11 +01:00
while ( demand > gc * 5 )
2013-07-15 23:14:47 +01:00
{
2013-07-26 18:52:11 +01:00
// asking for more than 5TC each probably means there
// won't be time to pick it all up anyway
demand = Math . ceil ( demand / 2 ) ;
2013-07-15 23:14:47 +01:00
}
2013-07-26 18:52:11 +01:00
if ( demand < 2 )
2013-07-15 23:14:47 +01:00
{
2013-07-26 18:52:11 +01:00
demand = 2 ;
2013-07-15 23:14:47 +01:00
}
2013-07-26 18:52:11 +01:00
* /
2013-07-15 23:14:47 +01:00
2013-07-26 18:52:11 +01:00
/* Record our demand with the group leader */
if ( this . ship . group && this . ship . group . leader )
2013-07-21 11:10:47 +01:00
{
2013-07-26 18:52:11 +01:00
this . ship . group . leader . AIScript . oolite _intership . cargodemanded = demand ;
2013-07-21 11:10:47 +01:00
}
2013-07-26 18:52:11 +01:00
else
2013-07-21 11:10:47 +01:00
{
2013-07-26 18:52:11 +01:00
this . ship . AIScript . oolite _intership . cargodemanded = demand ;
2013-07-21 11:10:47 +01:00
}
2013-07-26 18:52:11 +01:00
/* Inform the victim of the demand, if possible */
if ( this . ship . target . AIScript && this . ship . target . AIScript . oolite _intership )
2013-07-21 11:10:47 +01:00
{
2013-07-26 18:52:11 +01:00
this . ship . target . AIScript . oolite _intership . cargodemand = demand ;
2013-07-21 11:10:47 +01:00
}
2013-07-26 18:52:11 +01:00
this . communicate ( "oolite_piracyAlert" , this . ship . target . displayName , demand ) ;
this . ship . requestHelpFromGroup ( ) ;
/ * }
else
{
log ( this . ship . displayName , "Already asked for " + demand ) ; * /
2013-07-21 11:10:47 +01:00
}
2013-07-26 18:52:11 +01:00
var handlers = { } ;
this . responsesAddStandard ( handlers ) ;
2013-07-27 12:29:59 +01:00
this . applyHandlers ( handlers ) ;
2013-07-26 18:52:11 +01:00
this . ship . performAttack ( ) ;
}
2013-07-21 11:10:47 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . behaviourSunskim = function ( )
{
var handlers = { } ;
this . responsesAddStandard ( handlers ) ;
this . responsesAddScooping ( handlers ) ;
2013-07-27 12:29:59 +01:00
this . applyHandlers ( handlers ) ;
2013-07-26 18:52:11 +01:00
this . ship . performFlyToRangeFromDestination ( ) ;
}
2013-07-21 23:25:41 +01:00
2013-07-23 21:21:49 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . behaviourTumble = function ( )
{
2013-07-27 12:29:59 +01:00
this . applyHandlers ( { } ) ;
2013-07-26 18:52:11 +01:00
this . ship . performTumble ( ) ;
}
2013-07-27 12:29:59 +01:00
/* Missile behaviours: have different standard handler sets */
2013-07-26 18:52:11 +01:00
2013-07-27 12:29:59 +01:00
AILib . prototype . behaviourMissileInterceptTarget = function ( )
2013-07-26 18:52:11 +01:00
{
2013-07-27 12:29:59 +01:00
var handlers = { } ;
this . responsesAddMissile ( handlers ) ;
this . applyHandlers ( handlers ) ;
if ( this . ship . scriptInfo . oolite _missile _proximity )
2013-07-23 21:21:49 +01:00
{
2013-07-27 12:29:59 +01:00
this . ship . desiredRange = this . ship . scriptInfo . oolite _missile _proximity ;
2013-07-23 21:21:49 +01:00
}
2013-07-27 12:29:59 +01:00
else
{
this . ship . desiredRange = 25 ;
}
this . ship . performIntercept ( ) ;
2013-07-26 18:52:11 +01:00
}
2013-07-23 21:21:49 +01:00
2013-07-27 12:29:59 +01:00
AILib . prototype . behaviourMissileInterceptCoordinates = function ( )
2013-07-26 18:52:11 +01:00
{
2013-07-27 12:29:59 +01:00
var handlers = { } ;
this . responsesAddMissile ( handlers ) ;
this . applyHandlers ( handlers ) ;
if ( this . ship . scriptInfo . oolite _missile _proximity )
2013-07-23 21:21:49 +01:00
{
2013-07-27 12:29:59 +01:00
this . ship . desiredRange = this . ship . scriptInfo . oolite _missile _proximity ;
2013-07-23 21:21:49 +01:00
}
2013-07-27 12:29:59 +01:00
else
2013-07-23 21:21:49 +01:00
{
2013-07-27 12:29:59 +01:00
this . ship . desiredRange = 25 ;
2013-07-23 21:21:49 +01:00
}
2013-07-27 12:29:59 +01:00
var dest = this . getParameter ( "oolite_interceptCoordinates" ) ;
if ( dest == null )
2013-07-23 22:37:07 +01:00
{
2013-07-27 12:29:59 +01:00
return ;
}
this . ship . destination = dest
this . ship . desiredSpeed = this . ship . maxSpeed ;
this . ship . performFlyToRangeFromDestination ( ) ;
// if we have an intercept target, try to restore it
var oldtarget = this . getParameter ( "oolite_interceptTarget" ) ;
if ( oldtarget && ! oldtarget . isCloaked && oldtarget . isInSpace )
{
this . ship . target = oldtarget ;
2013-07-26 18:52:11 +01:00
}
2013-07-27 12:29:59 +01:00
}
2013-07-26 18:52:11 +01:00
2013-07-27 12:29:59 +01:00
AILib . prototype . behaviourMissileSelfDestruct = function ( ) {
this . ship . explode ( ) ;
2013-07-26 18:52:11 +01:00
}
2013-07-27 12:29:59 +01:00
/* Station behaviours: have different standard handler sets */
AILib . prototype . behaviourStationLaunchDefenseShips = function ( )
2013-07-26 18:52:11 +01:00
{
2013-07-27 12:29:59 +01:00
if ( this . ship . target && this . isAggressive ( this . ship . target ) )
2013-07-26 18:52:11 +01:00
{
2013-07-27 12:29:59 +01:00
this . alertCondition = 3 ;
this . ship . launchDefenseShip ( ) ;
this . ship . requestHelpFromGroup ( ) ;
2013-07-23 22:37:07 +01:00
}
2013-07-26 18:52:11 +01:00
var handlers = { } ;
this . responsesAddStation ( handlers ) ;
2013-07-27 12:29:59 +01:00
this . applyHandlers ( handlers ) ;
2013-07-26 18:52:11 +01:00
}
2013-07-23 22:37:07 +01:00
2013-07-27 12:29:59 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . behaviourStationLaunchMiner = function ( )
{
if ( this . alertCondition > 1 )
2013-07-23 21:21:49 +01:00
{
2013-07-26 18:52:11 +01:00
this . alertCondition -- ;
}
var handlers = { } ;
this . responsesAddStation ( handlers ) ;
2013-07-27 12:29:59 +01:00
this . applyHandlers ( handlers ) ;
2013-07-26 18:52:11 +01:00
if ( this . ship . group )
{
for ( var i = 0 ; i < this . ship . group . ships . length ; i ++ )
2013-07-23 22:37:07 +01:00
{
2013-07-26 18:52:11 +01:00
if ( this . ship . group . ships [ i ] . primaryRole == "miner" )
2013-07-23 22:37:07 +01:00
{
2013-07-26 18:52:11 +01:00
// only one in flight at once
return ;
2013-07-23 22:37:07 +01:00
}
}
2013-07-26 18:52:11 +01:00
}
this . ship . launchMiner ( ) ;
}
2013-07-23 22:37:07 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . behaviourStationLaunchPatrol = function ( )
{
if ( this . alertCondition > 1 )
{
this . alertCondition -- ;
2013-07-23 21:21:49 +01:00
}
2013-07-26 18:52:11 +01:00
var handlers = { } ;
this . responsesAddStation ( handlers ) ;
2013-07-27 12:29:59 +01:00
this . applyHandlers ( handlers ) ;
2013-07-23 21:21:49 +01:00
2013-07-26 18:52:11 +01:00
if ( this . ship . group )
2013-07-23 21:21:49 +01:00
{
2013-07-26 18:52:11 +01:00
for ( var i = 0 ; i < this . ship . group . ships . length ; i ++ )
2013-07-23 21:21:49 +01:00
{
2013-07-26 18:52:11 +01:00
if ( this . ship . group . ships [ i ] . primaryRole == this . getParameter ( "oolite_stationPatrolRole" ) )
2013-07-23 21:21:49 +01:00
{
2013-07-26 18:52:11 +01:00
// only one in flight at once
return ;
2013-07-23 21:21:49 +01:00
}
}
}
2013-07-26 18:52:11 +01:00
this . ship . launchPatrol ( ) ;
}
2013-07-24 21:56:50 +01:00
2013-07-27 12:29:59 +01:00
AILib . prototype . behaviourStationLaunchSalvager = function ( )
{
if ( this . alertCondition > 1 )
{
this . alertCondition -- ;
}
this . ship . launchScavenger ( ) ;
var handlers = { } ;
this . responsesAddStation ( handlers ) ;
this . applyHandlers ( handlers ) ;
}
2013-07-26 18:52:11 +01:00
AILib . prototype . behaviourStationManageTraffic = function ( )
{
var handlers = { } ;
this . responsesAddStation ( handlers ) ;
2013-07-27 12:29:59 +01:00
this . applyHandlers ( handlers ) ;
2013-07-26 18:52:11 +01:00
if ( this . ship . hasNPCTraffic )
2013-07-24 21:56:50 +01:00
{
2013-07-26 18:52:11 +01:00
if ( Math . random ( ) < 0.3 )
2013-07-24 21:56:50 +01:00
{
2013-07-26 18:52:11 +01:00
var trader = this . ship . launchShipWithRole ( "trader" ) ;
trader . setCargoType ( "PLENTIFUL_GOODS" ) ;
2013-07-24 21:56:50 +01:00
}
2013-07-26 18:52:11 +01:00
if ( Math . random ( ) < 0.1 )
2013-07-24 21:56:50 +01:00
{
2013-07-26 18:52:11 +01:00
this . ship . launchShuttle ( ) ;
2013-07-24 21:56:50 +01:00
}
2013-07-26 18:52:11 +01:00
// TODO: integrate with system repopulator rather than just
// launching ships at random
2013-07-24 21:56:50 +01:00
}
2013-07-26 18:52:11 +01:00
}
2013-07-24 21:56:50 +01:00
2013-07-26 18:52:11 +01:00
2013-07-27 12:29:59 +01:00
AILib . prototype . behaviourStationRespondToDistressCall = function ( )
2013-07-26 18:52:11 +01:00
{
2013-07-27 12:29:59 +01:00
var aggressor = this . getParameter ( "oolite_distressAggressor" ) ;
var sender = this . getParameter ( "oolite_distressSender" ) ;
if ( sender . bounty > aggressor . bounty )
2013-07-26 18:52:11 +01:00
{
2013-07-27 12:29:59 +01:00
var tmp = sender ;
sender = aggressor ;
aggressor = tmp ;
2013-07-24 21:56:50 +01:00
}
2013-07-27 12:29:59 +01:00
if ( aggressor . position . distanceTo ( this . ship ) < this . ship . scannerRange )
2013-07-26 18:52:11 +01:00
{
2013-07-27 12:29:59 +01:00
this . ship . target = aggressor ;
this . ship . alertCondition = 3 ;
this . ship . launchDefenseShip ( ) ;
this . communicate ( "oolite_distressResponseAggressor" , aggressor . displayName ) ;
this . ship . requestHelpFromGroup ( ) ;
2013-07-26 18:52:11 +01:00
}
else
{
2013-07-27 12:29:59 +01:00
this . communicate ( "oolite_distressResponseSender" , sender . displayName ) ;
2013-07-24 21:56:50 +01:00
}
2013-07-26 18:52:11 +01:00
2013-07-27 12:29:59 +01:00
var handlers = { } ;
this . responsesAddStation ( handlers ) ;
this . applyHandlers ( handlers ) ;
2013-07-26 18:52:11 +01:00
}
2013-07-24 21:56:50 +01:00
2013-07-23 21:21:49 +01:00
2013-07-26 18:52:11 +01:00
/* ****************** Configuration functions ************** */
2013-07-12 19:44:14 +01:00
2013-07-26 18:52:11 +01:00
/ * C o n f i g u r a t i o n s . C o n f i g u r a t i o n s a r e s e t u p a c t i o n s f o r a b e h a v i o u r
* or behaviours . They can also be used on a fall - through conditional
* to set parameters for later tests * /
2013-07-12 19:44:14 +01:00
2013-07-27 12:29:59 +01:00
/*** Target acquisition configuration ***/
2013-07-26 18:52:11 +01:00
AILib . prototype . configurationAcquireCombatTarget = function ( )
{
if ( this . ship . target && this . allied ( this . ship , this . ship . target ) )
2013-07-12 19:44:14 +01:00
{
2013-07-26 18:52:11 +01:00
// don't shoot at allies even if they have ended up as a target...
this . ship . removeDefenseTarget ( this . ship . target ) ;
this . ship . target = null ;
}
if ( this . ship . target && this . ship . target . scanClass == "CLASS_CARGO" )
{
this . ship . target = null ;
}
/ * I f f t h e s h i p d o e s n o t c u r r e n t l y h a v e a t a r g e t , s e l e c t a n e w o n e
* from the defense target list . * /
if ( this . ship . target && this . ship . target . isInSpace )
{
return ;
}
var dts = this . ship . defenseTargets
for ( var i = 0 ; i < dts . length ; i ++ )
{
if ( dts [ i ] . position . distanceTo ( this . ship ) < this . ship . scannerRange )
2013-07-12 19:44:14 +01:00
{
2013-07-26 18:52:11 +01:00
this . ship . target = dts [ 0 ] ;
2013-07-12 19:44:14 +01:00
return ;
}
2013-07-26 18:52:11 +01:00
}
if ( this . ship . group != null )
{
for ( var i = 0 ; i < this . ship . group . length ; i ++ )
2013-07-13 11:36:28 +01:00
{
2013-07-26 18:52:11 +01:00
if ( this . ship . group . ships [ i ] != this . ship )
2013-07-13 11:36:28 +01:00
{
2013-07-26 18:52:11 +01:00
if ( this . ship . group . ships [ i ] . target && this . isFighting ( this . ship . group . ships [ i ] ) && this . ship . group . ships [ i ] . target . position . distanceTo ( this . ship ) < this . ship . scannerRange )
2013-07-13 11:36:28 +01:00
{
2013-07-26 18:52:11 +01:00
this . ship . target = this . ship . group . ships [ i ] . target ;
return ;
2013-07-13 11:36:28 +01:00
}
}
}
2013-07-26 18:52:11 +01:00
}
if ( this . ship . escortGroup != null )
{
for ( var i = 0 ; i < this . ship . escortGroup . length ; i ++ )
2013-07-13 11:36:28 +01:00
{
2013-07-26 18:52:11 +01:00
if ( this . ship . escortGroup . ships [ i ] != this . ship )
2013-07-13 11:36:28 +01:00
{
2013-07-26 18:52:11 +01:00
if ( this . ship . escortGroup . ships [ i ] . target && this . isFighting ( this . ship . escortGroup . ships [ i ] ) && this . ship . escortGroup . ships [ i ] . target . position . distanceTo ( this . ship ) < this . ship . scannerRange )
2013-07-13 11:36:28 +01:00
{
2013-07-26 18:52:11 +01:00
this . ship . target = this . ship . escortGroup . ships [ i ] . target ;
return ;
2013-07-13 11:36:28 +01:00
}
}
2013-07-12 19:44:14 +01:00
}
}
2013-07-26 18:52:11 +01:00
}
2013-07-12 19:44:14 +01:00
2013-07-27 12:29:59 +01:00
AILib . prototype . configurationAcquireDefensiveEscortTarget = function ( )
2013-07-26 18:52:11 +01:00
{
2013-07-27 12:29:59 +01:00
if ( this . ship . group && this . ship . group . leader )
{
var leader = this . ship . group . leader ;
if ( leader . target && leader . target . target == leader && this . isFighting ( leader ) && leader . target . position . distanceTo ( this . ship ) < this . ship . scannerRange )
{
this . ship . target = leader . target ;
}
else
{
var dts = leader . defenseTargets ;
for ( var i = 0 ; i < dts . length ; i ++ )
{
if ( dts [ i ] . target == leader && this . isAggressive ( dts [ i ] ) && dts [ i ] . position . distanceTo ( this . ship ) < this . ship . scannerRange )
{
this . ship . target = dts [ i ] ;
}
}
}
}
}
// TODO: reuse code from AcquireCombatTarget better
AILib . prototype . configurationAcquireHostileCombatTarget = function ( )
{
if ( this . ship . target && this . allied ( this . ship , this . ship . target ) )
2013-07-15 23:14:47 +01:00
{
2013-07-26 18:52:11 +01:00
// don't shoot at allies even if they have ended up as a target...
this . ship . removeDefenseTarget ( this . ship . target ) ;
this . ship . target = null ;
}
/ * I f f t h e s h i p d o e s n o t c u r r e n t l y h a v e a t a r g e t , s e l e c t a n e w o n e
* from the defense target list . * /
if ( this . ship . target && this . ship . target . isInSpace && this . isAggressive ( this . ship . target ) )
{
return ;
}
var dts = this . ship . defenseTargets
for ( var i = 0 ; i < dts . length ; i ++ )
{
if ( dts [ i ] . position . distanceTo ( this . ship ) < this . ship . scannerRange && this . isAggressive ( dts [ i ] ) )
2013-07-15 23:14:47 +01:00
{
2013-07-26 18:52:11 +01:00
this . ship . target = dts [ 0 ] ;
2013-07-15 23:14:47 +01:00
return ;
}
2013-07-26 18:52:11 +01:00
}
if ( this . ship . group != null )
{
for ( var i = 0 ; i < this . ship . group . length ; i ++ )
2013-07-15 23:14:47 +01:00
{
2013-07-26 18:52:11 +01:00
if ( this . ship . group . ships [ i ] != this . ship )
2013-07-15 23:14:47 +01:00
{
2013-07-26 18:52:11 +01:00
if ( this . ship . group . ships [ i ] . target && this . isFighting ( this . ship . group . ships [ i ] ) && this . ship . group . ships [ i ] . target . position . distanceTo ( this . ship ) < this . ship . scannerRange && this . isAggressive ( this . ship . group . ships [ i ] . target ) )
2013-07-15 23:14:47 +01:00
{
2013-07-26 18:52:11 +01:00
this . ship . target = this . ship . group . ships [ i ] . target ;
return ;
2013-07-15 23:14:47 +01:00
}
}
}
2013-07-26 18:52:11 +01:00
}
if ( this . ship . escortGroup != null )
{
for ( var i = 0 ; i < this . ship . escortGroup . length ; i ++ )
2013-07-15 23:14:47 +01:00
{
2013-07-26 18:52:11 +01:00
if ( this . ship . escortGroup . ships [ i ] != this . ship )
2013-07-15 23:14:47 +01:00
{
2013-07-26 18:52:11 +01:00
if ( this . ship . escortGroup . ships [ i ] . target && this . isFighting ( this . ship . escortGroup . ships [ i ] ) && this . ship . escortGroup . ships [ i ] . target . position . distanceTo ( this . ship ) < this . ship . scannerRange && this . isAggressive ( this . ship . escortGroup . ships [ i ] . target ) )
2013-07-15 23:14:47 +01:00
{
2013-07-26 18:52:11 +01:00
this . ship . target = this . ship . escortGroup . ships [ i ] . target ;
return ;
2013-07-15 23:14:47 +01:00
}
}
}
}
2013-07-26 18:52:11 +01:00
}
2013-07-15 23:14:47 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . configurationAcquireOffensiveEscortTarget = function ( )
{
if ( this . ship . group && this . ship . group . leader && this . ship . group . leader . target && this . ship . group . leader . hasHostileTarget )
2013-07-13 23:18:05 +01:00
{
2013-07-26 18:52:11 +01:00
if ( this . ship . position . distanceTo ( this . ship . group . leader . target ) < this . ship . scannerRange )
2013-07-13 23:18:05 +01:00
{
2013-07-26 18:52:11 +01:00
this . ship . target = this . ship . group . leader . target ;
this . ship . addDefenseTarget ( this . ship . target ) ;
2013-07-13 23:18:05 +01:00
}
}
2013-07-26 18:52:11 +01:00
}
2013-07-13 23:18:05 +01:00
2013-07-27 12:29:59 +01:00
AILib . prototype . configurationAcquirePlayerAsTarget = function ( )
2013-07-26 18:52:11 +01:00
{
2013-07-27 12:29:59 +01:00
this . ship . target = player . ship ;
2013-07-26 18:52:11 +01:00
}
2013-07-13 23:18:05 +01:00
2013-07-25 20:09:53 +01:00
2013-07-27 12:29:59 +01:00
AILib . prototype . configurationAcquireScannedTarget = function ( )
2013-07-26 18:52:11 +01:00
{
2013-07-27 12:29:59 +01:00
this . ship . target = this . getParameter ( "oolite_scanResultSpecific" ) ;
2013-07-26 18:52:11 +01:00
}
2013-07-25 20:09:53 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . configurationCheckScanner = function ( )
{
this . setParameter ( "oolite_scanResults" , this . ship . checkScanner ( ) ) ;
this . setParameter ( "oolite_scanResultSpecific" , null ) ;
}
2013-07-13 19:13:30 +01:00
2013-07-25 20:09:53 +01:00
2013-07-27 12:29:59 +01:00
/*** Navigation configuration ***/
AILib . prototype . configurationSelectRandomTradeStation = function ( )
2013-07-26 18:52:11 +01:00
{
2013-07-27 12:29:59 +01:00
var stations = system . stations ;
var threshold = 1E16 ;
var chosenStation = null ;
if ( this . ship . bounty == 0 )
{
if ( Math . random ( ) < 0.9 && this . friendlyStation ( system . mainStation ) )
{
this . setParameter ( "oolite_selectedStation" , system . mainStation ) ;
return ;
}
}
else if ( this . ship . bounty <= this . fineThreshold ( ) )
{
if ( Math . random ( ) < 0.5 && this . friendlyStation ( system . mainStation ) )
{
this . setParameter ( "oolite_selectedStation" , system . mainStation ) ;
return ;
}
}
var friendlies = 0 ;
for ( var i = 0 ; i < stations . length ; i ++ )
{
var station = stations [ i ] ;
if ( this . friendlyStation ( station ) )
{
friendlies ++ ;
// equivalent to filtering the list to only contain
// friendlies, then picking a random element.
if ( Math . random ( ) < 1 / friendlies )
{
chosenStation = station ;
}
}
}
this . setParameter ( "oolite_selectedStation" , system . mainStation ) ;
this . communicate ( "oolite_selectedStation" , system . mainStation . displayName ) ;
2013-07-26 18:52:11 +01:00
}
2013-07-13 19:13:30 +01:00
2013-07-27 12:29:59 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . configurationSelectShuttleDestination = function ( )
{
var possibles = system . planets . concat ( system . stations ) ;
var destinations1 = [ ] ;
var destinations2 = [ ] ;
for ( var i = 0 ; i < possibles . length ; i ++ )
2013-07-21 23:25:41 +01:00
{
2013-07-26 18:52:11 +01:00
var possible = possibles [ i ] ;
// travel at least a little way
var distance = possible . position . distanceTo ( this . ship ) ;
if ( distance > possible . collisionRadius + 10000 )
2013-07-21 23:25:41 +01:00
{
2013-07-26 18:52:11 +01:00
// must be friendly destination and not moving too fast
if ( possible . isPlanet || this . friendlyStation ( possible ) || possible . maxSpeed > this . ship . maxSpeed / 5 )
2013-07-21 23:25:41 +01:00
{
2013-07-26 18:52:11 +01:00
if ( distance > system . mainPlanet . radius * 5 )
2013-07-21 23:25:41 +01:00
{
2013-07-26 18:52:11 +01:00
destinations2 . push ( possible ) ;
}
else
{
destinations1 . push ( possible ) ;
2013-07-21 23:25:41 +01:00
}
}
}
2013-07-26 18:52:11 +01:00
}
// no nearby destinations
if ( destinations1 . length == 0 )
{
destinations1 = destinations2 ;
}
// no destinations
if ( destinations1 . length == 0 )
{
return ;
}
var destination = destinations1 [ Math . floor ( Math . random ( ) * destinations1 . length ) ] ;
if ( destination . isPlanet )
{
this . setParameter ( "oolite_selectedPlanet" , destination ) ;
this . setParameter ( "oolite_selectedStation" , null ) ;
}
else
{
this . setParameter ( "oolite_selectedStation" , destination ) ;
this . setParameter ( "oolite_selectedPlanet" , null ) ;
}
}
2013-07-27 12:29:59 +01:00
AILib . prototype . configurationSelectWitchspaceDestination = function ( )
2013-07-26 18:52:11 +01:00
{
2013-07-27 12:29:59 +01:00
if ( ! this . ship . hasHyperspaceMotor )
2013-07-26 18:52:11 +01:00
{
2013-07-27 12:29:59 +01:00
this . setParameter ( "oolite_witchspaceDestination" , null ) ;
return ;
}
var preselected = this . getParameter ( "oolite_witchspaceDestination" ) ;
if ( preselected != system . ID && system . info . distanceToSystem ( System . infoForSystem ( galaxyNumber , preselected ) ) <= this . ship . fuel )
2013-07-26 18:52:11 +01:00
{
2013-07-27 12:29:59 +01:00
// we've already got a destination
return ;
2013-07-21 23:25:41 +01:00
}
2013-07-27 12:29:59 +01:00
var possible = system . info . systemsInRange ( this . ship . fuel ) ;
var selected = possible [ Math . floor ( Math . random ( ) * possible . length ) ] ;
this . setParameter ( "oolite_witchspaceDestination" , selected . systemID ) ;
this . communicate ( "oolite_selectedWitchspaceDestination" , selected . name ) ;
}
/*** Destination configuration ***/
AILib . prototype . configurationSetDestinationToNearestFriendlyStation = function ( )
{
var stations = system . stations ;
var threshold = 1E16 ;
var chosenStation = null ;
2013-07-26 18:52:11 +01:00
for ( var i = 0 ; i < stations . length ; i ++ )
2013-07-14 19:02:16 +01:00
{
2013-07-26 18:52:11 +01:00
var station = stations [ i ] ;
if ( this . friendlyStation ( station ) )
2013-07-14 19:02:16 +01:00
{
2013-07-27 12:29:59 +01:00
var distance = station . position . distanceTo ( this . ship ) ;
if ( distance < threshold )
2013-07-14 19:02:16 +01:00
{
2013-07-27 12:29:59 +01:00
threshold = distance ;
2013-07-26 18:52:11 +01:00
chosenStation = station ;
2013-07-14 19:02:16 +01:00
}
}
}
2013-07-27 12:29:59 +01:00
if ( chosenStation == null )
{
this . ship . destination = this . ship . position ;
this . ship . desiredRange = 0 ;
}
else
{
this . ship . destination = chosenStation . position ;
this . ship . desiredRange = 15000 ;
this . ship . desiredSpeed = this . cruiseSpeed ( ) ;
}
2013-07-26 18:52:11 +01:00
}
2013-07-27 12:29:59 +01:00
AILib . prototype . configurationSetDestinationToHomeStation = function ( )
2013-07-26 18:52:11 +01:00
{
2013-07-27 12:29:59 +01:00
var home = this . homeStation ( ) ;
if ( home != null )
{
this . ship . destination = home . position ;
this . ship . desiredRange = 15000 ;
this . ship . desiredSpeed = this . cruiseSpeed ( ) ;
}
else
{
this . ship . destination = this . ship . position ;
this . ship . desiredRange = 0 ;
}
2013-07-26 18:52:11 +01:00
}
2013-07-27 12:29:59 +01:00
AILib . prototype . configurationSetDestinationToGroupLeader = function ( )
2013-07-26 18:52:11 +01:00
{
2013-07-27 12:29:59 +01:00
if ( ! this . ship . group || ! this . ship . group . leader )
{
this . ship . destination = this . ship . position ;
}
else
{
this . ship . destination = this . ship . group . leader . position ;
}
this . ship . desiredRange = 2000 ;
this . ship . desiredSpeed = this . ship . maxSpeed ;
2013-07-26 18:52:11 +01:00
}
2013-07-14 19:02:16 +01:00
2013-07-27 12:29:59 +01:00
AILib . prototype . configurationSetDestinationToMainPlanet = function ( )
2013-07-26 18:52:11 +01:00
{
2013-07-27 12:29:59 +01:00
if ( system . mainPlanet )
2013-07-13 23:18:05 +01:00
{
2013-07-27 12:29:59 +01:00
this . ship . destination = system . mainPlanet . position ;
this . ship . desiredRange = system . mainPlanet . radius * 3 ;
2013-07-13 23:18:05 +01:00
this . ship . desiredSpeed = this . cruiseSpeed ( ) ;
}
2013-07-26 18:52:11 +01:00
}
2013-07-13 23:18:05 +01:00
2013-07-27 12:29:59 +01:00
AILib . prototype . configurationSetDestinationToMainStation = function ( )
2013-07-26 18:52:11 +01:00
{
2013-07-27 12:29:59 +01:00
this . ship . destination = system . mainStation . position ;
this . ship . desiredRange = 15000 ;
this . ship . desiredSpeed = this . cruiseSpeed ( ) ;
2013-07-26 18:52:11 +01:00
}
2013-07-14 19:02:16 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . configurationSetDestinationToPirateLurk = function ( )
{
var lurk = this . getParameter ( "oolite_pirateLurk" ) ;
if ( lurk != null )
{
this . ship . destination = lurk ;
2013-07-14 19:02:16 +01:00
}
2013-07-26 18:52:11 +01:00
else
2013-07-14 19:02:16 +01:00
{
2013-07-26 18:52:11 +01:00
var code = "WITCHPOINT" ;
var p = this . ship . position ;
// if already on a lane, stay on it
2013-07-27 12:29:59 +01:00
if ( p . z < system . mainPlanet . position . z && ( ( p . x * p . x ) + ( p . y * p . y ) ) < this . scannerRange * this . scannerRange * 4 )
2013-07-14 19:02:16 +01:00
{
2013-07-26 18:52:11 +01:00
lurk = p ;
2013-07-14 19:02:16 +01:00
}
2013-07-26 18:52:11 +01:00
else if ( p . subtract ( system . mainPlanet ) . dot ( p . subtract ( system . sun ) ) < - 0.9 )
2013-07-21 23:25:41 +01:00
{
2013-07-26 18:52:11 +01:00
lurk = p ;
2013-07-21 23:25:41 +01:00
}
2013-07-26 18:52:11 +01:00
else if ( p . dot ( system . sun . position ) > 0.9 )
2013-07-15 23:14:47 +01:00
{
2013-07-26 18:52:11 +01:00
lurk = p ;
2013-07-15 23:14:47 +01:00
}
2013-07-26 18:52:11 +01:00
else // not on a lane, so pick somewhere at random
2013-07-15 23:14:47 +01:00
{
2013-07-26 18:52:11 +01:00
var choice = Math . random ( ) ;
if ( choice < 0.8 )
2013-07-15 23:14:47 +01:00
{
2013-07-26 18:52:11 +01:00
code = "LANE_WP" ;
2013-07-15 23:14:47 +01:00
}
2013-07-26 18:52:11 +01:00
else
2013-07-15 23:14:47 +01:00
{
2013-07-26 18:52:11 +01:00
code = "LANE_PS" ;
2013-07-15 23:14:47 +01:00
}
2013-07-26 18:52:11 +01:00
// code = "LANE_WS"? "WITCHPOINT"?
// what about other locations in less policed systems?
lurk = system . locationFromCode ( code ) ;
2013-07-15 23:14:47 +01:00
}
2013-07-26 18:52:11 +01:00
this . setParameter ( "oolite_pirateLurk" , lurk ) ;
2013-07-15 23:14:47 +01:00
}
2013-07-26 18:52:11 +01:00
this . ship . desiredRange = 1000 ;
this . ship . desiredSpeed = this . cruiseSpeed ( ) ;
}
2013-07-15 23:14:47 +01:00
2013-07-27 12:29:59 +01:00
AILib . prototype . configurationSetDestinationToSelectedPlanet = function ( )
2013-07-26 18:52:11 +01:00
{
2013-07-27 12:29:59 +01:00
var planet = this . getParameter ( "oolite_selectedPlanet" ) ;
if ( planet )
{
this . ship . destination = planet . position ;
this . ship . desiredRange = planet . radius + 100 ;
this . ship . desiredSpeed = this . cruiseSpeed ( ) ;
}
2013-07-26 18:52:11 +01:00
}
2013-07-14 19:02:16 +01:00
2013-07-26 18:52:11 +01:00
2013-07-27 12:29:59 +01:00
AILib . prototype . configurationSetDestinationToSelectedStation = function ( )
2013-07-26 18:52:11 +01:00
{
2013-07-27 12:29:59 +01:00
var station = this . getParameter ( "oolite_selectedStation" ) ;
if ( station )
2013-07-26 18:52:11 +01:00
{
2013-07-27 12:29:59 +01:00
this . ship . destination = station . position ;
2013-07-26 18:52:11 +01:00
this . ship . desiredRange = 15000 ;
this . ship . desiredSpeed = this . cruiseSpeed ( ) ;
}
}
2013-07-13 23:18:05 +01:00
2013-07-22 21:24:27 +01:00
2013-07-27 12:29:59 +01:00
AILib . prototype . configurationSetDestinationToSunskimEnd = function ( )
2013-07-26 18:52:11 +01:00
{
2013-07-27 12:29:59 +01:00
if ( system . sun )
2013-07-26 18:52:11 +01:00
{
2013-07-27 12:29:59 +01:00
var direction = Vector3D . random ( ) . cross ( this . ship . position . subtract ( system . sun . position ) ) ;
// 2km parallel to local sun surface for every LY of fuel
this . ship . destination = this . ship . position . add ( direction . multiply ( 2000 * ( 7 - this . ship . fuel ) ) ) ;
// max sunskim height is sqrt(4/3) radius
2013-07-26 18:52:11 +01:00
this . ship . desiredRange = 0 ;
2013-07-27 12:29:59 +01:00
this . ship . desiredSpeed = this . ship . maxSpeed ;
2013-07-22 21:24:27 +01:00
}
2013-07-26 18:52:11 +01:00
}
2013-07-22 21:24:27 +01:00
2013-07-27 12:29:59 +01:00
AILib . prototype . configurationSetDestinationToSunskimStart = function ( )
2013-07-26 18:52:11 +01:00
{
2013-07-27 12:29:59 +01:00
if ( system . sun )
2013-07-13 19:13:30 +01:00
{
2013-07-27 12:29:59 +01:00
this . ship . destination = system . sun . position ;
// max sunskim height is sqrt(4/3) radius
this . ship . desiredRange = system . sun . radius * 1.125 ;
this . ship . desiredSpeed = this . cruiseSpeed ( ) ;
2013-07-19 20:18:53 +01:00
}
2013-07-26 18:52:11 +01:00
}
2013-07-13 19:13:30 +01:00
2013-07-27 12:29:59 +01:00
AILib . prototype . configurationSetDestinationToWaypoint = function ( )
2013-07-26 18:52:11 +01:00
{
2013-07-27 12:29:59 +01:00
if ( this . getParameter ( "oolite_waypoint" ) != null && this . getParameter ( "oolite_waypointRange" ) != null )
2013-07-19 20:18:53 +01:00
{
2013-07-27 12:29:59 +01:00
this . ship . destination = this . getParameter ( "oolite_waypoint" ) ;
this . ship . desiredRange = this . getParameter ( "oolite_waypointRange" ) ;
this . ship . desiredSpeed = this . cruiseSpeed ( ) ;
2013-07-13 19:13:30 +01:00
}
2013-07-26 18:52:11 +01:00
}
2013-07-27 12:29:59 +01:00
AILib . prototype . configurationSetDestinationToWitchpoint = function ( )
2013-07-26 18:52:11 +01:00
{
2013-07-27 12:29:59 +01:00
this . ship . destination = new Vector3D ( 0 , 0 , 0 ) ;
this . ship . desiredRange = 10000 ;
2013-07-26 18:52:11 +01:00
this . ship . desiredSpeed = this . cruiseSpeed ( ) ;
}
2013-07-13 19:13:30 +01:00
2013-07-27 12:29:59 +01:00
AILib . prototype . configurationSetWaypoint = function ( )
2013-07-26 18:52:11 +01:00
{
2013-07-27 12:29:59 +01:00
var gen = this . getWaypointGenerator ( ) ;
if ( gen != null )
2013-07-26 18:52:11 +01:00
{
2013-07-27 12:29:59 +01:00
gen . call ( this ) ;
this . configurationSetDestinationToWaypoint ( ) ;
2013-07-13 19:13:30 +01:00
}
2013-07-26 18:52:11 +01:00
}
2013-07-12 19:44:14 +01:00
2013-07-27 12:29:59 +01:00
/*** Docking configurations ***/
2013-07-26 18:52:11 +01:00
AILib . prototype . configurationSetNearbyFriendlyStationForDocking = function ( )
{
var stations = system . stations ;
for ( var i = 0 ; i < stations . length ; i ++ )
2013-07-13 23:18:05 +01:00
{
2013-07-26 18:52:11 +01:00
var station = stations [ i ] ;
if ( this . friendlyStation ( station ) )
2013-07-13 23:18:05 +01:00
{
2013-07-26 18:52:11 +01:00
// this is not a very good check for friendliness, but
// it will have to do for now
if ( station . position . distanceTo ( this . ship ) < this . ship . scannerRange )
2013-07-13 23:18:05 +01:00
{
2013-07-26 18:52:11 +01:00
this . setParameter ( "oolite_dockingStation" , station )
return ;
2013-07-13 23:18:05 +01:00
}
}
}
2013-07-26 18:52:11 +01:00
}
2013-07-13 23:18:05 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . configurationSetHomeStationForDocking = function ( )
{
if ( this . ship . owner && this . ship . owner . isStation && this . friendlyStation ( this . ship . owner ) )
2013-07-22 21:24:27 +01:00
{
2013-07-26 18:52:11 +01:00
this . setParameter ( "oolite_dockingStation" , this . ship . owner )
return ;
2013-07-22 21:24:27 +01:00
}
2013-07-26 18:52:11 +01:00
}
2013-07-22 21:24:27 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . configurationSetSelectedStationForDocking = function ( )
{
this . setParameter ( "oolite_dockingStation" , this . getParameter ( "oolite_selectedStation" ) ) ;
}
2013-07-14 19:02:16 +01:00
2013-07-27 12:29:59 +01:00
/*** Miscellaneous configuration ***/
2013-07-26 18:52:11 +01:00
AILib . prototype . configurationAppointGroupLeader = function ( )
{
if ( this . ship . group && ! this . ship . group . leader )
2013-07-14 23:11:25 +01:00
{
2013-07-26 18:52:11 +01:00
this . ship . group . leader = this . ship . group . ships [ 0 ] ;
for ( var i = 0 ; i < this . ship . group . ships . length ; i ++ )
2013-07-14 23:11:25 +01:00
{
2013-07-26 18:52:11 +01:00
if ( this . ship . group . ships [ i ] . hasHyperspaceMotor )
2013-07-18 23:00:23 +01:00
{
2013-07-26 18:52:11 +01:00
// bias towards jump-capable ships
this . ship . group . leader = this . ship . group . ships [ i ] ;
break ;
2013-07-18 23:00:23 +01:00
}
2013-07-14 23:11:25 +01:00
}
2013-07-26 18:52:11 +01:00
var leadrole = this . getParameter ( "oolite_leaderRole" )
if ( leadrole != null )
{
this . ship . group . leader . primaryRole = leadrole ;
}
2013-07-14 23:11:25 +01:00
}
2013-07-26 18:52:11 +01:00
}
2013-07-14 23:11:25 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . configurationEscortGroupLeader = function ( )
{
if ( ! this . ship . group || ! this . ship . group . leader || this . ship . group . leader == this . ship )
2013-07-18 23:00:23 +01:00
{
2013-07-26 18:52:11 +01:00
return ;
}
if ( this . ship . group . leader . escortGroup && this . ship . group . leader . escortGroup . containsShip ( this . ship ) )
{
return ;
}
var escrole = this . getParameter ( "oolite_escortRole" )
if ( escrole != null )
{
var oldrole = this . ship . primaryRole ;
this . ship . primaryRole = escrole ;
var accepted = this . ship . offerToEscort ( this . ship . group . leader ) ;
if ( ! accepted )
2013-07-18 23:00:23 +01:00
{
2013-07-26 18:52:11 +01:00
this . ship . primaryRole = oldrole ;
2013-07-18 23:00:23 +01:00
}
}
2013-07-26 18:52:11 +01:00
}
2013-07-18 23:00:23 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . configurationForgetCargoDemand = function ( )
{
/ * i f ( t h i s . s h i p . g r o u p & & t h i s . s h i p . g r o u p . l e a d e r & & t h i s . s h i p . g r o u p . l e a d e r . A I S c r i p t . o o l i t e _ i n t e r s h i p . c a r g o d e m a n d e d )
{
delete this . ship . group . leader . AIScript . oolite _intership . cargodemanded ;
} * / / / not sure about this , maybe not needed
2013-07-15 23:14:47 +01:00
2013-07-26 18:52:11 +01:00
if ( this . ship . AIScript . oolite _intership . cargodemanded )
{
delete this . ship . AIScript . oolite _intership . cargodemanded ;
delete this . ship . AIScript . oolite _intership . cargodemandmet ;
// and make the group lose the cargo count from the last demand
if ( this . ship . group )
2013-07-15 23:14:47 +01:00
{
2013-07-26 18:52:11 +01:00
for ( var i = 0 ; i < this . ship . group . ships . length ; i ++ )
2013-07-17 22:44:26 +01:00
{
2013-07-26 18:52:11 +01:00
var ship = this . ship . group . ships [ i ] ;
if ( ship . AIScript && ship . AIScript . oolite _priorityai )
2013-07-17 22:44:26 +01:00
{
2013-07-26 18:52:11 +01:00
ship . AIScript . oolite _priorityai . setParameter ( "oolite_cargoDropped" , 0 ) ;
2013-07-17 22:44:26 +01:00
}
}
2013-07-15 23:14:47 +01:00
}
}
2013-07-26 18:52:11 +01:00
}
2013-07-15 23:14:47 +01:00
2013-07-27 15:39:23 +01:00
AILib . prototype . configurationLeaveEscortGroup = function ( )
{
if ( this . ship . group && this . ship . group . leader && this . ship . group . leader != this . ship && this . ship . group . leader . escortGroup && this . ship . group . leader . escortGroup . containsShip ( this . ship ) )
{
this . ship . group . leader . escortGroup . removeShip ( this . ship ) ;
if ( this . ship . group )
{
this . ship . group . removeShip ( this . ship ) ;
this . ship . group = null ;
}
}
}
2013-07-27 12:29:59 +01:00
/*** Station configuration ***/
2013-07-26 18:52:11 +01:00
AILib . prototype . configurationStationReduceAlertLevel = function ( )
{
if ( this . ship . alertCondition > 1 )
2013-07-23 21:21:49 +01:00
{
2013-07-26 18:52:11 +01:00
this . ship . alertCondition -- ;
2013-07-23 21:21:49 +01:00
}
2013-07-26 18:52:11 +01:00
}
2013-07-23 21:21:49 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . configurationStationValidateTarget = function ( )
{
if ( this . ship . target )
2013-07-23 21:21:49 +01:00
{
2013-07-26 18:52:11 +01:00
if ( this . ship . position . distanceTo ( this . ship . target ) > this . ship . scannerRange )
2013-07-23 21:21:49 +01:00
{
2013-07-26 18:52:11 +01:00
// station behaviour does not generally validate target
this . ship . target = null ;
2013-07-23 21:21:49 +01:00
}
}
2013-07-26 18:52:11 +01:00
}
2013-07-21 11:10:47 +01:00
2013-07-26 18:52:11 +01:00
/* ****************** Response definition functions ************** */
2013-07-12 19:44:14 +01:00
2013-07-26 18:52:11 +01:00
/ * S t a n d a r d s t a t e - m a c h i n e r e s p o n s e s . T h e s e s e t u p a s e t o f s t a n d a r d
* state machine responses where incoming events will cause reasonable
* default behaviour and often force a reconsideration of
* priorities . Many behaviours will need to supplement the standard
* responses with additional definitions . * /
AILib . prototype . responsesAddStandard = function ( handlers )
{
handlers . cascadeWeaponDetected = function ( weapon )
{
this . ship . clearDefenseTargets ( ) ;
this . ship . addDefenseTarget ( weapon ) ;
this . setParameter ( "oolite_cascadeDetected" , weapon . position ) ;
this . ship . target = weapon ;
this . ship . performFlee ( ) ;
this . reconsiderNow ( ) ;
} ;
2013-07-12 19:44:14 +01:00
2013-07-26 18:52:11 +01:00
handlers . shipAttackedWithMissile = function ( missile , whom )
2013-07-13 23:18:05 +01:00
{
2013-07-26 18:52:11 +01:00
if ( ! this . ship . hasHostileTarget && this . getParameter ( "oolite_flag_sendsDistressCalls" ) )
{
this . ship . broadcastDistressMessage ( ) ;
}
if ( this . ship . equipmentStatus ( "EQ_ECM" ) == "EQUIPMENT_OK" )
{
this . ship . fireECM ( ) ;
this . ship . addDefenseTarget ( missile ) ;
this . ship . addDefenseTarget ( whom ) ;
// but don't reconsider immediately
}
else
2013-07-13 11:36:28 +01:00
{
2013-07-26 18:52:11 +01:00
this . ship . addDefenseTarget ( missile ) ;
this . ship . addDefenseTarget ( whom ) ;
var tmp = this . ship . target ;
this . ship . target = whom ;
this . ship . requestHelpFromGroup ( ) ;
this . ship . target = tmp ;
2013-07-13 19:13:30 +01:00
this . reconsiderNow ( ) ;
2013-07-26 18:52:11 +01:00
}
} ;
handlers . shipBeingAttacked = function ( whom )
{
if ( whom . target != this . ship && whom != player . ship )
2013-07-12 23:00:39 +01:00
{
2013-07-26 18:52:11 +01:00
// was accidental
if ( this . allied ( whom , this . ship ) )
2013-07-14 21:28:19 +01:00
{
2013-07-26 18:52:11 +01:00
this . communicate ( "oolite_friendlyFire" , whom . displayName ) ;
// ignore it
return ;
2013-07-12 23:00:39 +01:00
}
2013-07-26 18:52:11 +01:00
if ( Math . random ( ) > 0.1 )
2013-07-12 19:44:14 +01:00
{
2013-07-26 18:52:11 +01:00
// usually ignore it anyway
return ;
2013-07-12 23:00:39 +01:00
}
2013-07-26 18:52:11 +01:00
}
if ( ! this . ship . hasHostileTarget && this . getParameter ( "oolite_flag_sendsDistressCalls" ) )
2013-07-12 23:00:39 +01:00
{
2013-07-26 18:52:11 +01:00
this . ship . broadcastDistressMessage ( ) ;
}
if ( this . ship . defenseTargets . indexOf ( whom ) < 0 )
{
this . ship . addDefenseTarget ( whom ) ;
this . reconsiderNow ( ) ;
}
else
{
// else we know about this attacker already
if ( this . ship . energy * 4 < this . ship . maxEnergy )
2013-07-12 23:00:39 +01:00
{
2013-07-26 18:52:11 +01:00
// but at low energy still reconsider
2013-07-13 19:13:30 +01:00
this . reconsiderNow ( ) ;
2013-07-26 18:52:11 +01:00
this . ship . requestHelpFromGroup ( ) ;
2013-07-12 23:00:39 +01:00
}
2013-07-26 18:52:11 +01:00
}
if ( this . ship . hasHostileTarget )
{
if ( ! this . isAggressive ( this . ship . target ) )
2013-07-12 19:44:14 +01:00
{
2013-07-26 18:52:11 +01:00
// if our current target is running away, switch targets
this . ship . target = whom ;
2013-07-12 23:00:39 +01:00
}
2013-07-26 18:52:11 +01:00
else if ( this . ship . target . target != this . ship )
2013-07-15 23:14:47 +01:00
{
2013-07-26 18:52:11 +01:00
// if our current target isn't aiming at us
if ( Math . random ( ) < 0.2 )
2013-07-15 23:14:47 +01:00
{
2013-07-26 18:52:11 +01:00
// occasionally switch
2013-07-15 23:14:47 +01:00
this . ship . target = whom ;
}
}
2013-07-26 18:52:11 +01:00
}
2013-07-15 23:14:47 +01:00
2013-07-26 18:52:11 +01:00
if ( this . ship . escortGroup != null )
2013-07-12 23:00:39 +01:00
{
2013-07-26 18:52:11 +01:00
this . ship . requestHelpFromGroup ( ) ;
}
} ;
handlers . shipBeingAttackedUnsuccessfully = function ( whom )
{
if ( ! this . ship . hasHostileTarget && this . getParameter ( "oolite_flag_sendsDistressCalls" ) )
{
this . ship . broadcastDistressMessage ( ) ;
}
if ( this . ship . defenseTargets . indexOf ( whom ) < 0 )
{
this . ship . addDefenseTarget ( whom ) ;
this . reconsiderNow ( ) ;
}
} ;
handlers . shipTargetLost = function ( target )
{
this . reconsiderNow ( ) ;
} ;
// overridden for escorts
handlers . helpRequestReceived = function ( ally , enemy )
{
this . ship . addDefenseTarget ( enemy ) ;
if ( ! this . ship . hasHostileTarget )
2013-07-12 23:00:39 +01:00
{
2013-07-13 19:13:30 +01:00
this . reconsiderNow ( ) ;
2013-07-26 18:52:11 +01:00
return ; // not in a combat mode
}
if ( ally . energy / ally . maxEnergy < this . ship . energy / this . ship . maxEnergy )
2013-07-13 11:36:28 +01:00
{
2013-07-26 18:52:11 +01:00
// not in worse shape than ally
if ( this . ship . target . target != ally && this . ship . target != ally . target )
2013-07-13 11:36:28 +01:00
{
2013-07-26 18:52:11 +01:00
// not already helping, go for it...
this . ship . target = enemy ;
2013-07-15 23:14:47 +01:00
this . reconsiderNow ( ) ;
2013-07-13 11:36:28 +01:00
}
}
2013-07-26 18:52:11 +01:00
}
handlers . cargoDumpedNearby = function ( cargo , ship )
{
if ( this . getParameter ( "oolite_flag_watchForCargo" ) )
2013-07-14 23:11:25 +01:00
{
2013-07-26 18:52:11 +01:00
var previously = this . getParameter ( "oolite_cargoDropped" ) ;
if ( previously == null )
2013-07-14 23:11:25 +01:00
{
2013-07-26 18:52:11 +01:00
previously = 0 ;
2013-07-14 23:11:25 +01:00
}
2013-07-26 18:52:11 +01:00
previously ++ ;
this . setParameter ( "oolite_cargoDropped" , previously ) ;
}
}
handlers . approachingPlanetSurface = function ( )
{
if ( this . getParameter ( "oolite_flag_allowPlanetaryLanding" ) )
{
this . ship . desiredSpeed = this . ship . maxSpeed / 4 ;
this . ship . performLandOnPlanet ( ) ;
this . ship . AIScriptWakeTime = 0 ; // cancel reconsiderations
2013-07-27 12:29:59 +01:00
this . applyHandlers ( { } ) ; // cancel interruptions
2013-07-26 18:52:11 +01:00
this . communicate ( "oolite_landingOnPlanet" ) ;
}
else
{
this . reconsiderNow ( ) ;
}
}
handlers . shipLaunchedFromStation = function ( station )
{
// clear the station
this . ship . destination = station . position ;
this . ship . desiredSpeed = this . cruiseSpeed ( ) ;
this . ship . desiredRange = 15000 ;
this . ship . performFlyToRangeFromDestination ( ) ;
}
handlers . shipWillEnterWormhole = function ( )
{
2013-07-27 12:29:59 +01:00
this . applyHandlers ( { } ) ;
2013-07-26 18:52:11 +01:00
}
handlers . shipExitedWormhole = function ( )
{
this . ship . AIScript . oolite _intership = { } ;
// this.reconsiderNow();
}
handlers . distressMessageReceived = function ( aggressor , sender )
{
if ( this . getParameter ( "oolite_flag_listenForDistressCall" ) != true )
{
return ;
2013-07-14 23:11:25 +01:00
}
2013-07-26 18:52:11 +01:00
this . setParameter ( "oolite_distressAggressor" , aggressor ) ;
this . setParameter ( "oolite_distressSender" , sender ) ;
this . setParameter ( "oolite_distressTimestamp" , clock . adjustedSeconds ) ;
this . reconsiderNow ( ) ;
}
handlers . offenceCommittedNearby = function ( attacker , victim )
{
if ( this . getParameter ( "oolite_flag_markOffenders" ) )
{
attacker . setBounty ( attacker . bounty | 7 , "seen by police" ) ;
this . ship . addDefenseTarget ( attacker ) ;
this . reconsiderNow ( ) ;
}
}
handlers . playerWillEnterWitchspace = function ( )
{
var wormhole = this . getParameter ( "oolite_witchspaceWormhole" ) ;
if ( wormhole != null )
{
this . ship . enterWormhole ( wormhole ) ;
}
}
handlers . wormholeSuggested = function ( hole )
{
this . setParameter ( "oolite_witchspaceWormhole" , hole ) ;
this . reconsiderNow ( ) ;
}
// TODO: more event handlers
}
/* Additional handlers for use while docking */
AILib . prototype . responsesAddDocking = function ( handlers )
{
handlers . stationWithdrewDockingClearance = function ( )
{
this . setParameter ( "oolite_dockingStation" , null ) ;
this . reconsiderNow ( ) ;
} ;
handlers . shipAchievedDesiredRange = function ( )
{
var message = this . ship . dockingInstructions . ai _message ;
if ( message == "APPROACH" || message == "BACK_OFF" || message == "APPROACH_COORDINATES" )
{
this . reconsiderNow ( ) ;
}
} ;
}
/* Override of standard handlers for use while escorting */
AILib . prototype . responsesAddEscort = function ( handlers )
{
handlers . helpRequestReceived = function ( ally , enemy )
{
// always help the leader
if ( ally == this . ship . group . leader )
2013-07-13 11:36:28 +01:00
{
2013-07-26 18:52:11 +01:00
if ( ! this . ship . target || this . ship . target . target != ally )
2013-07-21 23:25:41 +01:00
{
2013-07-26 18:52:11 +01:00
this . ship . target = enemy ;
this . reconsiderNow ( ) ;
return ;
2013-07-21 23:25:41 +01:00
}
2013-07-26 18:52:11 +01:00
}
this . ship . addDefenseTarget ( enemy ) ;
if ( ! this . ship . hasHostileTarget )
{
this . reconsiderNow ( ) ;
return ; // not in a combat mode
}
if ( ally . energy / ally . maxEnergy < this . ship . energy / this . ship . maxEnergy )
{
// not in worse shape than ally
if ( this . ship . target . target != ally && this . ship . target != ally . target )
2013-07-21 23:25:41 +01:00
{
2013-07-26 18:52:11 +01:00
// not already helping, go for it...
this . ship . target = enemy ;
2013-07-21 23:25:41 +01:00
this . reconsiderNow ( ) ;
}
2013-07-13 19:13:30 +01:00
}
2013-07-26 18:52:11 +01:00
}
handlers . escortDock = function ( )
{
this . reconsiderNow ( ) ;
}
}
/* Additional handlers for scooping */
AILib . prototype . responsesAddScooping = function ( handlers )
{
handlers . shipAchievedDesiredRange = function ( )
{
this . reconsiderNow ( ) ;
}
handlers . shipScoopedFuel = function ( )
{
if ( this . ship . fuel == 7 )
{
this . reconsiderNow ( ) ;
}
}
}
// shorter list than before
AILib . prototype . responsesAddStation = function ( handlers )
{
handlers . cascadeWeaponDetected = function ( weapon )
{
this . ship . alertCondition = 3 ;
this . reconsiderNow ( ) ;
} ;
handlers . shipAttackedWithMissile = function ( missile , whom )
{
this . ship . alertCondition = 3 ;
if ( this . ship . equipmentStatus ( "EQ_ECM" ) == "EQUIPMENT_OK" )
2013-07-13 23:18:05 +01:00
{
2013-07-26 18:52:11 +01:00
this . ship . fireECM ( ) ;
this . ship . addDefenseTarget ( missile ) ;
this . ship . addDefenseTarget ( whom ) ;
// but don't reconsider immediately
2013-07-13 23:18:05 +01:00
}
2013-07-26 18:52:11 +01:00
else
2013-07-14 21:28:19 +01:00
{
2013-07-26 18:52:11 +01:00
this . ship . addDefenseTarget ( missile ) ;
this . ship . addDefenseTarget ( whom ) ;
var tmp = this . ship . target ;
this . ship . target = whom ;
this . ship . requestHelpFromGroup ( ) ;
this . ship . target = tmp ;
this . reconsiderNow ( ) ;
2013-07-14 21:28:19 +01:00
}
2013-07-26 18:52:11 +01:00
} ;
handlers . shipBeingAttacked = function ( whom )
{
if ( ! whom )
2013-07-13 23:18:05 +01:00
{
2013-07-26 18:52:11 +01:00
this . reconsiderNow ( ) ;
return ;
2013-07-13 23:18:05 +01:00
}
2013-07-26 18:52:11 +01:00
if ( whom . target != this . ship && whom != player . ship )
2013-07-13 19:13:30 +01:00
{
2013-07-26 18:52:11 +01:00
// was accidental
if ( this . allied ( whom , this . ship ) )
2013-07-13 19:13:30 +01:00
{
2013-07-26 18:52:11 +01:00
this . communicate ( "oolite_friendlyFire" , whom . displayName ) ;
// ignore it
2013-07-13 19:13:30 +01:00
return ;
}
2013-07-26 18:52:11 +01:00
if ( Math . random ( ) > 0.1 )
2013-07-19 20:18:53 +01:00
{
2013-07-26 18:52:11 +01:00
// usually ignore it anyway
return ;
2013-07-19 20:18:53 +01:00
}
}
2013-07-26 18:52:11 +01:00
this . ship . alertCondition = 3 ;
if ( this . ship . defenseTargets . indexOf ( whom ) < 0 )
2013-07-13 23:18:05 +01:00
{
2013-07-26 18:52:11 +01:00
this . ship . addDefenseTarget ( whom ) ;
2013-07-13 23:18:05 +01:00
this . reconsiderNow ( ) ;
}
2013-07-26 18:52:11 +01:00
else
2013-07-12 23:00:39 +01:00
{
2013-07-26 18:52:11 +01:00
// else we know about this attacker already
if ( this . ship . energy * 4 < this . ship . maxEnergy )
2013-07-12 23:00:39 +01:00
{
2013-07-26 18:52:11 +01:00
// but at low energy still reconsider
2013-07-13 19:13:30 +01:00
this . reconsiderNow ( ) ;
2013-07-26 18:52:11 +01:00
this . ship . requestHelpFromGroup ( ) ;
2013-07-12 23:00:39 +01:00
}
2013-07-26 18:52:11 +01:00
}
if ( this . ship . hasHostileTarget )
2013-07-13 23:18:05 +01:00
{
2013-07-26 18:52:11 +01:00
if ( ! this . isAggressive ( this . ship . target ) )
2013-07-13 23:18:05 +01:00
{
2013-07-26 18:52:11 +01:00
// if our current target is running away, switch targets
this . ship . target = whom ;
2013-07-13 23:18:05 +01:00
}
2013-07-26 18:52:11 +01:00
else if ( this . ship . target . target != this . ship )
2013-07-13 23:18:05 +01:00
{
2013-07-26 18:52:11 +01:00
// if our current target isn't aiming at us
if ( Math . random ( ) < 0.2 )
2013-07-13 23:18:05 +01:00
{
2013-07-26 18:52:11 +01:00
// occasionally switch
this . ship . target = whom ;
2013-07-13 23:18:05 +01:00
}
}
}
2013-07-26 18:52:11 +01:00
} ;
handlers . shipTargetLost = function ( target )
{
this . reconsiderNow ( ) ;
} ;
handlers . helpRequestReceived = function ( ally , enemy )
{
this . ship . addDefenseTarget ( enemy ) ;
if ( ! this . ship . alertCondition == 3 )
2013-07-13 23:18:05 +01:00
{
2013-07-26 18:52:11 +01:00
this . ship . target = enemy ;
2013-07-13 23:18:05 +01:00
this . reconsiderNow ( ) ;
2013-07-26 18:52:11 +01:00
return ; // not in a combat mode
2013-07-13 23:18:05 +01:00
}
2013-07-26 18:52:11 +01:00
this . ship . target = enemy ;
2013-07-12 23:00:39 +01:00
}
2013-07-12 19:44:14 +01:00
2013-07-26 18:52:11 +01:00
handlers . distressMessageReceived = function ( aggressor , sender )
2013-07-14 19:02:16 +01:00
{
2013-07-26 18:52:11 +01:00
if ( this . getParameter ( "oolite_flag_listenForDistressCall" ) != true )
2013-07-14 19:02:16 +01:00
{
2013-07-26 18:52:11 +01:00
return ;
2013-07-14 19:02:16 +01:00
}
2013-07-26 18:52:11 +01:00
this . setParameter ( "oolite_distressAggressor" , aggressor ) ;
this . setParameter ( "oolite_distressSender" , sender ) ;
this . setParameter ( "oolite_distressTimestamp" , clock . adjustedSeconds ) ;
this . reconsiderNow ( ) ;
}
handlers . offenceCommittedNearby = function ( attacker , victim )
{
if ( this . getParameter ( "oolite_flag_markOffenders" ) )
2013-07-14 19:02:16 +01:00
{
2013-07-26 18:52:11 +01:00
attacker . setBounty ( attacker . bounty | 7 , "seen by police" ) ;
this . ship . addDefenseTarget ( attacker ) ;
if ( this . ship . alertCondition < 3 )
2013-07-14 19:02:16 +01:00
{
2013-07-26 18:52:11 +01:00
this . ship . alertCondition = 3 ;
this . ship . target = attacker ;
2013-07-14 19:02:16 +01:00
}
2013-07-26 18:52:11 +01:00
this . reconsiderNow ( ) ;
2013-07-14 19:02:16 +01:00
}
}
2013-07-26 18:52:11 +01:00
}
2013-07-12 19:44:14 +01:00
2013-07-23 21:21:49 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . responsesAddMissile = function ( handlers ) {
handlers . shipHitByECM = function ( )
{
if ( this . ship . scriptInfo . oolite _missile _ecmResponse )
2013-07-23 21:21:49 +01:00
{
2013-07-26 18:52:11 +01:00
var fn = this . ship . scriptInfo . oolite _missile _ecmResponse ;
if ( this . ship . AIScript [ fn ] )
2013-07-23 21:21:49 +01:00
{
2013-07-26 18:52:11 +01:00
this . ship . AIScript [ fn ] ( ) ;
2013-07-23 21:21:49 +01:00
this . reconsiderNow ( ) ;
2013-07-26 18:52:11 +01:00
return ;
2013-07-23 21:21:49 +01:00
}
2013-07-26 18:52:11 +01:00
if ( this . ship . script [ fn ] )
2013-07-25 18:31:14 +01:00
{
2013-07-26 18:52:11 +01:00
this . ship . script [ fn ] ( ) ;
2013-07-25 18:31:14 +01:00
this . reconsiderNow ( ) ;
return ;
}
2013-07-26 18:52:11 +01:00
}
/ * T h i s s e c t i o n f o r t h e h a r d h e a d s s h o u l d b e a n E C M
* response function , and that is used in the default
* shipdata . plist , but for compatibility with older OXPs
* it ' s also hardcoded here for now .
*
* OXPs wanting to overrule this for hardheads can set a
* response function to do so .
* /
if ( this . ship . primaryRole == "EQ_HARDENED_MISSILE" )
{
if ( Math . random ( ) < 0.1 ) //10% chance per pulse
2013-07-23 21:21:49 +01:00
{
2013-07-26 18:52:11 +01:00
if ( Math . random ( ) < 0.5 )
2013-07-23 21:21:49 +01:00
{
2013-07-26 18:52:11 +01:00
// 50% chance responds by detonation
this . ship . AIScript . shipAchievedDesiredRange ( ) ;
2013-07-23 21:21:49 +01:00
return ;
}
2013-07-26 18:52:11 +01:00
// otherwise explode as normal below
2013-07-23 21:21:49 +01:00
}
2013-07-26 18:52:11 +01:00
else // 90% chance unaffected
2013-07-23 21:21:49 +01:00
{
2013-07-26 18:52:11 +01:00
return ;
2013-07-23 21:21:49 +01:00
}
2013-07-26 18:52:11 +01:00
}
2013-07-23 21:21:49 +01:00
2013-07-26 18:52:11 +01:00
this . ship . explode ( ) ;
}
handlers . shipTargetCloaked = function ( )
{
this . setParameter ( "oolite_interceptCoordinates" , this . ship . target . position ) ;
this . setParameter ( "oolite_interceptTarget" , this . ship . target ) ;
// stops performIntercept sending AchievedDesiredRange
this . ship . performIdle ( ) ;
}
handlers . shipTargetLost = function ( )
{
this . reconsiderNow ( ) ;
}
handlers . shipAchievedDesiredRange = function ( )
{
if ( this . ship . scriptInfo . oolite _missile _detonation )
2013-07-23 21:21:49 +01:00
{
2013-07-26 18:52:11 +01:00
var fn = this . ship . scriptInfo . oolite _missile _detonation ;
if ( this . ship . AIScript [ fn ] )
2013-07-23 21:21:49 +01:00
{
2013-07-26 18:52:11 +01:00
this . ship . AIScript [ fn ] ( ) ;
2013-07-23 21:21:49 +01:00
this . reconsiderNow ( ) ;
2013-07-26 18:52:11 +01:00
return ;
2013-07-23 21:21:49 +01:00
}
2013-07-26 18:52:11 +01:00
if ( this . ship . script [ fn ] )
2013-07-23 21:21:49 +01:00
{
2013-07-26 18:52:11 +01:00
this . ship . script [ fn ] ( ) ;
this . reconsiderNow ( ) ;
2013-07-23 21:21:49 +01:00
return ;
}
}
2013-07-26 18:52:11 +01:00
/ * D e f a u l t s t o s t a n d a r d m i s s i l e s e t t i n g s , i n c a s e t h e y ' r e
* not specified in scriptInfo * /
var blastpower = 170 ;
var blastradius = 32.5 ;
var blastshaping = 0.25 ;
if ( this . ship . scriptInfo . oolite _missile _blastPower )
2013-07-23 21:21:49 +01:00
{
2013-07-26 18:52:11 +01:00
blastpower = this . ship . scriptInfo . oolite _missile _blastPower ;
}
if ( this . ship . scriptInfo . oolite _missile _blastRadius )
{
blastradius = this . ship . scriptInfo . oolite _missile _blastRadius ;
}
if ( this . ship . scriptInfo . oolite _missile _blastShaping )
{
blastshaping = this . ship . scriptInfo . oolite _missile _blastShaping ;
2013-07-23 21:21:49 +01:00
}
2013-07-26 18:52:11 +01:00
this . ship . dealEnergyDamage ( blastpower , blastradius , blastshaping ) ;
this . ship . explode ( ) ;
2013-07-23 21:21:49 +01:00
}
2013-07-26 18:52:11 +01:00
}
2013-07-23 21:21:49 +01:00
2013-07-24 21:56:50 +01:00
2013-07-26 18:52:11 +01:00
/* ******************* Waypoint generators *********************** */
/ * W a y p o i n t g e n e r a t o r s . W h e n t h e s e a r e c a l l e d , t h e y s h o u l d s e t u p
* the next waypoint for the ship . Ideally ships should either
* reach that waypoint or formally give up on it before asking for
* the next one , but the generator shouldn ' t assume that unless
* it ' s one written specifically for a particular AI . * /
2013-07-24 21:56:50 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . waypointsSpacelanePatrol = 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" ;
2013-07-24 21:56:50 +01:00
}
2013-07-26 18:52:11 +01:00
else
2013-07-24 21:56:50 +01:00
{
2013-07-26 18:52:11 +01:00
choice = "SUN" ;
2013-07-24 21:56:50 +01:00
}
2013-07-26 18:52:11 +01:00
}
else if ( p . distanceTo ( system . mainPlanet ) < system . mainPlanet . radius * 2 )
{
// near planet
if ( Math . random ( ) < 0.75 )
{
// mostly go to witchpoint
choice = "WITCHPOINT" ;
2013-07-24 21:56:50 +01:00
}
2013-07-26 18:52:11 +01:00
else
2013-07-24 21:56:50 +01:00
{
2013-07-26 18:52:11 +01:00
choice = "SUN" ;
2013-07-24 21:56:50 +01:00
}
}
2013-07-26 18:52:11 +01:00
else if ( p . distanceTo ( system . sun ) < system . sun . radius * 3 )
2013-07-19 20:18:53 +01:00
{
2013-07-26 18:52:11 +01:00
// near sun
if ( Math . random ( ) < 0.9 )
{
// mostly return to planet
choice = "PLANET" ;
}
else
2013-07-19 20:18:53 +01:00
{
2013-07-26 18:52:11 +01:00
choice = "SUN" ;
2013-07-19 20:18:53 +01:00
}
2013-07-26 18:52:11 +01:00
}
2013-07-27 12:29:59 +01:00
else if ( p . z < system . mainPlanet . position . z && ( ( p . x * p . x ) + ( p . y * p . y ) ) < this . ship . scannerRange * this . ship . scannerRange * 4 )
2013-07-26 18:52:11 +01:00
{
// on lane 1
if ( Math . random ( ) < 0.5 )
2013-07-19 20:18:53 +01:00
{
2013-07-26 18:52:11 +01:00
choice = "PLANET" ;
2013-07-19 20:18:53 +01:00
}
2013-07-26 18:52:11 +01:00
else
2013-07-19 20:18:53 +01:00
{
2013-07-26 18:52:11 +01:00
choice = "WITCHPOINT" ;
2013-07-19 20:18:53 +01:00
}
2013-07-26 18:52:11 +01:00
}
else if ( p . subtract ( system . mainPlanet ) . dot ( p . subtract ( system . sun ) ) < - 0.9 )
{
// on lane 2
if ( Math . random ( ) < 0.5 )
2013-07-19 20:18:53 +01:00
{
2013-07-26 18:52:11 +01:00
choice = "PLANET" ;
2013-07-19 20:18:53 +01:00
}
2013-07-26 18:52:11 +01:00
else
2013-07-19 20:18:53 +01:00
{
2013-07-26 18:52:11 +01:00
choice = "SUN" ;
2013-07-19 20:18:53 +01:00
}
2013-07-26 18:52:11 +01:00
}
else if ( p . dot ( system . sun . position ) > 0.9 )
{
// on lane 3
if ( Math . random ( ) < 0.5 )
2013-07-19 20:18:53 +01:00
{
2013-07-26 18:52:11 +01:00
choice = "WITCHPOINT" ;
2013-07-19 20:18:53 +01:00
}
else
{
2013-07-26 18:52:11 +01:00
choice = "SUN" ;
2013-07-19 20:18:53 +01:00
}
2013-07-26 18:52:11 +01:00
}
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_waypoint" , new Vector3D ( 0 , 0 , 0 ) ) ;
this . setParameter ( "oolite_waypointRange" , 7500 ) ;
break ;
case "PLANET" :
this . setParameter ( "oolite_waypoint" , system . mainPlanet . position ) ;
this . setParameter ( "oolite_waypointRange" , system . mainPlanet . radius * 2 ) ;
break ;
case "SUN" :
this . setParameter ( "oolite_waypoint" , system . sun . position ) ;
this . setParameter ( "oolite_waypointRange" , system . sun . radius * 2.5 ) ;
break ;
2013-07-19 20:18:53 +01:00
}
2013-07-26 18:52:11 +01:00
}
2013-07-19 20:18:53 +01:00
2013-07-26 18:52:11 +01:00
AILib . prototype . waypointsStationPatrol = function ( )
{
var station = null ;
if ( this . ship . group )
2013-07-19 20:18:53 +01:00
{
2013-07-26 18:52:11 +01:00
station = this . ship . group . leader ;
}
if ( ! station )
{
station = system . mainStation ;
2013-07-19 20:18:53 +01:00
if ( ! station )
{
2013-07-26 18:52:11 +01:00
this . setParameter ( "oolite_waypoint" , new Vector3D ( 0 , 0 , 0 ) ) ;
this . setParameter ( "oolite_waypointRange" , 7500 ) ;
return ;
2013-07-20 09:14:58 +01:00
}
2013-07-26 18:52:11 +01:00
}
var z = station . vectorForward ;
var tmp = new Vector3D ( 0 , 1 , 0 ) ;
if ( system . sun )
{
tmp = z . cross ( system . sun . position . direction ( ) ) ;
}
var x = z . cross ( tmp ) ;
var y = z . cross ( x ) ;
// x and y now consistent vectors relative to a rotating station
2013-07-19 20:18:53 +01:00
2013-07-26 18:52:11 +01:00
var waypoints = [
station . position . add ( x . multiply ( 25000 ) ) ,
station . position . add ( y . multiply ( 25000 ) ) ,
station . position . add ( x . multiply ( - 25000 ) ) ,
station . position . add ( y . multiply ( - 25000 ) )
] ;
var waypoint = waypoints [ 0 ] ;
for ( var i = 0 ; i <= 3 ; i ++ )
{
if ( this . ship . position . distanceTo ( waypoints [ i ] ) < 500 )
2013-07-19 20:18:53 +01:00
{
2013-07-26 18:52:11 +01:00
waypoint = waypoints [ ( i + 1 ) % 4 ] ;
break ;
2013-07-19 20:18:53 +01:00
}
}
2013-07-26 18:52:11 +01:00
this . setParameter ( "oolite_waypoint" , waypoint ) ;
this . setParameter ( "oolite_waypointRange" , 100 ) ;
}