Files
lab1/processors/ripr_agents/aiai/aiai_processor.txt
2025-09-12 15:20:28 +08:00

519 lines
21 KiB
Plaintext

# ****************************************************************************
# 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.
# ****************************************************************************
#always requires a commander (in order to do anything interesting)
#does not create any jobs
include_once processors/ripr_agents/common/common_platform_script.txt
include_once processors/ripr_agents/aiai/behavior_bid_on_jobs.txt
include_once processors/ripr_agents/aiai/behavior_cap-route.txt
include_once processors/ripr_agents/aiai/behavior_default-flight.txt
include_once processors/ripr_agents/aiai/behavior_engage-target.txt
include_once processors/ripr_agents/aiai/behavior_escort.txt
include_once processors/ripr_agents/aiai/behavior_evade.txt
include_once processors/ripr_agents/aiai/behavior_go_home.txt
include_once processors/ripr_agents/aiai/behavior_guide_weapons.txt
include_once processors/ripr_agents/aiai/behavior_pincer.txt
include_once processors/ripr_agents/aiai/behavior_pincer_fsm.txt
include_once processors/ripr_agents/aiai/behavior_pursue-point.txt
include_once processors/ripr_agents/aiai/behavior_pursue-target.txt
include_once processors/ripr_agents/aiai/behavior_radar-control.txt
#include_once processors/ripr_agents/aiai/behavior_sar_job.txt
#include_once processors/ripr_agents/aiai/behavior_weapon-uplink.txt
processor AIAI-thinker WSF_RIPR_PROCESSOR
update_interval 1.0 sec
script_debug_writes off
script_variables
// agent constants
double cMIN_JOB_BID = -MATH.DOUBLE_MAX();
//**********************************************************************//
//** bidding parameters **//
//** slant range and closing speed are the most important **//
//** bids are now in units of distance (meters) **//
//** all other bid contributions are converted with their weight **//
//** range will dominate the bids **//
//**********************************************************************//
double cMAX_SLANT_RANGE = 1000000.0; #over 539 nm away, target ranges beyond this are considered unfavorable
double cWEIGHT_SLANT_RANGE_TO = 1.0;
#double cWEIGHT_SLANT_RANGE_TO = -4.0; #-3.0 (legacy value)
double cMIN_CLOSING_SPEED = -1050.0; #threats running away (negative closing) faster are considered unfavorable
double cWEIGHT_CLOSING_SPEED = 1.0; #scale for how closing speed translates to distance
double cWEIGHT_FUEL = 0.0; #try a value of 2.0 if you care about fuel
double cWEIGHT_MY_WEAPONS_ACTIVE = 0.0; #changes bid if your own weapons are active on target
double cWEIGHT_PEERS_WEAPONS_ACTIVE = 0.0; #changes bid if your peers weapons are active on target
double cWEIGHT_THREAT_WEAPONS_ENVELOPE = 0.0; #uses the global "mWeaponsEnvelope" array, try value of 10000 if you care about that
//careful with these two parameters, they are stateful
double cWEIGHT_CURRENT_TARGET = 0.0; #changes bid if you are currently targeting the threat
#double cWEIGHT_CURRENT_TARGET = 10.0; #cap route jobs
#double cWEIGHT_CURRENT_TARGET = 1.0; #weapon uplink jobs
double cWEIGHT_OTHERS_TARGETING = 0.0; #changes bid if peers are currently targeting the threat
//**********************************************************************//
//** control / mode of operation parameters **//
//**********************************************************************//
bool mFilterJobsOnWeapons = true; # ignore pursue-target jobs that we cant shoot a weapon at
bool mFilterJobsOnCategory = false; # ignore pursue-target jobs that are for platform of unknown category
bool mFilterJobsOnFuel = false; # ignore pursue-target jobs that we dont have the fuel to reach
bool mFilterJobsOnZone = false; # ignore pursue-target jobs that are for platforms outsize of zone "mZoneName"
string mZoneName = "";
WsfZone mFezZone;
string mRequiredWeaponForCap = "";
bool mAllowCoopEngage = true;
string mUplinkSensorName = "geo_sensor"; //name of sensor object
double cDEFAULT_ALTITUDE = 9144; // ~30,000 feet
// the interceptor uses these threat priority pairs to determine who is the most important threat of concern
Map<string, double> ThreatTypePriority = Map<string, double>();
ThreatTypePriority["unknown"] = 0.0;
ThreatTypePriority["uav"] = 2.0;
ThreatTypePriority["sam"] = 4.0;
ThreatTypePriority["ship"] = 4.0;
ThreatTypePriority["awacs"] = -500.0;
ThreatTypePriority["bomber"] = 2.0;
ThreatTypePriority["jammer"] = 0.0;
ThreatTypePriority["fighter"] = 10.0;
ThreatTypePriority["missile"] = 9.0;
ThreatTypePriority["missile_fast"] = 9.0; // try new category for cmd
Array<Map<string, Object>> mWeaponArray = Array<Map<string, Object>>();
////EXAMPLE:
//mWeaponArray[0] = Map<string, Object>();
//mWeaponArray[0].Set("name", "blue_lr_a2a_rf_missile");
//mWeaponArray[0].Set("weapon", PLATFORM.Weapon("blue_lr_a2a_rf_missile"));
//mWeaponArray[0].Set("rangeMin", 1852/2); // only used if the weapon does NOT have a launch computer
//mWeaponArray[0].Set("rangeMax", 60*1852); // only used if the weapon does NOT have a launch computer
//mWeaponArray[0].Set("onlyUseInRange", 1); // only considered if the target is already in range
//mWeaponArray[0].Set("numActiveMax", 1); // how many weapons of this type can be in play simultaneously
//mWeaponArray[0].Set("AIR", 1); // DOMAIN CAPABLE, yes, this weapon can hit air (default true)
//mWeaponArray[0].Set("LAND", 0); // DOMAIN CAPABLE, no, this weapon can NOT hit land (default false)
double mEngagementAggressiveness = 0.4; // value in range [0, 1]. 1 is suicidal, 0 is very cautious.
// used by behavior_in_danger, behavior_evade, & behavior_disengage.
end_script_variables
behavior_tree
behavior_node bid_on_jobs
selector
behavior_node evade
behavior_node go_home
behavior_node escort
behavior_node cap-route
behavior_node pincer_fsm
sequence
selector
behavior_node pursue-target
#behavior_node sar_job
behavior_node pursue-point
behavior_node default-flight
end_selector
behavior_node guide_weapons
end_sequence
end_selector
behavior_node radar-control
behavior_node engage-target
# behavior_node weapon-uplink
end_behavior_tree
###########################################################################
## utility script methods
###########################################################################
script bool HaveWeaponsForThreat(WsfTrack track)
#extern bool IsWeaponDomainCapable(WsfTrack, Map<string, Object>);
#extern Array<Map<string, Object>> mWeaponArray;
foreach (Map<string, Object> curWeapon in mWeaponArray)
{
WsfWeapon weapon = (WsfWeapon)curWeapon["weapon"];
if (weapon.QuantityRemaining() > 0 &&
IsWeaponDomainCapable(track,curWeapon))
{
if (curWeapon.Exists("onlyUseInRange") &&
(int)curWeapon["onlyUseInRange"] == 1 &&
PLATFORM.SlantRangeTo(track) > (double)curWeapon["rangeMax"] )
{
continue;
}
return true;
}
}
return false;
end_script
###########################################################################
## this runs when the processor initializes (when the platform does)
###########################################################################
# on_initialize
# writeln_d(PLATFORM.Name(), " executing on initialze!");
# end_on_initialize
###########################################################################
## deprecated, plz use query_bid_type <job-name> script blocks now
###########################################################################
#query_bid
# return cMIN_JOB_BID;
#end_query_bid
query_bid_type pursue-target
#extern Map<string, double> ThreatTypePriority;
#extern WsfTrack GetTrackByName (WsfPlatform, string);
#extern bool HasEnoughFuelToTravel (WsfPlatform,double);
#extern string DetermineTrackCategory (WsfTrack);
#extern bool TestTrackCategory (WsfTrack, string);
#extern double GetWeaponsEnvelope (WsfPlatform);
#extern double GetWeaponRangeMax(WsfPlatform aPlatform, Array<Map<string, Object>> aWeaponArray);
#extern Array<Map<string, Object>> mWeaponArray;
if (!JOB.IsValid())
{
writeln_d("query_bid_type pursue-target: JOB not valid");
return cMIN_JOB_BID;
}
string targetTrackName = (string)JOB.GetData("targetTrackName");
WsfTrack targetTrack = GetTrackByName(PLATFORM, targetTrackName);
if (!targetTrack.IsValid())
{
writeln_d("!!! No track for JOB: ", JOB.Name(), ", ", JOB.GetDescription(), ", ", targetTrackName);
return cMIN_JOB_BID;
}
double slantRangeTo = PLATFORM.SlantRangeTo(targetTrack);
double closingSpeed = PLATFORM.ClosingSpeedOf(targetTrack);
double maxWeaponRange = GetWeaponRangeMax(PLATFORM, mWeaponArray);
if (mFilterJobsOnFuel == true)
{
if (!HasEnoughFuelToTravel(PLATFORM,slantRangeTo-maxWeaponRange))
{
writeln_d("!!! Not enough fuel for JOB: ", JOB.Name(), ", ", JOB.GetDescription(), ", ", targetTrackName);
return cMIN_JOB_BID;
}
}
if (mFilterJobsOnCategory == true)
{
if (TestTrackCategory(targetTrack, "unknown"))
{
writeln_d("!!! Target type unknown for current job. ");
return cMIN_JOB_BID;
}
}
if (mFilterJobsOnWeapons == true)
{
//check here if we have any weapons remaining that are capable against target domain
if (!HaveWeaponsForThreat(targetTrack) &&
PROCESSOR.WeaponsActive(targetTrack) <= 0)
{
writeln_d("!!! No domain capable weapons left for target!");
return cMIN_JOB_BID;
}
}
if (mFilterJobsOnZone == true)
{
if (mZoneName != "")
{
mFezZone = PLATFORM.Zone(mZoneName);
if (!mFezZone.IsValid() || !mFezZone.PointIsInside(PLATFORM.Location()))
{
writeln_d("!!! Target outside of given FEZ!");
return cMIN_JOB_BID;
}
}
}
double weight_closing_speed = cWEIGHT_CLOSING_SPEED;
if (targetTrack.LandDomain())
{
weight_closing_speed = 2.0 * cWEIGHT_CLOSING_SPEED;
}
/////////////////////////////////////////////////////////////////////////
// calculate bulk of the bid HERE
double bid = 0.0;
bid += cWEIGHT_SLANT_RANGE_TO * (cMAX_SLANT_RANGE - slantRangeTo);
bid += weight_closing_speed * (-cMIN_CLOSING_SPEED + closingSpeed);
// the bid has its major contributers now
/////////////////////////////////////////////////////////////////////////
//calculate other optional bid contributions here
WsfFuel fuelObj = PLATFORM.Fuel();
if (fuelObj.IsValid())
{
bid = bid + cWEIGHT_FUEL * fuelObj.QuantityRemaining();
}
//contribution if I have an active weapon on the target
bid = bid + cWEIGHT_MY_WEAPONS_ACTIVE * PROCESSOR.WeaponsActive(targetTrack);
//contribution if peers have an active weapon on the target
bid = bid + cWEIGHT_PEERS_WEAPONS_ACTIVE * PROCESSOR.PeersWeaponsActive(targetTrack);
//contribution if I am currently targeting the target
if (PROCESSOR.GetTargetName() == targetTrackName)
{
bid = bid + cWEIGHT_CURRENT_TARGET;
}
//contribution if any peers are targeting the target
WsfRIPRProcessor commander = PROCESSOR.GetRIPRCommanderProcessor();
if (commander.IsValid())
{
bid = bid + cWEIGHT_OTHERS_TARGETING * commander.SubsTargeting(targetTrack, PLATFORM);
}
//contribution bonus if you care about weapon envelopes
if (slantRangeTo < GetWeaponsEnvelope(targetTrack.Target()))
{
bid = bid + cWEIGHT_THREAT_WEAPONS_ENVELOPE;
}
//contribution bonus from threat type (category)
string targetType = DetermineTrackCategory(targetTrack);
if( ThreatTypePriority.Exists( targetType ) )
{
bid = bid + ThreatTypePriority.Get( targetType );
}
writeln_d(PLATFORM.Name(), " bid on target ", targetTrackName, ": ", bid);
return bid;
end_query_bid_type
query_bid_type cap-route
//writeln_d("BEHAVIOR NODE query_bid_type cap-route");
if (!JOB.IsValid())
{
return -MATH.DOUBLE_MAX();
}
double current_bid = 10000.0;
Map<string, Object>tempData = JOB.GetData();
WsfGeoPoint point = (WsfGeoPoint)tempData["location"];
double heading = (double)tempData["heading"];
string routeName = (string)tempData["route name"];
WsfRoute route = WsfRoute.FindGlobal(routeName);
if (!point.IsValid())
{
writeln("!!! Invalid point for current job: ",JOB.Name(), ", ", JOB.GetDescription() );
return cMIN_JOB_BID;
}
if (!route.IsValid())
{
writeln("!!! Invalid route for job to bid on: ",JOB.Name(), ", ", JOB.GetDescription() );
return cMIN_JOB_BID;
}
// check fuel levels
#extern bool HasEnoughFuelToTravelRoute(WsfPlatform,WsfRoute);
if (mFilterJobsOnFuel && !HasEnoughFuelToTravelRoute(PLATFORM,route))
{
writeln_d("!!! Not enough fuel for JOB: ", JOB.Name(), ", ", JOB.GetDescription());
return cMIN_JOB_BID;
}
double bid = 1000000 - PLATFORM.SlantRangeTo(point);
if (mRequiredWeaponForCap != "")
{
double Q = PLATFORM.Weapon(mRequiredWeaponForCap).QuantityRemaining();
if (Q <= 0)
{
return 0.001;
}
bid = bid + 20000 * Q;
}
return bid;
end_query_bid_type
query_bid_type pincer
//writeln_d("BEHAVIOR NODE querybid_type pincer");
if (!JOB.IsValid())
{
return cMIN_JOB_BID;
}
double current_bid = 10000.0;
WsfGeoPoint point = (WsfGeoPoint)JOB.GetData("ZonePoint");
if (!point.IsValid())
{
writeln_d("!!! Invalid point for current job: ",JOB.Name(), ", ", JOB.GetDescription() );
return cMIN_JOB_BID;
}
##extern Map<string, double> ThreatTypePriority;
#extern string DetermineTrackCategory (WsfTrack);
#extern bool TestTrackCategory (WsfTrack, string);
#extern double GetWeaponsEnvelope (WsfPlatform);
double slantRangeTo = PLATFORM.SlantRangeTo(point);
// calculate bulk of the bid now //
double weight_closing_speed = 2.0 * cWEIGHT_CLOSING_SPEED;
double closingSpeed = PLATFORM.Speed() * MATH.Cos(PLATFORM.RelativeBearingTo(point));
current_bid += cWEIGHT_SLANT_RANGE_TO * (cMAX_SLANT_RANGE - slantRangeTo);
current_bid += weight_closing_speed * (-cMIN_CLOSING_SPEED + closingSpeed);
// // // // // // // // // //
WsfFuel fuelObj = PLATFORM.Fuel();
if (fuelObj .IsValid())
{
current_bid = current_bid + cWEIGHT_FUEL * fuelObj.QuantityRemaining();
}
current_bid = current_bid + cWEIGHT_MY_WEAPONS_ACTIVE * PROCESSOR.WeaponsActive();
# if (slantRangeTo < GetWeaponsEnvelope(targetTrack.Target()))
# {
current_bid = current_bid + cWEIGHT_THREAT_WEAPONS_ENVELOPE;
# }
# if( ThreatTypePriority.Exists( targetType ) )
# { # current_bid = current_bid + ThreatTypePriority.Get( targetType ); # }
//lets include these in just so this bid is equally competitive with pursue-target jobs
current_bid = current_bid + cWEIGHT_CURRENT_TARGET;
//current_bid = current_bid + cWEIGHT_PEERS_WEAPONS_ACTIVE * (PROCESSOR.PeersWeaponsActive());
#extern Map<string, double> ThreatTypePriority;
#extern string DetermineTrackCategory(WsfTrack);
#extern WsfTrack GetTrackByName (WsfPlatform, string);
Array<string> targetNames = (Array<string>)JOB.GetData("ZoneThreatNameArray");
foreach(string tgtName in targetNames)
{
WsfTrack tgt = GetTrackByName(PLATFORM, tgtName);
if (tgt.IsValid())
{
string targetType = DetermineTrackCategory(tgt);
if( ThreatTypePriority.Exists( targetType ) )
{
current_bid = current_bid + ThreatTypePriority.Get( targetType );
}
}
}
return current_bid;
end_query_bid_type
query_bid_type pursue-point
writeln_d("BEHAVIOR NODE query_bid_type pursue-point");
if (!JOB.IsValid())
{
return cMIN_JOB_BID;
}
double current_bid = 10000.0;
WsfGeoPoint point = (WsfGeoPoint)JOB.GetData("targetPoint");
if (!point.IsValid())
{
writeln_d("!!! Invalid point for current job: ",JOB.Name(), ", ", JOB.GetDescription() );
return cMIN_JOB_BID;
}
double distToPoint = PLATFORM.SlantRangeTo(point);
// check fuel levels
#extern bool HasEnoughFuelToTravel(WsfPlatform,double);
if (mFilterJobsOnFuel &&
!HasEnoughFuelToTravel(PLATFORM,distToPoint))
{
writeln_d("!!! Not enough fuel for JOB: ", JOB.Name(), ", ", JOB.GetDescription());
return cMIN_JOB_BID;
}
current_bid += cWEIGHT_SLANT_RANGE_TO * (cMAX_SLANT_RANGE - distToPoint);
return current_bid;
end_query_bid_type
query_bid_type weapon_uplink
writeln_d("BEHAVIOR NODE query_bid_type weapon_uplink");
if (!JOB.IsValid())
{
return cMIN_JOB_BID;
}
double current_bid = 10000.0;
//check if I can support this weapon
#extern WsfTrack GetTrackByName(WsfPlatform, string);
string name = (string)JOB.GetData("targetTrackName");
int weaponPlatformIndex = (int)JOB.GetData("weaponPlatformIndex");
int targetPlatformIndex = (int)JOB.GetData("targetPlatformIndex");
WsfTrack track = GetTrackByName(PLATFORM, name);
WsfPlatform weaponPlatform = WsfSimulation.FindPlatform(weaponPlatformIndex);
WsfPlatform targetPlatform = WsfSimulation.FindPlatform(targetPlatformIndex);
WsfLocalTrack t = (WsfLocalTrack)track;
if (!weaponPlatform.IsValid() ||
!targetPlatform.IsValid() ||
!track.IsValid())
{
writeln_d("!!! Invalid weapon or target for job: ", JOB.GetDescription() );
return cMIN_JOB_BID;
}
if (!mAllowCoopEngage &&
!t.ContributorOf(PLATFORM))
{
return cMIN_JOB_BID;
}
if (PLATFORM.WithinFieldOfView(targetPlatform, mUplinkSensorName))
{
double alreadyUplinking = 0.0;
if (PROCESSOR.IsUplinkingTo(weaponPlatform))
{
alreadyUplinking = 1.0;
}
current_bid += cWEIGHT_SLANT_RANGE_TO * (cMAX_SLANT_RANGE - PLATFORM.SlantRangeTo(targetPlatform));
current_bid += cWEIGHT_CLOSING_SPEED * (-cMIN_CLOSING_SPEED + PLATFORM.ClosingSpeedOf(targetPlatform));
current_bid += cWEIGHT_CURRENT_TARGET * alreadyUplinking;
}
else
{
writeln_d("!!! target for uplink job is out of view: ", JOB.GetDescription() );
return cMIN_JOB_BID;
}
//writeln_d(" uplink returning calculated bid: ", current_bid);
return current_bid;
end_query_bid_type
########################################################################
### this script block is executed every update interval
### it runs before the behavior tree
########################################################################
# on_update
# #double startTime = PROCESSOR.WallClockTime();
# writeln_d(PLATFORM.Name(), " executing on update!");
# #double duration = PROCESSOR.WallClockTime() - startTime;
# #writeln_d("AIAI-thinker on update duration = ", duration);
# end_on_update
end_processor