# **************************************************************************** # 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 mCategories = Array(); 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> mWeaponsEnvelope = Map>(); mWeaponsEnvelope["red"] = Map(); mWeaponsEnvelope["blue"] = Map(); 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 diveDownMap = Map(); Map bankLeftMap = Map(); Array mBasicColors = Array(); 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 mRedColorValue = Map(); 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 mGreenColorValue = Map(); 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 mBlueColorValue = Map(); 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 ttrs = {"red_target_tracking_radar_1", "red_target_tracking_radar_2", "red_target_tracking_radar_3", "etc..."}; Array 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 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> 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 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> aWeaponArray ) foreach (Map 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 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> aWeaponArray, double aLaunchRangeMaxFraction) double desiredRange = EffectiveRange(aPlatform, aTarget); #writeln_d(" effective range from ", aPlatform.Name(), " to ", aTarget.TargetName(), " = ", desiredRange); foreach (Map 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> aWeaponArray) double rangeMax = 0; foreach (Map 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> aWeaponArray) double rangeMin = 99999999999.0; foreach (Map 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> aWeaponArray) double quant = 0.0; foreach (Map 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 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> 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 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