Add escortAI, update and debug AI library, system.stations property
This commit is contained in:
parent
eea8c6843d
commit
0e69dae8f4
@ -30,7 +30,7 @@ this.name = "Oolite Bounty Hunter AI";
|
|||||||
this.version = "1.79";
|
this.version = "1.79";
|
||||||
|
|
||||||
this.aiStarted = function() {
|
this.aiStarted = function() {
|
||||||
this.ai = new worldScripts["oolite-libPriorityAI"].AILib(this.ship);
|
var ai = new worldScripts["oolite-libPriorityAI"].AILib(this.ship);
|
||||||
|
|
||||||
ai.setParameter("oolite_flag_listenForDistressCall",true);
|
ai.setParameter("oolite_flag_listenForDistressCall",true);
|
||||||
|
|
||||||
|
115
Resources/AIs/escortAI.js
Normal file
115
Resources/AIs/escortAI.js
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
escortAI.js
|
||||||
|
|
||||||
|
Priority-based AI for escorts
|
||||||
|
|
||||||
|
Oolite
|
||||||
|
Copyright © 2004-2013 Giles C Williams and contributors
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||||
|
MA 02110-1301, USA.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
this.name = "Oolite Escort AI";
|
||||||
|
this.version = "1.79";
|
||||||
|
|
||||||
|
this.aiStarted = function() {
|
||||||
|
var ai = new worldScripts["oolite-libPriorityAI"].AILib(this.ship);
|
||||||
|
|
||||||
|
ai.setPriorities([
|
||||||
|
{
|
||||||
|
condition: ai.conditionLosingCombat,
|
||||||
|
behaviour: ai.behaviourFleeCombat,
|
||||||
|
reconsider: 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
condition: ai.conditionMothershipInCombat,
|
||||||
|
truebranch: [
|
||||||
|
{
|
||||||
|
condition: ai.conditionMothershipUnderAttack,
|
||||||
|
configuration: ai.configurationAcquireDefensiveEscortTarget,
|
||||||
|
behaviour: ai.behaviourRepelCurrentTarget,
|
||||||
|
reconsider: 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
condition: ai.conditionMothershipIsAttacking,
|
||||||
|
configuration: ai.configurationAcquireOffensiveEscortTarget,
|
||||||
|
behaviour: ai.behaviourDestroyCurrentTarget,
|
||||||
|
reconsider: 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
behaviour: ai.behaviourRejoinMothership,
|
||||||
|
reconsider: 5
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// if we're in combat but mothership isn't, then we need
|
||||||
|
// to finish this fight off and get back to them
|
||||||
|
condition: ai.conditionInCombat,
|
||||||
|
configuration: ai.configurationAcquireCombatTarget,
|
||||||
|
behaviour: ai.behaviourRepelCurrentTarget,
|
||||||
|
reconsider: 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
condition: ai.conditionHasMothership,
|
||||||
|
behaviour: ai.behaviourEscortMothership,
|
||||||
|
reconsider: 60
|
||||||
|
},
|
||||||
|
/* Don't have a mothership */
|
||||||
|
{
|
||||||
|
condition: ai.conditionWitchspaceEntryRequested,
|
||||||
|
behaviour: ai.behaviourEnterWitchspace,
|
||||||
|
reconsider: 15
|
||||||
|
},
|
||||||
|
/* And it's not because they've recently jumped out */
|
||||||
|
{
|
||||||
|
condition: ai.conditionFriendlyStationNearby,
|
||||||
|
configuration: ai.configurationSetNearbyFriendlyStationForDocking,
|
||||||
|
behaviour: ai.behaviourDockWithStation,
|
||||||
|
reconsider: 30
|
||||||
|
},
|
||||||
|
/* And it's not because they just docked either */
|
||||||
|
{
|
||||||
|
preconfiguration: ai.configurationCheckScanner,
|
||||||
|
condition: ai.conditionScannerContainsShipNeedingEscort,
|
||||||
|
behaviour: ai.behaviourOfferToEscort,
|
||||||
|
reconsider: 15
|
||||||
|
},
|
||||||
|
{
|
||||||
|
condition: ai.conditionFriendlyStationExists,
|
||||||
|
configuration: ai.configurationSetDestinationToNearestFriendlyStation,
|
||||||
|
behaviour: ai.behaviourApproachDestination,
|
||||||
|
reconsider: 30
|
||||||
|
},
|
||||||
|
/* No friendly stations and no nearby ships needing escort */
|
||||||
|
{
|
||||||
|
condition: ai.conditionCanWitchspaceOut,
|
||||||
|
configuration: ai.configurationSelectWitchspaceDestination,
|
||||||
|
behaviour: ai.behaviourEnterWitchspace,
|
||||||
|
reconsider: 20
|
||||||
|
},
|
||||||
|
/* And we're stuck here */
|
||||||
|
{
|
||||||
|
configuration: ai.configurationSetDestinationToWitchpoint,
|
||||||
|
behaviour: ai.approachDestination,
|
||||||
|
reconsider: 30
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
}
|
@ -230,6 +230,37 @@ this.AILib = function(ship)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.friendlyStation = function(station)
|
||||||
|
{
|
||||||
|
return (station.target != this.ship || !station.hasHostileTarget);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.cruiseSpeed = function()
|
||||||
|
{
|
||||||
|
var cruise = this.ship.maxSpeed * 0.8;
|
||||||
|
if (this.ship.group)
|
||||||
|
{
|
||||||
|
for (var i = 0 ; i < this.ship.group.ships.length ; i++)
|
||||||
|
{
|
||||||
|
if (cruise > this.ship.group.ships[i].maxSpeed)
|
||||||
|
{
|
||||||
|
cruise = this.ship.group.ships[i].maxSpeed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.ship.escortGroup)
|
||||||
|
{
|
||||||
|
for (var i = 0 ; i < this.ship.escortGroup.ships.length ; i++)
|
||||||
|
{
|
||||||
|
if (cruise > this.ship.escortGroup.ships[i].maxSpeed)
|
||||||
|
{
|
||||||
|
cruise = this.ship.escortGroup.ships[i].maxSpeed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cruise;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ****************** Condition functions ************** */
|
/* ****************** Condition functions ************** */
|
||||||
|
|
||||||
@ -324,6 +355,82 @@ this.AILib = function(ship)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.conditionHasMothership = function()
|
||||||
|
{
|
||||||
|
return (this.ship.group && this.ship.group.leader != this.ship && this.ship.group.leader.escortGroup.containsShip(this.ship));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.conditionMothershipInCombat = function()
|
||||||
|
{
|
||||||
|
if (this.ship.group && this.ship.group.leader != this.ship && this.ship.group.leader.escortGroup.containsShip(this.ship))
|
||||||
|
{
|
||||||
|
var leader = this.ship.group.leader;
|
||||||
|
if (leader.position.distanceTo(this.ship) > this.ship.scannerRange)
|
||||||
|
{
|
||||||
|
return false; // can't tell
|
||||||
|
}
|
||||||
|
if (leader.hasHostileTarget)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (leader.target && leader.target.target == leader && leader.target.hasHostileTarget)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
var dts = leader.defenseTargets;
|
||||||
|
for (var i = 0 ; i < dts.length ; i++)
|
||||||
|
{
|
||||||
|
if (dts[i].target == leader && dts[i].hasHostileTarget)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// no mothership
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.conditionMothershipUnderAttack = function()
|
||||||
|
{
|
||||||
|
if (this.ship.group && this.ship.group.leader != this.ship && this.ship.group.leader.escortGroup.containsShip(this.ship))
|
||||||
|
{
|
||||||
|
var leader = this.ship.group.leader;
|
||||||
|
if (leader.target.target == leader && leader.target.hasHostileTarget && leader.target.position.distanceTo(this.ship) < this.ship.scannerRange)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
var dts = leader.defenseTargets;
|
||||||
|
for (var i = 0 ; i < dts.length ; i++)
|
||||||
|
{
|
||||||
|
if (dts[i].target == leader && dts[i].hasHostileTarget && dts[i].position.distanceTo(this.ship) < this.ship.scannerRange)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.conditionMothershipIsAttacking = function()
|
||||||
|
{
|
||||||
|
if (this.ship.group && this.ship.group.leader != this.ship && this.ship.group.leader.escortGroup.containsShip(this.ship))
|
||||||
|
{
|
||||||
|
var leader = this.ship.group.leader;
|
||||||
|
if (leader.target && leader.hasHostileTarget && leader.target.position.distanceTo(this.ship) < this.ship.scannerRange)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
this.conditionNearDestination = function()
|
this.conditionNearDestination = function()
|
||||||
{
|
{
|
||||||
@ -348,7 +455,7 @@ this.AILib = function(ship)
|
|||||||
|
|
||||||
this.conditionScannerContainsSalvage = function()
|
this.conditionScannerContainsSalvage = function()
|
||||||
{
|
{
|
||||||
if (this.ship.cargoSpaceAvailable == 0)
|
if (this.ship.cargoSpaceAvailable == 0 || this.ship.equipmentStatus("EQ_FUEL_SCOOPS") != "EQUIPMENT_OK")
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -381,6 +488,71 @@ this.AILib = function(ship)
|
|||||||
return system.isInterstellarSpace;
|
return system.isInterstellarSpace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.conditionWitchspaceEntryRequested = function()
|
||||||
|
{
|
||||||
|
return (this.getParameter("oolite_witchspaceWormhole") != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.conditionFriendlyStationNearby = function()
|
||||||
|
{
|
||||||
|
var stations = system.stations;
|
||||||
|
for (var i = 0 ; i < stations.length ; i++)
|
||||||
|
{
|
||||||
|
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
|
||||||
|
if (station.position.distanceTo(this.ship) < this.ship.scannerRange)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.conditionFriendlyStationExists = function()
|
||||||
|
{
|
||||||
|
var stations = system.stations;
|
||||||
|
for (var i = 0 ; i < stations.length ; i++)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.conditionScannerContainsShipNeedingEscort = function()
|
||||||
|
{
|
||||||
|
if (this.ship.bounty == 0)
|
||||||
|
{
|
||||||
|
return this.checkScannerWithPredicate(function(s) {
|
||||||
|
return s.bounty == 0 && (!s.escortGroup || s.escortGroup.count <= s.maxEscorts);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return this.checkScannerWithPredicate(function(s) {
|
||||||
|
return s.bounty > 0 && (!s.escortGroup || s.escortGroup.count <= s.maxEscorts);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.conditionCanWitchspaceOut = function()
|
||||||
|
{
|
||||||
|
if (!this.ship.hasHyperspaceMotor)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return (system.info.systemsInRange(this.ship.fuel).length > 0);
|
||||||
|
}
|
||||||
|
|
||||||
/* ****************** Behaviour functions ************** */
|
/* ****************** Behaviour functions ************** */
|
||||||
|
|
||||||
/* Behaviours. Behaviours are effectively a state definition,
|
/* Behaviours. Behaviours are effectively a state definition,
|
||||||
@ -444,6 +616,30 @@ this.AILib = function(ship)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
this.behaviourRepelCurrentTarget = function()
|
||||||
|
{
|
||||||
|
var handlers = {};
|
||||||
|
this.responsesAddStandard(handlers);
|
||||||
|
this.setUpHandlers(handlers);
|
||||||
|
if (this.ship.target.isFleeing || this.ship.target.isDerelict)
|
||||||
|
{
|
||||||
|
// repelling succeeded
|
||||||
|
this.ship.removeDefenseTarget(this.ship.target);
|
||||||
|
this.ship.target = null;
|
||||||
|
this.reconsiderNow();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!this.ship.hasHostileTarget)
|
||||||
|
{
|
||||||
|
// entering attack mode
|
||||||
|
this.communicate("oolite_beginningAttack",this.ship.target.displayName);
|
||||||
|
}
|
||||||
|
this.ship.performAttack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
this.behaviourCollectSalvage = function()
|
this.behaviourCollectSalvage = function()
|
||||||
{
|
{
|
||||||
var handlers = {};
|
var handlers = {};
|
||||||
@ -609,6 +805,15 @@ this.AILib = function(ship)
|
|||||||
// the wormhole we were trying for has expired
|
// the wormhole we were trying for has expired
|
||||||
this.setParameter("oolite_witchspaceWormhole",null);
|
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();
|
||||||
|
this.setUpHandlers(handlers);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var destID = this.getParameter("oolite_witchspaceDestination");
|
var destID = this.getParameter("oolite_witchspaceDestination");
|
||||||
if (destID == null)
|
if (destID == null)
|
||||||
@ -645,7 +850,7 @@ this.AILib = function(ship)
|
|||||||
{
|
{
|
||||||
this.ship.setDestination = blocker.position;
|
this.ship.setDestination = blocker.position;
|
||||||
this.ship.setDesiredRange = 30000;
|
this.ship.setDesiredRange = 30000;
|
||||||
this.ship.setDesiredSpeed = this.ship.maxSpeed;
|
this.ship.setDesiredSpeed = this.cruiseSpeed();
|
||||||
this.ship.performFlyToRangeFromDestination();
|
this.ship.performFlyToRangeFromDestination();
|
||||||
// no reconsidering yet
|
// no reconsidering yet
|
||||||
}
|
}
|
||||||
@ -661,6 +866,56 @@ this.AILib = function(ship)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
this.behaviourEscortMothership = function()
|
||||||
|
{
|
||||||
|
var handlers = {};
|
||||||
|
this.responsesAddStandard(handlers);
|
||||||
|
this.responsesAddEscort(handlers);
|
||||||
|
this.setUpHandlers(handlers);
|
||||||
|
this.ship.desiredRange = 0;
|
||||||
|
this.ship.performEscort();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Separate behaviour just in case we want to change it later
|
||||||
|
// This is the one to catch up with a distant mothership
|
||||||
|
this.behaviourRejoinMothership = function()
|
||||||
|
{
|
||||||
|
var handlers = {};
|
||||||
|
this.responsesAddStandard(handlers);
|
||||||
|
this.responsesAddEscort(handlers);
|
||||||
|
this.setUpHandlers(handlers);
|
||||||
|
// 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
this.behaviourOfferToEscort = function()
|
||||||
|
{
|
||||||
|
var handlers = {};
|
||||||
|
this.responsesAddStandard(handlers);
|
||||||
|
this.setUpHandlers(handlers);
|
||||||
|
|
||||||
|
var possible = this.getParameter("oolite_scanResultSpecific");
|
||||||
|
if (possible == null)
|
||||||
|
{
|
||||||
|
this.reconsiderNow();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (this.ship.offerToEscort(possible))
|
||||||
|
{
|
||||||
|
// accepted
|
||||||
|
this.reconsiderNow();
|
||||||
|
}
|
||||||
|
// if rejected, wait for next scheduled reconsideration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* ****************** Configuration functions ************** */
|
/* ****************** Configuration functions ************** */
|
||||||
|
|
||||||
/* Configurations. Configurations are set up actions for a behaviour
|
/* Configurations. Configurations are set up actions for a behaviour
|
||||||
@ -676,10 +931,13 @@ this.AILib = function(ship)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var dts = this.ship.defenseTargets
|
var dts = this.ship.defenseTargets
|
||||||
if (dts.length > 0)
|
for (var i = 0; i < dts.length ; i++)
|
||||||
{
|
{
|
||||||
this.ship.target = dts[0];
|
if (dts[i].position.distanceTo(this.ship) < this.ship.scannerRange)
|
||||||
return;
|
{
|
||||||
|
this.ship.target = dts[0];
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (this.ship.group != null)
|
if (this.ship.group != null)
|
||||||
{
|
{
|
||||||
@ -687,7 +945,7 @@ this.AILib = function(ship)
|
|||||||
{
|
{
|
||||||
if (this.ship.group.ships[i] != this.ship)
|
if (this.ship.group.ships[i] != this.ship)
|
||||||
{
|
{
|
||||||
if (this.ship.group.ships[i].target && this.ship.group.ships[i].hasHostileTarget)
|
if (this.ship.group.ships[i].target && this.ship.group.ships[i].hasHostileTarget && this.ship.group.ships[i].target.position.distanceTo(this.ship) < this.ship.scannerRange)
|
||||||
{
|
{
|
||||||
this.ship.target = this.ship.group.ships[i].target;
|
this.ship.target = this.ship.group.ships[i].target;
|
||||||
return;
|
return;
|
||||||
@ -701,7 +959,7 @@ this.AILib = function(ship)
|
|||||||
{
|
{
|
||||||
if (this.ship.escortGroup.ships[i] != this.ship)
|
if (this.ship.escortGroup.ships[i] != this.ship)
|
||||||
{
|
{
|
||||||
if (this.ship.escortGroup.ships[i].target && this.ship.escortGroup.ships[i].hasHostileTarget)
|
if (this.ship.escortGroup.ships[i].target && this.ship.escortGroup.ships[i].hasHostileTarget && this.ship.escortGroup.ships[i].target.position.distanceTo(this.ship) < this.ship.scannerRange)
|
||||||
{
|
{
|
||||||
this.ship.target = this.ship.escortGroup.ships[i].target;
|
this.ship.target = this.ship.escortGroup.ships[i].target;
|
||||||
return;
|
return;
|
||||||
@ -711,6 +969,53 @@ this.AILib = function(ship)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.configurationAcquireOffensiveEscortTarget = function()
|
||||||
|
{
|
||||||
|
if (this.ship.group && this.ship.group.leader && this.ship.group.leader.hasHostileTarget)
|
||||||
|
{
|
||||||
|
if (this.ship.distanceTo(this.ship.group.leader.target) < this.ship.scannerRange)
|
||||||
|
{
|
||||||
|
this.ship.target = this.ship.group.leader.target;
|
||||||
|
this.ship.addDefenseTarget(this.ship.target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.configurationAcquireDefensiveEscortTarget = function()
|
||||||
|
{
|
||||||
|
if (this.ship.group && this.ship.group.leader)
|
||||||
|
{
|
||||||
|
var leader = this.ship.group.leader;
|
||||||
|
if (leader.target.target == leader && leader.hasHostileTarget && 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 && dts[i].hasHostileTarget && !dts[i].isFleeing && dts[i].position.distanceTo(this.ship) < this.ship.scannerRange)
|
||||||
|
{
|
||||||
|
this.ship.target = dts[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.configurationAcquireOffensiveEscortTarget = function()
|
||||||
|
{
|
||||||
|
if (this.ship.group && this.ship.group.leader)
|
||||||
|
{
|
||||||
|
var leader = this.ship.group.leader;
|
||||||
|
if (leader.hasHostileTarget)
|
||||||
|
{
|
||||||
|
this.ship.target = leader.target;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.configurationCheckScanner = function()
|
this.configurationCheckScanner = function()
|
||||||
{
|
{
|
||||||
this.setParameter("oolite_scanResults",this.ship.checkScanner());
|
this.setParameter("oolite_scanResults",this.ship.checkScanner());
|
||||||
@ -722,11 +1027,49 @@ this.AILib = function(ship)
|
|||||||
this.ship.target = this.getParameter("oolite_scanResultSpecific");
|
this.ship.target = this.getParameter("oolite_scanResultSpecific");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.configurationSetDestinationToWitchpoint = function()
|
||||||
|
{
|
||||||
|
this.ship.destination = new Vector3D(0,0,0);
|
||||||
|
this.ship.desiredRange = 10000;
|
||||||
|
this.ship.desiredSpeed = this.cruiseSpeed();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.configurationSetDestinationToNearestFriendlyStation = function()
|
||||||
|
{
|
||||||
|
var stations = system.stations;
|
||||||
|
var threshold = 1E16;
|
||||||
|
var chosenStation = null;
|
||||||
|
for (var i = 0 ; i < stations.length ; i++)
|
||||||
|
{
|
||||||
|
var station = stations[i];
|
||||||
|
if (this.friendlyStation(station))
|
||||||
|
{
|
||||||
|
var distance = station.position.distanceTo(this.ship);
|
||||||
|
if (distance < threshold)
|
||||||
|
{
|
||||||
|
threshold = distance;
|
||||||
|
chosenStation = station;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.configurationSetDestinationFromPatrolRoute = function()
|
this.configurationSetDestinationFromPatrolRoute = function()
|
||||||
{
|
{
|
||||||
this.ship.destination = this.getParameter("oolite_patrolRoute");
|
this.ship.destination = this.getParameter("oolite_patrolRoute");
|
||||||
this.ship.desiredRange = this.getParameter("oolite_patrolRouteRange");
|
this.ship.desiredRange = this.getParameter("oolite_patrolRouteRange");
|
||||||
this.ship.desiredSpeed = this.ship.maxSpeed;
|
this.ship.desiredSpeed = this.cruiseSpeed();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.configurationMakeSpacelanePatrolRoute = function()
|
this.configurationMakeSpacelanePatrolRoute = function()
|
||||||
@ -845,6 +1188,26 @@ this.AILib = function(ship)
|
|||||||
this.setParameter("oolite_witchspaceDestination",possible[Math.floor(Math.random()*possible.length)].systemID);
|
this.setParameter("oolite_witchspaceDestination",possible[Math.floor(Math.random()*possible.length)].systemID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.configurationSetNearbyFriendlyStationForDocking = function()
|
||||||
|
{
|
||||||
|
var stations = system.stations;
|
||||||
|
for (var i = 0 ; i < stations.length ; i++)
|
||||||
|
{
|
||||||
|
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
|
||||||
|
if (station.position.distanceTo(this.ship) < this.ship.scannerRange)
|
||||||
|
{
|
||||||
|
this.setParameter("oolite_dockingStation",station)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ****************** Response definition functions ************** */
|
/* ****************** Response definition functions ************** */
|
||||||
|
|
||||||
/* Standard state-machine responses. These set up a set of standard
|
/* Standard state-machine responses. These set up a set of standard
|
||||||
@ -853,7 +1216,8 @@ this.AILib = function(ship)
|
|||||||
* priorities. Many behaviours will need to supplement the standard
|
* priorities. Many behaviours will need to supplement the standard
|
||||||
* responses with additional definitions. */
|
* responses with additional definitions. */
|
||||||
|
|
||||||
this.responsesAddStandard = function(handlers) {
|
this.responsesAddStandard = function(handlers)
|
||||||
|
{
|
||||||
handlers.cascadeWeaponDetected = function(weapon)
|
handlers.cascadeWeaponDetected = function(weapon)
|
||||||
{
|
{
|
||||||
this.ship.clearDefenseTargets();
|
this.ship.clearDefenseTargets();
|
||||||
@ -957,6 +1321,15 @@ this.AILib = function(ship)
|
|||||||
{
|
{
|
||||||
this.reconsiderNow();
|
this.reconsiderNow();
|
||||||
}
|
}
|
||||||
|
handlers.shipLaunchedFromStation = function()
|
||||||
|
{
|
||||||
|
this.reconsiderNow();
|
||||||
|
}
|
||||||
|
handlers.shipExitedWormhole = function()
|
||||||
|
{
|
||||||
|
this.reconsiderNow();
|
||||||
|
}
|
||||||
|
|
||||||
handlers.distressMessageReceived = function(aggressor, sender)
|
handlers.distressMessageReceived = function(aggressor, sender)
|
||||||
{
|
{
|
||||||
if (this.getParameter("oolite_flag_listenForDistressCall") != true)
|
if (this.getParameter("oolite_flag_listenForDistressCall") != true)
|
||||||
@ -967,10 +1340,25 @@ this.AILib = function(ship)
|
|||||||
this.setParameter("oolite_distressSender",sender);
|
this.setParameter("oolite_distressSender",sender);
|
||||||
this.reconsiderNow();
|
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
|
// TODO: more event handlers
|
||||||
}
|
}
|
||||||
|
|
||||||
this.responsesAddDocking = function(handlers) {
|
/* Additional handlers for use while docking */
|
||||||
|
this.responsesAddDocking = function(handlers)
|
||||||
|
{
|
||||||
handlers.stationWithdrewDockingClearance = function()
|
handlers.stationWithdrewDockingClearance = function()
|
||||||
{
|
{
|
||||||
this.setParameter("oolite_dockingStation",null);
|
this.setParameter("oolite_dockingStation",null);
|
||||||
@ -985,10 +1373,49 @@ this.AILib = function(ship)
|
|||||||
this.reconsiderNow();
|
this.reconsiderNow();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Override of standard handlers for use while escorting */
|
||||||
|
this.responsesAddEscort = function(handlers)
|
||||||
|
{
|
||||||
|
handlers.helpRequestReceived = function(ally, enemy)
|
||||||
|
{
|
||||||
|
// always help the leader
|
||||||
|
if (ally == this.ship.group.leader)
|
||||||
|
{
|
||||||
|
if (!this.ship.target || this.ship.target.target != ally)
|
||||||
|
{
|
||||||
|
this.ship.target = enemy;
|
||||||
|
this.reconsiderNow();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
// not already helping, go for it...
|
||||||
|
this.ship.target = enemy;
|
||||||
|
this.reconsiderNow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
handlers.escortDock = function()
|
||||||
|
{
|
||||||
|
this.reconsiderNow();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}; // end object constructor
|
}; // end object constructor
|
||||||
|
|
||||||
|
|
||||||
|
@ -2199,6 +2199,8 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
|
|||||||
{
|
{
|
||||||
StationEntity *stationLaunchedFrom = [UNIVERSE nearestEntityMatchingPredicate:IsStationPredicate parameter:NULL relativeToEntity:self];
|
StationEntity *stationLaunchedFrom = [UNIVERSE nearestEntityMatchingPredicate:IsStationPredicate parameter:NULL relativeToEntity:self];
|
||||||
[self setStatus:STATUS_IN_FLIGHT];
|
[self setStatus:STATUS_IN_FLIGHT];
|
||||||
|
// awaken JS-based AIs
|
||||||
|
[self doScriptEvent:OOJSID("aiStarted")];
|
||||||
[self doScriptEvent:OOJSID("shipLaunchedFromStation") withArgument:stationLaunchedFrom];
|
[self doScriptEvent:OOJSID("shipLaunchedFromStation") withArgument:stationLaunchedFrom];
|
||||||
[shipAI reactToMessage:@"LAUNCHED OKAY" context:@"launched"];
|
[shipAI reactToMessage:@"LAUNCHED OKAY" context:@"launched"];
|
||||||
}
|
}
|
||||||
@ -12178,10 +12180,15 @@ Vector positionOffsetForShipInRotationToAlignment(ShipEntity* ship, Quaternion q
|
|||||||
idleEscorts = [NSMutableSet set];
|
idleEscorts = [NSMutableSet set];
|
||||||
for (escortEnum = [self escortEnumerator]; (escort = [escortEnum nextObject]); )
|
for (escortEnum = [self escortEnumerator]; (escort = [escortEnum nextObject]); )
|
||||||
{
|
{
|
||||||
if (![[[escort getAI] name] isEqualToString:@"interceptAI.plist"])
|
if (![[[escort getAI] name] isEqualToString:@"interceptAI.plist"] && ![[[escort getAI] name] isEqualToString:@"nullAI.plist"])
|
||||||
{
|
{
|
||||||
[idleEscorts addObject:escort];
|
[idleEscorts addObject:escort];
|
||||||
}
|
}
|
||||||
|
else if ([[[escort getAI] name] isEqualToString:@"nullAI.plist"])
|
||||||
|
{
|
||||||
|
// JS-based escorts get a help request
|
||||||
|
[escort doScriptEvent:OOJSID("helpRequestReceived") withArgument:self andArgument:[self primaryTarget]];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
escortCount = [idleEscorts count];
|
escortCount = [idleEscorts count];
|
||||||
@ -12225,7 +12232,10 @@ Vector positionOffsetForShipInRotationToAlignment(ShipEntity* ship, Quaternion q
|
|||||||
if ([escort owner] == self) [escort setOwner:escort];
|
if ([escort owner] == self) [escort setOwner:escort];
|
||||||
if(target && [target isStation]) [escort setTargetStation:target];
|
if(target && [target isStation]) [escort setTargetStation:target];
|
||||||
// JSAI: needs slightly different implementation of delay
|
// JSAI: needs slightly different implementation of delay
|
||||||
[escort setAITo:@"dockingAI.plist"];
|
if (![[[escort getAI] name] isEqualToString:@"nullAI.plist"])
|
||||||
|
{
|
||||||
|
[escort setAITo:@"dockingAI.plist"];
|
||||||
|
}
|
||||||
[ai setState:@"ABORT" afterDelay:delay + 0.25];
|
[ai setState:@"ABORT" afterDelay:delay + 0.25];
|
||||||
[escort doScriptEvent:OOJSID("escortDock") withArgument:[NSNumber numberWithFloat:delay]];
|
[escort doScriptEvent:OOJSID("escortDock") withArgument:[NSNumber numberWithFloat:delay]];
|
||||||
}
|
}
|
||||||
|
@ -433,8 +433,11 @@ static void DrawWormholeCorona(GLfloat inner_radius, GLfloat outer_radius, int s
|
|||||||
}
|
}
|
||||||
[ship setSpeed:[self exitSpeed]]; // all ships from this wormhole have same velocity
|
[ship setSpeed:[self exitSpeed]]; // all ships from this wormhole have same velocity
|
||||||
|
|
||||||
|
// awaken JS-based AIs
|
||||||
// Should probably pass the wormhole, but they have no JS representation
|
[ship doScriptEvent:OOJSID("aiStarted")];
|
||||||
|
|
||||||
|
// Wormholes now have a JS representation, so we could provide it
|
||||||
|
// but is it worth it for the exit wormhole?
|
||||||
[ship doScriptEvent:OOJSID("shipExitedWormhole") andReactToAIMessage:@"EXITED WITCHSPACE"];
|
[ship doScriptEvent:OOJSID("shipExitedWormhole") andReactToAIMessage:@"EXITED WITCHSPACE"];
|
||||||
|
|
||||||
// update the ships's position
|
// update the ships's position
|
||||||
|
@ -130,6 +130,7 @@ enum
|
|||||||
kSystem_pseudoRandom256, // constant-per-system pseudorandom number in [0..256), integer, read-only
|
kSystem_pseudoRandom256, // constant-per-system pseudorandom number in [0..256), integer, read-only
|
||||||
kSystem_pseudoRandomNumber, // constant-per-system pseudorandom number in [0..1), double, read-only
|
kSystem_pseudoRandomNumber, // constant-per-system pseudorandom number in [0..1), double, read-only
|
||||||
kSystem_sun, // system's sun, Planet, read-only
|
kSystem_sun, // system's sun, Planet, read-only
|
||||||
|
kSystem_stations, // list of dockable entities, read-only
|
||||||
kSystem_techLevel, // tech level ID, integer, read/write
|
kSystem_techLevel, // tech level ID, integer, read/write
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -159,6 +160,7 @@ static JSPropertySpec sSystemProperties[] =
|
|||||||
{ "pseudoRandom100", kSystem_pseudoRandom100, OOJS_PROP_READONLY_CB },
|
{ "pseudoRandom100", kSystem_pseudoRandom100, OOJS_PROP_READONLY_CB },
|
||||||
{ "pseudoRandom256", kSystem_pseudoRandom256, OOJS_PROP_READONLY_CB },
|
{ "pseudoRandom256", kSystem_pseudoRandom256, OOJS_PROP_READONLY_CB },
|
||||||
{ "pseudoRandomNumber", kSystem_pseudoRandomNumber, OOJS_PROP_READONLY_CB },
|
{ "pseudoRandomNumber", kSystem_pseudoRandomNumber, OOJS_PROP_READONLY_CB },
|
||||||
|
{ "stations", kSystem_stations, OOJS_PROP_READONLY_CB },
|
||||||
{ "sun", kSystem_sun, OOJS_PROP_READONLY_CB },
|
{ "sun", kSystem_sun, OOJS_PROP_READONLY_CB },
|
||||||
{ "techLevel", kSystem_techLevel, OOJS_PROP_READWRITE_CB },
|
{ "techLevel", kSystem_techLevel, OOJS_PROP_READWRITE_CB },
|
||||||
{ 0 }
|
{ 0 }
|
||||||
@ -259,6 +261,16 @@ static JSBool SystemGetProperty(JSContext *context, JSObject *this, jsid propID,
|
|||||||
handled = YES;
|
handled = YES;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case kSystem_stations:
|
||||||
|
/* Optimise? This may be called enough times that it's worth
|
||||||
|
* having a list of stations cached and edited on station
|
||||||
|
* creation/destruction, as we do for planets - CIM 13/7/2013 */
|
||||||
|
OOJS_BEGIN_FULL_NATIVE(context)
|
||||||
|
result = [UNIVERSE findShipsMatchingPredicate:IsStationPredicate parameter:NULL inRange:-1 ofEntity:nil];
|
||||||
|
OOJS_END_FULL_NATIVE
|
||||||
|
handled = YES;
|
||||||
|
break;
|
||||||
|
|
||||||
case kSystem_allShips:
|
case kSystem_allShips:
|
||||||
OOJS_BEGIN_FULL_NATIVE(context)
|
OOJS_BEGIN_FULL_NATIVE(context)
|
||||||
result = [UNIVERSE findShipsMatchingPredicate:JSEntityIsJavaScriptSearchablePredicate parameter:NULL inRange:-1 ofEntity:nil];
|
result = [UNIVERSE findShipsMatchingPredicate:JSEntityIsJavaScriptSearchablePredicate parameter:NULL inRange:-1 ofEntity:nil];
|
||||||
|
Loading…
x
Reference in New Issue
Block a user