# **************************************************************************** # 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 ThreatTypePriority = Map(); 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> mWeaponArray = Array>(); ////EXAMPLE: //mWeaponArray[0] = Map(); //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); #extern Array> mWeaponArray; foreach (Map 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 script blocks now ########################################################################### #query_bid # return cMIN_JOB_BID; #end_query_bid query_bid_type pursue-target #extern Map 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> aWeaponArray); #extern Array> 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; MaptempData = 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 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 ThreatTypePriority; #extern string DetermineTrackCategory(WsfTrack); #extern WsfTrack GetTrackByName (WsfPlatform, string); Array targetNames = (Array)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