Files
lab1/processors/ripr_agents/aiai/aiai_processor.old.txt
2025-09-12 15:20:28 +08:00

2008 lines
74 KiB
Plaintext

# ****************************************************************************
# CUI
#
# The Advanced Framework for Simulation, Integration, and Modeling (AFSIM)
#
# The use, dissemination or disclosure of data in this file is subject to
# limitation or restriction. See accompanying README and LICENSE for details.
# ****************************************************************************
#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<string> mTargetTrackerTaskManagerStrings = Array<string>();
mTargetTrackerTaskManagerStrings[0] = "WSF_TASK_MANAGER";
mTargetTrackerTaskManagerStrings[1] = "RED_SAM_RADAR_TASK_MANAGER";
mTargetTrackerTaskManagerStrings[2] = "task_manager";
mTargetTrackerTaskManagerStrings[3] = "task_mgr";
Array<string> mMustShootAtCategories = Array<string>();
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<string> mEscortNames = Array<string>();
Map<string, double> ThreatTypePriority = Map<string, double>();
# 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<string, double> ThreatTypeOffsetAngle = Map<string, double>();
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<string, int> ThreatTypeSalvo = Map<string, int>();
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<string, double> ThreatTypeRequiredTrackQuality = Map<string, double>();
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<string, string> ThreatTypeWeapon = Map<string, string>();
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<string, double> WeaponTypeMaxFiringAngle = Map<string, double>();
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<string, double> ThreatTypeLaunchPercentRangeMax = Map<string, double>();
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<Map<string, Object>> mWeaponArray = Array<Map<string, Object>>();
//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<string, Object>();
// 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<WsfPlatform> mIncoming = Array<WsfPlatform>();
string mState = "";
string mRouteType = "";
string mPursuitMode = "";
string mOldCommandComment = "no command";
string mOldTOOComment = "Targets of opportunity: ";
WsfRIPRJob mCurrentJob;
WsfGeoPoint mCurrentPointIntercept;
Map<string,double> mTrackWeaponActiveMap = Map<string,double>();
Map<string,bool> mTrackMinRangeOkMap = Map<string,bool>();
Array<string> mZoneNames = Array<string>(); #dlc
Map<WsfTrack, double> mRoundsFiredAtMap = Map<WsfTrack, double>(); #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<Map<string, Object>> weapons, double percent)
bool checkName = false;
string name = "";
#extern bool IsWeaponDomainCapable(WsfTrack, Map<string, Object>);
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<string, Object> 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<Map<string, Object>>);
#extern double GetWeaponRangeMin (WsfPlatform, Array<Map<string, Object>>);
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<Map<string, Object>>);
#extern double GetWeaponRangeMin (WsfPlatform, Array<Map<string, Object>>);
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<WsfPlatform>(); // 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<WsfPlatform>)(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<Map<string, Object>>);
# 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<WsfRIPRJob> 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<string, Object> 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<string,Object> 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<Map<string, Object>>);
#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<Map<string, Object>>);
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<Map<string, Object>>);
#extern double GetWeaponRangeMin (WsfPlatform, Array<Map<string, Object>>);
ownshipEngagementRangeMin = GetWeaponRangeMin(PLATFORM, mWeaponArray);
ownshipEngagementRangeMax = GetWeaponRangeMax(PLATFORM, mWeaponArray);
mTrackWeaponActiveMap = Map<string,double>();
#can win a number of jobs, not just one
SetNumJobChannels(cMAX_ACTIVE_WEAPONS);
Array<WsfZone> 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")
{
Map<string, Object>tempData = 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<string, Object>);
foreach (Map<string, Object> 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" )
{
Map<string, Object>tempData = 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<string> 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<WsfPlatform>, 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<Map<string, Object>>);
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