# **************************************************************************** # 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