# **************************************************************************** # CUI # # The Advanced Framework for Simulation, Integration, and Modeling (AFSIM) # # The use, dissemination or disclosure of data in this file is subject to # limitation or restriction. See accompanying README and LICENSE for details. # **************************************************************************** #always requires a commander #bids on "pursue-target" and "pursue-point" jobs #performs "pursue-target" and "pursue-point" jobs #does not create any jobs include_once processors/ripr_agents/common/common_platform_script.txt processor AIAI-thinker WSF_AIAI_PROCESSOR update_interval 2.0 sec #script_debug_writes on script_debug_writes off script_variables //radar control bool mTurnOnFiringRadarInRange = false; string mFiringRadarName = "firing_radar"; // replace with sensor name on platform double mFiringRadarRange = 1852 * 50; // 50 nautical miles (units: meters) bool mTurnOnFiringRadarIfRWR = false; string mRWR_RadarType = "ESM_RADAR"; // replace with sensor name on platform //agent constants double cLAUNCH_TQ = 0.49; double cFAST_UPDATE_RATE = 1.0; double cSLOW_UPDATE_RATE = 3.0; double cTHREAT_TOLERANCE = 0; double cTHREAT_GONE = 0; double cMAX_DIST = MATH.DOUBLE_MAX(); double cBUCKET_BASE = 1.2; double cWAIT_SPEED = 200; # m/s double cINTERCEPT_SPEED = 1000; # m/s ###double cDEFAULT_ALTITUDE = 12049; # approximately 40,000 feet double cDEFAULT_ALTITUDE = 9144; # approximately 30,000 feet double cCLOSING_SPEED_MIN = -100; double cCLOSING_SPEED_MAX = 1000; double cMIN_JOB_BID = -MATH.DOUBLE_MAX(); ###int cMAX_ACTIVE_WEAPONS = 4; int cMAX_ACTIVE_WEAPONS = 1; int cAirSalvoCount = 1; int cGndSalvoCount = 1; //type of mover bool mUsePathFinder = false; bool mUseMoverDuringPursuit = true; #set to false to force aiai to follow route during pursuit of target int cROUTE_WAYPOINT_INDEX = -1; # use negative for "CLOSEST_POINT" // input weights double cWEIGHT_BEING_TARGETED = 100.0; double cWEIGHT_CURRENT_TARGET = 100.0; double cWEIGHT_CLOSING_SPEED_OF = 1.0; double cWEIGHT_SLANT_RANGE_TO = -3.0; double cWEIGHT_OTHERS_TARGETING = 0.0; double cWEIGHT_WEAPONS_IN_FLIGHT = 50.0; double cWEIGHT_WEAPONS_FIRED_AT = 0.0; #double cWEIGHT_ANY_WEAPONS_ACTIVE = -50000; double cWEIGHT_ANY_WEAPONS_ACTIVE = 100; double cBASE_SLANT_RANGE_CONSTANT = 600000 * MATH.Fabs(cWEIGHT_SLANT_RANGE_TO); #over 300 nm away double cBASE_CLOSING_SPEED_CONSTANT = 1050 * MATH.Fabs(cWEIGHT_CLOSING_SPEED_OF); #over 2000 kts closing speed string mFireControlRadarCategory = "FIRE_CONTROL"; //include types or names Array mTargetTrackerTaskManagerStrings = Array(); mTargetTrackerTaskManagerStrings[0] = "WSF_TASK_MANAGER"; mTargetTrackerTaskManagerStrings[1] = "RED_SAM_RADAR_TASK_MANAGER"; mTargetTrackerTaskManagerStrings[2] = "task_manager"; mTargetTrackerTaskManagerStrings[3] = "task_mgr"; Array mMustShootAtCategories = Array(); mMustShootAtCategories[0] = "sam"; mMustShootAtCategories[1] = "FIRE_CONTROL"; ###double mEngagementAggressiveness = 0.5; // value between 0 and 1. 1 being suicidal kamikaze, and 0 being cautious pansy double mEngagementAggressiveness = 0.7; // value between 0 and 1. 1 being suicidal kamikaze, and 0 being cautious pansy bool mCoopEngageOne = false; bool mEscortFollowing = false; double mGoodFormationRatio = 0.15; #percentage of total offset double mFormationLookAhead = 30.0; #seconds bool mLastInPosition = false; #boolean flag double mFormationPositionX = 0; #meters in front of of package double mFormationPositionY = 0; #meters off right wing of package ## double escortProtectDistance = 125.0 * MATH.M_PER_NM(); #should try to stay within this range of the escort package double escortProtectDistance = 100.0 * MATH.M_PER_NM(); #engage threats within this range of the escort package double escortChaseDistance = 15.0 * MATH.M_PER_NM(); #allowed to chase a threat this far out of protect area if it entered bool escortAddMissileProtectRange = false; string mEscortName = ""; Array mEscortNames = Array(); Map ThreatTypePriority = Map(); # the interceptor uses these threat priority pairs to # determine who is the most important threat of concern # category string threat priority ThreatTypePriority["unknown"] = 0.0; ThreatTypePriority["uav"] = 2.0; ThreatTypePriority["sam"] = 4.0; ThreatTypePriority["ship"] = 4.0; ThreatTypePriority["awacs"] = -500.0; ThreatTypePriority["bomber"] = 2.0; ThreatTypePriority["jammer"] = 0.0; ThreatTypePriority["fighter"] = 50000.0; ThreatTypePriority["missile"] = 9.0; ThreatTypePriority["missile_fast"] = 9.0; // try new category for cmd ## let the strike aircraft set these individually #ThreatTypePriority["strike_target"] = 100.0; #ThreatTypePriority["primary_target"] = 100.0; #ThreatTypePriority["secondary_target"] = 50.0; #ThreatTypePriority["2D_RADAR"] = 0.0; #ThreatTypePriority["3D_RADAR"] = 0.0; #ThreatTypePriority["ACQUISITION"] = 0.0; #ThreatTypePriority["HF_RADAR"] = 0.0; //fly different offset angles, depending on the type or category of threat Map ThreatTypeOffsetAngle = Map(); ThreatTypeOffsetAngle["unknown"] = 45.0; ThreatTypeOffsetAngle["uav"] = 15.0; ThreatTypeOffsetAngle["sam"] = 50.0; ThreatTypeOffsetAngle["ship"] = 45.0; ThreatTypeOffsetAngle["awacs"] = 15.0; ThreatTypeOffsetAngle["bomber"] = 25.0; ThreatTypeOffsetAngle["jammer"] = 50.0; ThreatTypeOffsetAngle["fighter"] = 35.0; ThreatTypeOffsetAngle["missile"] = 20.0; ThreatTypeOffsetAngle["missile_fast"] = 15.0; // try new category for cmd //fire off different kinds of salvos at different types of threats Map ThreatTypeSalvo = Map(); ThreatTypeSalvo["unknown"] = 1; ThreatTypeSalvo["uav"] = 1; ThreatTypeSalvo["sam"] = 1; ThreatTypeSalvo["ship"] = 1; ThreatTypeSalvo["awacs"] = 1; ThreatTypeSalvo["bomber"] = 1; ThreatTypeSalvo["jammer"] = 1; ThreatTypeSalvo["fighter"] = 1; ThreatTypeSalvo["missile"] = 1; ThreatTypeSalvo["missile_fast"] = 1; // try new category for cmd ThreatTypeSalvo["FIRE_CONTROL"] = 2; //require different track qualities to fire on different kinds of threats Map ThreatTypeRequiredTrackQuality = Map(); ThreatTypeRequiredTrackQuality["unknown"] = 0.49; ThreatTypeRequiredTrackQuality["uav"] = 0.49; ThreatTypeRequiredTrackQuality["sam"] = 0.49; ThreatTypeRequiredTrackQuality["ship"] = 0.49; ThreatTypeRequiredTrackQuality["awacs"] = 0.49; ThreatTypeRequiredTrackQuality["bomber"] = 0.49; ThreatTypeRequiredTrackQuality["jammer"] = 0.49; ThreatTypeRequiredTrackQuality["fighter"] = 0.49; ThreatTypeRequiredTrackQuality["missile"] = 0.49; ThreatTypeRequiredTrackQuality["missile_fast"] = 0.49; // try new category for cmd ThreatTypeRequiredTrackQuality["FIRE_CONTROL"] = 0.49; //fly different offset angles, depending on the type or category of threat Map ThreatTypeWeapon = Map(); ThreatTypeWeapon["unknown"] = ""; ThreatTypeWeapon["uav"] = ""; ThreatTypeWeapon["sam"] = ""; ThreatTypeWeapon["ship"] = ""; ThreatTypeWeapon["awacs"] = ""; ThreatTypeWeapon["bomber"] = ""; ThreatTypeWeapon["jammer"] = ""; ThreatTypeWeapon["fighter"] = ""; ThreatTypeWeapon["missile"] = ""; ThreatTypeWeapon["missile_fast"] = ""; // try new category for cmd #ThreatTypeWeapon["FIRE_CONTROL"] = ""; double mMaxFiringAngle = 45.0; // this should be missile specific double mDegradedFiringAngle = 55.0; //negative if not valid double mDegradedPercentRange = 0.50; //additional range constraint on launch if past degraded firing angle Map WeaponTypeMaxFiringAngle = Map(); WeaponTypeMaxFiringAngle["sdb"] = 45.0; // Need target specific option WeaponTypeMaxFiringAngle["srm"] = 90.0; // Need target specific option WeaponTypeMaxFiringAngle["mrm"] = 60.0; // Need target specific option WeaponTypeMaxFiringAngle["lrm"] = 180.0; // Need target specific option double mLaunchPercentRangeMax = 0.80; // don't launch until X fraction of Rmax Map ThreatTypeLaunchPercentRangeMax = Map(); ThreatTypeLaunchPercentRangeMax["sam"] = 0.95; ThreatTypeLaunchPercentRangeMax["FIRE_CONTROL"] = 0.95; ThreatTypeLaunchPercentRangeMax["ship"] = 0.95; ThreatTypeLaunchPercentRangeMax["unknown"] = 0.80; ThreatTypeLaunchPercentRangeMax["uav"] = 0.80; ThreatTypeLaunchPercentRangeMax["awacs"] = 0.80; ThreatTypeLaunchPercentRangeMax["bomber"] = 0.80; ThreatTypeLaunchPercentRangeMax["jammer"] = 0.80; ThreatTypeLaunchPercentRangeMax["fighter"] = 0.80; ThreatTypeLaunchPercentRangeMax["missile"] = 0.80; ThreatTypeLaunchPercentRangeMax["missile_fast"] = 0.80; // try new category for cmd //use this offset angle if a category specific offset isn't found double mFPoleAngle = 45.0; // this should be radar-specific // hacks double weightPeersForEvade = 0.25; //percentage to scale peers influence for evasion vector double mAltitudeMax = 20000; // meters, hack double mAltitudeMin = 1000; # double mAltitudeToDiveEvade = 10000; //distance to dive (meters) double mAltitudeToDiveEvade = 5000; //distance to dive (try this instead) double mAltitudeBeforeEvade = -1.0; //utility variable (don't adjust) double mSafeAltitudeToDiveTo = 1000; //utility variable (don't adjust) double mLastWeaponFiredTime = 0.0; double mLaunchWeaponDelay = 3.0; double mLastActiveWeaponTime = 0.0; #double mInactiveLaunchDelay = 3.0; // Wait 3 seconds after your last missile detonated. double mInactiveLaunchDelay = 1.0; // Wait 3 seconds after your last missile detonated. int mPreviousJobId = -1; #double mLastTimeSoarCalled = 0.0; Array> mWeaponArray = Array>(); //example weapon input block for a ripr aiai platform: // // weapon blue_lr_a2a_rf_missile quantity 8 end_weapon // // processor int-thinker AIAI-thinker // script_variables // mWeaponArray[0] = Map(); // mWeaponArray[0].Set("name", "blue_lr_a2a_rf_missile"); // mWeaponArray[0].Set("weapon", PLATFORM.Weapon("blue_lr_a2a_rf_missile")); // mWeaponArray[0].Set("rangeMin", 1000); // mWeaponArray[0].Set("rangeMax", 111120); // ~60 miles // mWeaponArray[0].Set("numActiveMax", 1); // how many weapons of this type can be in play simultaneously // mWeaponArray[0].Set("AIR", 1); // DOMAIN CAPABLE, yes, this weapon can hit air (default true) // mWeaponArray[0].Set("LAND", 0); // DOMAIN CAPABLE, no, this weapon can NOT hit land (default false) // end_script_variables // end_processor // Inputs to RIPR double ownshipSpeed = 0; double ownshipAmmo = 0; double ownshipEngagementRangeMin = 0; // set later GetWeaponRangeMin(PLATFORM, mWeaponArray); double ownshipEngagementRangeMax = 0; // set later GetWeaponRangeMax(PLATFORM, mWeaponArray); int ownshipWeaponsIncoming = 0; Array mIncoming = Array(); string mState = ""; string mRouteType = ""; string mPursuitMode = ""; string mOldCommandComment = "no command"; string mOldTOOComment = "Targets of opportunity: "; WsfRIPRJob mCurrentJob; WsfGeoPoint mCurrentPointIntercept; Map mTrackWeaponActiveMap = Map(); Map mTrackMinRangeOkMap = Map(); Array mZoneNames = Array(); #dlc Map mRoundsFiredAtMap = Map(); #useful for bombs, that don't show up as active weapons #must keep track of number fired end_script_variables script bool MustShootAt(WsfTrack track) WsfPlatform plat = WsfSimulation.FindPlatform( track.TargetName() ); if (plat.IsValid()) { foreach( string aCategory in mMustShootAtCategories ) { if( plat.CategoryMemberOf( aCategory ) ) { return true; } } } return false; end_script script int GetSalvoForThreat(WsfTrack track) #extern string DetermineTrackCategory(WsfTrack); #string category = DetermineTrackCategory(track); #writeln_d("checking salvo size for category: ", category); #WsfPlatform plat = WsfSimulation.FindPlatform( track.TargetIndex() ); WsfPlatform plat = WsfSimulation.FindPlatform( track.TargetName() ); if (plat.IsValid()) { foreach( string aCategory : int salvo in ThreatTypeSalvo ) { if( plat.CategoryMemberOf( aCategory ) ) { writeln_d("salvo for type ", aCategory, " = ", salvo); return salvo; } } } #extern string GetTargetDomain(WsfTrack); string sTargetDomain = GetTargetDomain(track); if ( (sTargetDomain == "LAND") || (sTargetDomain == "SURFACE") ) { return cGndSalvoCount; } return cAirSalvoCount; end_script script string GetWeaponForThreat(WsfPlatform platform, WsfTrack track, Array> weapons, double percent) bool checkName = false; string name = ""; #extern bool IsWeaponDomainCapable(WsfTrack, Map); WsfPlatform plat = WsfSimulation.FindPlatform( track.TargetName() ); if (plat.IsValid()) { foreach( string aCategory : string wpnStr in ThreatTypeWeapon ) { #writeln_d("checking if ", plat.Name(), " is category: ", aCategory); if( wpnStr.Length()>0 && plat.CategoryMemberOf( aCategory ) ) { checkName = true; name = wpnStr; writeln_d(PLATFORM.Name(), " searching only for weapon: ", name, " (for use against ", plat.Name(), ")"); writeln_d("weapon for type ", aCategory, " = ", wpnStr); break; } } } else { writeln_d("platform for target ", track.TargetName()," is not valid!"); } #extern double EffectiveRange(WsfPlatform, WsfTrack); double desiredRange = EffectiveRange(platform, track); #writeln_d(" effective range from ", platform.Name(), " to ", aTarget.TargetName(), " = ", desiredRange); foreach (Map curWeapon in weapons) { if (checkName && ((string)(curWeapon["name"]))!=name) { continue; } if (((WsfWeapon)curWeapon["weapon"]).QuantityRemaining() <= 0) { continue; } if (!IsWeaponDomainCapable(track,curWeapon)) { continue; } if ((double)curWeapon["rangeMin"] > desiredRange) { continue; } if ((double)curWeapon["rangeMax"] * percent < desiredRange) { continue; } #writeln_d(" returning best weapon: ", (string)curWeapon["name"]); return (string)curWeapon["name"]; } return ""; end_script script double GetOffsetAngleOnThreat(WsfTrack threat) #extern string DetermineTrackCategory(WsfTrack); #string category = DetermineTrackCategory(threat); #if (ThreatTypeOffsetAngle.Exists(category)) #{ # return ThreatTypeOffsetAngle[category]; #} #WsfPlatform plat = WsfSimulation.FindPlatform( threat.TargetIndex() ); WsfPlatform plat = WsfSimulation.FindPlatform( threat.TargetName() ); if (plat.IsValid()) { foreach( string aCategory : double angle in ThreatTypeOffsetAngle ) { if( plat.CategoryMemberOf( aCategory ) ) { writeln_d("offset angle for type ", aCategory, " = ", angle); return angle; } } } return mFPoleAngle; end_script script double GetRequiredTrackQualityForThreat(WsfTrack threat) #extern string DetermineTrackCategory(WsfTrack); #string category = DetermineTrackCategory(threat); writeln_d("checking required TQ for track: ", threat.TargetName()); #WsfPlatform plat = WsfSimulation.FindPlatform( threat.TargetIndex() ); WsfPlatform plat = WsfSimulation.FindPlatform( threat.TargetName() ); if (plat.IsValid()) { foreach( string aCategory : double quality in ThreatTypeRequiredTrackQuality ) { if( plat.CategoryMemberOf( aCategory ) ) { writeln_d("TQ for type ", aCategory, " = ", quality); return quality; } } } #if (ThreatTypeRequiredTrackQuality.Exists(category)) #{ # return ThreatTypeRequiredTrackQuality[category]; #} return cLAUNCH_TQ; end_script // currently only considers weapon in firing angle; needs to determine firing angle for weapon/target pairing script double GetMaxFiringAngleForWeapon(WsfWeapon weapon) if (weapon.IsValid()) { foreach( string aName : double angle in WeaponTypeMaxFiringAngle ) { if( weapon.Name() == aName ) { writeln_d("firing angle for weapon/target pairing ", aName, " = ", angle); return angle; } } } return mMaxFiringAngle; end_script script double GetLaunchPercentRangeMaxOnThreat(WsfTrack threat) WsfPlatform plat = WsfSimulation.FindPlatform( threat.TargetName() ); if (plat.IsValid()) { foreach( string aCategory : double percent in ThreatTypeLaunchPercentRangeMax ) { if( plat.CategoryMemberOf( aCategory ) ) { return percent; } } } return mLaunchPercentRangeMax; end_script script WsfProcessor GetPlatformsTaskManager(WsfPlatform aPlat) for (int i=0; i < aPlat.ProcessorCount(); i=i+1) { WsfProcessor proc = aPlat.ProcessorEntry(i); foreach (string procString in mTargetTrackerTaskManagerStrings) { if (proc.Type() == procString || proc.Name() == procString) { return proc; } } } end_script script WsfGeoPoint GetFormationPoint( WsfPlatform reference, double xOff, double yOff ) WsfGeoPoint formationPoint = reference.Location(); formationPoint.Offset(reference.Heading(), xOff, yOff, 0); return formationPoint; end_script script bool AmInFormationPosition(WsfGeoPoint formationPoint, double radius) //make it fly to the inner 50% of the acceptable radius on re-entry if (!mLastInPosition) { radius = 0.5 * radius; } mLastInPosition = false; double range = PLATFORM.GroundRangeTo(formationPoint); if (range <= radius) { mLastInPosition = true; } return mLastInPosition; end_script script bool FlyEscortFormation() if (!mEscortFollowing) { return false; } //make sure escorted platform exists, find it, save it WsfPlatform escortPlatform; #if ( !mEscortNames.Empty() ) #{ foreach ( string sEscortName in mEscortNames ) { escortPlatform = WsfSimulation.FindPlatform(sEscortName); if (escortPlatform.IsValid() ) { mEscortName = sEscortName; writeln_d("--- fighter ", PLATFORM.Name(), " is escorting ", mEscortName); break; } } #} if ( escortPlatform.IsValid() ) { //check if I am approximately in my formation position WsfGeoPoint formationPoint = GetFormationPoint( escortPlatform, mFormationPositionX, mFormationPositionY ); if (!formationPoint.IsValid()) { writeln_d("--- fighter ", PLATFORM.Name(), " invalid formation point from ", escortPlatform.Name()); return false; } double radius = mGoodFormationRatio * escortPlatform.SlantRangeTo(formationPoint); bool bAlt = true; if (escortPlatform.Altitude() > PLATFORM.Altitude()) { bAlt = PLATFORM.GoToAltitude ( escortPlatform.Altitude(), 200 ); } if (AmInFormationPosition(formationPoint, radius)) { //match speed and heading of escorted platform # bool GoToAltitude (double aAlt, double aAltRateOfChange); # bool GoToSpeed (double aSpeed, double aLinearAccel ); # bool TurnToHeading(double aHeading, double aRadialAccel ); bool bVel = PLATFORM.GoToSpeed ( escortPlatform.Speed() ); bool bYaw = PLATFORM.TurnToHeading( escortPlatform.Heading() ); #PLATFORM.Comment(write_str("formation: alt=", bAlt, " vel=", bVel, " yaw=",bYaw)); } else { //fly towards formation position, extrapolated ahead X seconds double lookAheadDistance = mFormationLookAhead * escortPlatform.Speed(); formationPoint.Offset(escortPlatform.Heading(), lookAheadDistance, 0, 0); double myDistanceToExtrap = PLATFORM.GroundRangeTo(formationPoint); double mySpeedToExtrap = myDistanceToExtrap / mFormationLookAhead; #bool bVel = PLATFORM.GoToSpeed(cINTERCEPT_SPEED); bool bVel = PLATFORM.GoToSpeed(mySpeedToExtrap); bool bYaw = PLATFORM.TurnToHeading( PLATFORM.TrueBearingTo(formationPoint) ); #PLATFORM.Comment(write_str("re-enter: vel=", bVel, " yaw=",bYaw)); } return true; } writeln_d("--- fighter ", PLATFORM.Name(), " no valid platform to escort!"); return false; end_script ####### script bool RejoinEscort() bool bEscortRejoined = false; if ( !mEscortFollowing || (mEscortName != "") ) { WsfPlatform escortPlatform = WsfSimulation.FindPlatform(mEscortName); if ( escortPlatform.IsValid() ) { WsfGeoPoint joinGeoPoint0 = PLATFORM.Location(); WsfGeoPoint joinGeoPoint1 = escortPlatform.Location(); double dDeltaTime = PROCESSOR.UpdateInterval(); double dRejoinSpeed = escortPlatform.Speed(); double dRejoinSpeedFast = dRejoinSpeed*1.2; double dRejoinSpeedSlow = dRejoinSpeed*0.8; double dRejoinHeadingTolerance = 15; double dRejoinTimeTolerance = 15; #writeln_d("$$$1 ", TIME_NOW, " ", PLATFORM.Name() , " ", mFormationPositionX, " ", mFormationPositionY); joinGeoPoint1.Offset(escortPlatform.Heading(), mFormationPositionX, mFormationPositionY, 0); double dRejoinDistance = joinGeoPoint0.SlantRangeTo(joinGeoPoint1); double dRejoinTime = dRejoinDistance/dRejoinSpeed; double dRejoinDownrange = PLATFORM.DownRangeTo(joinGeoPoint1); double dHeadingDiff = MATH.Fabs(PLATFORM.Heading()-escortPlatform.Heading()); #if (dRejoinDownrange > 0) #{ if ( dRejoinTime > (dDeltaTime + dRejoinTimeTolerance) ) { dRejoinSpeed = Math.Min(dRejoinSpeedFast,cINTERCEPT_SPEED); } else if ( dRejoinTime < dDeltaTime ) { joinGeoPoint1.Extrapolate(escortPlatform.Heading(), (dDeltaTime - dRejoinTime)*dRejoinSpeed); dRejoinSpeed = dRejoinSpeedSlow; } #} #else #{ # writeln_d("$$ $$ $$1"); # dRejoinSpeed = dRejoinSpeedSlow; # if ( (dHeadingDiff < dRejoinHeadingTolerance) && (dRejoinDistance < 10*MATH.M_PER_NM()) ) # { # joinGeoPoint1 = joinGeoPoint0; # joinGeoPoint1.Extrapolate(escortPlatform.Heading(), (dDeltaTime*1.01)*dRejoinSpeed); # writeln_d("$$ $$ $$2"); # } #} #writeln_d("$$$2 ", dRejoinSpeed*MATH.NMPH_PER_MPS()); #For some reason the GoToLocation and GoToSpeed commands never work so I resort to making a route... WsfRoute joinRoute = WsfRoute().Create("joinRouteName"); WsfWaypoint joinWaypoint1 = WsfWaypoint().Create(joinGeoPoint1.Latitude(), joinGeoPoint1.Longitude(), cDEFAULT_ALTITUDE, dRejoinSpeed, "LATITUDE_AND_LONGITUDE", "EXTRAPOLATE"); joinRoute.Append(joinWaypoint1); PLATFORM.FollowRoute(joinRoute); bEscortRejoined = true; } } return bEscortRejoined; end_script script bool UpdatePointInterceptLocation (WsfPlatform aPlatform, WsfGeoPoint aPoint) if (!aPoint.IsValid()) { PLATFORM.Comment("ignoring invalid point"); return false; } double interceptAltitude = aPoint.Altitude(); if (interceptAltitude < 0) { PLATFORM.Comment("ignoring invalid point"); return false; } double interceptRange = aPlatform.SlantRangeTo(aPoint); double interceptHeading = aPlatform.TrueBearingTo(aPoint); aPlatform.TurnToHeading(interceptHeading); writeln_d(" T=", TIME_NOW, ", range: ", interceptRange, " true-bearing: ", interceptHeading); # #if ( (interceptAltitude - aPlatform.Altitude()) > 5) # if ( (interceptAltitude - aPlatform.Altitude()) > 10000*MATH.M_PER_FT()) # { # writeln_d("GoToAltitude: ",interceptAltitude); # #aPlatform.GoToAltitude(interceptAltitude); # } 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(); if (!aPlatform.FindAndSetPath(startGeoPoint, aPoint) && mRouteType != "DEFAULT") { if ( cROUTE_WAYPOINT_INDEX < 0) { PLATFORM.FollowRoute("DEFAULT_ROUTE","CLOSEST_POINT"); } else { PLATFORM.FollowRoute("DEFAULT_ROUTE",cROUTE_WAYPOINT_INDEX); } PLATFORM.Comment("Route: DEFAULT"); mRouteType = "DEFAULT"; } else if(mRouteType != "PATH") { PLATFORM.Comment("Route: PATH"); mRouteType = "PATH"; } if ( (interceptAltitude - PLATFORM.Altitude()) > 10000*MATH.M_PER_FT()) #if ( (interceptAltitude - aPlatform.Altitude()) > 5) { writeln_d("GoToAltitude: ",interceptAltitude); #aPlatform.GoToAltitude(interceptAltitude); } return true; end_script /* * bool UpdateInterceptLocationWithPathing () * * Intercept aTarget. This should eventually be replaced by methods in the mover. */ script bool UpdateInterceptLocationWithPathing (WsfTrack aTarget, string pursuitMode) if (aTarget.IsNull()) { writeln_d(" UpdateInterceptLocationWithPathing, aTarget is null"); return false; } // If we got the altitude from the TRACK, match it double interceptAltitude = cDEFAULT_ALTITUDE; //double interceptAltitude = PLATFORM.Altitude(); double interceptHeading = PLATFORM.Heading(); double distanceToTarget = PLATFORM.SlantRangeTo(aTarget); double desiredSpeed = cINTERCEPT_SPEED; if (aTarget.VelocityValid() && aTarget.AirDomain()) { #extern double EffectiveRange(WsfPlatform, WsfTrack); #extern double GetWeaponRangeMax (WsfPlatform, Array>); #extern double GetWeaponRangeMin (WsfPlatform, Array>); double rangeMin = GetWeaponRangeMin(PLATFORM, mWeaponArray); double rangeMax = GetWeaponRangeMax(PLATFORM, mWeaponArray); double speedOfTarget = aTarget.Speed(); double effRange = EffectiveRange(PLATFORM, aTarget); double missileWindow = rangeMax - rangeMin; double speedWindow = cINTERCEPT_SPEED - speedOfTarget; if(effRange < rangeMax && effRange > rangeMin) { double rangeScale = (effRange - rangeMin) / missileWindow; desiredSpeed = speedOfTarget + (speedWindow * rangeScale); } else if (effRange <= rangeMin) { desiredSpeed = speedOfTarget; } if (desiredSpeed < cWAIT_SPEED) { desiredSpeed = cWAIT_SPEED; } } PLATFORM.GoToSpeed(desiredSpeed); WsfGeoPoint startGeoPoint = PLATFORM.Location(); WsfGeoPoint endGeoPoint = aTarget.ReportedLocation(); if (pursuitMode == "lead") { double timeToIntercept = 0.0; WsfWaypoint interceptPoint = WsfWaypoint(); timeToIntercept = PLATFORM.InterceptLocation3D(aTarget, interceptPoint); // If timeToIntercept is positive then we know intercept is possible if (timeToIntercept > 0.0) { writeln_d(" T=", TIME_NOW, " TTI=", timeToIntercept, " range: ", PLATFORM.SlantRangeTo(aTarget), " true-bearing: ", interceptPoint.Heading()); writeln_d(" lead pursuit: ", interceptPoint.Latitude(), ", ", interceptPoint.Longitude(), ", ", interceptPoint.Altitude()); startGeoPoint = PLATFORM.Location(); endGeoPoint = aTarget.ReportedLocation(); } else { writeln_d(" lead pursuit attempt with timeToIntercept < 0"); } } else if (pursuitMode == "f-pole") { #extern double MaximizeFPole(WsfPlatform, WsfTrack, double); interceptHeading = MaximizeFPole(PLATFORM, aTarget, GetOffsetAngleOnThreat(aTarget)); startGeoPoint = PLATFORM.Location(); endGeoPoint = PLATFORM.Location(); //f-pole towards a point 30 miles away in the correct direction endGeoPoint.Extrapolate(interceptHeading, 55560); writeln_d(" T=", TIME_NOW, ", range: ", PLATFORM.SlantRangeTo(aTarget), " true-bearing: ", PLATFORM.TrueBearingTo(aTarget)); writeln_d(" ", pursuitMode, " pursuit"); } else { //otherwise... just fly at the target startGeoPoint = PLATFORM.Location(); endGeoPoint = aTarget.ReportedLocation(); writeln_d(" T=", TIME_NOW, ", range: ", PLATFORM.SlantRangeTo(aTarget), " true-bearing: ", PLATFORM.TrueBearingTo(aTarget), " (", endGeoPoint.Latitude(), "/", aTarget.Latitude(), ",", endGeoPoint.Longitude(), "/", aTarget.Longitude(), ")"); writeln_d(" ", pursuitMode, " pursuit"); } //make sure we don't dive, staying above the target is fine if (endGeoPoint.Altitude() < interceptAltitude) { endGeoPoint.Set(endGeoPoint.Latitude(), endGeoPoint.Longitude(), interceptAltitude); } if (!PLATFORM.FindAndSetPath(startGeoPoint, endGeoPoint) && mRouteType != "DEFAULT") { if ( cROUTE_WAYPOINT_INDEX < 0) { PLATFORM.FollowRoute("DEFAULT_ROUTE","CLOSEST_POINT"); } else { PLATFORM.FollowRoute("DEFAULT_ROUTE",cROUTE_WAYPOINT_INDEX); } PLATFORM.Comment("Route: DEFAULT"); mRouteType = "DEFAULT"; } else if(mRouteType != "PATH") { PLATFORM.Comment("Route: PATH"); mRouteType = "PATH"; } return true; end_script /* * bool UpdateInterceptLocation () * * Intercept aTarget. This should eventually be replaced by methods in the mover. */ script bool UpdateInterceptLocation (WsfTrack aTarget, string pursuitMode) if (aTarget.IsNull()) { writeln_d(" UpdateInterceptLocation, aTarget is null"); return false; } // If we got the altitude from the TRACK, match it double interceptAltitude = cDEFAULT_ALTITUDE; //double interceptAltitude = PLATFORM.Altitude(); double interceptHeading = PLATFORM.Heading(); double distanceToTarget = PLATFORM.SlantRangeTo(aTarget); if (aTarget.ElevationValid() || aTarget.LocationValid()) { #writeln_d("dlc ", aTarget.Altitude()*MATH.FT_PER_M(), ", ", interceptAltitude*MATH.FT_PER_M()); if (aTarget.Altitude() > interceptAltitude) { interceptAltitude = aTarget.Altitude(); } } double desiredSpeed = cINTERCEPT_SPEED; if (aTarget.VelocityValid() && aTarget.AirDomain()) { #extern double EffectiveRange(WsfPlatform, WsfTrack); #extern double GetWeaponRangeMax (WsfPlatform, Array>); #extern double GetWeaponRangeMin (WsfPlatform, Array>); double rangeMin = GetWeaponRangeMin(PLATFORM, mWeaponArray); double rangeMax = GetWeaponRangeMax(PLATFORM, mWeaponArray); double speedOfTarget = aTarget.Speed(); double effRange = EffectiveRange(PLATFORM, aTarget); double missileWindow = rangeMax - rangeMin; double speedWindow = cINTERCEPT_SPEED - speedOfTarget; if(effRange < rangeMax && effRange > rangeMin) { double rangeScale = (effRange - rangeMin) / missileWindow; desiredSpeed = speedOfTarget + (speedWindow * rangeScale); } else if (effRange <= rangeMin) { desiredSpeed = speedOfTarget; } if (desiredSpeed < cWAIT_SPEED) { desiredSpeed = cWAIT_SPEED; } } PLATFORM.GoToSpeed(desiredSpeed); if (pursuitMode == "lead") { double timeToIntercept = 0.0; WsfWaypoint interceptPoint = WsfWaypoint(); timeToIntercept = PLATFORM.InterceptLocation3D(aTarget, interceptPoint); // If timeToIntercept is positive then we know intercept is possible if (timeToIntercept > 0.0) { writeln_d(" T=", TIME_NOW, " TTI=", timeToIntercept, " range: ", PLATFORM.SlantRangeTo(aTarget), " true-bearing: ", interceptPoint.Heading()); writeln_d(" lead pursuit: ", interceptPoint.Latitude(), ", ", interceptPoint.Longitude(), ", ", interceptPoint.Altitude()); interceptHeading = interceptPoint.Heading(); } else { writeln_d(" lead pursuit attempt with timeToIntercept < 0, flying straight at target for now"); interceptHeading = PLATFORM.TrueBearingTo(aTarget); } } else if (pursuitMode == "f-pole") { #extern double MaximizeFPole(WsfPlatform, WsfTrack, double); interceptHeading = MaximizeFPole(PLATFORM, aTarget, GetOffsetAngleOnThreat(aTarget)); writeln_d(" T=", TIME_NOW, ", range: ", PLATFORM.SlantRangeTo(aTarget), " true-bearing: ", PLATFORM.TrueBearingTo(aTarget)); writeln_d(" ", pursuitMode, " pursuit"); } else { interceptHeading = PLATFORM.TrueBearingTo(aTarget); //writeln_d(" T=", TIME_NOW, ", range: ", PLATFORM.SlantRangeTo(aTarget), " true-bearing: ", PLATFORM.TrueBearingTo(aTarget), // " (", endGeoPoint.Latitude(), "/", aTarget.Latitude(), ",", endGeoPoint.Longitude(), "/", aTarget.Longitude(), ")"); writeln_d(" ", pursuitMode, " pursuit"); } //PLATFORM.Comment("USING TURNTOHEADING"); // Head towards the target using the interceptHeading instead of Pathfinder PLATFORM.TurnToHeading(interceptHeading); ###if ( (interceptAltitude - PLATFORM.Altitude()) > 10000*MATH.M_PER_FT()) if ( (interceptAltitude - PLATFORM.Altitude()) > 100) { writeln_d("GoToAltitude: ",interceptAltitude); PLATFORM.GoToAltitude(interceptAltitude, 200); } return true; end_script script string Think() //always evade incoming weapons //mIncoming = Array(); // clear the existing incoming weapons mIncoming.Clear(); ### use darin's custom threat processor instead ### ###ownshipWeaponsIncoming = WeaponsIncoming(mIncoming); ### # WsfProcessor proc = PLATFORM.Processor("incoming_threats"); # if (proc.IsValid()) # { # writeln_d("using incoming_threats threat processor!!!"); # mIncoming = (Array)(proc.Execute("ThreatProcessorWeaponsIncoming")); # ownshipWeaponsIncoming = mIncoming.Size(); # } # else # { # writeln_d("using standard WSF_THREAT_PROCESSOR!!!"); ownshipWeaponsIncoming = WeaponsIncoming(mIncoming); # } if (ownshipWeaponsIncoming > 0) { if (mState != "EVADE_INCOMING") { writeln_d("EVASION BLOCK : ", PLATFORM.Name(), " :"); foreach(WsfPlatform p in mIncoming) { string msg = write_str("Evading: ", p.Name()); PLATFORM.Comment(msg); writeln_d(msg); } } //we now have weapons incoming, check to see if we are currently guiding any missiles with an uplink //basically: check if we have any active weapons int WeaponCount = WeaponsActive(); if (WeaponCount > 0) { writeln_d(PLATFORM.Name(), " weapons incoming, checking weapons active, count: ", WeaponCount); double threat = 1000.0; double asset = 1000.0; //find most threatening incoming weapon foreach(WsfPlatform p in mIncoming) { double range = PLATFORM.SlantRangeTo(p); # meters double speed = p.Speed(); # meters/sec double time = range / speed; # seconds if (time < threat) { threat = time; } } //find most valuable launched weapon (most threatening to enemy) for (int i=0; i< WeaponCount; i=i+1) { WsfPlatform w = ActiveWeaponPlatform(i); WsfTrack t = w.CurrentTargetTrack(); if (t.IsValid()) { double range = w.SlantRangeTo(t); # meters double speed = w.Speed(); # meters/sec double time = range / speed; # seconds if (time < asset) { asset = time; } } } //factor in our aggressiveness, and decide whether or not we should evade yet double requiredAggressiveness = threat / (threat + asset); writeln_d(PLATFORM.Name(), " threat: ", threat, ", asset: ", asset, ", required aggressiveness: ", requiredAggressiveness); if (mEngagementAggressiveness < requiredAggressiveness) { return "EVADE_INCOMING"; } } else { return "EVADE_INCOMING"; } } // if we're low on fuel, go home if (PLATFORM.FuelRemaining() < PLATFORM.FuelBingoQuantity()) { return "BINGO_FUEL"; } // if no weapons are available to use, don't fight # #extern double GetWeaponQuantityRemainingMax(WsfPlatform,Array>); # double wRemaining = GetWeaponQuantityRemainingMax(PLATFORM, mWeaponArray); # if (wRemaining < 1) # { # writeln_d(" no weapons left, WAITing"); # return "WAIT"; # } # else # { # writeln_d(" weapons left: ", wRemaining); # } #if (PLATFORM.WeaponEntry(0).QuantityRemaining() < 1) #{ # return "WAIT"; #} bool wait = true; foreach( WsfPlatform sub in GetRIPRCommanderPlatform().Subordinates() ) { if (sub.WeaponEntry(0).QuantityRemaining() > 0) { wait = false; } } if (wait == true) { return "WAIT"; } if (GetRIPRCommanderProcessor().IsBidWindowOpen()) { writeln_d(" Jobs:"); Array jobs = GetRIPRCommanderProcessor().GetJobs(); writeln_d(" (jobs fetched): ", jobs.Size()); // bid on jobs foreach (WsfRIPRJob aJob in jobs) { double bidVal = QueryBid(aJob); #writeln_d(PLATFORM.Name(), " bid val for ", aJob.GetDescription(), " = ", bidVal); #writeln_d(aJob.Name(), " priority: ", aJob.GetPriority()); writeln_d(PLATFORM.Name(), " bid on job ", aJob.GetDescription(), " == ", bidVal, ", priority = ", aJob.GetPriority()); if (bidVal < 0) { #unbid all jobs for (int channel = 0; channel < GetNumJobChannels(); channel = channel + 1) { aJob.UnbidJob( PROCESSOR, channel); } } else { //bid normal value for primary job (channel zero) aJob.BidJob( PROCESSOR, bidVal ); //writeln_d("Main Channel\'s bid value: ", bidVal); for (int channel = 1; channel < GetNumJobChannels(); channel = channel + 1) { //scale down bid value to 25% of max for all other channels // or to 250% of max if bid is negative //basically, ensure that half the magnitude of the default channel can //beat the full magnitude of the sub channels double scaledBidValue = bidVal * 0.25; if (bidVal < 0.0) { scaledBidValue = bidVal * 2.5; } double progress = 0.0; aJob.BidJob( PROCESSOR, (int)channel, scaledBidValue, progress ); //writeln_d("Channel ", channel, "\'s bid value: ", scaledBidValue); } } } } // win and execute primary job if (GetRIPRCommanderProcessor().IsJobWindowOpen()) { // now check the board to see what we've won! mCurrentJob = GetRIPRCommanderProcessor().GetJobFor(TIME_NOW, PROCESSOR); } if (!(mCurrentJob.IsValid())) { writeln_d(" no valid job from job board, WAITing"); return "WAIT"; } string commandComment = "Job: " + mCurrentJob.Name() + ", " + mCurrentJob.GetDescription(); // + " pursuit-mode: " + mPursuitMode; writeln_d(" - ", commandComment); if (commandComment != mOldCommandComment) { PLATFORM.Comment(commandComment); mOldCommandComment = commandComment; } // Clear the variables we'll use to store the agent's output ClearTarget(); if (mCurrentJob.Name() == "pursue-target") { #extern int GetBucket (double, double); #extern WsfTrack GetTrackByName (WsfPlatform, string); #extern bool TestTrackCategory (WsfTrack, string); #extern string CalculatePositioning (WsfPlatform, WsfTrack, double); #extern string DetermineTrackCategory(WsfTrack); Map tempData = mCurrentJob.GetData(); string targetName = (string)tempData["targetTrackName"]; WsfTrack targetTrack = GetTrackByName(PLATFORM, targetName); if (targetTrack.IsValid()) { //writeln_d(" Setting target to ", targetName, ", type: ", DetermineTrackCategory(targetTrack)); SetTarget(targetName); } else { writeln_d(" No track found for target named ", targetName); ClearTarget(); } //get target from ripr processor, to be sure targetTrack = GetTarget(); if (!targetTrack.IsValid() || #!targetTrack.IFF_Foe() || // Was commented out - see if this helps. TestTrackCategory(targetTrack, "unknown")) { writeln_d(" No valid target set yet, go to WAIT mode."); return "WAIT"; } double ownSpeed = GetBucket(PLATFORM.Speed(), cBUCKET_BASE); double engageRangeMin = GetBucket(ownshipEngagementRangeMin, cBUCKET_BASE); double engageRangeMax = GetBucket(ownshipEngagementRangeMax, cBUCKET_BASE); double slantRangeTo = GetBucket(PLATFORM.SlantRangeTo(targetTrack), cBUCKET_BASE); double targetSpeed = GetBucket(targetTrack.Speed(), cBUCKET_BASE); string positioning = CalculatePositioning(PLATFORM, targetTrack, GetOffsetAngleOnThreat(targetTrack)); int weaponsActive = WeaponsActive(targetTrack); if (weaponsActive > 0) { mPursuitMode = "f-pole"; } else if (targetTrack.AirDomain()) { if (slantRangeTo >= engageRangeMax && positioning != "head-to-head" && positioning != "head-to-tail" && targetSpeed >= ownSpeed) { mPursuitMode = "lead"; } else if (slantRangeTo <= engageRangeMax && positioning != "head-to-head" && positioning != "head-to-tail") { mPursuitMode = "lag"; } else if (slantRangeTo > engageRangeMax || (slantRangeTo <= engageRangeMax && (positioning == "head-to-head" || positioning == "head-to-tail"))) { mPursuitMode = "pure"; } } else { mPursuitMode = "pure"; } //target is valid if this line is reached //pursuit mode should be set, its a go return "INTERCEPT"; } // Clear the variables we'll use to store the agent's output ClearTarget(); // If we're supposed to fly towards a point, go for it! if (mCurrentJob.Name() == "pursue-point") { Map tempData = mCurrentJob.GetData(); WsfGeoPoint temp = (WsfGeoPoint)tempData["targetPoint"]; if (temp.IsValid()) { mCurrentPointIntercept = temp; } return "POINT"; } // If we don't have a target, just keep waiting return "WAIT"; end_script script bool CheckAndFire (WsfTrack aTarget) bool launched = false; if (aTarget.IsNull() || !aTarget.BelievedAlive()) { writeln_d(" No target to fire on"); return launched; } if ( (WeaponsActive(aTarget) > 0) || (PeersWeaponsActive(aTarget) > 0) ) #if (WeaponsActive(aTarget) > 0) { mLastActiveWeaponTime = TIME_NOW; mTrackWeaponActiveMap[aTarget.TargetName()] = TIME_NOW; writeln_d(" Weapons already active against ", aTarget.TargetName()); return launched; } if ((TIME_NOW - mTrackWeaponActiveMap[aTarget.TargetName()]) < mInactiveLaunchDelay) { writeln_d(" Waiting to see what last active weapon did, score a kill?"); return launched; } writeln_d(" CheckAndFire() against: ", aTarget.TargetName(), " Index: ", aTarget.TargetIndex(), " Type: ", aTarget.TargetType()); if (!mCoopEngageOne) { if (aTarget.AuxDataString("notlocal") != "true") { WsfLocalTrack targetLocalTrack = (WsfLocalTrack)aTarget; if (targetLocalTrack.IsValid()) { if(!targetLocalTrack.ContributorOf(PLATFORM) && !targetLocalTrack.IsPredefined()) { writeln_d(" Not able to coop engage! ", PLATFORM.Name(), " targeting ",aTarget.TargetName(), ". NumContributors: ", targetLocalTrack.NumContributors() ); return launched; } } } } // We can launch once we have a target-quality track. //TODO probably need something to test for failure to lockon writeln_d (" aTarget.TrackQuality == ", aTarget.TrackQuality()); double dRelativeBearing = MATH.Fabs(PLATFORM.RelativeBearingTo( aTarget )); double dSlantRange = PLATFORM.SlantRangeTo(aTarget); writeln_d("abs relative bearing: ", dRelativeBearing, ", slant range: ", dSlantRange); if (aTarget.TrackQuality() < GetRequiredTrackQualityForThreat(aTarget)) { writeln_d("track quality not good enough to fire on target"); return launched; } // Launch the weapon. Returns false if not launched. #extern bool LaunchWeapon(WsfPlatform, WsfTrack, WsfWeapon, int); #extern double GetMaxLaunchRange (WsfPlatform, WsfTrack, string, Array>); #extern double EffectiveRange (WsfPlatform, WsfTrack); #extern string GetTargetDomain(WsfTrack); double dLaunchRangePercentage = GetLaunchPercentRangeMaxOnThreat(aTarget); string sTargetDomain = GetTargetDomain(aTarget); #int salvoCount = 1; int salvoCount = GetSalvoForThreat(aTarget); writeln_d("salvo count: ", salvoCount); string selectedWeapon = GetWeaponForThreat(PLATFORM, aTarget, mWeaponArray, dLaunchRangePercentage); if (selectedWeapon == "") { writeln_d(" No domain capable weapon within range available!"); return launched; } WsfWeapon weaponToLaunch = PLATFORM.Weapon(selectedWeapon); if (dRelativeBearing > GetMaxFiringAngleForWeapon( weaponToLaunch )) { writeln_d("relative bearing towards ", aTarget.TargetName(), " is too high for selected weapon ", weaponToLaunch.Name()); return launched; } #extern int GetWeaponNumberActiveMax(string, Array>); int maxActiveOfType = GetWeaponNumberActiveMax(selectedWeapon,mWeaponArray); int curActiveOfType = WeaponsActiveOfType(weaponToLaunch); if (MustShootAt(aTarget)) { curActiveOfType = maxActiveOfType - 1; } if (curActiveOfType >= maxActiveOfType) { writeln_d(" Max number (", maxActiveOfType,")of ", selectedWeapon, " weapon type are already active! (", curActiveOfType,")"); return launched; } double effectiveRange = EffectiveRange(PLATFORM, aTarget); double dMaxLaunchRange = GetMaxLaunchRange(PLATFORM, aTarget, selectedWeapon, mWeaponArray); double rangeScale = dLaunchRangePercentage; //no change to scaling yet (use normal launch percent) if (dRelativeBearing > mDegradedFiringAngle) { rangeScale = MATH.Min(mDegradedPercentRange, dLaunchRangePercentage); } if ( effectiveRange > (dMaxLaunchRange*rangeScale) ) { //writeln_d(" Slantrange, ", dSlantRange*(1/MATH.M_PER_NM()), " nmi, To Target Greater Than Weapon Max Launch Range, ", dMaxLaunchRange*(1/MATH.M_PER_NM()), " nmi!"); writeln_d(PLATFORM.Name(), " failed weapon range check against ", aTarget.TargetName()); return launched; } launched = LaunchWeapon(PLATFORM, aTarget, weaponToLaunch, salvoCount); writeln_d(" launched == ", launched, ", weapon: ", selectedWeapon); if (launched == true) { mLastWeaponFiredTime = TIME_NOW; ####### double dPreviousRoundsFiredAt = mRoundsFiredAtMap.Get(aTarget); mRoundsFiredAtMap.Set(aTarget,dPreviousRoundsFiredAt + salvoCount); writeln_d(" F-pole after shot fired"); PLATFORM.Comment("Shot at: " + aTarget.TargetName()); //PLATFORM.Comment("Fired " + selectedWeapon + " at " + aTarget.TargetName()); mPursuitMode = "f-pole"; writeln_d(" mPursuitMode == ", mPursuitMode); } return launched; end_script // These Transition methods are intended to handle any bookkeeping required when changing // into a certain state. script void TransitionToWAIT(bool resumeDefaultRoute) PLATFORM.GoToSpeed(cWAIT_SPEED); //stay at wait speed if (resumeDefaultRoute) { bool success = false; if ( cROUTE_WAYPOINT_INDEX < 0) { success = PLATFORM.FollowRoute("DEFAULT_ROUTE", "CLOSEST_POINT"); } else { success = PLATFORM.FollowRoute("DEFAULT_ROUTE", cROUTE_WAYPOINT_INDEX); } PLATFORM.GoToAltitude(cDEFAULT_ALTITUDE, 200, true); if (!success) { PLATFORM.Comment("ERROR: transition to wait, could not follow default route!"); } if (mRouteType != "DEFAULT") { PLATFORM.Comment("Route: DEFAULT"); mRouteType = "DEFAULT"; } } else { ### PLATFORM.GoToAltitude(PLATFORM.Altitude(), 100); //stay at same altitude PLATFORM.TurnToHeading(PLATFORM.Heading()); //stay at same heading } ### PLATFORM.GoToAltitude(cDEFAULT_ALTITUDE); PROCESSOR.SetUpdateInterval(cSLOW_UPDATE_RATE); writeln_d(" Transition to WAIT due to Think()"); end_script script void TransitionToINTERCEPT(WsfTrack aTarget, string pursuitMode) PLATFORM.GoToSpeed(cINTERCEPT_SPEED); if (mUseMoverDuringPursuit) { #nothing PLATFORM.GoToAltitude(cDEFAULT_ALTITUDE, 200); } else { #TransitionToWAIT(true); #FAIL #PLATFORM.FollowRoute("DEFAULT_ROUTE", "CLOSEST_POINT"); #better PLATFORM.ReturnToRoute(); PLATFORM.GoToAltitude(cDEFAULT_ALTITUDE, 200, true); } PROCESSOR.SetUpdateInterval(cFAST_UPDATE_RATE); writeln_d(" Transition to INTERCEPT due to pursuing ", aTarget.TargetName(), " mode ", pursuitMode); end_script script void TransitionToPOINT() PROCESSOR.SetUpdateInterval(cSLOW_UPDATE_RATE); PLATFORM.GoToSpeed(cINTERCEPT_SPEED); PLATFORM.GoToAltitude(cDEFAULT_ALTITUDE, 200); writeln_d(" Transition to pursue POINT!"); end_script script void TransitionToEVADE_INCOMING() PROCESSOR.SetUpdateInterval(cFAST_UPDATE_RATE); PLATFORM.GoToSpeed(cINTERCEPT_SPEED); #PLATFORM.GoToAltitude(cDEFAULT_ALTITUDE, 200, true); writeln_d(" Transition to EVADE_INCOMING"); end_script on_initialize #extern double GetWeaponRangeMax (WsfPlatform, Array>); #extern double GetWeaponRangeMin (WsfPlatform, Array>); ownshipEngagementRangeMin = GetWeaponRangeMin(PLATFORM, mWeaponArray); ownshipEngagementRangeMax = GetWeaponRangeMax(PLATFORM, mWeaponArray); mTrackWeaponActiveMap = Map(); #can win a number of jobs, not just one SetNumJobChannels(cMAX_ACTIVE_WEAPONS); Array zoneList = PLATFORM.Zones(); foreach( WsfZone z in zoneList) { mZoneNames.PushBack(z.Name()); } foreach( string x in mZoneNames ) { writeln_d("--- Aircraft ", PLATFORM.Name(), " is now monitoring retrieved zone: ", x ); } if( mZoneNames.Size() == 0 ) { writeln_d( "--- Aircraft ", PLATFORM.Name(), " has no zones defined." ); } end_on_initialize query_bid if (!JOB.IsValid()) { return cMIN_JOB_BID; } double current_bid = 10000.0; //writeln_d(" - bidding on ", JOB.Name(), ", desc: ", JOB.GetDescription()); if (JOB.Name() == "pursue-target") { MaptempData = JOB.GetData(); string name = (string)tempData["targetTrackName"]; #extern WsfTrack GetTrackByName(WsfPlatform, string); WsfTrack track = GetTrackByName(PLATFORM, name); // if the track is not a foe or is damaged, we'll ignore it if (!(track.IsValid())) // || !(track.IFF_Foe())) { writeln_d("!!! No track for JOB: ", JOB.Name(), ", ", JOB.GetDescription(), ", ", name); return cMIN_JOB_BID; } #extern double EffectiveRange (WsfPlatform, WsfTrack); double effRange = EffectiveRange(PLATFORM, track); double slantRange = PLATFORM.SlantRangeTo(track); bool isCapable = false; string tName = track.TargetName(); if (!mTrackMinRangeOkMap.Exists(tName)) { mTrackMinRangeOkMap.Set(tName,true); } double maxCapableWeaponRange = 0.0; //determine if this agent has any weapons that are capable of engaging this kind of target (domain check) #extern bool IsWeaponDomainCapable(WsfTrack,Map); foreach (Map curWeapon in mWeaponArray) { #writeln_d(" ", (string)curWeapon["name"], " weapon is domain capable: ", IsWeaponDomainCapable(track,curWeapon)); #writeln_d(" ", (string)curWeapon["name"], " weapons remaining : ", ((WsfWeapon)curWeapon["weapon"]).QuantityRemaining()); if ( IsWeaponDomainCapable(track,curWeapon) && (((WsfWeapon)curWeapon["weapon"]).QuantityRemaining() > 0)) { isCapable = true; double curRange = (double)curWeapon["rangeMax"]; if (curRange > maxCapableWeaponRange) maxCapableWeaponRange = curRange; if (mTrackMinRangeOkMap.Get(tName)==true && (double)curWeapon["rangeMin"] < effRange ) { mTrackMinRangeOkMap.Set(tName, true); } else if (mTrackMinRangeOkMap.Get(tName)==false && ((double)curWeapon["rangeMin"] * 2.0) < slantRange ) { mTrackMinRangeOkMap.Set(tName, true); } else { mTrackMinRangeOkMap.Set(tName, false); writeln_d(" weapon min range failure"); } } } if (isCapable==false) { #extern string GetTargetDomain(WsfTrack); writeln_d("!!! No weapon capable in the ", GetTargetDomain(track)," domain and in range for: ", JOB.GetDescription()); return cMIN_JOB_BID; } if (mTrackMinRangeOkMap.Get(tName)==false) { writeln_d("!!! TrackMinRangeOk == false"); return cMIN_JOB_BID; } double currentlyTargeted = 0; if (GetTargetName() == name) { currentlyTargeted = 1.0; } //writeln_d(" Currently Targeted: ", currentlyTargeted ); //determine if the missile range is added to the escort protect radius if (!escortAddMissileProtectRange) { maxCapableWeaponRange = 0.0; } // if escoring a package, determine if the threat is engageable // check if it lies within the protect radius if (mEscortFollowing) { #if already engaging the threat, allow a little chase if (slantRange > (escortProtectDistance + maxCapableWeaponRange + (currentlyTargeted * escortChaseDistance))) { #writeln_d(" Target not a threat to escort package!"); return cMIN_JOB_BID; } } #extern string DetermineTrackCategory (WsfTrack); string targetType = DetermineTrackCategory(track); //writeln_d(" track category: ",targetType); #extern bool TestTrackCategory(WsfTrack, string); if (TestTrackCategory(track, "unknown")) { writeln_d("!!! Target type unknown for current job. "); return cMIN_JOB_BID; } int othersTargeting = GetRIPRCommanderProcessor().SubsTargeting( track, PLATFORM ); //writeln_d(" Others Targeting: ", othersTargeting ); // set the target type //writeln_d(" -Creating track record for ", name, " -- ", targetType); //writeln_d(" track closing speed: ", PLATFORM.ClosingSpeedOf(track) ); //writeln_d(" track slant range : ", PLATFORM.SlantRangeTo(track) ); // account for bidding parameters #extern int GetBucket(double, double); //writeln_d(" GetBucket(track closing speed): ", GetBucket(PLATFORM.ClosingSpeedOf(track), cBUCKET_BASE) ); //writeln_d(" GetBucket(track slant range): ", GetBucket(PLATFORM.SlantRangeTo(track), cBUCKET_BASE) ); //current_bid = current_bid + cWEIGHT_BEING_TARGETED * beingTargeted; current_bid = current_bid + cWEIGHT_CURRENT_TARGET * currentlyTargeted; current_bid = current_bid + cWEIGHT_CLOSING_SPEED_OF * GetBucket(PLATFORM.ClosingSpeedOf(track), cBUCKET_BASE) + GetBucket(cBASE_CLOSING_SPEED_CONSTANT, cBUCKET_BASE); current_bid = current_bid + cWEIGHT_SLANT_RANGE_TO * GetBucket(PLATFORM.SlantRangeTo(track), cBUCKET_BASE) + GetBucket(cBASE_SLANT_RANGE_CONSTANT, cBUCKET_BASE); current_bid = current_bid + cWEIGHT_OTHERS_TARGETING * othersTargeting; current_bid = current_bid + cWEIGHT_WEAPONS_IN_FLIGHT * PROCESSOR.WeaponsActive(track); current_bid = current_bid + cWEIGHT_WEAPONS_FIRED_AT * mRoundsFiredAtMap.Get(track); current_bid = current_bid + cWEIGHT_ANY_WEAPONS_ACTIVE * (WeaponsActive(track) + PeersWeaponsActive(track)); ### if ( (WeaponsActive(aTarget) > 0) || (PeersWeaponsActive(aTarget) > 0) ) if( ThreatTypePriority.Exists( targetType ) ) { current_bid = current_bid + ThreatTypePriority.Get( targetType ); } } else if( JOB.Name() == "pursue-point" ) { MaptempData = JOB.GetData(); string name = (string)tempData["targetTrackName"]; WsfGeoPoint point = (WsfGeoPoint)tempData["targetPoint"]; if (!point.IsValid()) { writeln_d("!!! Invalid point for current job: ",JOB.Name(), ", ", JOB.GetDescription() ); return cMIN_JOB_BID; } // account for bidding parameters #extern int GetBucket(double, double); current_bid = current_bid + cWEIGHT_SLANT_RANGE_TO * GetBucket(PLATFORM.SlantRangeTo(point), cBUCKET_BASE) + GetBucket(cBASE_SLANT_RANGE_CONSTANT, cBUCKET_BASE); } //writeln_d(" calculated bid: ", current_bid); return current_bid; end_query_bid on_update int WeaponCount = WeaponsActive(); for (int i=0; i< WeaponCount; i=i+1) { WsfPlatform w = ActiveWeaponPlatform(i); if (IsUplinkingTo(w)) { foreach( WsfRIPRProcessor proc in GetRIPRCommanderProcessor().GetRIPRSubordinateProcessors() ) { if ( ! proc.IsUplinkingTo(w)) { proc.StartUplinking(w); PROCESSOR.StopUplinking(w); break; } } } } #extern Array ttrs; foreach(string ttr in ttrs) { if (PLATFORM.AuxDataBool(ttr)) #shoot at this guy if we can { writeln_d(PLATFORM.Name(), " trying to shoot at ttr: ", ttr); WsfPlatform ttrPlatform = WsfSimulation.FindPlatform(ttr); if (ttrPlatform.IsValid()) #take a shot { WsfTrack ttrTrack = ttrPlatform.MakeTrack(); ttrTrack.SetAuxData("notlocal", "true"); if (CheckAndFire(ttrTrack)) { writeln_d(PLATFORM.Name(), " shot at the ttr: ", ttr); PLATFORM.SetAuxData(ttr, false); } } } } #extern bool TestTrackCategory(WsfTrack, string); double duration = 0.0; double lStartTime = GetWallClockTime(); writeln_d("--- on_update Platform: ", PLATFORM.Name(), ", State: ", mState, ", Time: ", TIME_NOW); string oldState = mState; string oldPursuitMode = mPursuitMode; mState = Think(); WsfTrack curTarget = GetTarget(); string targetType; bool turnOnFiringRadar = false; //turn on firing radar if in range if (mTurnOnFiringRadarInRange && !curTarget.IsNull() && curTarget.IsValid()) { //check range against radar range if (PLATFORM.SlantRangeTo(curTarget) < mFiringRadarRange) { #writeln_d(PLATFORM.Name()," within range of curTarget!"); turnOnFiringRadar = true; } else { #writeln_d(PLATFORM.Name()," NOT within range of curTarget!"); } } //turn on firing radar if being tracked if (mTurnOnFiringRadarIfRWR && !turnOnFiringRadar) { WsfLocalTrackList localTracks = PLATFORM.MasterTrackList(); foreach (WsfLocalTrack t in localTracks) { if (t.SensorTypeContributor(mRWR_RadarType)) { turnOnFiringRadar = true; #writeln_d(PLATFORM.Name(), " is being tracked! RWR signal from ", mRWR_RadarType); break; } } if (!turnOnFiringRadar) { #writeln_d(PLATFORM.Name(), " not being tracked. No RWR signal from ", mRWR_RadarType); } } if (turnOnFiringRadar) { //make sure radar is on WsfSensor firingRadar = PLATFORM.Sensor(mFiringRadarName); if (firingRadar.IsValid()) { if (!firingRadar.IsTurnedOn()) { firingRadar.TurnOn(); #writeln_d(PLATFORM.Name(), " turned on fire control radar ", mFiringRadarName); } else { #writeln_d(PLATFORM.Name(), " has fire control radar ", mFiringRadarName, " already on!"); } } else { #writeln_d("fire control radar ", mFiringRadarName," not found on ", PLATFORM.Name()); } } if (oldState != mState) { PLATFORM.Comment("State: " + mState); } if (mState == "POINT") { if (oldState != "POINT") { TransitionToPOINT(); } if (mUsePathFinder) { //extern bool UpdatePointInterceptLocationWithPathing(WsfPlatform, WsfGeoPoint); UpdatePointInterceptLocationWithPathing (PLATFORM, mCurrentPointIntercept); } else { //extern bool UpdatePointInterceptLocation(WsfPlatform, WsfGeoPoint); UpdatePointInterceptLocation (PLATFORM, mCurrentPointIntercept); } duration = GetWallClockTime() - lStartTime; writeln_d("--- on_update Platform: ", PLATFORM.Name(), ", Process Time: ", duration); return; } // Process our state if (mState == "EVADE_INCOMING") { if (oldState != "EVADE_INCOMING") { TransitionToEVADE_INCOMING(); #mAltitudeBeforeEvade = PLATFORM.Altitude(); mAltitudeBeforeEvade = cDEFAULT_ALTITUDE; mSafeAltitudeToDiveTo = MATH.Max(mAltitudeMin, (mAltitudeBeforeEvade - mAltitudeToDiveEvade)); } CheckAndFire(curTarget); writeln_d(" Evading incoming"); #extern bool EvadeIncoming(WsfPlatform, WsfAIAIProcessor, Array, double, double, double); ###EvadeIncoming(PLATFORM, PROCESSOR, mIncoming, mAltitudeBeforeEvade, mSafeAltitudeToDiveTo, weightPeersForEvade); EvadeIncoming(PLATFORM, PROCESSOR, mIncoming, mAltitudeBeforeEvade, mAltitudeBeforeEvade, weightPeersForEvade); duration = GetWallClockTime() - lStartTime; writeln_d("--- on_update Platform: ", PLATFORM.Name(), ", Process Time: ", duration); return; } if (TestTrackCategory(curTarget, "unknown")) { writeln_d("Platform: ", PLATFORM.Name(), " current target: ", curTarget, " unknown or not valid, default mode to WAIT."); mState = "WAIT"; } if (mState == "INTERCEPT") { if (oldState != "INTERCEPT") { TransitionToINTERCEPT( curTarget, mPursuitMode ); } ####### PLATFORM.SetCurrentTarget(curTarget); CheckAndFire(curTarget); if (mUseMoverDuringPursuit) { // Our track quality may not be good enough yet, so keep moving towards the target. if (mUsePathFinder) { UpdateInterceptLocationWithPathing (curTarget, mPursuitMode); } else { UpdateInterceptLocation (curTarget, mPursuitMode); } } if (mPursuitMode != oldPursuitMode) { //PLATFORM.Comment("Pursuit Mode: " + mPursuitMode); } //writeln_d(" Heading: ", PLATFORM.Heading (), " Altitude: ", PLATFORM.Altitude (), " Speed: ", PLATFORM.Speed()); //writeln_d(" (", PLATFORM.Latitude(), ", ", PLATFORM.Longitude(), ", ", PLATFORM.Altitude(), ")"); //duration = GetWallClockTime() - lStartTime; //writeln_d("--- on_update Platform: ", PLATFORM.Name(), ", Process Time: ", duration); //return; } else if (mState == "BINGO_FUEL") { writeln_d(" bingo_fuel, return to base or something"); PLATFORM.Comment("Bingo fuel"); PLATFORM.GoToSpeed(0); } else //if (mState == "WAIT") { mState = "WAIT"; bool flyingEscort = false; if (mUseMoverDuringPursuit) { flyingEscort = FlyEscortFormation(); } if (flyingEscort) { writeln_d("flying escort formation!"); } else { writeln_d("Platform: ", PLATFORM.Name(), " not flying escort, flying regular WAIT state."); if (oldState != "WAIT") { TransitionToWAIT(true); //TransitionToWAIT(false); //LBM try this } } } //give attention to secondary jobs string tooComment = "Targets of opportunity: "; for (int channel = 1; channel < GetNumJobChannels(); channel = channel + 1) { //writeln_d("Getting job for channel: ", channel); WsfRIPRJob aJob = GetRIPRCommanderProcessor().GetJobFor(TIME_NOW, PROCESSOR, channel); if (!aJob.IsValid()) { //writeln_d("Job NOT VALID for channel: ", channel); continue; } if (aJob.Name() == "pursue-target") { string targetName = (string)aJob.GetData("targetTrackName"); #extern WsfTrack GetTrackByName(WsfPlatform, string); WsfTrack targetTrack = GetTrackByName(PLATFORM, targetName); if (!targetTrack.IsValid() || !targetTrack.BelievedAlive()) // || !targetTrack.IFF_Foe()) { writeln_d("Job TRACK is NOT valid for channel: ", channel, " job: ", aJob.GetDescription()); continue; } tooComment = (tooComment + targetName + " "); //don't fire last weapon at target thats not primary target #extern double GetWeaponQuantityRemainingMax(WsfPlatform, Array>); if (GetWeaponQuantityRemainingMax(PLATFORM, mWeaponArray) > 1) { writeln_d("Platform: ", PLATFORM.Name(), " Looking to fire at target of opportunity: ", targetName, " for channel: ", channel); CheckAndFire(targetTrack); } } else { //writeln_d("Job is NOT pursue-target for channel: ", channel); } } if (mOldTOOComment != tooComment) { //PLATFORM.Comment(tooComment); mOldTOOComment = tooComment; } duration = GetWallClockTime() - lStartTime; writeln_d("--- on_update Platform: ", PLATFORM.Name(), ", Process Time: ", duration); end_on_update end_processor