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

1155 lines
39 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.
# ****************************************************************************
# * * ************************************** * *
# * ****** Demonstration input file ****** *
# * ****** UNCLASSIFIED ****** *
# * * ************************************** * *
# --------------------------------------------------------------
# Common Script Methods
# --------------------------------------------------------------
script_interface
script_debug_writes off
script_variables
Array<string> mCategories = Array<string>();
mCategories.PushBack("primary_target");
mCategories.PushBack("secondary_target");
mCategories.PushBack("fighter");
mCategories.PushBack("bomber");
mCategories.PushBack("jammer");
mCategories.PushBack("uav");
mCategories.PushBack("awacs");
mCategories.PushBack("ship");
mCategories.PushBack("sam");
mCategories.PushBack("missile");
mCategories.PushBack("acquisition");
mCategories.PushBack("cruise-missile");
mCategories.PushBack("insurgent");
mCategories.PushBack("ambush_site");
Map<string, Map<string, double>> mWeaponsEnvelope = Map<string, Map<string, double>>();
mWeaponsEnvelope["red"] = Map<string, double>();
mWeaponsEnvelope["blue"] = Map<string, double>();
mWeaponsEnvelope["red"].Set( "fighter", 40 * 1852); //40 nm (units of meters)
mWeaponsEnvelope["red"].Set( "bomber" , 40 * 1852); //40 nm (units of meters)
mWeaponsEnvelope["red"].Set( "ship" , 40 * 1852); //40 nm (units of meters)
mWeaponsEnvelope["red"].Set( "sam" , 40 * 1852); //40 nm (units of meters)
mWeaponsEnvelope["blue"].Set("fighter", 50 * 1852); //50 nm (units of meters)
mWeaponsEnvelope["blue"].Set("bomber" , 50 * 1852); //50 nm (units of meters)
mWeaponsEnvelope["blue"].Set("ship" , 50 * 1852); //50 nm (units of meters)
mWeaponsEnvelope["blue"].Set("sam" , 50 * 1852); //50 nm (units of meters)
double mDefaultWeaponsEnvelope = 40 * 1852; //40 nm (units of meters)
#flag variables for evading (both by diving/climbing and banking left/right)
Map<string,bool> diveDownMap = Map<string,bool>();
Map<string,bool> bankLeftMap = Map<string,bool>();
Array<string> mBasicColors = Array<string>();
mBasicColors.Set(0, "Red");
mBasicColors.Set(1, "Green");
mBasicColors.Set(2, "Blue");
mBasicColors.Set(3, "Yellow");
mBasicColors.Set(4, "Teal");
mBasicColors.Set(5, "Violet");
Map<string, double> mRedColorValue = Map<string, double>();
mRedColorValue.Set("Red", 1.0);
mRedColorValue.Set("Green", 0.0);
mRedColorValue.Set("Blue", 0.0);
mRedColorValue.Set("Yellow",1.0);
mRedColorValue.Set("Teal", 0.0);
mRedColorValue.Set("Violet",1.0);
Map<string, double> mGreenColorValue = Map<string, double>();
mGreenColorValue.Set("Red", 0.0);
mGreenColorValue.Set("Green", 1.0);
mGreenColorValue.Set("Blue", 0.0);
mGreenColorValue.Set("Yellow",1.0);
mGreenColorValue.Set("Teal", 1.0);
mGreenColorValue.Set("Violet",0.0);
Map<string, double> mBlueColorValue = Map<string, double>();
mBlueColorValue.Set("Red", 0.0);
mBlueColorValue.Set("Green", 0.0);
mBlueColorValue.Set("Blue", 1.0);
mBlueColorValue.Set("Yellow",0.0);
mBlueColorValue.Set("Teal", 1.0);
mBlueColorValue.Set("Violet",1.0);
Array<string> ttrs = {"red_target_tracking_radar_1",
"red_target_tracking_radar_2",
"red_target_tracking_radar_3",
"etc..."};
Array<string> aiais = {"blue_striker_1",
"blue_striker_2",
"blue_striker_3",
"etc..."};
end_script_variables
/* #put this script somewhere in the simulation input if you want the aiai to be reactive to certain target tracking radars
#goal: determine when a target tracking radar is active on an AIAI
#observer callback for new sensor tracks
script void MySensorTrackInitiated(WsfPlatform aPlatform, WsfSensor aSensor, WsfTrack aTrack)
foreach(string aiai in aiais)
{
if (aiai == aTrack.TargetName()) #an aiai is being tracked
{
foreach(string ttr in ttrs)
{
if (ttr == aPlatform.Name()) #a ttr of interest is tracking him
{
WsfPlatform aiaiPlatform = WsfSimulation.FindPlatform(aiai);
if (aiaiPlatform.IsValid())
{
aiaiPlatform.SetAuxData(ttr, true);
writeln_d(ttr, " is tracking ", aiai);
}
}
}
}
}
end_script
observer
enable SENSOR_TRACK_INITIATED MySensorTrackInitiated
end_observer
*/
script string GetNextBasicColor()
static int mNextColor = 0;
if (mNextColor >= mBasicColors.Size())
{
mNextColor = 0;
}
string color = mBasicColors.Get(mNextColor);
mNextColor = mNextColor + 1;
return color;
end_script
script double RedVal(string color)
return mRedColorValue.Get(color);
end_script
script double GrnVal(string color)
return mGreenColorValue.Get(color);
end_script
script double BluVal(string color)
return mBlueColorValue.Get(color);
end_script
script bool FlyHold (WsfPlatform flyer, double heading, double altitude, double speed)
if (flyer.Mover().IsValid())
{
if (flyer.Mover().IsA_TypeOf("WSF_6DOF_MOVER"))
{
# flyer.GoToSpeed(speed);
# WsfGeoPoint pt = WsfGeoPoint.Construct(flyer.Latitude(), flyer.Longitude(), altitude);
# pt.Offset(heading, 18520, 0, 0); //10 nm away
# flyer.GoToLocation(pt);
# return true;
flyer.GoToSpeed(speed);
flyer.GoToAltitude(altitude);
flyer.TurnToHeading(heading, 500);
return true;
}
else if (flyer.Mover().IsA_TypeOf("WSF_AIR_MOVER"))
{
flyer.GoToSpeed(speed);
flyer.GoToAltitude(altitude);
flyer.TurnToHeading(heading);
return true;
}
}
writeln_d(flyer.Name(), " aiai error: unknown or invalid mover for flight");
return false;
end_script
script bool FlyTarget (WsfPlatform flyer, WsfGeoPoint location, double speed)
if (flyer.Mover().IsValid())
{
if (flyer.Mover().IsA_TypeOf("WSF_6DOF_MOVER"))
{
flyer.GoToSpeed(speed);
flyer.GoToLocation(location);
return true;
}
else if (flyer.Mover().IsA_TypeOf("WSF_AIR_MOVER"))
{
flyer.GoToSpeed(speed);
double altRateOfChange = flyer.Speed() * MATH.Sin(35.0);
flyer.GoToAltitude(location.Altitude(), altRateOfChange);
flyer.TurnToHeading(flyer.TrueBearingTo(location));
return true;
}
}
writeln_d(flyer.Name(), " aiai error: unknown or invalid mover for flight");
return false;
end_script
script string DeterminePlatformCategory(WsfPlatform aPlatform)
if( aPlatform.IsValid() )
{
foreach( string aCategory in mCategories )
{
if( aPlatform.CategoryMemberOf( aCategory ) )
{
return aCategory;
}
}
}
return "unknown";
end_script
script string DetermineTrackCategory(WsfTrack aTrack)
if (!aTrack.IsValid())
{
writeln_d("DetermineTrackCategory() invalid track!");
return "unknown";
}
int ind = aTrack.TargetIndex();
WsfPlatform plat;
plat = WsfSimulation.FindPlatform( ind );
if (!plat.IsValid())
{
writeln_d("DetermineTrackCategory() invalid platform from track!");
return "unknown";
}
string cat = DeterminePlatformCategory( plat );
return cat;
end_script
script string DetermineSensorCategory(WsfSensor aSensor)
if( aSensor.IsValid() )
{
foreach( string aCategory in mCategories )
{
if( aSensor.CategoryMemberOf( aCategory ) )
{
return aCategory;
}
}
}
return "unknown";
end_script
script bool TestPlatformCategory(WsfPlatform aPlatform, string aCategory)
if (!aPlatform.IsValid())
{
writeln_d("--- TestPlatformCategory(), aPlatform is not valid!");
return (aCategory == "unknown");
}
else if( aPlatform.CategoryMemberOf( aCategory ) )
{
writeln_d("--- TestPlatformCategory(), aCategory, ", aCategory, ", MATCH with platform, ", aPlatform.Name(), "!");
return true;
}
else if (aCategory == DeterminePlatformCategory(aPlatform))
{
writeln_d("--- TestPlatformCategory(), aCategory, ", aCategory, ", MATCH with platform, ", aPlatform.Name(), "!");
return true;
}
#writeln_d("--- TestPlatformCategory(), aCategory, ", aCategory, ", NOT A MATCH with platform, ", aPlatform.Name(), "!");
return false;
end_script
script bool TestTrackCategory(WsfTrack aTrack, string aCategory)
if (!aTrack.IsValid())
{
writeln_d("--- TestTrackCategory(), aTrack is not valid!");
// "unknown" returns true when aTrack is invalid
return (aCategory == "unknown");
}
int ind = aTrack.TargetIndex();
//writeln_d("--- TestTrackCategory(), target index: ", ind);
WsfPlatform plat;
plat = WsfSimulation.FindPlatform(ind);
if (!plat.IsValid())
{
writeln_d("--- TestTrackCategory(), plat is not valid!");
// "unknown" returns true when aTrack is invalid
return (aCategory == "unknown");
}
bool match = TestPlatformCategory(plat, aCategory);
return match;
end_script
script bool TestSensorCategory(WsfSensor aSensor, string aCategory)
if (!aSensor.IsValid())
{
writeln_d("--- TestSensorCategory(), aSensor is not valid!");
return (aCategory == "unknown");
}
else if( aSensor.CategoryMemberOf( aCategory ) )
{
writeln_d("--- TestSensorCategory(), aCategory, ", aCategory, ", is a match!");
return true;
}
else if (aCategory == DetermineSensorCategory(aSensor))
{
writeln_d("--- TestSensorCategory(), aCategory, ", aCategory, ", is a match!");
return true;
}
writeln_d("--- TestSensorCategory(), aCategory, ", aCategory, ", is NOT a match with sensor, ", aSensor.Name(), "!");
return false;
end_script
script double GetWeaponsEnvelope(WsfPlatform aThreatPlatform)
if (aThreatPlatform.IsValid() && mWeaponsEnvelope.Exists(aThreatPlatform.Side()))
{
Map<string, double> categoryRangeMap = mWeaponsEnvelope.Get(aThreatPlatform.Side());
foreach (string aCategory : double range in categoryRangeMap)
{
if( aThreatPlatform.CategoryMemberOf( aCategory ) )
{
return range;
}
}
}
return mDefaultWeaponsEnvelope;
end_script
//script double GetWeaponsEnvelope(WsfTrack aThreat)
// return GetWeaponsEvelope(aThreat.Target());
//end_script
// converts the actual groundRange into an effectiveRange that indicates "how far" aPlatform and aTrack
// are from each other given their closing speed and the thrust duration of the missle
// VERY HACKY
script double EffectiveRange (WsfPlatform aPlatform, WsfTrack aTarget)
double groundRange = aPlatform.GroundRangeTo(aTarget);
double closingSpeed = aPlatform.ClosingSpeedOf(aTarget);
double relativeAltitude = aPlatform.RelativeAltitudeOf(aTarget);
#double relativeAltitudeMod = aPlatform.RelativeAltitudeOf(aTarget) * 2;
#// mach 3 = 1 020.87 meters / second
#double closingSpeedMod = ((closingSpeed / 2 + 1520) / 1520);
#double effectiveRange = (groundRange + (relativeAltitudeMod)) / closingSpeedMod;
#writeln_d(" ", effectiveRange, " (effectiveRange) == ", groundRange, " ((groundRange) + ", relativeAltitudeMod, " (relativeAltitudeMod)) / ", closingSpeedMod, " (speedThrustMod), closingSpeed: ", closingSpeed);
double effectiveRange = (groundRange + relativeAltitude) + closingSpeed * 15; //look ahead 15 seconds
return effectiveRange;
end_script
#######
script double TargetAspect (WsfPlatform aPlatform, WsfTrack aTarget)
WsfGeoPoint platformLoc = aPlatform.Location();
WsfGeoPoint targetLoc = aTarget.CurrentLocation(); #extrapolated to current time
# all calculataions are in WCS
double dLosX = targetLoc.X() - platformLoc.X();
double dLosY = targetLoc.Y() - platformLoc.Y();
double dLosZ = targetLoc.Z() - platformLoc.Z();
double dLosMag = MATH.Sqrt( dLosX*dLosX + dLosY*dLosY + dLosZ*dLosZ );
dLosX = dLosX/dLosMag;
dLosY = dLosY/dLosMag;
dLosZ = dLosZ/dLosMag;
double dTgtVx = aTarget.Vx();
double dTgtVy = aTarget.Vy();
double dTgtVz = aTarget.Vz();
double dTgtVmag = MATH.Sqrt( dTgtVx*dTgtVx + dTgtVy*dTgtVy + dTgtVz*dTgtVz );
dTgtVx = dTgtVx/dTgtVmag;
dTgtVy = dTgtVy/dTgtVmag;
dTgtVz = dTgtVz/dTgtVmag;
double dotProd = dLosX*dTgtVx + dLosY*dTgtVy + dLosZ*dTgtVz;
return MATH.ACos(dotProd);
end_script
#######
script double GetMaxLaunchRange (WsfPlatform aPlatform,
WsfTrack aTarget,
string aWeaponName,
Array<Map<string, Object>> aWeaponArray) #double aMaxTOF, double aMaxFlyoutRange)
double dSlantRange = aPlatform.SlantRangeTo(aTarget);
double dTgtSpeed = aTarget.Speed();
double dTgtAspectAngle = TargetAspect( aPlatform, aTarget);
double dMaxTOF = 0;
double dMaxFlyoutRange = 0;
double dMaxLaunchRange = 0;
foreach (Map<string, Object> curWeapon in aWeaponArray)
{
if ( (string)curWeapon["name"] == aWeaponName )
{
if (curWeapon.Exists("maxFlyoutRange") &&
curWeapon.Exists("maxTimeOfFlight"))
{
dMaxFlyoutRange = (double)curWeapon["maxFlyoutRange"];
dMaxTOF = (double)curWeapon["maxTimeOfFlight"];
}
else
{
dMaxFlyoutRange = (double)curWeapon.Get("rangeMax");
dMaxTOF = 0;
}
break;
}
}
dMaxLaunchRange = dMaxFlyoutRange;
if ( dTgtSpeed > 5*MATH.MPS_PER_NMPH() )
{
dMaxLaunchRange = dMaxFlyoutRange - dTgtSpeed * MATH.Cos(dTgtAspectAngle) * dMaxTOF;
}
#writeln_d("$$$$ ", dSlantRange*(1/MATH.M_PER_NM()), ", ", dTgtAspectAngle ", ", dEffectiveRange*(1/MATH.M_PER_NM()));
#double effectiveRange = (groundRange + (relativeAltitudeMod)) / closingSpeedMod;
#writeln_d(" ", effectiveRange, " (effectiveRange) == ", groundRange, " ((groundRange) + ", relativeAltitudeMod, " (relativeAltitudeMod)) / ", closingSpeedMod, " (speedThrustMod), closingSpeed: ", closingSpeed);
return dMaxLaunchRange;
end_script
/*
* bool LaunchWeapon ()
*
* Launch a missile at the tracked target.
*/
script bool LaunchWeapon (WsfPlatform aPlatform, WsfTrack aTarget, WsfWeapon aWeapon, int salvo)
bool launched = false;
if (!aTarget.IsValid() || !aWeapon.IsValid())
{
writeln_d("!!! LaunchWeapon(): Invalid aWeapon or aTarget");
return launched;
}
// We can select the weapon only if it exists, has enough rounds and is not already busy launching
// (i.e.: it doesn't currently have a task assigned to it...)
if (aWeapon.IsTurnedOn() && (aWeapon.QuantityRemaining() >= 1 ))
{
writeln_d(" Attempting launch at ", aTarget.TargetName());
launched = aWeapon.FireSalvo(aTarget, salvo);
}
return launched;
end_script
script int GetWeaponNumberActiveMax( string weaponName, Array<Map<string, Object>> aWeaponArray )
foreach (Map<string, Object> curWeapon in aWeaponArray)
{
string curWeaponName = (string)curWeapon["name"];
#writeln_d("curWeapon[name] = ", curWeaponName, ". searching for: ", weaponName);
if( curWeaponName == weaponName )
{
#writeln_d("searched for weapon ", weaponName, ". found ", curWeaponName);
if( curWeapon.Exists("numActiveMax") )
{
return (int)curWeapon["numActiveMax"];
}
}
}
return 1;
end_script
script string GetTargetDomain(WsfTrack aTarget)
if (aTarget.AirDomain())
{
return "AIR";
}
if (aTarget.LandDomain())
{
return "LAND";
}
if (aTarget.SurfaceDomain())
{
return "SURFACE";
}
if (aTarget.SubsurfaceDomain())
{
return "SUBSURFACE";
}
if (aTarget.SpaceDomain())
{
return "SPACE";
}
if ( (aTarget.LocationValid() && aTarget.Altitude() <= 500.0) || aTarget.Speed() <= 50.0 )
{
return "LAND";
}
if ((aTarget.LocationValid() && aTarget.Altitude() > 500.0) || aTarget.Speed() > 50.0 )
{
return "AIR";
}
return "UNKNOWN";
end_script
// return true or false depending on if the given weapon can be fired on the
//given track (which represents a target of a particular domain)
script bool IsWeaponDomainCapable(WsfTrack aTarget, Map<string, Object> aWeaponMap)
string domain = GetTargetDomain(aTarget);
if (domain!="UNKNOWN")
{
if (domain=="AIR")
{
//AIR is a special case that defaults to true, when it doens't exist
if ((!aWeaponMap.Exists(domain)) || ((int)aWeaponMap[domain] == 1))
{
return true;
}
}
else // LAND, SPACE, SURFACE, SUBSURFACE
{
if (aWeaponMap.Exists(domain) && ((int)aWeaponMap[domain] == 1))
{
return true;
}
}
}
//else, no domains matched
return false;
end_script
// return the name of the first weapon from aWeaponArray that can hit aTarget
script string GetBestWeapon(WsfPlatform aPlatform,
WsfTrack aTarget,
Array<Map<string, Object>> aWeaponArray,
double aLaunchRangeMaxFraction)
double desiredRange = EffectiveRange(aPlatform, aTarget);
#writeln_d(" effective range from ", aPlatform.Name(), " to ", aTarget.TargetName(), " = ", desiredRange);
foreach (Map<string, Object> curWeapon in aWeaponArray)
{
if (((WsfWeapon)curWeapon["weapon"]).QuantityRemaining() <= 0)
{
continue;
}
if (!IsWeaponDomainCapable(aTarget,curWeapon))
{
continue;
}
if ((double)curWeapon["rangeMin"] > desiredRange)
{
continue;
}
if ((double)curWeapon["rangeMax"] * aLaunchRangeMaxFraction < desiredRange)
{
continue;
}
#writeln_d(" returning best weapon: ", (string)curWeapon["name"]);
return (string)curWeapon["name"];
}
return "";
end_script
// return the range of the longest-ranged weapon with ammo remaining
script double GetWeaponRangeMax(WsfPlatform aPlatform, Array<Map<string, Object>> aWeaponArray)
double rangeMax = 0;
foreach (Map<string, Object> curWeapon in aWeaponArray)
{
if (((WsfWeapon)curWeapon["weapon"]).QuantityRemaining() <= 0)
{
continue;
}
if ((double)curWeapon["rangeMax"] > rangeMax)
{
rangeMax = (double)curWeapon["rangeMax"];
}
}
return rangeMax;
end_script
// return the range of the weapon with smallest min range and with ammo remaining
script double GetWeaponRangeMin(WsfPlatform aPlatform, Array<Map<string, Object>> aWeaponArray)
double rangeMin = 99999999999.0;
foreach (Map<string, Object> curWeapon in aWeaponArray)
{
if (((WsfWeapon)curWeapon["weapon"]).QuantityRemaining() <= 0)
{
continue;
}
if ((double)curWeapon["rangeMin"] < rangeMin)
{
rangeMin = (double)curWeapon["rangeMin"];
}
}
return rangeMin;
end_script
// return the amount of ammo remaining for the weapon with the most ammo
script double GetWeaponQuantityRemainingMax(WsfPlatform aPlatform, Array<Map<string, Object>> aWeaponArray)
double quant = 0.0;
foreach (Map<string, Object> curWeapon in aWeaponArray)
{
if (((WsfWeapon)curWeapon["weapon"]).QuantityRemaining() > quant)
{
quant = ((WsfWeapon)curWeapon["weapon"]).QuantityRemaining();
}
}
return quant;
end_script
script int GetBucket (double x, double aBucketBase)
if (x == 0)
{
return 0;
}
double abs_x = MATH.Fabs(x);
// convert the log base-10 to a log with the base
int temp = MATH.Log10(abs_x) / MATH.Log10(aBucketBase);
// return a negative bucket if our source number is negative
if (x > 0)
{
return temp;
}
else
{
return -temp;
}
end_script
script WsfTrack GetTrackByName(WsfPlatform aPlatform, string trackName)
WsfLocalTrackList trackList = aPlatform.MasterTrackList();
foreach (WsfTrack track in trackList)
{
if (track.TargetName() == trackName)
{
return track;
}
}
WsfTrack x; // since we can't return null
return x;
end_script
script WsfTrack GetTrackById(WsfPlatform aPlatform, WsfTrackId trackId)
WsfLocalTrackList trackList = aPlatform.MasterTrackList();
foreach (WsfTrack track in trackList)
{
if (track.TrackId() == trackId )
{
return track;
}
}
// since we can't return null
WsfTrack x;
return x;
end_script
// Calculate the relative positioning of aPlatform and aTrack
script string CalculatePositioning (WsfPlatform aPlatform, WsfTrack aTrack, double aAngleTolerance)
// Are we heading the same direction?
bool sameHeading = false;
bool oppHeading = false;
bool oppHeadingValid = aTrack.HeadingValid();
double headingDiff = MATH.Fabs(MATH.NormalizeAngleMinus180_180(aPlatform.Heading() - aTrack.Heading()));
if (oppHeadingValid && headingDiff < aAngleTolerance)
{
sameHeading = true;
}
if (oppHeadingValid && headingDiff > (180 - aAngleTolerance))
{
oppHeading = true;
}
// Is either one of us pointing at the other?
// Apparently bearing is always valid (?)
bool pointingMeYou = false;
bool pointingYouMe = false;
double pMeYou = MATH.Fabs(aPlatform.RelativeBearingTo(aTrack));
double pYouMe = MATH.Fabs(aTrack.RelativeBearingTo(aPlatform));
if (pMeYou < aAngleTolerance)
{
pointingMeYou = true;
}
if (pYouMe < aAngleTolerance)
{
pointingYouMe = true;
}
// Put them together and we've got relative positioning
string positioning = "";
if (sameHeading && pointingMeYou)
{
positioning = "head-to-tail";
}
else if (sameHeading && pointingYouMe)
{
positioning = "tail-to-head";
}
else if (oppHeading && (pointingMeYou || pointingYouMe))
{
positioning = "head-to-head";
}
else if (pointingMeYou && pointingYouMe)
{
positioning = "head-to-head";
}
else if (oppHeading)
{
positioning = "tail-to-tail";
}
else if (pointingMeYou)
{
positioning = "me-facing-target";
}
else if (pointingYouMe)
{
positioning = "target-facing-me";
}
else
{
positioning = "none";
}
// Debug, in case my angle math is bad
// writeln_d(" ", aPlatform.Name(), " to ", aTrack.TargetName(), ", headingDiff: ", headingDiff, ", pMeYou: ", pMeYou, ", pYouMe: ", pYouMe);
// writeln_d(" meHeading: ", aPlatform.Heading(), ", youHeading: ", aTrack.Heading());
// writeln_d(" sameHeading: ", sameHeading, ", oppHeading: ", oppHeading,
// ", pointingMeYou: ", pointingMeYou, ", pointingYouMe: ", pointingYouMe,
// ", positioning: ", positioning);
return positioning;
end_script
// Calculate a heading to evade all incoming missiles, weighted by distance, and then turn aPlatform to it
script bool EvadeIncoming(WsfPlatform aPlatform, WsfRIPRProcessor aProc, Array<WsfPlatform> aIncoming, double originalAltitude, double diveAltitude, double weightPeers)
double evadeHeading = 0;
double evadeDivisor = 0;
double distMod = 0;
double bearingMod = 0;
int incomingCount = aIncoming.Size();
writeln_d(aPlatform.Name(), " evade. dive/climb between altitudes: ", originalAltitude, " <-> ", diveAltitude);
writeln_d("evading ", incomingCount, " threats");
double bankAngle = 40; //degrees
if (!diveDownMap.Exists(aPlatform.Name()))
{
diveDownMap[aPlatform.Name()] = true;
}
if (!bankLeftMap.Exists(aPlatform.Name()))
{
bankLeftMap[aPlatform.Name()] = true;
}
#extern Map<string, Array<WsfPlatform>> mEveryonesIncomingThreatsMap;
#if ( !mEveryonesIncomingThreatsMap.Empty() )
#{
# if ( mEveryonesIncomingThreatsMap.Exists(aPlatform.Name()) )
# {
# incoming = mEveryonesIncomingThreatsMap.Get(aPlatform.Name());
# if ( !incoming.Empty() )
# {
# incomingCount = incoming.Size();
# }
# }
#}
if (incomingCount == 0)
{
writeln_d(" no incoming weapons");
return false;
}
double y = 0;
double x = 0;
// calculate an average heading to incoming platforms weighted by distance
for (int i = 0; i < incomingCount; i = i + 1)
{
WsfPlatform temp = (WsfPlatform)(aIncoming[i]);
if (!temp.IsValid() || (temp.Index() == aPlatform.Index()))
{
continue;
}
writeln_d("calculating danger from: ", temp.Name());
double range = aPlatform.SlantRangeTo(temp);
if (range > 0)
{
distMod = 1 / range;
}
else
{
distMod = 1000000;
}
bearingMod = MATH.NormalizeAngle0_360(aPlatform.TrueBearingTo(temp));
x = x + MATH.Sin(bearingMod) * distMod;
y = y + MATH.Cos(bearingMod) * distMod;
writeln_d(" Incoming ", temp.Name(), " at distance: ", 1 / distMod, ", bearing: ", bearingMod, ", x: ", MATH.Sin(bearingMod), ", y: ", MATH.Cos(bearingMod), ", (", temp.Latitude(), ", ", temp.Longitude(), ", ", temp.Altitude(), ") @ ", temp.Speed(), "m/s");
evadeDivisor = evadeDivisor + distMod;
evadeHeading = evadeHeading + bearingMod * distMod;
}
// get the GCI if there is one
WsfRIPRProcessor aiflProc = aProc.GetRIPRCommanderProcessor();
WsfRIPRProcessor gciProc = null;
WsfPlatform aiflPlat;// = null;
WsfPlatform gciPlat;// = null;
if (aiflProc.IsValid())
{
gciProc = aiflProc.GetRIPRCommanderProcessor();
aiflPlat = aiflProc.Platform();
}
else
{
//writeln_d("!!! aiflProc not valid");
}
if (gciProc.IsValid())
{
gciPlat = gciProc.Platform();
}
else
{
//writeln_d("!!! gciProc not valid");
}
// if there's a gci, avoid centroids of all his subs
if (gciPlat.IsValid())
{
foreach (WsfPlatform aifl in gciPlat.Subordinates())
{
if (!aifl.IsValid() || aifl == aPlatform || aifl == aiflPlat)
{
continue;
}
WsfGeoPoint centroid = aifl.GetSubsCentroid();
if (centroid.X() == 0 && centroid.Y() == 0 && centroid.Z() == 0)
{
continue;
}
//writeln_d("!!! centroid: (", centroid.X(), ", ", centroid.Y(), ", ", centroid.Z(), "), dist: ", (aPlatform.SlantRangeTo(centroid)));
distMod = 1 / (aPlatform.SlantRangeTo(centroid));
bearingMod = MATH.NormalizeAngle0_360(aPlatform.TrueBearingTo(centroid));
x = x + MATH.Sin(bearingMod) * distMod * weightPeers;
y = y + MATH.Cos(bearingMod) * distMod * weightPeers;
writeln_d(" AIFL ", aifl.Name(), " at distance: ", 1 / distMod, ", bearing: ", bearingMod, ", x: ", MATH.Sin(bearingMod), ", y: ", MATH.Cos(bearingMod), ", (", centroid.Latitude(), ", ", centroid.Longitude(), ", ", centroid.Altitude(), ")");
// but we'll avoid peers with less strength than we avoid incoming missiles
// so let's divide the distMod by 2
evadeDivisor = evadeDivisor + distMod;
evadeHeading = evadeHeading + bearingMod * distMod;
}
}
// otherwise, avoid members in your own squadron
else if (aiflPlat.IsValid())
{
foreach (WsfPlatform sub in aiflPlat.Subordinates())
{
if (!sub.IsValid() || sub == aPlatform)
{
continue;
}
distMod = 1 / (aPlatform.SlantRangeTo(sub));
bearingMod = MATH.NormalizeAngle0_360(aPlatform.TrueBearingTo(sub));
x = x + MATH.Sin(bearingMod) * distMod * weightPeers;
y = y + MATH.Cos(bearingMod) * distMod * weightPeers;
writeln_d(" Peer ", sub.Name(), " at distance: ", 1 / distMod, ", bearing: ", bearingMod, ", x: ", MATH.Sin(bearingMod), ", y: ", MATH.Cos(bearingMod), ", (", sub.Latitude(), ", ", sub.Longitude(), ", ", sub.Altitude(), ") @ ", sub.Speed(), "m/s");
// but we'll avoid peers with less strength than we avoid incoming missiles
// so let's divide the distMod by 2
evadeDivisor = evadeDivisor + distMod;
evadeHeading = evadeHeading + bearingMod * distMod;
}
}
if (evadeDivisor == 0)
{
return false;
}
// writeln_d(" evadeHeading: ", evadeHeading, ", evadeDivisor: ", evadeDivisor, ", eH/eD: ", evadeHeading / evadeDivisor, ", x: ", x, ", y: ", y);
// evadeHeading = evadeHeading / evadeDivisor;
// evadeHeading = MATH.NormalizeAngle0_360(evadeHeading - 180);
// correct for quadrant
double theta = MATH.NormalizeAngle0_360(MATH.ATan(x/y));
if (y < 0)
{
theta = MATH.NormalizeAngle0_360(theta - 180);
}
writeln_d(" x: ", x, ", y: ", y, ", theta: ", theta);
//turn to angle to evade
if (bankLeftMap[aPlatform.Name()] == true)
{
evadeHeading = MATH.NormalizeAngle0_360(theta - 180 - bankAngle);
double headDiff = MATH.NormalizeAngleMinus180_180( evadeHeading - MATH.NormalizeAngle0_360(aPlatform.Heading()) );
if (MATH.Fabs(headDiff) < 2.0)
{
bankLeftMap[aPlatform.Name()] = false;
}
}
else
{
evadeHeading = MATH.NormalizeAngle0_360(theta - 180 + bankAngle);
double headDiff = MATH.NormalizeAngleMinus180_180(evadeHeading - MATH.NormalizeAngle0_360(aPlatform.Heading()));
if (MATH.Fabs(headDiff) < 2.0)
{
bankLeftMap[aPlatform.Name()] = true;
}
}
writeln_d(" Evading incoming at heading ", evadeHeading);
aPlatform.TurnToHeading(evadeHeading);
//do the dive or climb now
if (diveDownMap[aPlatform.Name()] == true)
{
writeln_d(aPlatform.Name(), " diving to ", diveAltitude);
aPlatform.GoToAltitude(diveAltitude, 200, true);
if (aPlatform.Altitude() <= (originalAltitude - 0.95*(originalAltitude-diveAltitude)))
{
diveDownMap[aPlatform.Name()] = false;
}
}
else
{
writeln_d(aPlatform.Name(), " climbing to ", originalAltitude);
aPlatform.GoToAltitude(originalAltitude, 200, true);
if (aPlatform.Altitude() >= (diveAltitude + 0.95*(originalAltitude-diveAltitude)))
{
diveDownMap[aPlatform.Name()] = true;
}
}
return true;
end_script
script bool UpdatePointInterceptLocation (WsfPlatform aPlatform, WsfGeoPoint aPoint)
double interceptAltitude = aPoint.Altitude();
double interceptHeading = aPlatform.TrueBearingTo(aPoint);
double interceptRange = aPlatform.SlantRangeTo(aPoint);
writeln_d(" T=", TIME_NOW, ", range: ", interceptRange, " true-bearing: ", interceptHeading);
aPlatform.TurnToHeading(interceptHeading);
if (MATH.Fabs(interceptAltitude - aPlatform.Altitude()) > 5)
{
writeln_d("GoToAltitude: ",interceptAltitude);
aPlatform.GoToAltitude(interceptAltitude, 200);
}
return true;
end_script
script bool UpdatePointInterceptLocationWithPathing(WsfPlatform aPlatform, WsfGeoPoint aPoint)
double interceptAltitude = aPoint.Altitude();
double interceptHeading = aPlatform.TrueBearingTo(aPoint);
double interceptRange = aPlatform.SlantRangeTo(aPoint);
writeln_d(" T=", TIME_NOW, ", range: ", interceptRange, " true-bearing: ", interceptHeading);
WsfGeoPoint startGeoPoint = aPlatform.Location();
aPlatform.FindAndSetPath(startGeoPoint, aPoint);
if (MATH.Fabs (interceptAltitude - aPlatform.Altitude()) > 5)
{
writeln_d("GoToAltitude: ",interceptAltitude);
aPlatform.GoToAltitude(interceptAltitude, 200);
}
return true;
end_script
// Attempt to maximize our distance from aTarget at the time of weapon detonation
script double MaximizeFPole(WsfPlatform aPlatform, WsfTrack aTarget, double aFPoleAngle)
writeln_d(" f-pole angle ", aFPoleAngle, " on: ", aTarget.TargetName()); //Try this
double allowedError = 5.0; // allow for this many degrees of error
// Normalize within +/-180 so absolute value calculations make sense
double relativeBearing = aPlatform.RelativeBearingTo(aTarget);
//writeln_d("--- relative bearing: ", relativeBearing);
// lean in the direction we're closest to already satisfying
double desiredBearing = aFPoleAngle;
if (relativeBearing > 0)
{
desiredBearing = desiredBearing * (double) -1.0;
}
//writeln_d("--- desired bearing: ", desiredBearing);
// calculate the difference between our desired and current bearings
double currentError = MATH.Fabs(MATH.NormalizeAngleMinus180_180(desiredBearing - relativeBearing));
//writeln_d("--- current error: ", currentError);
// if we're within the error tolerance, do nothing
if (currentError <= allowedError)
{
return aPlatform.Heading();
}
// otherwise, normalize to 0-360 and calculate the change in bearing required
double fPoleHeading = MATH.NormalizeAngle0_360(aPlatform.TrueBearingTo(aTarget) + desiredBearing);
//writeln_d("--- f-pole heading: ", fPoleHeading);
// do the turn
return fPoleHeading;
// aPlatform.TurnToHeading(fPoleHeading);
end_script
// test if the platform has enough fuel to travel the given distance
script bool HasEnoughFuelToTravel(WsfPlatform aPlatform,
double aDistance)
bool result = true;
WsfFuel fuelObj = aPlatform.Fuel();
if (fuelObj.IsValid())
{
double fuelRemaining = fuelObj.QuantityRemaining();
double bingoQuantity = fuelObj.BingoQuantity();
double distQuantity = fuelObj.QuantityRequired(aDistance);
//writeln("HasEnoughFuelToTravel(", aPlatform.Name(), ",", aDistance," m) - fuelRemaining=", fuelRemaining, " | distQuantity=", distQuantity, " | bingoQuantity=", bingoQuantity);
if ((fuelRemaining - distQuantity) < bingoQuantity)
{
result = false;
}
}
return result;
end_script
// test if the platform has enough fuel to travel the given route
script bool HasEnoughFuelToTravelRoute(WsfPlatform aPlatform,
WsfRoute aRoute)
bool result = false;
WsfFuel fuelObj = aPlatform.Fuel();
double fuelRemaining = fuelObj.QuantityRemaining();
double bingoQuantity = fuelObj.BingoQuantity();
double distQuantity = fuelObj.QuantityRequired(aRoute);
//writeln("HasEnoughFuelToTravelRoute(",aPlatform.Name(),") - fuelRemaining=", fuelRemaining, " | distQuantity=", distQuantity, " | bingoQuantity=", bingoQuantity);
if ((fuelRemaining - distQuantity) > bingoQuantity)
{
result = true;
}
return result;
end_script
script bool ReEnterRoute(WsfPlatform aPlatform)
#only command the platform to do something different if its not currently flying a route
WsfMover aMover = aPlatform.Mover();
if (aMover.IsValid())
{
if (aMover.IsExtrapolating())
{
WsfGeoPoint pt = aPlatform.Location();
#WsfRoute ro = aPlatform.Route().Copy(); #now we have a modifiable route
WsfRoute ro = aMover.DefaultRoute().Copy(); #now we have a modifiable route
if (!ro.IsValid())
{
return false;
}
WsfGeoPoint close = ro.LocationAtDistance(ro.DistanceAlongRoute(pt));
if (!close.IsValid())
{
return false;
}
close.SetAltitudeAGL(pt.Altitude());
double d1 = ro.DistanceFromRoute(pt);
double d2 = pt.GroundRangeTo(close);
double d3 = -1;
Array<double> turnRad = aMover.PropertyDouble("turn_radius");
if (turnRad.Size() > 0)
{
d3 = 2*turnRad[0];
}
for (int i = 0; i < ro.Size(); i = i+1)
{
WsfWaypoint wpt = ro.Waypoint(i);
WsfGeoPoint rpt = wpt.Location();
//first check if we are close enough (half mile)
if (rpt.GroundRangeTo(close) < 926)
{
return aPlatform.FollowRoute(ro, i);
}
double dist = ro.DistanceAlongRoute(rpt);
if (dist > d1)
{
if (d2 > d3)
{
ro.Insert(i, WsfWaypoint.Create(close, wpt.Speed()));
}
return aPlatform.FollowRoute(ro, i);
}
}
return aPlatform.FollowRoute(ro, (ro.Size()-1));
}
}
return true;
end_script
end_script_interface