# **************************************************************************** # 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. # **************************************************************************** include_once behavior_timeline_reposition.txt #drag to restart further back on timeline include_once behavior_timeline_delay.txt #maneuver to delay enemy's engagement include_once behavior_timeline_engage.txt #intercept/shoot timeline targets #include_once behavior_timeline_support.txt #fly support role on a timeline (usually behind lead shooter role) include_once behavior_weapon_support.txt #crank & support weapon include_once behavior_planned_route.txt #no timeline tasks, just return to route include_once behavior_evade.txt #evade iminent threats (missiles) include_once behavior_go_home.txt #disengage, go back to initial location #include_once behavior_fly_timeline.txt processor TIMELINE_PROC WSF_QUANTUM_TASKER_PROCESSOR update_interval 2 sec script_variables double mGeesToTurnWith = 6.0; #update this however intelligently you can (based on risk level?) #double mOffsetAngle = 45.0; #TODO - calculate half sensor angle? double mOffsetAngle = 30.0; #TODO - calculate half sensor angle? double mDelaySpeed = 204; #0.6 double mEngageSpeed = 237; #0.8 double mDragSpeed = 309; #1.2 double mDefaultAltitude = 35000 * MATH.M_PER_FT(); #double mDragAltitude = 30000 * MATH.M_PER_FT(); double mDragAltitude = 35000 * MATH.M_PER_FT(); #testing bool mConsiderPeersWeapons = true; #do not shoot if peers already are #bool mRequiredToSupportWeapons = true; #TODO - update dynamically somehow? bool mRequiredToSupportWeapons = true; #TODO - update dynamically somehow? double DefaultPercentRangeMax = 0.80; # don't launch unless within this percent of Rmax double DefaultPercentRangeMin = 1.20; # don't launch unless beyond this percent of Rmin ##weapon + threat specific shooting parameters ##specify an Rmax based on which weapon used and which threat engaged #Map> WeaponThreatRmaxMap = Map>(); #WeaponThreatRmaxMap["base_weapon"] = Map(); #WeaponThreatRmaxMap["base_weapon"].Set("fighter", 0.80); bool mDrawSeparationData = true; string mSeparateSide = "LEFT"; #this is dynamically updated based on engagement axis #do not edit these: bool mSeparateEngagement = false; double mEngagementTrueBearing = -1.0; #valid if in [0,360], update based on engagement axis WsfDraw mDraw = WsfDraw(); Array mTimeLineLocalTargets; WsfLocalTrack mNearestTimeLineTarget; Array mTimeLineLocalTargetsToShoot = Array(); end_script_variables on_update #update these if necessary mSeparateEngagement = false; mEngagementTrueBearing = -1.0; #populate shared variables WsfTask timeline = GetTimeLineTask(PROCESSOR); mTimeLineLocalTargets = GetTimeLineTaskLocalTargets(PLATFORM, timeline); Array times = Array(); foreach(WsfLocalTrack target in mTimeLineLocalTargets) { double time = TimeToReachPoint(target, PLATFORM.Location(), mGeesToTurnWith); times.PushBack(time); } SortLocalTracksByValue(mTimeLineLocalTargets, times); mNearestTimeLineTarget = GetNearestTimeLineTaskLocalTarget(PLATFORM, timeline); if (timeline.IsValid() && timeline.AuxDataExists("point_a") && timeline.AuxDataExists("point_b") ) { WsfGeoPoint SeparateA = (WsfGeoPoint)timeline.AuxDataObject("point_a"); WsfGeoPoint SeparateB = (WsfGeoPoint)timeline.AuxDataObject("point_b"); if (SeparateA.IsValid() && SeparateB.IsValid()) { WsfGeoPoint near; WsfGeoPoint far; if (PLATFORM.GroundRangeTo(SeparateA) < PLATFORM.GroundRangeTo(SeparateB)) { near = SeparateA; far = SeparateB; } else { near = SeparateB; far = SeparateA; } mDraw.SetLayer("timeline_proc"); mDraw.SetId("timeline_proc"); mDraw.SetDuration(PROCESSOR.UpdateInterval()); mDraw.SetLineSize(1); mDraw.SetLineStyle("solid"); Array targets = (Array)timeline.AuxDataObject("targets"); #check if platform is on the correct side of separation line WsfGeoPoint clusterMeanLocation = (WsfGeoPoint)timeline.AuxDataObject("cluster_mean"); double refAz = near.TrueBearingTo(far); #save this engagement axis true bearing! mSeparateEngagement = true; mEngagementTrueBearing = MATH.NormalizeAngle0_360(refAz); double ownAz = near.TrueBearingTo(PLATFORM.Location()) - refAz; double tgtAz = near.TrueBearingTo(clusterMeanLocation) - refAz; ownAz = MATH.NormalizeAngleMinus180_180(ownAz); tgtAz = MATH.NormalizeAngleMinus180_180(tgtAz); #save off turn direction if (tgtAz < 0) { mSeparateSide = "LEFT"; } else { mSeparateSide = "RIGHT"; } bool CorrectSide = ((ownAz * tgtAz) > 0); #draw lines for separation divide mDraw.SetColor(0.0, 0.0, 0.0); #black mDraw.BeginLines(); mDraw.Vertex(near); mDraw.Vertex(far); mDraw.End(); if (CorrectSide) { mDraw.SetColor(0.0, 1.0, 1.0); #aqua } else { mDraw.SetColor(1.0, 0.0, 0.0); #red } #draw line from me to target center of gravity mDraw.BeginLines(); mDraw.Vertex(PLATFORM); #mDraw.Vertex(targetCluster.MeanLocation()); mDraw.Vertex(mTimeLineLocalTargets.Front().CurrentLocation()); mDraw.End(); # mDraw.SetEllipseMode("line"); # mDraw.BeginCircle(0.0, 4.0 * MATH.M_PER_NM()); # mDraw.Vertex(PLATFORM); # mDraw.End(); } } #update the "mTimeLineLocalTargetsToShoot" list mTimeLineLocalTargetsToShoot.Clear(); if (timeline.IsValid()) { string RISK = timeline.AuxDataString("RISK"); foreach(WsfLocalTrack target in mTimeLineLocalTargets) { writeln_d("T=",TIME_NOW," ", PLATFORM.Name(), " checking if shootable: ", target.TargetName()); if (FiredOn(PLATFORM, target, mConsiderPeersWeapons)) { writeln_d(" NO - already fired on!"); continue; } if (mRequiredToSupportWeapons == true && RISK != "HIGH") #can support any shot when risk is high (won't be dragging) { double gate = timeline.AuxDataDouble("DOR"); #range (meters) if (RISK == "MEDIUM") { gate = timeline.AuxDataDouble("MAR"); #range (meters) } #calculate if we have time or range to support a shot to this target: ################################################################### ################################################################### ################################################################### #figure out weapon range & time of flight double weaponMaxRange = 0.0; WsfWeapon maxRangeWeapon; for (int i=0; i < PLATFORM.WeaponCount(); i+=1) { WsfWeapon weapon = PLATFORM.WeaponEntry(i); if (WeaponCapableAvailableAgainstThreat(weapon, target)) { double weaponRange = MaxRange(PLATFORM,weapon,target); if (weaponRange > weaponMaxRange) { weaponMaxRange = weaponRange; maxRangeWeapon = weapon; } } } if (!maxRangeWeapon.IsValid()) { writeln_d(" NO - do not have a weapon for the target"); continue; #no weapon for this target } #estimate time before we can shoot #hypothetical shot #estimate time cranking (based on weapon travel time) #does this leave us enough time to turn to drag? double weaponTOF = TimeToHit(PLATFORM, maxRangeWeapon, target); if (weaponTOF <= 0) { writeln_d(" NO - could not find TOF data for weapon"); #good weapon data no found continue; } double firingRange = DefaultPercentRangeMax * weaponMaxRange; writeln_d(" INFO - weapon \"", maxRangeWeapon.Name(), "\" firing range = ", firingRange, " TOF = ", weaponTOF); double targetRange = PLATFORM.GroundRangeTo(target.CurrentLocation()); double rangeToGo = targetRange - firingRange; double timeTilShot = 0.0; double range = PLATFORM.GroundRangeTo(mNearestTimeLineTarget.CurrentLocation()); if (rangeToGo > 0) { #assume target continues on its current heading #assume nearest threat closes towards you #assume we close towards target double myRelativeBearingToThreat = MATH.Fabs(MATH.NormalizeAngleMinus180_180(PLATFORM.TrueBearingTo(mNearestTimeLineTarget) - PLATFORM.TrueBearingTo(target))); double targetRelativeBearingToMe = target.RelativeBearingTo(PLATFORM); double closingSpeedToTarget = PLATFORM.Speed() + MATH.Cos(targetRelativeBearingToMe) * target.Speed(); double closingSpeedOfThreat = mNearestTimeLineTarget.Speed() + MATH.Cos(myRelativeBearingToThreat) * PLATFORM.Speed(); if (closingSpeedToTarget <= 0) { writeln_d(" NO - negative closing speed to target with range remaining to shoot"); continue; } writeln_d(" INFO - closing to target = ", closingSpeedToTarget, " closing of threat = ", closingSpeedOfThreat); #subtract off closing distance to nearest threat during the time before shot timeTilShot = rangeToGo / closingSpeedToTarget; double temp = range; range -= (timeTilShot * closingSpeedOfThreat); writeln_d(" INFO - starting threat range = ", temp, " range after closing to shot loc = ", range); } #subtract off closing distance to nearest target during the time of weapon's flight double closingSpeedOfThreat = (mDelaySpeed * MATH.Cos(mOffsetAngle)) + mNearestTimeLineTarget.Speed(); double temp = range; range -= (weaponTOF * closingSpeedOfThreat); writeln_d(" INFO - range at shot = ", temp, " range after supporting shot = ", range); # #calculate time to turn to drag (after cranking) # Array vals = Array(); # double turnAngle = 180 - mOffsetAngle; # TurnAngleTimeAndDistance(turnAngle, mEngageSpeed, mGeesToTurnWith, vals); # double turnTime = vals[0]; # double distSep = vals[1]; # #subtract off closing distance to nearest target during the time of turning to drag # range += distSep; # range -= (turnTime*mNearestTimeLineTarget.Speed()); if (range >= gate) { writeln_d(" YES - have time & range to support the shot."); mTimeLineLocalTargetsToShoot.PushBack(target); } else { writeln_d(" NO - do not have time & range to support the shot."); ##TODO - should we break here? ## its highly unlikely futher away targets will be shootable #break; } ################################################################### ################################################################### ################################################################### } else if (mRequiredToSupportWeapons == false || RISK == "HIGH") { writeln_d(" YES - risk is high or not required to support."); #all targets are for shooting (if not already shot on) mTimeLineLocalTargetsToShoot.PushBack(target); } } } end_on_update behavior_tree selector behavior_node evade # behavior_node go_home # behavior_node timeline_reposition # #behavior_node timeline_support #TODO - integrate kyle's grinder behavior support stuff behavior_node timeline_delay #TODO - integrate nick's delay script behavior_node timeline_engage #TODO - only shoot if there is time to support it behavior_node weapon_support # behavior_node planned_route # end_selector end_behavior_tree end_processor