Add pirate interceptor AI, fix some bugs in pirate freighter AI

This commit is contained in:
cim 2013-08-09 18:00:18 +01:00
parent b00b1bb550
commit 9edbe45d63
5 changed files with 204 additions and 47 deletions

View File

@ -51,6 +51,12 @@ this.aiStarted = function() {
behaviour: ai.behaviourDestroyCurrentTarget, behaviour: ai.behaviourDestroyCurrentTarget,
reconsider: 5 reconsider: 5
}, },
/* Follow leader to witchspace */
{
condition: ai.conditionWitchspaceEntryRequested,
behaviour: ai.behaviourEnterWitchspace,
reconsider: 15
},
/* Check for distress calls */ /* Check for distress calls */
{ {
condition: ai.conditionHasReceivedDistressCall, condition: ai.conditionHasReceivedDistressCall,

View File

@ -126,11 +126,11 @@ this.aiStarted = function() {
specific = [ specific = [
{ {
condition: ai.conditionGroupHasEnoughLoot, condition: ai.conditionGroupHasEnoughLoot,
truebranch: ai.templateWitchspaceJumpOutbound() truebranch: ai.templateWitchspaceJumpInbound()
}, },
{ {
condition: ai.conditionGroupAttritionReached, condition: ai.conditionGroupAttritionReached,
truebranch: ai.templateWitchspaceJumpOutbound() truebranch: ai.templateWitchspaceJumpInbound()
}, },
{ {
condition: ai.conditionInInterstellarSpace, condition: ai.conditionInInterstellarSpace,

View File

@ -0,0 +1,139 @@
/*
pirateInterceptorAI.js
Priority-based AI for pirate interceptors (fly defense for
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 Pirate Interceptor AI";
this.version = "1.79";
this.aiStarted = function() {
this.ai = new worldScripts["oolite-libPriorityAI"].AILib(this.ship);
ai.setParameter("oolite_flag_surrendersLate",true);
// to hunt the hunters, go where they go
ai.setWaypointGenerator(ai.waypointsSpacelanePatrol);
ai.setCommunicationsRole("pirate");
var common = [
/* Combat */
{
condition: ai.conditionLosingCombat,
behaviour: ai.behaviourFleeCombat,
reconsider: 5
},
{
condition: ai.conditionInCombat,
configuration: ai.configurationAcquireCombatTarget,
behaviour: ai.behaviourDestroyCurrentTarget,
reconsider: 10
},
{
/* don't check odds first, make sure we get at least a little
* weapons fire */
preconfiguration: ai.configurationCheckScanner,
condition: ai.conditionScannerContainsHunters,
configuration: ai.configurationAcquireScannedTarget,
behaviour: ai.behaviourDestroyCurrentTarget,
reconsider: 20
}
];
var specific;
if (this.ship.homeSystem == this.ship.destinationSystem)
{
/* Patrol waypoints for a bit, then return */
specific = [
{
condition: ai.conditionHasWaypoint,
configuration: ai.configurationSetDestinationToWaypoint,
behaviour: ai.behaviourApproachDestination,
reconsider: 30
},
{
condition: ai.conditionPatrolIsOver,
truebranch: ai.templateReturnToBaseOrPlanet()
},
{
configuration: ai.configurationSetWaypoint,
behaviour: ai.behaviourApproachDestination,
reconsider: 30
}
];
}
else if (this.ship.homeSystem == system.ID && this.ship.fuel == 7)
{
// jump to destination system independently of freighters
// (since interceptors are just added *with* them, not to
// their group)
specific = ai.templateWitchspaceJumpOutbound().concat(ai.templateReturnToBaseOrPlanet);
}
else if (this.ship.homeSystem == system.ID)
{
// if not at full fuel, we're probably returning home. Or
// something went wrong when trying to enter witchspace that
// needed injectors to fix.
specific = ai.templateReturnToBaseOrPlanet();
}
else
{
/* Patrol waypoints for a bit, then return */
specific = [
{
condition: ai.conditionHasWaypoint,
configuration: ai.configurationSetDestinationToWaypoint,
behaviour: ai.behaviourApproachDestination,
reconsider: 30
},
{
condition: ai.conditionPatrolIsOver,
truebranch: ai.templateWitchspaceJumpOutbound()
},
{
configuration: ai.configurationSetWaypoint,
behaviour: ai.behaviourApproachDestination,
reconsider: 30
}
];
}
var fallback = [
{
// stuck in system and no friendly stations
configuration: ai.configurationSetDestinationToWitchpoint,
// TODO: behaviour search for wormholes
behaviour: ai.behaviourApproachDestination,
reconsider: 30
}
];
var priorities = common.concat(specific).concat(fallback);
ai.setPriorities(priorities);
}

View File

@ -409,6 +409,8 @@ this.AILib = function(ship)
this.setCommunicationsRole = function(role) this.setCommunicationsRole = function(role)
{ {
commsRole = role; commsRole = role;
// TODO: if personality is generic, pick a new one from the
// allowed list. If possible use the same as the group leader.
} }
@ -514,14 +516,22 @@ AILib.prototype.checkScannerWithPredicate = function(predicate)
{ {
return false; return false;
} }
// if current target matches, use that
if (this.ship.target && predicate.call(this,this.ship.target))
{
this.setParameter("oolite_scanResultSpecific",this.ship.target);
return true;
}
var sl = scan.length; var sl = scan.length;
// scan upwards; lower indices tend to be closer, though this is // use a random offset so if several ships make the same scan
// not guaranteed // they don't all pick the same target
var offset = Math.floor(Math.random()*sl);
for (var i = 0 ; i < sl ; i++) for (var i = 0 ; i < sl ; i++)
{ {
if (predicate.call(this,scan[i])) var io = (i+offset)%sl;
if (predicate.call(this,scan[io]))
{ {
this.setParameter("oolite_scanResultSpecific",scan[i]); this.setParameter("oolite_scanResultSpecific",scan[io]);
return true; return true;
} }
} }
@ -630,7 +640,7 @@ AILib.prototype.friendlyStation = function(station)
return false; return false;
} }
// this will do until we have a proper friendliness system for stations // this will do until we have a proper friendliness system for stations
if (this.ship.primaryRole == "pirate" && station.bounty == 0) if (this.ship.primaryRole.match(/^pirate/) && station.bounty == 0)
{ {
return false; return false;
} }
@ -1616,7 +1626,7 @@ AILib.prototype.conditionScannerContainsSeriousOffender = function()
AILib.prototype.conditionScannerContainsHunters = function() AILib.prototype.conditionScannerContainsHunters = function()
{ {
return this.checkScannerWithPredicate(function(s) { return this.checkScannerWithPredicate(function(s) {
return s.primaryRole == "hunter" || s.scanClass == "CLASS_POLICE" || (s.isStation && s.isMainStation); return (s.primaryRole && s.primaryRole.match(/^hunter/)) || s.scanClass == "CLASS_POLICE" || (s.isStation && s.isMainStation);
}); });
} }
@ -4617,6 +4627,7 @@ AILib.prototype.templateLeadPirateMission = function()
{ {
return [ return [
{ {
label: "Pirate mission",
preconfiguration: this.configurationForgetCargoDemand, preconfiguration: this.configurationForgetCargoDemand,
condition: this.conditionScannerContainsPirateVictims, condition: this.conditionScannerContainsPirateVictims,
configuration: this.configurationAcquireScannedTarget, configuration: this.configurationAcquireScannedTarget,
@ -4644,6 +4655,7 @@ AILib.prototype.templateReturnToBase = function()
{ {
return [ return [
{ {
label: "Return to base",
condition: this.conditionHasSelectedStation, condition: this.conditionHasSelectedStation,
truebranch: [ truebranch: [
{ {
@ -4687,6 +4699,7 @@ AILib.prototype.templateReturnToBaseOrPlanet = function()
{ {
return [ return [
{ {
label: "Return to base or planet",
condition: this.conditionFriendlyStationNearby, condition: this.conditionFriendlyStationNearby,
configuration: this.configurationSetNearbyFriendlyStationForDocking, configuration: this.configurationSetNearbyFriendlyStationForDocking,
behaviour: this.behaviourDockWithStation, behaviour: this.behaviourDockWithStation,
@ -4731,6 +4744,7 @@ AILib.prototype.templateWitchspaceJumpInbound = function()
{ {
return [ return [
{ {
label: "Jump inbound",
preconfiguration: this.configurationSelectWitchspaceDestinationInbound, preconfiguration: this.configurationSelectWitchspaceDestinationInbound,
condition: this.conditionCanWitchspaceOnRoute, condition: this.conditionCanWitchspaceOnRoute,
behaviour: this.behaviourEnterWitchspace, behaviour: this.behaviourEnterWitchspace,
@ -4756,6 +4770,7 @@ AILib.prototype.templateWitchspaceJumpOutbound = function()
{ {
return [ return [
{ {
label: "Jump outbound",
preconfiguration: this.configurationSelectWitchspaceDestinationOutbound, preconfiguration: this.configurationSelectWitchspaceDestinationOutbound,
condition: this.conditionCanWitchspaceOnRoute, condition: this.conditionCanWitchspaceOnRoute,
behaviour: this.behaviourEnterWitchspace, behaviour: this.behaviourEnterWitchspace,

View File

@ -1120,21 +1120,26 @@ this._addPirateAssistant = function(role,lead)
{ {
var asst = system.addShips("pirate",1,lead.position,4E3); var asst = system.addShips("pirate",1,lead.position,4E3);
} }
asst[0].setBounty(20+system.government+Math.floor(Math.random()*12),"setup actions"); asst[0].homeSystem = lead.homeSystem;
asst[0].group = lead.group; asst[0].destinationSystem = lead.destinationSystem;
lead.group.addShip(asst[0]); if (role == "pirate-interceptor")
/* if (role == "pirate-interceptor")
{ {
asst[0].switchAI("pirateInterceptorAI.js"); asst[0].switchAI("pirateInterceptorAI.js");
asst[0].setBounty(50+system.government+Math.floor(Math.random()*36),"setup actions");
// interceptors not actually part of group: they just get the
// same destinations
} }
else else
{ */ {
asst[0].group = lead.group;
lead.group.addShip(asst[0]);
asst[0].switchAI("pirateFighterAI.js"); asst[0].switchAI("pirateFighterAI.js");
// } asst[0].setBounty(20+system.government+Math.floor(Math.random()*12),"setup actions");
}
} }
this._addPiratePack = function(pos,leader,lf,mf,hf,thug) this._addPiratePack = function(pos,leader,lf,mf,hf,thug,home,destination)
{ {
if (this._roleExists(leader)) if (this._roleExists(leader))
{ {
@ -1146,6 +1151,9 @@ this._addPiratePack = function(pos,leader,lf,mf,hf,thug)
var lead = system.addShips("pirate",1,pos,0); var lead = system.addShips("pirate",1,pos,0);
} }
lead[0].setBounty(60+system.government+Math.floor(Math.random()*8),"setup actions"); lead[0].setBounty(60+system.government+Math.floor(Math.random()*8),"setup actions");
lead[0].homeSystem = home;
lead[0].destinationSystem = destination;
var group = new ShipGroup("pirate pack",lead[0]); var group = new ShipGroup("pirate pack",lead[0]);
lead[0].group = group; lead[0].group = group;
for (var i = Math.floor(lf+(0.5+Math.random()-Math.random())); i > 0; i--) for (var i = Math.floor(lf+(0.5+Math.random()-Math.random())); i > 0; i--)
@ -1176,76 +1184,65 @@ this._addPiratePack = function(pos,leader,lf,mf,hf,thug)
} }
// next line is temporary for debugging! // next line is temporary for debugging!
lead[0].displayName = lead[0].name + " - FLAGSHIP"; lead[0].displayName = lead[0].name + " - FLAGSHIP";
this._setFuel(lead[0]);
lead[0].switchAI("pirateFreighterAI.js");
return lead[0]; return lead[0];
} }
this._addLightPirateLocal = function(pos) this._addLightPirateLocal = function(pos)
{ {
var lead = this._addPiratePack(pos,"pirate-light-freighter",2,1,-1,0); var lead = this._addPiratePack(pos,"pirate-light-freighter",2,1,-1,0,system.ID,system.ID);
lead.homeSystem = system.ID;
lead.destinationSystem = system.ID;
lead.switchAI("pirateFreighterAI.js");
} }
this._addLightPirateRemote = function(pos) this._addLightPirateRemote = function(pos)
{ {
pos.z = pos.z % 100000; pos.z = pos.z % 100000;
var lead = this._addPiratePack(pos,"pirate-light-freighter",2,1,-1,0); var lead = this._addPiratePack(pos,"pirate-light-freighter",2,1,-1,0,this._nearbyDangerousSystem(system.info.government-1),system.ID);
lead.homeSystem = this._nearbyDangerousSystem(system.info.government-1);
this._setFuel(lead);
lead.destinationSystem = system.ID;
lead.switchAI("pirateFreighterAI.js");
} }
this._addLightPirateOutbound = function(pos) this._addLightPirateOutbound = function(pos)
{ {
var lead = this._addPiratePack(pos,"pirate-light-freighter",2,1,-1,0); var lead = this._addPiratePack(pos,"pirate-light-freighter",2,1,-1,0,system.ID,this._nearbySafeSystem(system.info.government+1));
lead.destinationSystem = this._nearbySafeSystem(system.info.government+1);
lead.fuel = 7
lead.homeSystem = system.ID;
lead.switchAI("pirateFreighterAI.js");
} }
this._addMediumPirateLocal = function(pos) this._addMediumPirateLocal = function(pos)
{ {
var lead = this._addPiratePack(pos,"pirate-medium-freighter",3,2,0,1); var lead = this._addPiratePack(pos,"pirate-medium-freighter",3,2,0,1,system.ID,system.ID);
lead.homeSystem = system.ID;
lead.destinationSystem = system.ID;
lead.switchAI("pirateFreighterAI.js");
} }
this._addMediumPirateRemote = function(pos) this._addMediumPirateRemote = function(pos)
{ {
pos.z = pos.z % 100000; pos.z = pos.z % 100000;
var lead = this._addPiratePack(pos,"pirate-medium-freighter",3,2,0,1); var lead = this._addPiratePack(pos,"pirate-medium-freighter",3,2,0,1,this._nearbyDangerousSystem(Math.min(system.info.government-1,3)),system.ID);
lead.homeSystem = this._nearbyDangerousSystem(system.info.government-1); }
this._setFuel(lead);
lead.destinationSystem = system.ID;
lead.switchAI("pirateFreighterAI.js"); this._addMediumPirateOutbound = function(pos)
{
var lead = this._addPiratePack(pos,"pirate-medium-freighter",3,2,0,1,system.ID,this._nearbySafeSystem(system.info.government+1));
} }
this._addHeavyPirateLocal = function(pos) this._addHeavyPirateLocal = function(pos)
{ {
var lead = this._addPiratePack(pos,"pirate-heavy-freighter",4,4,2,2); var lead = this._addPiratePack(pos,"pirate-heavy-freighter",4,4,2,2,system.ID,system.ID);
lead.homeSystem = system.ID;
lead.destinationSystem = system.ID;
lead.switchAI("pirateFreighterAI.js");
} }
this._addHeavyPirateRemote = function(pos) this._addHeavyPirateRemote = function(pos)
{ {
pos.z = pos.z % 100000; pos.z = pos.z % 100000;
var lead = this._addPiratePack(pos,"pirate-heavy-freighter",4,4,2,2); var lead = this._addPiratePack(pos,"pirate-heavy-freighter",4,4,2,2,this._nearbyDangerousSystem(Math.min(system.info.government-1,1)),system.ID);
lead.homeSystem = this._nearbyDangerousSystem(system.info.government-1); }
this._setFuel(lead);
lead.destinationSystem = system.ID;
lead.switchAI("pirateFreighterAI.js"); this._addHeavyPirateOutbound = function(pos)
{
var lead = this._addPiratePack(pos,"pirate-heavy-freighter",4,4,2,2,system.ID,this._nearbySafeSystem(system.info.government+1));
} }