# **************************************************************************** # 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. # **************************************************************************** behavior pincer script_debug_writes off script_variables //debug parameters bool mDrawSteering = false; //parameters for how to initially fly pincer (1st phase, separation) string mDirection = "none"; double mPincerSpeed = 500 * MATH.MPS_PER_NMPH(); //400 kts double mPincerOffsetAngle = 70.0; //degrees //parameters for determining if to chase and how to do so (2nd phase, option A) double mEnemyFOVHalfAngle = 50.0; //degrees double mChaseAngle = 75.0; //degrees double mChaseSpeedlnsideFOV = 600 * MATH.MPS_PER_NMPH(); //600 kts double mChaseSpeedOutsideFOV = 1200 * MATH.MPS_PER_NMPH(); //1200 kts //parameters for determining if to drag (run) and how to do so (2nd phase, option B) double mRunDistance = 130 * 1852; //130nm (meters) double mRunAngleLimit = 15.0; //degrees double mDragSpeed = 800 * MATH.MPS_PER_NMPH(); //800 kts double mDragAddedAngle = -1.0; //degrees //util var, not for user edit WsfGeoPoint mPincerPoint; bool mDragging = false; bool mChasing = false; WsfDraw mDraw = WsfDraw(); WsfRIPRJob mCurrentJob; end_script_variables script double GetPincerDragOffset(WsfTrack aTgt) if (aTgt.Speed() >= PLATFORM.Speed()) { return 180.0; } else { return (180 - MATH.ACos(aTgt.Speed()/PLATFORM.Speed())); } end_script precondition #writeln_d("precondition pincer"); if (!PROCESSOR.IsA_TypeOf("WSF_RIPR_PROCESSOR")) { return Failure("behavior not attached to a RIPR processor!"); } // ((WsfRIPRProcessor)PROCESSOR) if (((WsfRIPRProcessor)PROCESSOR).GetRIPRCommanderProcessor().IsValid()) { mCurrentJob = ((WsfRIPRProcessor)PROCESSOR).GetRIPRCommanderProcessor().GetJobFor(TIME_NOW, ((WsfRIPRProcessor)PROCESSOR)); if (mCurrentJob.IsValid()) { // If we're supposed to fly towards a point, go for it! if (mCurrentJob.Name() == "pincer") { mPincerPoint = (WsfGeoPoint)mCurrentJob.GetData("ZonePoint"); mDirection = (string)mCurrentJob.GetData(PLATFORM.Name()); if (mPincerPoint.IsValid()) { return true; } else { writeln_d(PLATFORM.Name(), " pincer point not valid!"); return Failure("pincer job did not have valid point"); } } else { writeln_d(PLATFORM.Name(), " job not a pincer job: ", mCurrentJob.Name()); } } else { writeln_d(PLATFORM.Name(), " job not valid!"); } } else { writeln_d(PLATFORM.Name(), " commander not found!"); return Failure("no commander found"); } return Failure("current job not a valid pincer job"); end_precondition execute writeln_d(PLATFORM.Name(), " executing pincer!, T=", TIME_NOW); //provide for another channel for pursue-target jobs if (((WsfRIPRProcessor)PROCESSOR).NumJobChannels() <= 1) { ((WsfRIPRProcessor)PROCESSOR).SetNumJobChannels(2); } //writelnd("executing pincer."); ((WsfRIPRProcessor)PROCESSOR).ClearTarget(); //calculate heading if we are still flying offset double angle = 0; if (mDirection == "left") { angle = -mPincerOffsetAngle; } else if (mDirection == "right") { angle = mPincerOffsetAngle; } double heading = MATH.NormalizeAngle0_360(PLATFORM.TrueBearingTo(mPincerPoint) + angle); //find out if we are being chased & should drag threats away WsfTrack worstTrack; double worstDist = MATH.DOUBLE_MAX(); double worstFOV = MATH.DOUBLE_MAX(); Array targetNames = (Array)mCurrentJob.GetData("ZoneThreatNameArray"); extern WsfTrack GetTrackByName (WsfPlatform, string); int allOnCap = (int)mCurrentJob.GetData("all_on_cap"); if (allOnCap <= 0) { //save off the closest opponent track foreach(string tgtName in targetNames) { WsfTrack tgt = GetTrackByName(PLATFORM, tgtName); if (tgt.IsValid() && tgt.LocationValid()) { double attackRange = tgt.GroundRangeTo(PLATFORM); if (attackRange < worstDist) { //run away, drag threats out worstDist = attackRange; worstTrack = tgt; } double fov = MATH.Fabs(tgt.RelativeBearingTo(PLATFORM)); if (fov < worstFOV) { worstFOV = fov; } } } //manage dragging state if ( (mDragging == false) && (worstDist < mRunDistance) && (worstTrack.IsValid()) && (worstTrack.HeadingValid()) && (MATH.Fabs(worstTrack.TrueBearingTo(PLATFORM)-worstTrack.Heading()) < mRunAngleLimit)) { mDragging = true; if (mDirection == "right") { int count = (int)mCurrentJob.GetData("right_drag"); mCurrentJob.SetData("right_drag",count+1); writeln_d(PLATFORM.Name(), " increased right_drag to: ", count+1); } else if (mDirection == "left") { int count = (int)mCurrentJob.GetData("left_drag"); mCurrentJob.SetData("left_drag",count+1); writeln_d(PLATFORM.Name(), " increased left_drag to: ", count+1); } } else if ( (mDragging == true) && ( (!worstTrack.IsValid()) || (worstDist > (mRunDistance*1.1)) || (!worstTrack.HeadingValid()) || (MATH.Fabs(worstTrack.TrueBearingTo(PLATFORM)-worstTrack.Heading()) > (mRunAngleLimit*1.1)))) { mDragging = false; if (mDirection == "right") { int count = (int)mCurrentJob.GetData("right_drag"); mCurrentJob.SetData("right_drag",count-1); writeln_d(PLATFORM.Name(), " decreased right_drag to: ", count-1); } else if (mDirection == "left") { int count = (int)mCurrentJob.GetData("left_drag"); mCurrentJob.SetData("left_drag",count -1); writeln_d(PLATFORM.Name(), " decreased left_drag to: ", count-1); } } mChasing = false; if (mDragging == true) { writeln_d("dragging!"); //try to maintain distance PLATFORM.GoToSpeed(mDragSpeed); double dragOffset = GetPincerDragOffset(worstTrack); if (mDirection == "right") { if (mDragAddedAngle > 0) { heading = MATH.NormalizeAngle0_360(heading + mDragAddedAngle); } else { heading = MATH.NormalizeAngle0_360(PLATFORM.TrueBearingTo(mPincerPoint) + dragOffset); } } else if (mDirection == "left") { if (mDragAddedAngle > 0) { heading = MATH.NormalizeAngle0_360(heading - mDragAddedAngle); } else { heading = MATH.NormalizeAngle0_360(PLATFORM.TrueBearingTo(mPincerPoint) - dragOffset); } } } else { //look for reasons to chase PLATFORM.GoToSpeed(mPincerSpeed); //check if other pair is dragging, so we should chase int count = 0; if (mDirection == "right") { count = (int)mCurrentJob.GetData("left_drag"); } else if (mDirection == "left") { count = (int)mCurrentJob.GetData("right_drag"); } double diff = 0; if (worstTrack.IsValid() && worstTrack.HeadingValid()) { double b1 = worstTrack.Heading(); double b2 = worstTrack.TrueBearingTo(PLATFORM.Location()); diff = MATH.NormalizeAngleMinus180_180(b2 - b1); } if (count > 0 && MATH.Fabs(diff) > mEnemyFOVHalfAngle) { //the other pincer group is being engaged, turn in now writeln_d(PLATFORM.Name(), " chasing because other pair is dragging"); mChasing = true; } //check if we have flanked & can now chase else { if (mDirection == "right" && diff < -mChaseAngle) { writeln_d(PLATFORM.Name(), " right chasing because past chase angle"); mChasing = true; } else if (mDirection == "left" && diff > mChaseAngle) { mChasing = true; writeln_d(PLATFORM.Name(), " left chasing because past chase angle"); } } } } else { writeln_d("All targets still on cap, no dragging or chasing yet!"); } if (mChasing == true) { writeln_d("chasing!"); //double FOV = MATH.Fabs(worstTrack.RelativeBearingTo(PLATFORM)); if (worstFOV <= mEnemyFOVHalfAngle) { PLATFORM.GoToSpeed(mChaseSpeedlnsideFOV); } else { PLATFORM.GoToSpeed(mChaseSpeedOutsideFOV); } if (worstTrack.IsValid()) { heading = PLATFORM.TrueBearingTo(worstTrack); ((WsfRIPRProcessor)PROCESSOR).SetTarget(worstTrack); } else { heading = PLATFORM.TrueBearingTo((WsfGeoPoint)mCurrentJob.GetData("ZonePoint")); } } PLATFORM.TurnToHeading(heading); if (mDrawSteering == true) { WsfGeoPoint pt = PLATFORM.Location(); pt.Extrapolate(heading, 185200); mDraw.SetLayer("behavior_pincer"); mDraw.SetDuration(PROCESSOR.UpdateInterval()); mDraw.SetColor(0.0, 1.0, 0.75); //green-blue mDraw.SetLineSize(1); mDraw.BeginLines(); mDraw.Vertex(PLATFORM.Location()); mDraw.Vertex(pt); mDraw.Vertex(PLATFORM.Location()); mDraw.Vertex(mPincerPoint); mDraw.End(); } # # writeln_d(" T=", TIME_NOW, ", range: ", interceptRange, " true-bearing; interceptHeading); # ##if ( (interceptAltitude - PLATFORM.Altitude()) > 5) #if ( (interceptAltitude - PLATFORM.Altitude()) > 10000*MATH.M_PER_FT()) #{ # writeln_d("GoToAltitude: ",interceptAltitude); # #PLATF0RM.GoToAltitude(interceptAltitude); #> end_execute end_behavior