-- region InterceptConfigFunctions -- @type InterceptConfig -- @field #string name Name of the intercept scenario. -- @field #boolean enable Enable the intercept scenario. -- @field #coalition.side benefitCoalition Benefit coalition. -- @field #JTFF_INTERCEPT.Type type Type of intercept. -- @field #string skill Skill of the intercept. -- @field #string[] templates Templates of the intercept (string or table of strings). --- Parse a RAT config Object. -- @param #JsonObject config Config object to parse -- @return #InterceptConfig interceptConfigJson Parsed INTERCEPT config object function ParseInterceptConfigJson(config) local json = require('Scripts/json') local parser_name = "INTERCEPT" -- ************************************************************************** -- enable -- ************************************************************************** local interceptConfigJson = {} if config.enable == true then interceptConfigJson = config else interceptConfigJson = { enable = false, } end Jtff_log.debug( string.format( "parsed INTERCEPT config for %s, resulting config :\n%s", config.name or "", json:encode( interceptConfigJson, { indent = true } ) ), parser_name ) return interceptConfigJson end -- endregion InterceptConfigFunctions -- region InterceptFunctions function clearIntercept(param) local objInterceptIndex = param[1] local objIntercept = InterceptArray[objInterceptIndex] Jtff_log.debug(string.format("objIntercept.objSpawn is %s", net.lua2json(objIntercept.objSpawn)),"INTERCEPT") local GroupPlane, Index = objIntercept.objSpawn:GetFirstAliveGroup() while GroupPlane ~= nil do GroupPlane:ScheduleStop() GroupPlane:Destroy(true,0) GroupPlane, Index = objIntercept.objSpawn:GetNextAliveGroup( Index ) end collectgarbage() end function interceptDefendFicghter(targetGroup) targetGroup:OptionROEWeaponFree() targetGroup:OptionROTVertical() targetGroup:OptionRTBBingoFuel(true) targetGroup:OptionRestrictBurner(false) targetGroup:EnableEmission(true) targetGroup:OptionAlarmStateRed() targetGroup:OptionECM_DetectedLockByRadar() targetGroup:CommandEPLRS(true) end function interceptDefendFastBomber(targetGroup) targetGroup:OptionRestrictBurner(false) local targetDestinationCoord = targetGroup:GetCoordinate():Translate( UTILS.NMToMeters(150), targetGroup:GetHeading(), true, false ):SetAltitude(UTILS.FeetToMeters(55000), true) targetGroup:Route( { targetDestinationCoord:WaypointAirTurningPoint( COORDINATE.WaypointAltType.BARO, UTILS.KnotsToKmph(5000), nil, "End interception" ), targetDestinationCoord:GetClosestAirbase( targetGroup:GetCategory(), targetGroup:GetCoalition() ):GetCoordinate():WaypointAirLanding( UTILS.KnotsToKmph(250), targetDestinationCoord:GetClosestAirbase( targetGroup:GetCategory(), targetGroup:GetCoalition() ) ) } ) end function interceptDetection(param) local objIntercept = param[1] Jtff_log.debug(string.format("objIntercept.interceptDetectionZone is %s", net.lua2json(objIntercept.interceptDetectionZone)),"INTERCEPT") --Jtff_log.debug(string.format("interceptorUnitName is %s", net.lua2json(interceptorUnitName)),"INTERCEPT") if ( objIntercept.bubbleInvaded == false ) then Jtff_log.trace(string.format("%s has not yet been intercepted", objIntercept.interceptTarget:GetName()),"INTERCEPT") --Jtff_log.debug(string.format("interceptDetectionZone is %s", net.lua2json(interceptDetectionZone)),"INTERCEPT") if (SET_CLIENT:New():FilterZones({objIntercept.interceptDetectionZone}):FilterOnce():CountAlive() > 0) then objIntercept.bubbleInvaded = true Jtff_log.info(string.format("%s has been intercepted", objIntercept.interceptTarget:GetName()),"INTERCEPT") if (objIntercept.knowIsIntercepted == false) then if (math.random(1,100) >= 75) then local delay = math.random(15,120) Jtff_log.info(string.format("%s has detected it has been intercepted : he will react accordingly in %i seconds !", objIntercept.interceptTarget:GetName(), delay),"INTERCEPT") objIntercept.knowIsIntercepted = true if objIntercept.customconfig.type == 'fastbomber' then SCHEDULER:New( objIntercept.interceptTarget, interceptDefendFastBomber, {}, delay ) elseif objIntercept.customconfig.type == 'fighter' then SCHEDULER:New( objIntercept.interceptTarget, interceptDefendFicghter, {}, delay ) end else Jtff_log.info(string.format("%s has not detected soon enough it has been intercepted", objIntercept.interceptTarget:GetName()),"INTERCEPT") end end end end end function StartInterceptTraining(param) local fighterUnitName = param[1] local objInterceptIndex = param[2] Jtff_log.debug(string.format("fighterUnitName is %s", fighterUnitName),"INTERCEPT") Jtff_log.debug(string.format("objInterceptIndex is %i", objInterceptIndex),"INTERCEPT") local minTA = param[3] local maxTA = param[4] local fighterUnit = UNIT:FindByName(fighterUnitName) Jtff_log.debug(string.format("fighterUnit is %s", net.lua2json(fighterUnit)),"INTERCEPT") local fighterGroup = fighterUnit:GetGroup() local fighterCoord = fighterUnit:GetCoordinate() Jtff_log.debug(string.format("fighterCoord is x=%d y=%d z=%d", fighterCoord.x, fighterCoord.y, fighterCoord.z),"INTERCEPT") local fighterHeading = fighterUnit:GetHeading() Jtff_log.debug(string.format("fighterHeading is %i", fighterHeading),"INTERCEPT") local fighterAltitude = fighterUnit:GetAltitude(false) local deltaAltMax = nil local targetGroup = nil local targetRange = nil local targetGroundSpeed = 450 local targetAngle = math.mod(minTA + math.random(0,maxTA-minTA),360) if (math.abs(math.mod(targetAngle,180)) > 50) then targetRange = 40 deltaAltMax = 7000 elseif (math.abs(math.mod(targetAngle,180)) > 20) then targetRange = 60 deltaAltMax = 10000 else targetRange = 90 deltaAltMax = 15000 end Jtff_log.info(string.format("Launching exercise TargetAngle %i degrees", targetAngle),"INTERCEPT") Jtff_log.debug(string.format("Index is : %i", objInterceptIndex),"INTERCEPT") local targetSpawnObj = InterceptArray[objInterceptIndex].objSpawn local targetCoord = COORDINATE:NewFromVec3( { x = fighterCoord.x + math.floor(UTILS.NMToMeters(targetRange) * math.cos(math.rad(fighterHeading))), y = math.max( math.min( math.random( fighterCoord.y - UTILS.FeetToMeters(deltaAltMax), fighterCoord.y + UTILS.FeetToMeters(deltaAltMax) ), UTILS.FeetToMeters(32000) ), UTILS.FeetToMeters(8000) ), z = fighterCoord.z + math.floor(UTILS.NMToMeters(targetRange) * math.sin(math.rad(fighterHeading))), } ) Jtff_log.info(string.format("Spawning target based on %s with TargetAngle of %i degrees", targetSpawnObj.SpawnTemplatePrefix, targetAngle),"INTERCEPT") targetGroup = targetSpawnObj:InitHeading(math.mod(fighterHeading + 180 + targetAngle,360)):SpawnFromVec3(targetCoord:GetVec3()) targetGroup:OptionROE(ENUMS.ROE.WeaponHold) targetGroup:OptionROT(ENUMS.ROT.NoReaction) targetGroup:OptionRTBBingoFuel(true) targetGroup:OptionRestrictBurner(false) targetGroup:EnableEmission(false) targetGroup:OptionAlarmStateGreen() targetGroup:OptionECM_Never() targetGroup:CommandEPLRS(true) InterceptArray[objInterceptIndex].interceptTarget = targetGroup InterceptArray[objInterceptIndex].knowIsIntercepted = false InterceptArray[objInterceptIndex].bubbleInvaded = false local targetDetectionRange = 1.5 --targetDetectionRange = 70 InterceptArray[objInterceptIndex].interceptDetectionZone = ZONE_GROUP:New( "intercept-" .. targetGroup:GetName(), targetGroup, UTILS.NMToMeters(targetDetectionRange) ) InterceptArray[objInterceptIndex].interceptTarget:ScheduleRepeat( 0, 5, nil, nil, interceptDetection, { InterceptArray[objInterceptIndex] } ) local targetDestinationCoord = targetGroup:GetCoordinate():Translate( UTILS.NMToMeters(200), math.mod(fighterHeading+180+ targetAngle,360), true, false ) Jtff_log.debug(string.format("targetDestinationCoord is %s", targetDestinationCoord:ToStringMGRS()),"INTERCEPT") local targetDestinationAirbase = targetDestinationCoord:GetClosestAirbase( targetGroup:GetCategory(), targetGroup:GetCoalition() ) if type(targetDestinationAirbase) == 'nil' then targetDestinationAirbase = targetDestinationCoord:GetClosestAirbase( targetGroup:GetCategory(), coalition.side.NEUTRAL ) Jtff_log.info(string.format("no airbase in target coalition, choosing neutral coalition Airbase %s", targetDestinationAirbase:GetName()),"INTERCEPT") end Jtff_log.debug(string.format("targetDestinationAirbase is %s", targetDestinationAirbase:GetName()),"INTERCEPT") local targetRoute = {} targetRoute[1] = targetDestinationCoord:WaypointAirTurningPoint( COORDINATE.WaypointAltType.BARO, UTILS.KnotsToKmph(targetGroundSpeed), nil, "End interception" ) targetRoute[2] = targetDestinationAirbase:GetCoordinate():WaypointAirLanding( UTILS.KnotsToKmph(targetGroundSpeed), targetDestinationAirbase ) targetGroup:Route(targetRoute) return targetGroup end -- endregion InterceptFunctions -- ***************************************************************************** -- ** Interception Training ** -- ********************************************************* InterceptArray = {} local compteur = #InterceptArray MenuCoalitionIntercept = {} for _k, _coalition in pairs(coalition.side) do MenuCoalitionIntercept[UTILS.GetCoalitionName(_coalition)] = MENU_COALITION:New(_coalition, "Intercept Training", MenuCoalition[UTILS.GetCoalitionName(_coalition)]) end for index, currentInterceptConfigObject in ipairs(InterceptConfig) do local intconfig = ParseInterceptConfigJson(currentInterceptConfigObject) if intconfig.enable == true then Jtff_log.info( string.format( "Enable %s with %s behavior", intconfig.name, intconfig.type ), "INTERCEPT" ) compteur = compteur +1 local objIntercept = { customconfig = {}, objSpawn = nil, menus = {}, menu_finex = {}, knowIsIntercepted = false, bubbleInvaded = false, } objIntercept.objSpawn = SPAWN:New(intconfig.templates[1]) :InitSkill(intconfig.skill) :InitRandomizeTemplatePrefixes(intconfig.templates) if (intconfig.type == JTFF_INTERCEPT.Type.Civilian) then for _k, _coalition in pairs(coalition.side) do objIntercept.menus[_coalition] = MENU_COALITION:New(_coalition, intconfig.name, MenuCoalitionIntercept[UTILS.GetCoalitionName(_coalition)]) objIntercept.menu_finex[_coalition] = MENU_COALITION_COMMAND:New( _coalition, "Knock it off, FinEx !!", objIntercept.menus[_coalition], clearIntercept, { compteur } ) end else objIntercept.menus[intconfig.benefitCoalition] = MENU_COALITION:New(intconfig.benefitCoalition, intconfig.name, MenuCoalitionIntercept[UTILS.GetCoalitionName(intconfig.benefitCoalition)]) objIntercept.menu_finex[intconfig.benefitCoalition] = MENU_COALITION_COMMAND:New( intconfig.benefitCoalition, "Knock it off, FinEx !!", objIntercept.menus[intconfig.benefitCoalition], clearIntercept, { compteur } ) end objIntercept.customconfig = intconfig InterceptArray[compteur] = objIntercept end end if #InterceptArray == 0 then for _k, _coalition in pairs(coalition.side) do MenuCoalitionIntercept[UTILS.GetCoalitionName(_coalition)]:Remove() end MenuCoalitionIntercept = {} end