init
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
# ****************************************************************************
|
||||
# CUI
|
||||
#
|
||||
# The Advanced Framework for Simulation, Integration, and Modeling (AFSIM)
|
||||
#
|
||||
# The use, dissemination or disclosure of data in this file is subject to
|
||||
# limitation or restriction. See accompanying README and LICENSE for details.
|
||||
# ****************************************************************************
|
||||
|
||||
|
||||
behavior adjust_priority_for_escort
|
||||
|
||||
precondition
|
||||
return true;
|
||||
end_precondition
|
||||
|
||||
execute
|
||||
extern string mEscortName;
|
||||
WsfPlatform escortPlatform = WsfSimulation.FindPlatform( mEscortName );
|
||||
if( escortPlatform.IsValid() )
|
||||
{
|
||||
|
||||
extern double cPursueTargetPriority;
|
||||
Array<WsfRIPRJob> jobs = PROCESSOR.GetJobs();
|
||||
foreach (WsfRIPRJob x in jobs)
|
||||
{
|
||||
double jobPriority = cPursueTargetPriority / (1 + x.SlantRangeTo( escortPlatform ) );
|
||||
x.Priority( jobPriority );
|
||||
}
|
||||
}
|
||||
end_execute
|
||||
|
||||
end_behavior
|
||||
@@ -0,0 +1,59 @@
|
||||
# ****************************************************************************
|
||||
# CUI
|
||||
#
|
||||
# The Advanced Framework for Simulation, Integration, and Modeling (AFSIM)
|
||||
#
|
||||
# The use, dissemination or disclosure of data in this file is subject to
|
||||
# limitation or restriction. See accompanying README and LICENSE for details.
|
||||
# ****************************************************************************
|
||||
|
||||
|
||||
|
||||
behavior create_cap-routes
|
||||
|
||||
script_debug_writes off
|
||||
|
||||
script_variables
|
||||
Array<Map<string, Object>> mCapRoutes = Array<Map<string, Object>>();
|
||||
#mCapRoutes[0] = Map<string, Object>();
|
||||
#mCapRoutes[0].Set("route name", "GOALIE_CAP_CCW_ORBIT");
|
||||
#mCapRoutes[0].Set("location", WsfGeoPoint.Construct(12.60313, 117.37702, 40000));
|
||||
#mCapRoutes[0].Set("heading", 140.0);
|
||||
#mCapRoutes[0].Set("priority", 1000.0);
|
||||
#mCapRoutes[0].Set("max winners", 1);
|
||||
#mCapRoutes[0].Set("fez_zone", "lane_2");
|
||||
end_script_variables
|
||||
|
||||
on_init
|
||||
foreach( Map<string, Object> map in mCapRoutes)
|
||||
{
|
||||
//create a "cap-route" job
|
||||
string routeName = (string) map["route name"];
|
||||
WsfGeoPoint location = (WsfGeoPoint)map["location"];
|
||||
double heading = (double) map["heading"];
|
||||
double priority = (double) map["priority"];
|
||||
int maxWinners = (int) map["max winners"];
|
||||
string zoneName = (string) map["fez_zone"];
|
||||
string unique_desc = write_str("cap-route_", routeName, "_", location.Latitude(), "_", location.Longitude());
|
||||
writeln_d("CREATING CAP ROUTE JOB: ", unique_desc);
|
||||
WsfRIPRJob temp = WsfRIPRJob.Create( PROCESSOR, "cap-route", unique_desc, priority, maxWinners );
|
||||
temp.SetData( "location", location );
|
||||
temp.SetData( "heading", heading );
|
||||
temp.SetData( "route name", routeName );
|
||||
temp.SetData( "for_air", 1 );
|
||||
temp.SetData( "fez_zone", zoneName);
|
||||
PROCESSOR.AddJob(temp);
|
||||
}
|
||||
end_on_init
|
||||
|
||||
precondition
|
||||
writeln_d("precondition create_cap-routes");
|
||||
return false;
|
||||
end_precondition
|
||||
|
||||
execute
|
||||
writeln_d("executing create_cap-routes");
|
||||
end_execute
|
||||
|
||||
end_behavior
|
||||
|
||||
120
processors/quantum_agents/aifl/behavior_create_point_job.txt
Normal file
120
processors/quantum_agents/aifl/behavior_create_point_job.txt
Normal file
@@ -0,0 +1,120 @@
|
||||
# ****************************************************************************
|
||||
# CUI
|
||||
#
|
||||
# The Advanced Framework for Simulation, Integration, and Modeling (AFSIM)
|
||||
#
|
||||
# The use, dissemination or disclosure of data in this file is subject to
|
||||
# limitation or restriction. See accompanying README and LICENSE for details.
|
||||
# ****************************************************************************
|
||||
|
||||
|
||||
|
||||
behavior create_point_job
|
||||
|
||||
script_debug_writes off
|
||||
|
||||
script_variables
|
||||
int maxJobWinnersForPursueTrack = 1;
|
||||
string pointJobName = "-1";
|
||||
end_script_variables
|
||||
|
||||
|
||||
on_init
|
||||
//nothing here yet
|
||||
end_on_init
|
||||
|
||||
|
||||
precondition
|
||||
writeln_d("precondition create_point_job");
|
||||
|
||||
WsfRIPRProcessor commander = PROCESSOR.GetRIPRCommanderProcessor();
|
||||
if (!commander.IsValid())
|
||||
{
|
||||
return Failure("Agent does not have a commander to get jobs from!");
|
||||
}
|
||||
int NumSubordinates = PROCESSOR.GetRIPRSubordinateProcessors().Size();
|
||||
if (NumSubordinates <= 0)
|
||||
{
|
||||
return Failure("Agent has no subordinates to send to a point!");
|
||||
}
|
||||
return true;
|
||||
end_precondition
|
||||
|
||||
|
||||
execute
|
||||
writeln_d("executing create_point_job");
|
||||
|
||||
// now check the board to see what we've won!
|
||||
WsfRIPRJob currentJob = PROCESSOR.GetRIPRCommanderProcessor().GetJobFor(TIME_NOW, PROCESSOR);
|
||||
|
||||
if( currentJob.IsValid() && currentJob.Name() == "zone" )
|
||||
{
|
||||
//create a pursue-point job that allows for enough winners to send the whole squadron
|
||||
//this is useful in case some subordinates don't have a track for some of the threats
|
||||
//or if there are less threats than there are subordinates, so the whole squadron will be sent
|
||||
|
||||
string zName = (string)currentJob.GetData("ZoneName");
|
||||
WsfGeoPoint point = (WsfGeoPoint)currentJob.GetData("ZonePoint");
|
||||
if (point.IsValid())
|
||||
{
|
||||
string newPointJobName = "pursue-point-" + zName;
|
||||
WsfRIPRJob pointJob = PROCESSOR.GetJobByData("pointName", newPointJobName);
|
||||
if( !pointJob.IsValid() )
|
||||
{
|
||||
extern double cPursuePointPriority;
|
||||
//set max job winners to number of subordinates (so all can proceed into zone)
|
||||
int NumSubordinates = PROCESSOR.GetRIPRSubordinateProcessors().Size();
|
||||
pointJob = WsfRIPRJob.Create( PROCESSOR,
|
||||
"pursue-point",
|
||||
newPointJobName,
|
||||
cPursuePointPriority,
|
||||
NumSubordinates);
|
||||
pointJob.SetData( "targetTrackName", zName ); //hack for now, so other code here works
|
||||
pointJob.SetData( "targetPoint", point );
|
||||
pointJob.SetData( "pointName", newPointJobName );
|
||||
PROCESSOR.AddJob(pointJob);
|
||||
writeln_d("--- ", PLATFORM.Name(), " job change, ADD: pursue-point-", zName );
|
||||
}
|
||||
else
|
||||
{
|
||||
//update the job?
|
||||
pointJob.SetData( "targetPoint" , point );
|
||||
pointJob.SetData( "targetTrackName" , zName );
|
||||
}
|
||||
if (pointJobName != newPointJobName)
|
||||
{
|
||||
//remove old point job
|
||||
WsfRIPRJob prevPointJob = PROCESSOR.GetJobByData("pointName", pointJobName);
|
||||
if (prevPointJob.IsValid())
|
||||
{
|
||||
writeln_d("--- ", PLATFORM.Name(), " job change, REMOVE: ", pointJobName);
|
||||
PROCESSOR.RemoveJob(prevPointJob);
|
||||
}
|
||||
pointJobName = newPointJobName;
|
||||
}
|
||||
return; //step out of the behavior at this point, otherwise remove the job
|
||||
}
|
||||
else
|
||||
{
|
||||
writeln(PLATFORM.Name(), " has no valid zone point, not creating pursue-point job!");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
writeln_d(PLATFORM.Name(), " does not have a valid zone job for a point!");
|
||||
|
||||
//remove old point job
|
||||
WsfRIPRJob prevPointJob = PROCESSOR.GetJobByData("pointName", pointJobName);
|
||||
writeln_d("--- ", PLATFORM.Name(), " job change, REMOVE: ", pointJobName);
|
||||
pointJobName = "-1";
|
||||
if (prevPointJob.IsValid())
|
||||
{
|
||||
writeln_d("--- ", PLATFORM.Name(), " job change, REMOVE: ", pointJobName);
|
||||
PROCESSOR.RemoveJob(prevPointJob);
|
||||
}
|
||||
}
|
||||
|
||||
end_execute
|
||||
|
||||
end_behavior
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
# ****************************************************************************
|
||||
# CUI
|
||||
#
|
||||
# The Advanced Framework for Simulation, Integration, and Modeling (AFSIM)
|
||||
#
|
||||
# The use, dissemination or disclosure of data in this file is subject to
|
||||
# limitation or restriction. See accompanying README and LICENSE for details.
|
||||
# ****************************************************************************
|
||||
|
||||
|
||||
|
||||
behavior create_target_jobs_self
|
||||
|
||||
script_debug_writes off
|
||||
|
||||
|
||||
script_variables
|
||||
WsfRIPRJob mMyJob;
|
||||
int maxJobWinnersForPursueTrack = 1;
|
||||
end_script_variables
|
||||
|
||||
|
||||
on_init
|
||||
|
||||
end_on_init
|
||||
|
||||
|
||||
precondition
|
||||
writeln_d("precondition create_target_jobs_self");
|
||||
|
||||
//this behavior should probably always run, because it
|
||||
//removes stale jobs from old tracks that have gone away
|
||||
|
||||
return true;
|
||||
end_precondition
|
||||
|
||||
|
||||
execute
|
||||
writeln_d("executing create_target_jobs_self");
|
||||
|
||||
WsfLocalTrackList localTracks = PLATFORM.MasterTrackList();
|
||||
Map<string, int> updatedTracks = Map<string, int>();
|
||||
|
||||
writeln_d(" Flight Lead, Considering Num Tracks: ", localTracks.Count() );
|
||||
|
||||
foreach (WsfTrack x in localTracks)
|
||||
{
|
||||
// if the track is not a foe or is damaged, we'll ignore it
|
||||
if (!(x.IsValid()))
|
||||
{
|
||||
writeln_d("!!! Need to remove track: not valid!");
|
||||
continue;
|
||||
}
|
||||
|
||||
WsfTrackId tid = x.TrackId();
|
||||
writeln_d(" Considering: ", tid.Name(), ".", tid.Number(), " -> ", x.TargetName());
|
||||
updatedTracks.Set(x.TargetName(), 0);
|
||||
|
||||
if (x.IFF_Friend())
|
||||
{
|
||||
writeln_d("!!! Need to remove track: IFF FRIEND!");
|
||||
continue;
|
||||
}
|
||||
if (x.SideValid() && x.Side() == PLATFORM.Side())
|
||||
{
|
||||
writeln_d("!!! Need to remove track: SAME SIDE!");
|
||||
continue;
|
||||
}
|
||||
|
||||
extern string DetermineTrackCategory(WsfTrack);
|
||||
string category = DetermineTrackCategory(x);
|
||||
|
||||
if (category == "unknown")
|
||||
{
|
||||
writeln_d(" - Unknown type: ", x.TargetName(), " - ", x.TargetType() );
|
||||
continue;
|
||||
}
|
||||
|
||||
updatedTracks.Set(x.TargetName(), 1);
|
||||
|
||||
WsfRIPRJob job = PROCESSOR.GetJobByData("targetTrackName", x.TargetName());
|
||||
if (job.IsValid())
|
||||
{
|
||||
//update the already existing job
|
||||
job.SetData("targetLocation", x.CurrentLocation());
|
||||
}
|
||||
else
|
||||
{
|
||||
//create a job for this track
|
||||
extern double cPursueTargetPriority;
|
||||
WsfRIPRJob temp = WsfRIPRJob.Create( PROCESSOR,
|
||||
"pursue-target",
|
||||
"pursue-target-" + x.TargetName(),
|
||||
cPursueTargetPriority,
|
||||
maxJobWinnersForPursueTrack);
|
||||
temp.SetData("targetTrack", x);
|
||||
temp.SetData("targetTrackName", x.TargetName());
|
||||
temp.SetData("targetLocation", x.CurrentLocation());
|
||||
writeln_d(" - Adding job");
|
||||
PROCESSOR.AddJob(temp);
|
||||
writeln_d("--- ", PLATFORM.Name(), " job change, ADD: ", temp.GetDescription() );
|
||||
PLATFORM.Comment(write_str("AIFL - new job: ", temp.GetDescription()));
|
||||
}
|
||||
}
|
||||
|
||||
Array<WsfRIPRJob> jobs = PROCESSOR.GetJobs();
|
||||
foreach (WsfRIPRJob x in jobs)
|
||||
{
|
||||
string name = (string)x.GetData("targetTrackName");
|
||||
if (updatedTracks[name] == 0 && x.Name() == "pursue-target")
|
||||
{
|
||||
string temp = write_str("--- ", PLATFORM.Name(), " job change, REMOVE: ", x.GetDescription());
|
||||
writeln_d(temp);
|
||||
PLATFORM.Comment(temp);
|
||||
PROCESSOR.RemoveJob(x);
|
||||
}
|
||||
}
|
||||
|
||||
end_execute
|
||||
|
||||
end_behavior
|
||||
262
processors/quantum_agents/aifl/behavior_interpret_flank_jobs.txt
Normal file
262
processors/quantum_agents/aifl/behavior_interpret_flank_jobs.txt
Normal file
@@ -0,0 +1,262 @@
|
||||
# ****************************************************************************
|
||||
# CUI
|
||||
#
|
||||
# The Advanced Framework for Simulation, Integration, and Modeling (AFSIM)
|
||||
#
|
||||
# The use, dissemination or disclosure of data in this file is subject to
|
||||
# limitation or restriction. See accompanying README and LICENSE for details.
|
||||
# ****************************************************************************
|
||||
|
||||
|
||||
|
||||
behavior interpret_flank_jobs
|
||||
|
||||
script_debug_writes off
|
||||
|
||||
script_variables
|
||||
WsfDraw draw = WsfDraw();
|
||||
bool mDrawFlankLines = false;
|
||||
string cPreferredFlank = "auto"; //or "left" or "right"
|
||||
WsfRIPRJob mMyJob;
|
||||
Map<int, WsfGeoPoint> mFlankJobIdToFlankPointMap = Map<int, WsfGeoPoint>();
|
||||
double cFlankWeighting = 0.0;
|
||||
end_script_variables
|
||||
|
||||
on_init
|
||||
draw.SetLineSize(2);
|
||||
draw.SetColor(1.0, 0.0, 1.0); //purple
|
||||
end_on_init
|
||||
|
||||
|
||||
|
||||
query_bid_type flank
|
||||
|
||||
if (PLATFORM.Subordinates().Count() <= 0)
|
||||
{
|
||||
writeln_d("no subordinates to carry out flank job");
|
||||
return -MATH.DOUBLE_MAX();
|
||||
}
|
||||
|
||||
WsfGeoPoint zonePoint = (WsfGeoPoint)JOB.GetData("ZonePoint");
|
||||
double zoneBearing = (double) JOB.GetData("ZoneBearing");
|
||||
WsfZone flankZone = (WsfZone) JOB.GetData("FlankZone");
|
||||
double flankDist = (double) JOB.GetData("FlankDistance");
|
||||
bool bearingValid = (bool) JOB.GetData("ZoneBearingValid");
|
||||
|
||||
//determine which side to flank on, based on subordinate that is closest to flank point
|
||||
//find closest subordinate & then calculate relative geometry
|
||||
|
||||
WsfPlatform ClosestFlanker;
|
||||
|
||||
if( zonePoint.IsValid() )
|
||||
{
|
||||
double MinRange = MATH.DOUBLE_MAX();
|
||||
double NumSubordinates = (double)(PLATFORM.Subordinates().Count());
|
||||
foreach (WsfPlatform sub in PLATFORM.Subordinates())
|
||||
{
|
||||
double range = sub.SlantRangeTo( zonePoint );
|
||||
if( range < MinRange )
|
||||
{
|
||||
MinRange = range;
|
||||
ClosestFlanker = sub;
|
||||
}
|
||||
}
|
||||
if (!ClosestFlanker.IsValid())
|
||||
{
|
||||
writeln_d("!!! no valid subordinates to compare to flank point!");
|
||||
return -MATH.DOUBLE_MAX();
|
||||
}
|
||||
|
||||
double clusterBearingTrue = 0.0;
|
||||
if (bearingValid)
|
||||
{
|
||||
//cluster heading is with reference to east (instead of north), so subtract 90 degrees
|
||||
#clusterBearingTrue = MATH.NormalizeAngle0_360( zoneBearing - 90.0 );
|
||||
clusterBearingTrue = MATH.NormalizeAngle0_360( zoneBearing );
|
||||
}
|
||||
else
|
||||
{
|
||||
writeln_d("cluster bearing invalid, bearing: ", zoneBearing);
|
||||
//assume cluster is flying straight at me, flank to side I'm already oriented towards
|
||||
clusterBearingTrue = ClosestFlanker.TrueBearingTo( zonePoint ) - 180.0;
|
||||
}
|
||||
|
||||
//don't need to normalize it here, the next line catches it
|
||||
double angle = ClosestFlanker.TrueBearingTo( zonePoint ) - 180.0;
|
||||
double relativeFlankBearing = MATH.NormalizeAngle0_360( angle - clusterBearingTrue );
|
||||
double flankAngle = 90.0;
|
||||
if( relativeFlankBearing > 180.0 )
|
||||
{
|
||||
flankAngle = 270.0;
|
||||
}
|
||||
|
||||
if (cPreferredFlank == "left")
|
||||
{
|
||||
flankAngle = 90.0;
|
||||
}
|
||||
else if(cPreferredFlank == "right")
|
||||
{
|
||||
flankAngle = 270.0;
|
||||
}
|
||||
|
||||
double flankBearing = MATH.NormalizeAngle0_360( clusterBearingTrue + flankAngle );
|
||||
WsfGeoPoint ePoint = WsfGeoPoint(zonePoint);
|
||||
ePoint.Extrapolate( flankBearing, flankDist );
|
||||
|
||||
//save off the flank point, in case we win this job
|
||||
mFlankJobIdToFlankPointMap.Set( JOB.GetId(), ePoint );
|
||||
|
||||
//find the range to the place we will fly so as to flank the target
|
||||
MinRange = ClosestFlanker.SlantRangeTo( ePoint );
|
||||
|
||||
double JobBidValue = 100000 + NumSubordinates * flankDist / MinRange;
|
||||
JobBidValue = JobBidValue + cFlankWeighting;
|
||||
return JobBidValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
writeln_d("!!! Invalid point in flank job");
|
||||
return -MATH.DOUBLE_MAX();
|
||||
}
|
||||
|
||||
end_query_bid_type
|
||||
|
||||
|
||||
|
||||
|
||||
precondition
|
||||
writeln_d("precondition interpret_flank_jobs");
|
||||
draw.SetDuration(PROCESSOR.UpdateInterval());
|
||||
WsfRIPRProcessor commander = PROCESSOR.GetRIPRCommanderProcessor();
|
||||
if (commander.IsValid())
|
||||
{
|
||||
mMyJob = commander.GetJobFor(TIME_NOW, PROCESSOR);
|
||||
if (mMyJob.IsValid() && mMyJob.Name() == "flank")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//remove any jobs this behavior created
|
||||
Array<WsfRIPRJob> jobs = PROCESSOR.GetJobs();
|
||||
foreach (WsfRIPRJob job in jobs)
|
||||
{
|
||||
if (job.IsValid() && job.Data().Exists("flankPointName"))
|
||||
{
|
||||
//its a valid flank point job created by this behavior, remove it
|
||||
PROCESSOR.RemoveJob(job);
|
||||
}
|
||||
}
|
||||
mFlankJobIdToFlankPointMap.Clear();
|
||||
|
||||
return Failure("Agent does not have a flank job!");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return Failure("Agent does not have a commander!");
|
||||
}
|
||||
end_precondition
|
||||
|
||||
|
||||
execute
|
||||
writeln_d("executing interpret_flank_jobs");
|
||||
|
||||
WsfGeoPoint zonePoint = (WsfGeoPoint)mMyJob.GetData("ZonePoint");
|
||||
double zoneBearing = (double) mMyJob.GetData("ZoneBearing");
|
||||
bool bearingValid = (bool) mMyJob.GetData("ZoneBearingValid");
|
||||
WsfZone flankZone = (WsfZone) mMyJob.GetData("FlankZone");
|
||||
double flankDist = (double) mMyJob.GetData("FlankDistance");
|
||||
string zoneName = (string) mMyJob.GetData("ZoneName");
|
||||
|
||||
WsfGeoPoint flankPoint = mFlankJobIdToFlankPointMap.Get( mMyJob.GetId() );
|
||||
|
||||
if (mDrawFlankLines)
|
||||
{
|
||||
//draw the outline of the flank zone
|
||||
flankZone.DebugDrawZone(zonePoint, zoneBearing*MATH.RAD_PER_DEG());
|
||||
|
||||
//draw flank point of interest (target we are flanking), white dot
|
||||
draw.BeginPoints();
|
||||
draw.SetColor(1.0, 1.0, 1.0);
|
||||
draw.Vertex(zonePoint);
|
||||
draw.End();
|
||||
|
||||
if (bearingValid)
|
||||
{
|
||||
//cluster heading is with reference to east (instead of north), so subtract 90 degrees
|
||||
#doulbe clusterBearingTrue = MATH.NormalizeAngle0_360( zoneBearing - 90.0 );
|
||||
double clusterBearingTrue = MATH.NormalizeAngle0_360( zoneBearing );
|
||||
|
||||
WsfGeoPoint bPoint = WsfGeoPoint(zonePoint);
|
||||
bPoint.Extrapolate( clusterBearingTrue, flankDist );
|
||||
|
||||
//draw red-orange line to represent heading of target's flight
|
||||
draw.BeginLines();
|
||||
draw.SetColor(1.0, 0.3, 0.1);
|
||||
draw.Vertex(zonePoint);
|
||||
draw.Vertex(bPoint);
|
||||
draw.End();
|
||||
}
|
||||
|
||||
//draw green line to the flank point (the side we are flying towards)
|
||||
draw.BeginLines();
|
||||
draw.SetColor(0.1, 1.0, 0.4);
|
||||
draw.Vertex(zonePoint);
|
||||
draw.Vertex(flankPoint);
|
||||
draw.End();
|
||||
}
|
||||
|
||||
//see if any subordinates are in the flank zone, if they are... flanking is done
|
||||
foreach( WsfPlatform sub in PLATFORM.Subordinates() )
|
||||
{
|
||||
if (flankZone.PointIsInside(sub.Location(), zonePoint, zoneBearing*MATH.RAD_PER_DEG(), 0.0))
|
||||
{
|
||||
writeln_d( "@@@ aifl subordinate ", sub.Name(), " inside flank zone!");
|
||||
mMyJob.SetProgress( PROCESSOR, 1.0 ); #mark the job as complete
|
||||
}
|
||||
}
|
||||
|
||||
int NumSubordinates = PLATFORM.Subordinates().Count();
|
||||
|
||||
//if flank job doesn't exist yet, create it
|
||||
WsfRIPRJob job = PROCESSOR.GetJobByData("flankPointName", zoneName);
|
||||
if( ! job.IsValid() )
|
||||
{
|
||||
if (NumSubordinates > 0)
|
||||
{
|
||||
extern double cFlankPointPriority;
|
||||
//set max job winners to number of subordinates (so all can proceed into zone)
|
||||
WsfRIPRJob temp = WsfRIPRJob.Create( PROCESSOR,
|
||||
"pursue-point",
|
||||
"pursue-point-" + zoneName,
|
||||
cFlankPointPriority,
|
||||
NumSubordinates);
|
||||
temp.SetData( "targetTrackName", zoneName ); //hack for now, so other code here works
|
||||
temp.SetData( "targetPoint", flankPoint );
|
||||
temp.SetData( "flankPointName", zoneName );
|
||||
PROCESSOR.AddJob(temp);
|
||||
writeln_d("--- ", PLATFORM.Name(), " job change, ADD: ", zoneName );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
job.SetData( "targetPoint" , flankPoint );
|
||||
writeln_d(" aiFL - updated flank pursue-point job ", zoneName, ", ( ", flankPoint.Latitude(), ", ", flankPoint.Longitude(), " )" );
|
||||
}
|
||||
|
||||
//remove all jobs that aren't involved with flanking
|
||||
Array<WsfRIPRJob> jobs = PROCESSOR.GetJobs();
|
||||
foreach (WsfRIPRJob x in jobs)
|
||||
{
|
||||
string name = (string)x.GetData("targetTrackName");
|
||||
if ( name != zoneName )
|
||||
{
|
||||
writeln_d("--- ", PLATFORM.Name(), " job change, REMOVE: ", name);
|
||||
PROCESSOR.RemoveJob(x);
|
||||
}
|
||||
}
|
||||
|
||||
end_execute
|
||||
|
||||
end_behavior
|
||||
198
processors/quantum_agents/aifl/behavior_interpret_zone_jobs.txt
Normal file
198
processors/quantum_agents/aifl/behavior_interpret_zone_jobs.txt
Normal file
@@ -0,0 +1,198 @@
|
||||
# ****************************************************************************
|
||||
# CUI
|
||||
#
|
||||
# The Advanced Framework for Simulation, Integration, and Modeling (AFSIM)
|
||||
#
|
||||
# The use, dissemination or disclosure of data in this file is subject to
|
||||
# limitation or restriction. See accompanying README and LICENSE for details.
|
||||
# ****************************************************************************
|
||||
|
||||
|
||||
|
||||
//this behavior will be the only one in an agents tree that bids on "zone" jobs (compiler error otherwise)
|
||||
//this behavior should be the only one in an agents tree that creates "pursue-target" jobs when it runs (unexplained behavior otherwise)
|
||||
//in other words... if other behaviors also create "pursue-target" jobs, they should all be under a selector node, so only 1 runs on any update
|
||||
|
||||
|
||||
behavior interpret_zone_jobs
|
||||
|
||||
script_debug_writes off
|
||||
|
||||
|
||||
script_variables
|
||||
bool fastAndDirtyBidding = false;
|
||||
int maxJobWinnersForPursueTrack = 1;
|
||||
Map<string, string> ThreatTypeEngageZone = Map<string, string>();
|
||||
WsfRIPRJob mCurrentJob;
|
||||
end_script_variables
|
||||
|
||||
|
||||
on_init
|
||||
//nothing here yet
|
||||
end_on_init
|
||||
|
||||
|
||||
|
||||
query_bid_type zone
|
||||
|
||||
if (PLATFORM.Subordinates().Count() <= 0 || PROCESSOR.GetRIPRSubordinateProcessors().Size() <= 0)
|
||||
{
|
||||
writeln_d("behavior interpret_zone_jobs: not enough subordinates");
|
||||
return -MATH.DOUBLE_MAX();
|
||||
}
|
||||
|
||||
########################################################################
|
||||
## bid on the cluster is based on subordinate bids on their members
|
||||
########################################################################
|
||||
WsfRIPRJob tempJob = WsfRIPRJob.Create(PROCESSOR,"pursue-target","job description",1.0,1);
|
||||
Array<string> targetNames = (Array<string>)JOB.GetData("ZoneThreatNameArray");
|
||||
writeln_d("job ", JOB.GetDescription(), " -> number of target names considering: ", targetNames.Size());
|
||||
double maxBid = -MATH.DOUBLE_MAX();
|
||||
|
||||
foreach(string targetName in targetNames)
|
||||
{
|
||||
bool inZone = true;
|
||||
WsfPlatform target = WsfSimulation.FindPlatform(targetName);
|
||||
if (target.IsValid())
|
||||
{
|
||||
extern string DeterminePlatformCategory(WsfPlatform);
|
||||
string category = DeterminePlatformCategory(target);
|
||||
if (ThreatTypeEngageZone.Exists(category) && ThreatTypeEngageZone[category].Length()>0)
|
||||
{
|
||||
if ( ! target.Location().WithinZone(ThreatTypeEngageZone[category]))
|
||||
{
|
||||
inZone = false;
|
||||
writeln_d("aifl ", PLATFORM.Name(),", target ", targetName, " outside of category ", category," zone ", ThreatTypeEngageZone[category], ". bid = -DOUBLE_MAX.");
|
||||
}
|
||||
else
|
||||
{
|
||||
writeln_d("aifl ", PLATFORM.Name(),", target ", targetName, " inside category ", category," zone ", ThreatTypeEngageZone[category], ". bid as usual!!!");
|
||||
}
|
||||
}
|
||||
foreach ( string aZone in PLATFORM.ZoneNames())
|
||||
{
|
||||
if ( !target.WithinZoneOf(PLATFORM, aZone) )
|
||||
{
|
||||
inZone = false;
|
||||
writeln_d("ai flight lead, target ", targetName, " outside of defined zone ", aZone, " curBid from subordinate set to -DOUBLE_MAX.");
|
||||
}
|
||||
else
|
||||
{
|
||||
writeln_d("ai flight lead, target ", targetName, " inside of defined zone ", aZone, " curBid unchanged.");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (inZone == true)
|
||||
{
|
||||
tempJob.SetData("targetTrackName", targetName);
|
||||
if (fastAndDirtyBidding)
|
||||
{
|
||||
maxBid = PROCESSOR.GetRIPRSubordinateProcessors().Get(0).QueryBid(tempJob);
|
||||
writeln_d("ai flight lead, fast dirty bid on ", JOB.Description()," = ", maxBid);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
//by default this expands through job-pass-through agents to get all bids
|
||||
double curBid = PROCESSOR.QuerySubordinatesMaxBid(tempJob);
|
||||
|
||||
writeln_d("ai flight lead, max bid on ", targetName," from subordinates: ", curBid);
|
||||
if (curBid > maxBid)
|
||||
{
|
||||
maxBid = curBid;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
maxBid = -MATH.DOUBLE_MAX();
|
||||
}
|
||||
}
|
||||
return maxBid;
|
||||
|
||||
end_query_bid_type
|
||||
|
||||
|
||||
|
||||
precondition
|
||||
writeln_d("precondition interpret_zone_jobs");
|
||||
|
||||
if (PROCESSOR.GetRIPRCommanderProcessor().IsValid())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Failure("Agent does not have a commander to get jobs from!");
|
||||
}
|
||||
end_precondition
|
||||
|
||||
|
||||
|
||||
execute
|
||||
writeln_d(PLATFORM.Name(), " executing interpret_zone_jobs, T=", TIME_NOW);
|
||||
|
||||
// now check the board to see what we've won!
|
||||
Map<string, int> updatedTracks = Map<string, int>();
|
||||
WsfRIPRProcessor commander = PROCESSOR.GetRIPRCommanderProcessor();
|
||||
|
||||
if (commander.IsJobWindowOpen())
|
||||
{
|
||||
//we can get a new job for ourselves here
|
||||
mCurrentJob = commander.GetJobFor(TIME_NOW, PROCESSOR);
|
||||
}
|
||||
else if (commander.IsBidWindowOpen())
|
||||
{
|
||||
//we dont update our own job board until here
|
||||
if( mCurrentJob.IsValid() && mCurrentJob.Name() == "zone" )
|
||||
{
|
||||
Array<string> targetNames = (Array<string>)mCurrentJob.GetData("ZoneThreatNameArray");
|
||||
writeln_d(PLATFORM.Name(), " targetNames.Size() = ", targetNames.Size());
|
||||
foreach(string targetName in targetNames)
|
||||
{
|
||||
WsfPlatform target = WsfSimulation.FindPlatform(targetName);
|
||||
if (target.IsValid())
|
||||
{
|
||||
updatedTracks.Set( targetName, 1 );
|
||||
|
||||
WsfRIPRJob job = PROCESSOR.GetJobByData("targetTrackName", targetName);
|
||||
if (job.IsValid())
|
||||
{
|
||||
//just update it, it already exists
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
extern double cPursueTargetPriority;
|
||||
WsfRIPRJob temp = WsfRIPRJob.Create(PROCESSOR,
|
||||
"pursue-target",
|
||||
"pursue-target-" + targetName,
|
||||
cPursueTargetPriority,
|
||||
maxJobWinnersForPursueTrack);
|
||||
temp.SetData("targetTrackName", targetName);
|
||||
PROCESSOR.AddJob(temp);
|
||||
writeln_d("--- ", PLATFORM.Name(), " job change, ADD: ", targetName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
writeln_d("--- currentJob not a valid zone job!!!!! Removing all my aifl jobs.");
|
||||
}
|
||||
|
||||
Array<WsfRIPRJob> jobs = PROCESSOR.GetJobs();
|
||||
foreach (WsfRIPRJob x in jobs)
|
||||
{
|
||||
string name = (string)x.GetData("targetTrackName");
|
||||
if (updatedTracks.Get(name) != 1 && x.Name() == "pursue-target")
|
||||
{
|
||||
writeln_d("--- ", PLATFORM.Name(), " job change, REMOVE: ", name);
|
||||
PROCESSOR.RemoveJob(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
end_execute
|
||||
|
||||
end_behavior
|
||||
338
processors/quantum_agents/aifl/behavior_manage-pincer.txt
Normal file
338
processors/quantum_agents/aifl/behavior_manage-pincer.txt
Normal file
@@ -0,0 +1,338 @@
|
||||
# ****************************************************************************
|
||||
# CUI
|
||||
#
|
||||
# The Advanced Framework for Simulation, Integration, and Modeling (AFSIM)
|
||||
#
|
||||
# The use, dissemination or disclosure of data in this file is subject to
|
||||
# limitation or restriction. See accompanying README and LICENSE for details.
|
||||
# ****************************************************************************
|
||||
|
||||
|
||||
behavior manage-pincer
|
||||
|
||||
script_debug_writes off
|
||||
|
||||
script_variables
|
||||
|
||||
//for debugging
|
||||
bool mDrawClusters = false;
|
||||
|
||||
//parameters used to determine if a pincer is appropriate
|
||||
bool mRequireActiveWeapons = false; //if true, weapons must be in flight before pincer performed
|
||||
double mMaxSeparationAngle = 120.0; //degrees (pincer done if we've flanked by this much)
|
||||
int mNumSubsInvolved = 2; //not necessary to be an even number
|
||||
double mThresholdDistance = 160 * 1852; //160nm
|
||||
//clustering is performed to make sure the group of threats we are pincering against are grouped tightly together
|
||||
//if more than one group exist, the 2nd, 3rd, etc... groups have to be far enough away so that they aren't a
|
||||
//concern for the pincer maneuver (i.e. we wont head into them by separating around the target group)
|
||||
string mClusterMethod = "HTREEMAX"; //also valid: K_MEANS, H_TREE_MIN
|
||||
double mClusterDistanceLimit = 20*1852; //20nm - how close the group members have to be together
|
||||
double mMinDistanceRatio = 1.15; //other groups have to be 15% farther away than target group
|
||||
|
||||
// parameters useful for those performing the pincer
|
||||
bool mCross = false;
|
||||
string mCapZoneName = ""; //useful to specify the name of zone in which we ignore the threat's
|
||||
//orientation, because they are capping while in the zone
|
||||
|
||||
// script variables, used by methods below, do not change, not for user edit
|
||||
Array<WsfTrack> mTrackArray = Array<WsfTrack>();
|
||||
Array<string> mTargetNames = Array<string>();
|
||||
WsfDraw mDraw = WsfDraw();
|
||||
double mMeanBearing = 0;
|
||||
bool mMeanBearingValid = false;
|
||||
WsfClusterManager mClusterManager;
|
||||
WsfRIPRJob mPincerJob;
|
||||
WsfGeoPoint mMeanPoint;
|
||||
WsfGeoPoint mSubPoint;
|
||||
end_script_variables
|
||||
|
||||
|
||||
on_init
|
||||
mClusterManager = WsfClusterManager.Create(); // creates a cluster manager owned by this script
|
||||
mClusterManager.SetClusterMethod(mClusterMethod); // default is: "K_MEANS"
|
||||
mClusterManager.SetDistanceFunction("POSITION_VELOCITY"); // default is: "POSITION_ONLY"
|
||||
mClusterManager.SetDistanceLimit(mClusterDistanceLimit) ;
|
||||
end_on_init
|
||||
|
||||
## utility method used to draw lines around tracks in a cluster ## lines are drawn according to the convex hull of the cluster members
|
||||
script void draw_cluster_hull(WsfCluster cluster)
|
||||
Array<WsfGeoPoint> pts = cluster.ConvexHull();
|
||||
if (pts.Size() <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
WsfGeoPoint first = pts.Get(0);
|
||||
mDraw.SetColor(1.0,0.5,0.0); //orange?
|
||||
mDraw.SetLineStyle("solid");
|
||||
mDraw.SetLineSize(2);
|
||||
mDraw.BeginPolyline();
|
||||
for (int j = 0; j < pts.Size(); j = j + 1 )
|
||||
{
|
||||
WsfGeoPoint pt = pts.Get(j);
|
||||
mDraw.Vertex(pt);
|
||||
}
|
||||
mDraw.Vertex(first);
|
||||
mDraw.End();
|
||||
if (cluster.BearingValid())
|
||||
{
|
||||
double bearing = cluster.Bearing();
|
||||
WsfGeoPoint pt = cluster.MeanLocation();
|
||||
mDraw.SetColor(1.0,1.0,1.0); //white?
|
||||
mDraw.BeginLines();
|
||||
mDraw.Vertex(pt); pt.Extrapolate(cluster.Bearing(), 92600); //50 nautical miles
|
||||
mDraw.Vertex(pt);
|
||||
mDraw.End();
|
||||
}
|
||||
end_script
|
||||
|
||||
script WsfGeoPoint MeanLocation(Array<WsfPlatform> plats)
|
||||
Vec3 mean = Vec3.Construct(0, 0, 0);
|
||||
if (plats.Size() > 0)
|
||||
{
|
||||
double scale = 1.0/((double)plats.Size());
|
||||
foreach(WsfPlatform plat in plats)
|
||||
{
|
||||
Vec3 temp = plat.LocationWCS();
|
||||
temp.Scale(scale);
|
||||
mean = Vec3.Add(mean, temp);
|
||||
}
|
||||
}
|
||||
return WsfGeoPoint.ConstructWCS(mean);
|
||||
end_script
|
||||
|
||||
script WsfGeoPoint SubordinatesMeanLocation()
|
||||
return MeanLocation(PROCESSOR.SubordinatePlatforms());
|
||||
end_script
|
||||
|
||||
script void RemovePincerJob()
|
||||
if(mPincerJob.IsValid())
|
||||
{
|
||||
//remove job from board
|
||||
WsfRIPRJob fake;
|
||||
writeln_d(PLATFORM.Name(), " job change, REMOVE: ", mPincerJob.GetDescription());
|
||||
PLATFORM.Comment(write_str("REMOVE job: ", mPincerJob.GetDescription()));
|
||||
PROCESSOR.RemoveJob(mPincerJob);
|
||||
mPincerJob = fake;
|
||||
}
|
||||
end_script
|
||||
|
||||
|
||||
|
||||
precondition
|
||||
|
||||
#writeln_d("precondition manage-pincer");
|
||||
|
||||
if (PROCESSOR.SubordinateProcessors().Size() < mNumSubsInvolved)
|
||||
{
|
||||
RemovePincerJob();
|
||||
writeln_d("not enough subordinates");
|
||||
return Failure("not enough subordinates");
|
||||
}
|
||||
|
||||
if (mRequireActiveWeapons)
|
||||
{
|
||||
int weaponCount = 0;
|
||||
Array<WsfRIPRProcessor> subs = PROCESSOR.SubordinateProcessors();
|
||||
foreach(WsfRIPRProcessor proc in subs)
|
||||
{
|
||||
weaponCount = weaponCount + proc.WeaponsActive();
|
||||
}
|
||||
if (weaponCount <= 0)
|
||||
{
|
||||
RemovePincerJob();
|
||||
writeln_d("no active weapons, no pincer yet");
|
||||
return Failure("no active weapons, no pincer yet");
|
||||
}
|
||||
}
|
||||
|
||||
mSubPoint = SubordinatesMeanLocation();
|
||||
|
||||
extern bool TestTrackCategory(WsfTrack, string);
|
||||
mTrackArray.Clear();
|
||||
mTargetNames.Clear();
|
||||
foreach (WsfLocalTrack track in PLATFORM.MasterTrackList())
|
||||
{
|
||||
if ( (track.IFF_Friend()) ||
|
||||
(track.SideValid() && track.Side() == PLATFORM.Side()) ||
|
||||
(! track. LocationValid() ) ||
|
||||
(track.SlantRangeTo(mSubPoint) > mThresholdDistance) ||
|
||||
(TestTrackCategory(track, "unknown")) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
track.SetBearing( track.Heading() ); #useful for the cluster processing
|
||||
mTrackArray.PushBack(track);
|
||||
mTargetNames.PushBack(track.TargetName());
|
||||
}
|
||||
|
||||
if (mTrackArray.Size() > 0)
|
||||
{
|
||||
mClusterManager.UpdateClusters(TIME_NOW,mTrackArray);
|
||||
if (mDrawClusters == true)
|
||||
{
|
||||
for (int i = 0; i < mClusterManager.Count(); i = i + 1 )
|
||||
{
|
||||
draw_cluster_hull(mClusterManager.Entry(i));
|
||||
}
|
||||
}
|
||||
|
||||
if (mClusterManager.Count() > 1)
|
||||
{
|
||||
//check distances
|
||||
double near = MATH.DOUBLE_MAX();
|
||||
double near2 = MATH.DOUBLE_MAX();
|
||||
|
||||
for (int i = 0; i < mClusterManager.Count(); i = i + 1 )
|
||||
{
|
||||
double dist = mClusterManager.Entry(i).MeanLocation().SlantRangeTo(mSubPoint);
|
||||
if (dist < near)
|
||||
{
|
||||
if (near < near2)
|
||||
{
|
||||
near2 = near;
|
||||
}
|
||||
near = dist;
|
||||
}
|
||||
else if (dist < near2)
|
||||
{
|
||||
near2 = dist;
|
||||
}
|
||||
}
|
||||
|
||||
double ratio = near2/near;
|
||||
if (ratio < mMinDistanceRatio)
|
||||
{
|
||||
RemovePincerJob();
|
||||
writeln_d("threats too spread out!");
|
||||
return Failure("threats too spread out!");
|
||||
}
|
||||
}
|
||||
|
||||
WsfCluster cluster = mClusterManager.Entry(0);
|
||||
mMeanPoint = cluster.MeanLocation();
|
||||
mMeanBearingValid = cluster.BearingValid();
|
||||
mMeanBearing = cluster.Bearing();
|
||||
}
|
||||
else //no threats to pincer against, exit out
|
||||
{
|
||||
RemovePincerJob();
|
||||
writeln_d("no threats to pincer against yet!");
|
||||
return Failure("no threats to pincer against yet!");
|
||||
}
|
||||
|
||||
//check separation of all subordinates
|
||||
//only relavent if not currently in phase 2 (dragging & chasing)
|
||||
int dragging = 0;
|
||||
if(mPincerJob.IsValid())
|
||||
{
|
||||
dragging = (int)mPincerJob.GetData("left_drag") + (int)mPincerJob.GetData("right_drag");
|
||||
}
|
||||
if (dragging == 0)
|
||||
{
|
||||
Array<WsfPlatform> subs = PROCESSOR.SubordinatePlatforms();
|
||||
WsfGeoPoint subMean = MeanLocation(subs);
|
||||
double standard = mMeanPoint.TrueBearingTo(subMean);
|
||||
double min = 361;
|
||||
double max = -361;
|
||||
foreach(WsfPlatform p in subs)
|
||||
{
|
||||
double b = MATH.NormalizeAngleMinus180_180(mMeanPoint.TrueBearingTo(p.Location()) - standard);
|
||||
min = MATH.Min(min, b);
|
||||
max = MATH.Max(max, b);
|
||||
}
|
||||
double diff = max - min;
|
||||
if (diff >= mMaxSeparationAngle)
|
||||
{
|
||||
RemovePincerJob();
|
||||
writeln_d("pincer complete, targets flanked!");
|
||||
return Failure("pincer complete, targets flanked!");
|
||||
}
|
||||
}
|
||||
|
||||
mDraw.SetDuration(PROCESSOR.UpdateInterval());
|
||||
return true;
|
||||
end_precondition
|
||||
|
||||
|
||||
|
||||
execute
|
||||
writeln_d("executing manage-pincer, T=", TIME_NOW);
|
||||
//first find the group of target(s) we are going to perform the pincer against
|
||||
//generate a list of their names and get their mean location
|
||||
Array<WsfRIPRProcessor> subs = PROCESSOR.SubordinateProcessors();
|
||||
int N = subs.Size();
|
||||
if (mPincerJob.IsValid())
|
||||
{
|
||||
//pincer job already created! just update it
|
||||
mPincerJob.SetData("ZoneThreatNameArray", mTargetNames);
|
||||
mPincerJob.SetData("ZonePoint", mMeanPoint);
|
||||
mPincerJob.SetData("ZoneBearingValid", mMeanBearingValid);
|
||||
mPincerJob.SetData("ZoneBearing", mMeanBearing);
|
||||
mPincerJob.SetData("all_on_cap", 0);
|
||||
|
||||
if (mCapZoneName != "" && mPincerJob.IsValid())
|
||||
{
|
||||
bool allOnCap = true;
|
||||
foreach(WsfTrack t in mTrackArray)
|
||||
{
|
||||
if ( ! t.ReportedLocation().WithinZone(mCapZoneName))
|
||||
{
|
||||
allOnCap = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (allOnCap)
|
||||
{
|
||||
mPincerJob.SetData("all_on_cap", 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//create a pincer job for this flight group
|
||||
string desc = write_str("pincer-", mNumSubsInvolved);
|
||||
extern double cPincerPriority;
|
||||
mPincerJob = WsfRIPRJob.Create( PROCESSOR, //creator
|
||||
"pincer", //name
|
||||
desc, //description
|
||||
cPincerPriority * mNumSubsInvolved, //priority (must be enough to break even with "mNumSubsInvolved" jobs of another type
|
||||
mNumSubsInvolved); //max winnners
|
||||
mPincerJob.SetData("ZoneThreatNameArray", mTargetNames);
|
||||
mPincerJob.SetData("ZonePoint", mMeanPoint);
|
||||
mPincerJob.SetData("ZoneBearingValid", mMeanBearingValid);
|
||||
mPincerJob.SetData("ZoneBearing", mMeanBearing);
|
||||
mPincerJob.SetData("left_drag", 0);
|
||||
mPincerJob.SetData("rightdrag", 0);
|
||||
mPincerJob.SetData("all_on_cap", 0);
|
||||
mPincerJob.SetWinnersMin(mNumSubsInvolved);
|
||||
//setup the left & right flyers
|
||||
double avgBearing = mMeanPoint.TrueBearingTo(mSubPoint);
|
||||
foreach(WsfRIPRProcessor proc in subs)
|
||||
{
|
||||
//Vec3 temp = proc.Platform().LocationWCS();
|
||||
double bearing = mMeanPoint.TrueBearingTo(proc.Platform().Location());
|
||||
double relAngle = MATH.NormalizeAngleMinus180_180(bearing-avgBearing);
|
||||
if (mCross)
|
||||
{
|
||||
relAngle = -1 * relAngle;
|
||||
}
|
||||
if (relAngle < 0)
|
||||
{
|
||||
mPincerJob.SetData(proc.Platform().Name(), "right");
|
||||
}
|
||||
else
|
||||
{
|
||||
mPincerJob.SetData(proc.Platform().Name(), "left");
|
||||
}
|
||||
}
|
||||
PROCESSOR.AddJob(mPincerJob);
|
||||
writeln_d("--- ", PLATFORM.Name(), " job change, ADD: ", mPincerJob.GetDescription() );
|
||||
PLATFORM.Comment(write_str("ADD job: ", mPincerJob.GetDescription()));
|
||||
# foreach(string tgt in mTargetNames)
|
||||
# {
|
||||
# PLATFORM.Comment(tgt);
|
||||
# }
|
||||
}
|
||||
end_execute
|
||||
|
||||
end_behavior
|
||||
54
processors/quantum_agents/aifl/behavior_manage-uplinks.txt
Normal file
54
processors/quantum_agents/aifl/behavior_manage-uplinks.txt
Normal file
@@ -0,0 +1,54 @@
|
||||
# ****************************************************************************
|
||||
# CUI
|
||||
#
|
||||
# The Advanced Framework for Simulation, Integration, and Modeling (AFSIM)
|
||||
#
|
||||
# The use, dissemination or disclosure of data in this file is subject to
|
||||
# limitation or restriction. See accompanying README and LICENSE for details.
|
||||
# ****************************************************************************
|
||||
|
||||
|
||||
##############################################################################
|
||||
### assumes exists: extern WsfTrack GetTrackByName(WsfPlatform, string);
|
||||
##############################################################################
|
||||
|
||||
behavior manage-uplinks
|
||||
|
||||
script_debug_writes off
|
||||
|
||||
script_variables
|
||||
//agent constants
|
||||
end_script_variables
|
||||
|
||||
precondition
|
||||
writeln_d("precondition manage-uplinks");
|
||||
return true;
|
||||
end_precondition
|
||||
|
||||
#on_init
|
||||
#end_on_init
|
||||
|
||||
execute
|
||||
writeln_d("executing manage-uplinks");
|
||||
Array<WsfRIPRJob> jobs = PROCESSOR.GetJobs();
|
||||
foreach (WsfRIPRJob job in jobs)
|
||||
{
|
||||
if (job.Name() == "weapon_uplink")
|
||||
{
|
||||
int weaponPlatformIndex = (int)job.GetData("weaponPlatformIndex");
|
||||
int targetPlatformIndex = (int)job.GetData("targetPlatformIndex");
|
||||
WsfPlatform weaponPlatform = WsfSimulation.FindPlatform(weaponPlatformIndex);
|
||||
WsfPlatform targetPlatform = WsfSimulation.FindPlatform(targetPlatformIndex);
|
||||
if (!weaponPlatform.IsValid() || !targetPlatform.IsValid())
|
||||
{
|
||||
//either the weapon is gone or the target is gone, so the uplink is no longer needed, remove the job
|
||||
string msg = write_str("weapon or target for ", job.GetDescription(), " is gone, remove job");
|
||||
writeln_d(msg);
|
||||
PLATFORM.Comment(msg);
|
||||
PROCESSOR.RemoveJob(job);
|
||||
}
|
||||
}
|
||||
}
|
||||
end_execute
|
||||
|
||||
end_behavior
|
||||
443
processors/quantum_agents/aifl/fl_quantum_tasker.txt
Normal file
443
processors/quantum_agents/aifl/fl_quantum_tasker.txt
Normal file
@@ -0,0 +1,443 @@
|
||||
# ****************************************************************************
|
||||
# CUI
|
||||
#
|
||||
# The Advanced Framework for Simulation, Integration, and Modeling (AFSIM)
|
||||
#
|
||||
# The use, dissemination or disclosure of data in this file is subject to
|
||||
# limitation or restriction. See accompanying README and LICENSE for details.
|
||||
# ****************************************************************************
|
||||
|
||||
|
||||
include_once ../common/weapon_defs.txt
|
||||
|
||||
|
||||
processor FL_QUANTUM_TASKER WSF_QUANTUM_TASKER_PROCESSOR
|
||||
|
||||
script_variables
|
||||
|
||||
bool mSelfCreateTasks = false; //if false, simply interpret received tasks
|
||||
|
||||
#########################################################################
|
||||
## for evaluating weapon tasks
|
||||
#########################################################################
|
||||
//bool mFilterOnWeapons = true;
|
||||
//double mPercentRangeMaxFire = 0.70;
|
||||
double cWEIGHT_SLANT_RANGE_TO = 1.0;
|
||||
double cWEIGHT_CLOSING_SPEED = 1.0;
|
||||
#double cMAX_SLANT_RANGE = 20037500.0; #halfway around the earth (half circumference)
|
||||
double cMAX_SLANT_RANGE = 10018750.0; #quarter way around the earth (quarter circumference)
|
||||
double cMIN_CLOSING_SPEED = -1050.0;
|
||||
|
||||
#########################################################################
|
||||
## for creating pincer tasks
|
||||
#########################################################################
|
||||
bool mCreatePincerTasks = false;
|
||||
//for debugging
|
||||
bool mDrawClusters = false;
|
||||
//parameters used to determine if a pincer is appropriate
|
||||
bool mRequireActiveWeapons = false; //if true, weapons must be in flight before pincer performed
|
||||
double mMaxSeparationAngle = 120.0; //degrees (pincer done if we've flanked by this much)
|
||||
int mNumSubsInvolved = 2; //not necessary to be an even number
|
||||
double mThresholdDistance = 160 * 1852; //160nm
|
||||
//clustering is performed to make sure the group of threats we are pincering against are grouped tightly together
|
||||
//if more than one group exist, the 2nd, 3rd, etc... groups have to be far enough away so that they aren't a
|
||||
//concern for the pincer maneuver (i.e. we wont head into them by separating around the target group)
|
||||
string mClusterMethod = "HTREEMAX"; //also valid: K_MEANS, H_TREE_MIN
|
||||
double mClusterDistanceLimit = 20*1852; //20nm - how close the group members have to be together
|
||||
double mMinDistanceRatio = 1.15; //other groups have to be 15% farther away than target group
|
||||
// parameters useful for those performing the pincer
|
||||
bool mCross = false;
|
||||
string mCapZoneName = ""; //specify the name of a zone in which we ignore the threat's orientation, (when they are capping in the zone)
|
||||
// script variables, used by methods below, do not change, not for user edit
|
||||
Array<WsfTrack> mTrackArray = Array<WsfTrack>();
|
||||
Array<string> mTargetNames = Array<string>();
|
||||
WsfDraw mDraw = WsfDraw();
|
||||
double mMeanBearing = 0;
|
||||
bool mMeanBearingValid = false;
|
||||
WsfClusterManager mClusterManager;
|
||||
|
||||
//WsfQuantumTask mPincerTask;
|
||||
|
||||
WsfGeoPoint mMeanPoint;
|
||||
WsfGeoPoint mSubPoint;
|
||||
end_script_variables
|
||||
|
||||
|
||||
on_initialize
|
||||
mClusterManager = WsfClusterManager.Create(); // creates a cluster manager owned by this script
|
||||
mClusterManager.SetClusterMethod(mClusterMethod); // default is: "K_MEANS"
|
||||
mClusterManager.SetDistanceFunction("POSITION_VELOCITY"); // default is: "POSITION_ONLY"
|
||||
mClusterManager.SetDistanceLimit(mClusterDistanceLimit) ;
|
||||
mDraw.SetDuration(PROCESSOR.UpdateInterval());
|
||||
end_on_initialize
|
||||
|
||||
|
||||
## utility method used to draw lines around tracks in a cluster ## lines are drawn according to the convex hull of the cluster members
|
||||
script void draw_cluster_hull(WsfCluster cluster)
|
||||
Array<WsfGeoPoint> pts = cluster.ConvexHull();
|
||||
if (pts.Size() <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
WsfGeoPoint first = pts.Get(0);
|
||||
mDraw.SetColor(1.0,0.5,0.0); //orange?
|
||||
mDraw.SetLineStyle("solid");
|
||||
mDraw.SetLineSize(2);
|
||||
mDraw.BeginPolyline();
|
||||
for (int j = 0; j < pts.Size(); j = j + 1 )
|
||||
{
|
||||
WsfGeoPoint pt = pts.Get(j);
|
||||
mDraw.Vertex(pt);
|
||||
}
|
||||
mDraw.Vertex(first);
|
||||
mDraw.End();
|
||||
if (cluster.BearingValid())
|
||||
{
|
||||
double bearing = cluster.Bearing();
|
||||
WsfGeoPoint pt = cluster.MeanLocation();
|
||||
mDraw.SetColor(1.0,1.0,1.0); //white?
|
||||
mDraw.BeginLines();
|
||||
mDraw.Vertex(pt); pt.Extrapolate(cluster.Bearing(), 92600); //50 nautical miles
|
||||
mDraw.Vertex(pt);
|
||||
mDraw.End();
|
||||
}
|
||||
end_script
|
||||
|
||||
|
||||
script WsfGeoPoint MeanLocation(Array<WsfAssetPerception> assets)
|
||||
Vec3 mean = Vec3.Construct(0, 0, 0);
|
||||
if (assets.Size() > 0)
|
||||
{
|
||||
double scale = 1.0/((double)assets.Size());
|
||||
foreach(WsfAssetPerception asset in assets)
|
||||
{
|
||||
Vec3 temp = asset.Location().LocationWCS();
|
||||
temp.Scale(scale);
|
||||
mean = Vec3.Add(mean, temp);
|
||||
}
|
||||
}
|
||||
return WsfGeoPoint.ConstructWCS(mean);
|
||||
end_script
|
||||
|
||||
|
||||
script Array<WsfQuantumTask> FlightLeadTaskGeneration (Array<WsfLocalTrack> TRACKS, Array<WsfAssetPerception> ASSETS )
|
||||
Array<WsfQuantumTask> tasks = Array<WsfQuantumTask>();
|
||||
//check if we are creating tasks or if we have a commander for that
|
||||
if (mSelfCreateTasks == true)
|
||||
{
|
||||
writeln_d(PLATFORM.Name(), ", T=", TIME_NOW, ", creating tasks for:");
|
||||
//if its us, then create weapon tasks for enemy tracks
|
||||
for (int i=0; i<TRACKS.Size(); i=i+1)
|
||||
{
|
||||
WsfLocalTrack lt = TRACKS.Get(i);
|
||||
if (lt.IsValid() && (!lt.SideValid() || lt.Side() != PLATFORM.Side()))
|
||||
{
|
||||
WsfQuantumTask task = WsfQuantumTask.Construct(1.0, "weapon", lt);
|
||||
task.SetTaskType("WEAPON");
|
||||
tasks.PushBack(task);
|
||||
writeln_d("weapon task generated for: ", lt.TargetName(), ", updated time: ", lt.UpdateTime());
|
||||
}
|
||||
else
|
||||
{
|
||||
writeln_d("ignoring track for: ", lt.TargetName());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
WsfTaskList rcvdTasks = PROCESSOR.TasksReceivedOfType("CLUSTER");
|
||||
//do something with them, interpret them
|
||||
foreach (WsfTask t in rcvdTasks)
|
||||
{
|
||||
//writeln(PLATFORM.Name(), " received CLUSTER task: ", t.TaskType(), ", resource: ", t.ResourceName());
|
||||
Array<WsfTrack> perceivedThreats = PLATFORM.PerceivedThreats();
|
||||
Array<string> clusterMembers = (Array<string>)t.AuxDataObject("ClusterMemberNames");
|
||||
bool foundOne = false;
|
||||
foreach(string member in clusterMembers)
|
||||
{
|
||||
foreach(WsfTrack threat in perceivedThreats)
|
||||
{
|
||||
if (member == threat.TargetName())
|
||||
{
|
||||
if (threat.Target().IsValid())
|
||||
{
|
||||
//create a task for this target, we have perception of it
|
||||
WsfQuantumTask task = WsfQuantumTask.Construct(1.0, "weapon", threat);
|
||||
task.SetTaskType("WEAPON");
|
||||
tasks.PushBack(task);
|
||||
foundOne = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (foundOne == false)
|
||||
{
|
||||
//cluster task complete, all target members gone
|
||||
PROCESSOR.SetTaskComplete(t,"SUCCESSFUL");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#########################################################################
|
||||
## section for creating pincer tasks
|
||||
#########################################################################
|
||||
if (mCreatePincerTasks == false)
|
||||
{
|
||||
return tasks;
|
||||
}
|
||||
Array<WsfAssetPerception> assets = PLATFORM.PerceivedAssets();
|
||||
if (assets.Size() < mNumSubsInvolved)
|
||||
{
|
||||
writeln_d("not enough assets for a pincer maneuver, need ", mNumSubsInvolved);
|
||||
return tasks;
|
||||
}
|
||||
|
||||
if (mRequireActiveWeapons)
|
||||
{
|
||||
int weaponCount = 0;
|
||||
foreach(WsfAssetPerception perc in assets)
|
||||
{
|
||||
WsfPlatform plat = WsfSimulation.FindPlatform(perc.Index());
|
||||
weaponCount += plat.WeaponsActiveFor(WsfTrackId());
|
||||
}
|
||||
if (weaponCount <= 0)
|
||||
{
|
||||
writeln_d("no active weapons, no pincer yet");
|
||||
return tasks;
|
||||
}
|
||||
}
|
||||
|
||||
mSubPoint = MeanLocation(assets);
|
||||
|
||||
#extern bool TestTrackCategory(WsfTrack, string);
|
||||
mTrackArray.Clear();
|
||||
mTargetNames.Clear();
|
||||
Array<WsfTrack> threats = PLATFORM.PerceivedThreats();
|
||||
foreach(WsfTrack track in threats)
|
||||
{
|
||||
if ((track.IFF_Friend()) ||
|
||||
(track.SideValid() && track.Side() == PLATFORM.Side()) ||
|
||||
(!track. LocationValid()) ||
|
||||
(track.SlantRangeTo(mSubPoint) > mThresholdDistance) ||
|
||||
(TestTrackCategory(track, "unknown")) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
track.SetBearing( track.Heading() ); #useful for the cluster processing
|
||||
mTrackArray.PushBack(track);
|
||||
mTargetNames.PushBack(track.TargetName());
|
||||
}
|
||||
|
||||
if (mTrackArray.Size() > 0)
|
||||
{
|
||||
mClusterManager.UpdateClusters(TIME_NOW,mTrackArray);
|
||||
if (mDrawClusters == true)
|
||||
{
|
||||
for (int i = 0; i < mClusterManager.Count(); i = i + 1 )
|
||||
{
|
||||
draw_cluster_hull(mClusterManager.Entry(i));
|
||||
}
|
||||
}
|
||||
|
||||
if (mClusterManager.Count() > 1)
|
||||
{
|
||||
//check distances
|
||||
double near = MATH.DOUBLE_MAX();
|
||||
double near2 = MATH.DOUBLE_MAX();
|
||||
|
||||
for (int i = 0; i < mClusterManager.Count(); i = i + 1 )
|
||||
{
|
||||
double dist = mClusterManager.Entry(i).MeanLocation().SlantRangeTo(mSubPoint);
|
||||
if (dist < near)
|
||||
{
|
||||
if (near < near2)
|
||||
{
|
||||
near2 = near;
|
||||
}
|
||||
near = dist;
|
||||
}
|
||||
else if (dist < near2)
|
||||
{
|
||||
near2 = dist;
|
||||
}
|
||||
}
|
||||
|
||||
double ratio = near2/near;
|
||||
if (ratio < mMinDistanceRatio)
|
||||
{
|
||||
writeln_d("threats too spread out! no pincer tasks");
|
||||
return tasks;
|
||||
}
|
||||
}
|
||||
|
||||
WsfCluster cluster = mClusterManager.Entry(0);
|
||||
mMeanPoint = cluster.MeanLocation();
|
||||
mMeanBearingValid = cluster.BearingValid();
|
||||
mMeanBearing = cluster.Bearing();
|
||||
}
|
||||
else //no threats to pincer against, exit out
|
||||
{
|
||||
writeln_d("no threats to pincer against yet!");
|
||||
return tasks;
|
||||
}
|
||||
|
||||
//check separation of all subordinates
|
||||
//only relavent if not currently in phase 2 (dragging & chasing)
|
||||
int dragging = 0;
|
||||
# if(mPincerTask.IsValid())
|
||||
# {
|
||||
# dragging = mPincerTask.AuxDataInt("left_drag") + mPincerTask.AuxDataInt("right_drag");
|
||||
# }
|
||||
if (dragging == 0)
|
||||
{
|
||||
double standard = mMeanPoint.TrueBearingTo(mSubPoint);
|
||||
double min = 361;
|
||||
double max = -361;
|
||||
WsfPlatformList subs = PLATFORM.Subordinates();
|
||||
foreach(WsfPlatform p in subs)
|
||||
{
|
||||
double b = MATH.NormalizeAngleMinus180_180(mMeanPoint.TrueBearingTo(p.Location()) - standard);
|
||||
min = MATH.Min(min, b);
|
||||
max = MATH.Max(max, b);
|
||||
}
|
||||
double diff = max - min;
|
||||
if (diff >= mMaxSeparationAngle)
|
||||
{
|
||||
writeln_d("pincer complete, targets flanked! no more pincer task!");
|
||||
return tasks;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
writeln_d("creating pincers tasks! T=", TIME_NOW);
|
||||
//first find the group of target(s) we are going to perform the pincer against
|
||||
//generate a list of their names and get their mean location
|
||||
int N = assets.Size();
|
||||
for(int i=0; i<mNumSubsInvolved; i+=1)
|
||||
{
|
||||
//create a pincer task for this flight group
|
||||
//extern double cPincerPriority;
|
||||
WsfQuantumTask mPincerTask = WsfQuantumTask.Construct(1.0 * mNumSubsInvolved, "PINCER", mClusterManager.Entry(0).Entry(0));
|
||||
mPincerTask.SetAuxData( "ZoneThreatNameArray" , mTargetNames);
|
||||
mPincerTask.SetAuxData("ZonePoint", mMeanPoint);
|
||||
mPincerTask.SetAuxData("ZoneBearingValid", mMeanBearingValid);
|
||||
mPincerTask.SetAuxData("ZoneBearing", mMeanBearing);
|
||||
mPincerTask.SetAuxData("all_on_cap", 0);
|
||||
|
||||
mPincerTask.SetTaskType("PINCER");
|
||||
mPincerTask.SetUniqueId((10000000*(i+1)) + mClusterManager.Entry(0).Id());
|
||||
|
||||
//setup the left & right flyers
|
||||
double avgBearing = mMeanPoint.TrueBearingTo(mSubPoint);
|
||||
|
||||
foreach(WsfAssetPerception asset in assets)
|
||||
{
|
||||
//Vec3 temp = proc.Platform().LocationWCS();
|
||||
double bearing = mMeanPoint.TrueBearingTo(asset.Location());
|
||||
double relAngle = MATH.NormalizeAngleMinus180_180(bearing-avgBearing);
|
||||
if (mCross)
|
||||
{
|
||||
relAngle = -1 * relAngle;
|
||||
}
|
||||
if (relAngle < 0)
|
||||
{
|
||||
mPincerTask.SetAuxData(asset.Name(), "right");
|
||||
}
|
||||
else
|
||||
{
|
||||
mPincerTask.SetAuxData(asset.Name(), "left");
|
||||
}
|
||||
}
|
||||
tasks.PushBack(mPincerTask);
|
||||
}
|
||||
return tasks;
|
||||
end_script
|
||||
|
||||
|
||||
script double FlightLeadEvaluation ( WsfQuantumTask TASK, WsfAssetPerception ASSET)
|
||||
#TODO - include missile capability in evaluation
|
||||
# for now: just base value on range & whether or not asset as domain capable weapon
|
||||
WsfTrack track = PLATFORM.MasterTrackList().FindTrack(TASK.TrackId());
|
||||
|
||||
writeln_d(PLATFORM.Name(), " evaluating task type ", TASK.TaskType());
|
||||
|
||||
if (TASK.TaskType() == "WEAPON" && TASK.ResourceIsWeapon() && track.IsValid())
|
||||
{
|
||||
writeln_d("evaluating weapon task: ", track.TargetName(), ", updated time: ", track.UpdateTime());
|
||||
#TODO - select one of the systems?
|
||||
for (int i=0; i<ASSET.SystemCount(); i+=1)
|
||||
{
|
||||
writeln_d("system kind: ", ASSET.SystemKind(i));
|
||||
writeln_d("system name: ", ASSET.SystemName(i));
|
||||
writeln_d("system quantity: ", ASSET.SystemQuantityRemaining(i));
|
||||
writeln_d("system type: ", ASSET.SystemType(i));
|
||||
|
||||
if (ASSET.SystemKind(i) == "weapon" && ASSET.SystemQuantityRemaining(i) >= 1)
|
||||
{
|
||||
double value = 1.0 / track.SlantRangeTo(ASSET.Location());
|
||||
|
||||
struct weaponData = GetWeaponData(ASSET.SystemType(i));
|
||||
if (weaponData->type == ASSET.SystemType(i))
|
||||
{
|
||||
if ((weaponData->domainAir && track.AirDomain()) ||
|
||||
(weaponData->domainLand && track.LandDomain()) )
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//check launch computers
|
||||
WsfPlatform shooter = WsfSimulation.FindPlatform(ASSET.Index());
|
||||
if (shooter.IsValid())
|
||||
{
|
||||
WsfWeapon weapon = shooter.Weapon(ASSET.SystemName(i));
|
||||
if (weapon.IsValid())
|
||||
{
|
||||
WsfLaunchComputer lcPtr = weapon.LaunchComputer();
|
||||
if (lcPtr.IsValid())
|
||||
{
|
||||
if (track.AirDomain() && lcPtr.IsA_TypeOf("WSF_AIR_TO_AIR_LAUNCH_COMPUTER"))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
else if (track.LandDomain() && lcPtr.IsA_TypeOf("WSF_ATG_LAUNCH_COMPUTER"))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else if (TASK.TaskType() == "PINCER")
|
||||
{
|
||||
WsfGeoPoint pt = (WsfGeoPoint)TASK.AuxDataObject("ZonePoint");
|
||||
double dist = ASSET.Location().GroundRangeTo(pt);
|
||||
return 1.0/dist;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
end_script
|
||||
|
||||
#show_task_messages
|
||||
script_debug_writes off
|
||||
update_interval 10.0 sec
|
||||
asset_representation platform
|
||||
reallocation_strategy dynamic
|
||||
generator custom FlightLeadTaskGeneration
|
||||
evaluator custom FlightLeadEvaluation
|
||||
#generator simple_weapon
|
||||
#evaluator distance
|
||||
allocator optimal_profit
|
||||
#allocator_extra_tasks optimal_profit
|
||||
allocator_extra_assets optimal_profit
|
||||
|
||||
end_processor
|
||||
|
||||
Reference in New Issue
Block a user