Merge branch 'develop' into FF/Ops

This commit is contained in:
Frank 2021-01-31 00:50:14 +01:00
commit 0933eef4c3
10 changed files with 190 additions and 141 deletions

View File

@ -1140,8 +1140,8 @@ end
-- @param DCS#Vec3 CV2 Vec3
function AI_FORMATION:FollowMe(FollowGroup, ClientUnit, CT1, CV1, CT2, CV2)
if FollowGroup:GetState( FollowGroup, "Mode" ) == self.__Enum.Mode.Formation then
if FollowGroup:GetState( FollowGroup, "Mode" ) == self.__Enum.Mode.Formation and not self:Is("Stopped") then
self:T({Mode=FollowGroup:GetState( FollowGroup, "Mode" )})
FollowGroup:OptionROTEvadeFire()

View File

@ -122,7 +122,7 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
self.Schedule[Scheduler][CallID].Function = ScheduleFunction
self.Schedule[Scheduler][CallID].Arguments = ScheduleArguments
self.Schedule[Scheduler][CallID].StartTime = timer.getTime() + ( Start or 0 )
self.Schedule[Scheduler][CallID].Start = Start + 0.1
self.Schedule[Scheduler][CallID].Start = Start + 0.001
self.Schedule[Scheduler][CallID].Repeat = Repeat or 0
self.Schedule[Scheduler][CallID].Randomize = Randomize or 0
self.Schedule[Scheduler][CallID].Stop = Stop

View File

@ -5411,10 +5411,12 @@ do -- SET_ZONE
--- Get a random zone from the set.
-- @param #SET_ZONE self
-- @param #number margin Number of tries to find a zone
-- @return Core.Zone#ZONE_BASE The random Zone.
-- @return #nil if no zone in the collection.
function SET_ZONE:GetRandomZone()
function SET_ZONE:GetRandomZone(margin)
local margin = margin or 100
if self:Count() ~= 0 then
local Index = self.Index
@ -5423,9 +5425,11 @@ do -- SET_ZONE
-- Loop until a zone has been found.
-- The :GetZoneMaybe() call will evaluate the probability for the zone to be selected.
-- If the zone is not selected, then nil is returned by :GetZoneMaybe() and the loop continues!
while not ZoneFound do
local counter = 0
while (not ZoneFound) or (counter < margin) do
local ZoneRandom = math.random( 1, #Index )
ZoneFound = self.Set[Index[ZoneRandom]]:GetZoneMaybe()
counter = counter + 1
end
return ZoneFound

View File

@ -1,4 +1,4 @@
--- **Functional** -- Modular, Automatic and Network capable Targeting and Interception System for Air Defenses
--- **Functional** -- Modular, Automatic and Network capable Targeting and Interception System for Air Defenses
--
-- ===
--
@ -37,7 +37,7 @@
-- @field #table SAM_Table Table of SAM sites
-- @field #string lid Prefix for logging
-- @field @{#Functional.Detection#DETECTION_AREAS} Detection The #DETECTION_AREAS object for EWR
-- @field @{Functional.Detection#DETECTION_AREAS} AWACS_Detection The #DETECTION_AREAS object for AWACS
-- @field @{#Functional.Detection#DETECTION_AREAS} AWACS_Detection The #DETECTION_AREAS object for AWACS
-- @field #boolean debug Switch on extra messages
-- @field #boolean verbose Switch on extra logging
-- @field #number checkradius Radius of the SAM sites
@ -96,7 +96,7 @@
--
-- # 2. Start up your MANTIS with a basic setting
--
-- `myredmantis = MANTIS:New("myredmantis","Red SAM","Red EWR",nil,"red",false)`
-- `myredmantis = MANTIS:New("myredmantis","Red SAM","Red EWR",nil,"red",false)`
-- `myredmantis:Start()`
--
-- [optional] Use
@ -111,7 +111,7 @@
--
-- If you want to use a separate AWACS unit (default detection range: 250km) to support your EWR system, use e.g. the following setup:
--
-- `mybluemantis = MANTIS:New("bluemantis","Blue SAM","Blue EWR",nil,"blue",false,"Blue Awacs")`
-- `mybluemantis = MANTIS:New("bluemantis","Blue SAM","Blue EWR",nil,"blue",false,"Blue Awacs")`
-- `mybluemantis:Start()`
--
-- # 3. Default settings
@ -181,6 +181,26 @@ do
--@param #boolean dynamic Use constant (true) filtering or just filter once (false, default) (optional)
--@param #string awacs Group name of your Awacs (optional)
--@return #MANTIS self
--@usage Start up your MANTIS with a basic setting
--
-- `myredmantis = MANTIS:New("myredmantis","Red SAM","Red EWR",nil,"red",false)`
-- `myredmantis:Start()`
--
-- [optional] Use
--
-- * `MANTIS:SetEWRGrouping(radius)`
-- * `MANTIS:SetEWRRange(radius)`
-- * `MANTIS:SetSAMRadius(radius)`
-- * `MANTIS:SetDetectInterval(interval)`
-- * `MANTIS:SetAutoRelocate(hq, ewr)`
--
-- before starting #MANTIS to fine-tune your setup.
--
-- If you want to use a separate AWACS unit (default detection range: 250km) to support your EWR system, use e.g. the following setup:
--
-- `mybluemantis = MANTIS:New("bluemantis","Blue SAM","Blue EWR",nil,"blue",false,"Blue Awacs")`
-- `mybluemantis:Start()`
--
function MANTIS:New(name,samprefix,ewrprefix,hq,coaltion,dynamic,awacs)
-- DONE: Create some user functions for these
@ -307,7 +327,7 @@ do
self.engagerange = range
end
--- Function to set a new SAM firing engage range, use this method to adjust range while running MANTIS, e.g. for different setups day and night
--- Function to set a new SAM firing engage range, use this method to adjust range while running MANTIS, e.g. for different setups day and night
-- @param #MANTIS self
-- @param #number range Percent of the max fire range
function MANTIS:SetNewSAMRangeWhileRunning(range)
@ -535,7 +555,7 @@ do
end
end
--- Function to check if any object is in the given SAM zone
--- (Internal) Function to check if any object is in the given SAM zone
-- @param #MANTIS self
-- @param #table dectset Table of coordinates of detected items
-- @param samcoordinate Core.Point#COORDINATE Coordinate object.
@ -562,7 +582,7 @@ do
return false
end
--- Function to start the detection via EWR groups
--- (Internal) Function to start the detection via EWR groups
-- @param #MANTIS self
-- @return Functional.Detection #DETECTION_AREAS The running detection set
function MANTIS:StartDetection()
@ -593,7 +613,7 @@ do
return _MANTISdetection
end
--- Function to start the detection via AWACS if defined as separate
--- (Internal) Function to start the detection via AWACS if defined as separate
-- @param #MANTIS self
-- @return Functional.Detection #DETECTION_AREAS The running detection set
function MANTIS:StartAwacsDetection()
@ -625,7 +645,7 @@ do
return _MANTISAwacs
end
--- Function to set the SAM start state
--- (Internal) Function to set the SAM start state
-- @param #MANTIS self
-- @return #MANTIS self
function MANTIS:SetSAMStartState()

View File

@ -1318,6 +1318,10 @@ function ATIS:onafterBroadcast(From, Event, To)
time=time-UTILS.GMTToLocalTimeDifference()*60*60
end
if time < 0 then
time = 24*60*60 + time --avoid negative time around midnight
end
local clock=UTILS.SecondsToClock(time)
local zulu=UTILS.Split(clock, ":")
local ZULU=string.format("%s%s", zulu[1], zulu[2])

View File

@ -17,13 +17,13 @@
-- ===
--
-- ## Example Missions:
--
--
-- Demo missions can be found on [github](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/OPS%20-%20Flightgroup).
--
--
-- ===
--
-- ### Author: **funkyfranky**
--
--
-- ===
-- @module Ops.FlightGroup
-- @image OPS_FlightGroup.png
@ -234,7 +234,7 @@ function FLIGHTGROUP:New(group)
self.lid=string.format("FLIGHTGROUP %s | ", self.groupname)
-- Defaults
self.isFlightgroup=true
self.isFlightgroup=true
self:SetFuelLowThreshold()
self:SetFuelLowRTB()
self:SetFuelCriticalThreshold()
@ -325,10 +325,10 @@ function FLIGHTGROUP:New(group)
-- Start the status monitoring.
self:__Status(-1)
-- Start queue update timer.
self.timerQueueUpdate=TIMER:New(self._QueueUpdate, self):Start(2, 5)
-- Start check zone timer.
self.timerCheckZone=TIMER:New(self._CheckInZones, self):Start(3, 10)
@ -491,7 +491,7 @@ function FLIGHTGROUP:SetFuelCriticalRTB(switch)
return self
end
--- Enable to automatically engage detected targets.
--- Enable to automatically engage detected targets.
-- @param #FLIGHTGROUP self
-- @param #number RangeMax Max range in NM. Only detected targets within this radius from the group will be engaged. Default is 25 NM.
-- @param #table TargetTypes Types of target attributes that will be engaged. See [DCS enum attributes](https://wiki.hoggitworld.com/view/DCS_enum_attributes). Default "All".
@ -508,7 +508,7 @@ function FLIGHTGROUP:SetEngageDetectedOn(RangeMax, TargetTypes, EngageZoneSet, N
else
TargetTypes={"All"}
end
-- Ensure SET_ZONE if ZONE is provided.
if EngageZoneSet and EngageZoneSet:IsInstanceOf("ZONE_BASE") then
local zoneset=SET_ZONE:New():AddZone(EngageZoneSet)
@ -532,7 +532,7 @@ function FLIGHTGROUP:SetEngageDetectedOn(RangeMax, TargetTypes, EngageZoneSet, N
return self
end
--- Disable to automatically engage detected targets.
--- Disable to automatically engage detected targets.
-- @param #FLIGHTGROUP self
-- @return #FLIGHTGROUP self
function FLIGHTGROUP:SetEngageDetectedOff()
@ -762,45 +762,45 @@ function FLIGHTGROUP:onbeforeStatus(From, Event, To)
-- First we check if elements are still alive. Could be that they were despawned without notice, e.g. when landing on a too small airbase.
for i,_element in pairs(self.elements) do
local element=_element --#FLIGHTGROUP.Element
-- Check that element is not already dead or not yet alive.
if element.status~=OPSGROUP.ElementStatus.DEAD and element.status~=OPSGROUP.ElementStatus.INUTERO then
-- Unit shortcut.
local unit=element.unit
local isdead=false
local isdead=false
if unit and unit:IsAlive() then
-- Get life points.
local life=unit:GetLife() or 0
-- Units with life <=1 are dead.
if life<=1 then
--env.info(string.format("FF unit %s: live<=1 in status at T=%.3f", unit:GetName(), timer.getTime()))
isdead=true
end
else
-- Not alive any more.
--env.info(string.format("FF unit %s: NOT alive in status at T=%.3f", unit:GetName(), timer.getTime()))
isdead=true
end
-- This one is dead.
if isdead then
local text=string.format("Element %s is dead at t=%.3f! Maybe despawned without notice or landed at a too small airbase. Calling ElementDead in 60 sec to give other events a chance",
local text=string.format("Element %s is dead at t=%.3f! Maybe despawned without notice or landed at a too small airbase. Calling ElementDead in 60 sec to give other events a chance",
tostring(element.name), timer.getTime())
self:E(self.lid..text)
self:__ElementDead(60, element)
end
end
end
end
if self:IsDead() then
if self:IsDead() then
self:T(self.lid..string.format("Onbefore Status DEAD ==> false"))
return false
return false
elseif self:IsStopped() then
self:T(self.lid..string.format("Onbefore Status STOPPED ==> false"))
return false
@ -818,7 +818,7 @@ function FLIGHTGROUP:onafterStatus(From, Event, To)
-- FSM state.
local fsmstate=self:GetState()
-- Update position.
self:_UpdatePosition()
@ -865,22 +865,22 @@ function FLIGHTGROUP:onafterStatus(From, Event, To)
-- Short info.
if self.verbose>=1 then
local nTaskTot, nTaskSched, nTaskWP=self:CountRemainingTasks()
local nMissions=self:CountRemainingMissison()
local text=string.format("Status %s [%d/%d]: Tasks=%d (%d,%d) Curr=%d, Missions=%s, Waypoint=%d/%d, Detected=%d, Home=%s, Destination=%s",
fsmstate, #self.elements, #self.elements, nTaskTot, nTaskSched, nTaskWP, self.taskcurrent, nMissions, self.currentwp or 0, self.waypoints and #self.waypoints or 0,
self.detectedunits:Count(), self.homebase and self.homebase:GetName() or "unknown", self.destbase and self.destbase:GetName() or "unknown")
self:I(self.lid..text)
end
---
-- Elements
---
if self.verbose>=2 then
local text="Elements:"
for i,_element in pairs(self.elements) do
@ -958,7 +958,7 @@ function FLIGHTGROUP:onafterStatus(From, Event, To)
-- Log outut.
self:I(self.lid..string.format("Travelled ds=%.1f km dt=%.1f s ==> v=%.1f knots. Fuel left for %.1f min", self.traveldist/1000, dt, UTILS.MpsToKnots(v), TmaxFuel/60))
end
---
@ -1008,34 +1008,34 @@ function FLIGHTGROUP:onafterStatus(From, Event, To)
---
-- Engage Detected Targets
---
---
if self:IsAirborne() and self.detectionOn and self.engagedetectedOn and not (self.fuellow or self.fuelcritical) then
env.info("FF 100")
-- Target.
local targetgroup=nil --Wrapper.Group#GROUP
local targetdist=math.huge
-- Loop over detected groups.
for _,_group in pairs(self.detectedgroups:GetSet()) do
local group=_group --Wrapper.Group#GROUP
env.info("FF 200")
if group and group:IsAlive() then
env.info("FF 300")
-- Get 3D vector of target.
local targetVec3=group:GetVec3()
-- Distance to target.
-- Distance to target.
local distance=UTILS.VecDist3D(self.position, targetVec3)
if distance<=self.engagedetectedRmax and distance<targetdist then
env.info("FF 400")
-- Check type attribute.
local righttype=false
for _,attribute in pairs(self.engagedetectedTypes) do
@ -1046,13 +1046,13 @@ function FLIGHTGROUP:onafterStatus(From, Event, To)
break
end
end
-- We got the right type.
if righttype then
local insideEngage=true
local insideNoEngage=false
-- Check engage zones.
if self.engagedetectedEngageZones then
insideEngage=false
@ -1062,10 +1062,10 @@ function FLIGHTGROUP:onafterStatus(From, Event, To)
if inzone then
insideEngage=true
break
end
end
end
end
-- Check no engage zones.
if self.engagedetectedNoEngageZones then
for _,_zone in pairs(self.engagedetectedNoEngageZones.Set) do
@ -1077,25 +1077,25 @@ function FLIGHTGROUP:onafterStatus(From, Event, To)
end
end
end
-- If inside engage but not inside no engage zones.
if insideEngage and not insideNoEngage then
targetdist=distance
targetgroup=group
end
end
end
end
end
end
-- If we found a group, we engage it.
if targetgroup then
self:I(self.lid..string.format("Engaging target group %s at distance %d meters", targetgroup:GetName(), targetdist))
self:EngageTarget(targetgroup)
end
end
@ -1255,7 +1255,7 @@ function FLIGHTGROUP:OnEventCrash(EventData)
local element=self:GetElementByName(unitname)
if element and element.status~=OPSGROUP.ElementStatus.DEAD then
self:T(self.lid..string.format("EVENT: Element %s crashed ==> destroyed", element.name))
self:T(self.lid..string.format("EVENT: Element %s crashed ==> destroyed", element.name))
self:ElementDestroyed(element)
end
@ -1271,7 +1271,7 @@ function FLIGHTGROUP:OnEventUnitLost(EventData)
-- Check that this is the right group.
if EventData and EventData.IniGroup and EventData.IniUnit and EventData.IniGroupName and EventData.IniGroupName==self.groupname then
self:T2(self.lid..string.format("EVENT: Unit %s lost at t=%.3f", EventData.IniUnitName, timer.getTime()))
local unit=EventData.IniUnit
local group=EventData.IniGroup
local unitname=EventData.IniUnitName
@ -1283,7 +1283,7 @@ function FLIGHTGROUP:OnEventUnitLost(EventData)
self:T(self.lid..string.format("EVENT: Element %s unit lost ==> destroyed t=%.3f", element.name, timer.getTime()))
self:ElementDestroyed(element)
end
end
end
@ -1306,7 +1306,7 @@ function FLIGHTGROUP:onafterElementSpawned(From, Event, To, Element)
-- Set element status.
self:_UpdateStatus(Element, OPSGROUP.ElementStatus.SPAWNED)
if Element.unit:InAir() then
if Element.unit:InAir(true) then
-- Trigger ElementAirborne event. Add a little delay because spawn is also delayed!
self:__ElementAirborne(0.11, Element)
else
@ -1433,26 +1433,26 @@ end
-- @param Wrapper.Airbase#AIRBASE airbase The airbase if applicable or nil.
function FLIGHTGROUP:onafterElementLanded(From, Event, To, Element, airbase)
self:T2(self.lid..string.format("Element landed %s at %s airbase", Element.name, airbase and airbase:GetName() or "unknown"))
if self.despawnAfterLanding then
-- Despawn the element.
self:DespawnElement(Element)
else
-- Helos with skids land directly on parking spots.
if self.ishelo then
local Spot=self:GetParkingSpot(Element, 10, airbase)
self:_SetElementParkingAt(Element, Spot)
end
-- Set element status.
self:_UpdateStatus(Element, OPSGROUP.ElementStatus.LANDED, airbase)
end
end
@ -1483,7 +1483,7 @@ function FLIGHTGROUP:onafterElementDestroyed(From, Event, To, Element)
-- Call OPSGROUP function.
self:GetParent(self).onafterElementDestroyed(self, From, Event, To, Element)
end
--- On after "ElementDead" event.
@ -1503,7 +1503,7 @@ function FLIGHTGROUP:onafterElementDead(From, Event, To, Element)
-- Not parking any more.
Element.parking=nil
end
@ -1515,7 +1515,7 @@ end
function FLIGHTGROUP:onafterSpawned(From, Event, To)
self:T(self.lid..string.format("Flight spawned"))
-- Update position.
-- Update position.
self:_UpdatePosition()
if self.isAI then
@ -1525,32 +1525,32 @@ function FLIGHTGROUP:onafterSpawned(From, Event, To)
-- Set ROT.
self:SwitchROT(self.option.ROT)
-- Set Formation
self:SwitchFormation(self.option.Formation)
-- Set TACAN beacon.
self:_SwitchTACAN()
-- Set radio freq and modu.
if self.radioDefault then
self:SwitchRadio()
else
self:SetDefaultRadio(self.radio.Freq, self.radio.Modu, self.radio.On)
end
-- Set callsign.
if self.callsignDefault then
self:SwitchCallsign(self.callsignDefault.NumberSquad, self.callsignDefault.NumberGroup)
else
self:SetDefaultCallsign(self.callsign.NumberSquad, self.callsign.NumberGroup)
end
-- TODO: make this input.
self:GetGroup():SetOption(AI.Option.Air.id.PROHIBIT_JETT, true)
self:GetGroup():SetOption(AI.Option.Air.id.PROHIBIT_AB, true) -- Does not seem to work. AI still used the after burner.
self:GetGroup():SetOption(AI.Option.Air.id.RTB_ON_BINGO, false)
--self.group:SetOption(AI.Option.Air.id.RADAR_USING, AI.Option.Air.val.RADAR_USING.FOR_CONTINUOUS_SEARCH)
--self.group:SetOption(AI.Option.Air.id.RADAR_USING, AI.Option.Air.val.RADAR_USING.FOR_CONTINUOUS_SEARCH)
-- Update route.
self:__UpdateRoute(-0.5)
@ -1690,7 +1690,7 @@ function FLIGHTGROUP:onafterLanded(From, Event, To, airbase)
-- Add flight to taxiinb queue.
self.flightcontrol:SetFlightStatus(self, FLIGHTCONTROL.FlightStatus.TAXIINB)
end
end
--- On after "LandedAt" event.
@ -1699,7 +1699,7 @@ end
-- @param #string Event Event.
-- @param #string To To state.
function FLIGHTGROUP:onafterLandedAt(From, Event, To)
self:T(self.lid..string.format("Flight landed at"))
self:T(self.lid..string.format("Flight landed at"))
end
@ -1735,22 +1735,22 @@ function FLIGHTGROUP:onafterDead(From, Event, To)
self.flightcontrol:_RemoveFlight(self)
self.flightcontrol=nil
end
if self.Ndestroyed==#self.elements then
if self.squadron then
-- All elements were destroyed ==> Asset group is gone.
self.squadron:DelGroup(self.groupname)
end
end
else
if self.airwing then
-- Not all assets were destroyed (despawn) ==> Add asset back to airwing.
self.airwing:AddAsset(self.group, 1)
self.airwing:AddAsset(self.group, 1)
end
end
end
-- Call OPSGROUP function.
self:GetParent(self).onafterDead(self, From, Event, To)
end
@ -1799,10 +1799,10 @@ function FLIGHTGROUP:onbeforeUpdateRoute(From, Event, To, n)
end
if self.taskcurrent>0 then
--local task=self:GetTaskCurrent()
local task=self:GetTaskByID(self.taskcurrent)
if task then
if task.dcstask.id=="PatrolZone" then
-- For patrol zone, we need to allow the update.
@ -1861,7 +1861,7 @@ function FLIGHTGROUP:onafterUpdateRoute(From, Event, To, n)
-- Set current waypoint or we get problem that the _PassingWaypoint function is triggered too early, i.e. right now and not when passing the next WP.
local current=self.group:GetCoordinate():WaypointAir(COORDINATE.WaypointAltType.BARO, COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint, speed, true, nil, {}, "Current")
table.insert(wp, current)
local Nwp=self.waypoints and #self.waypoints or 0
-- Add remaining waypoints to route.
@ -1885,7 +1885,7 @@ function FLIGHTGROUP:onafterUpdateRoute(From, Event, To, n)
---
-- No waypoints left
---
if self:IsAirborne() then
self:T(self.lid.."No waypoints left ==> CheckGroupDone")
self:_CheckGroupDone()
@ -1919,7 +1919,7 @@ function FLIGHTGROUP:_CheckGroupDone(delay)
self:UnpauseMission()
return
end
-- Group is currently engaging.
if self:IsEngaging() then
return
@ -1939,7 +1939,7 @@ function FLIGHTGROUP:_CheckGroupDone(delay)
-- Number of remaining tasks/missions?
if nTasks==0 and nMissions==0 then
local destbase=self.destbase or self.homebase
local destzone=self.destzone or self.homezone
@ -2062,19 +2062,19 @@ function FLIGHTGROUP:onafterRTB(From, Event, To, airbase, SpeedTo, SpeedHold, Sp
-- Clear holding time in any case.
self.Tholding=nil
-- Cancel all missions.
for _,_mission in pairs(self.missionqueue) do
local mission=_mission --Ops.Auftrag#AUFTRAG
local mystatus=mission:GetGroupStatus(self)
-- Check if mission is already over!
if not (mystatus==AUFTRAG.GroupStatus.DONE or mystatus==AUFTRAG.GroupStatus.CANCELLED) then
local text=string.format("Canceling mission %s in state=%s", mission.name, mission.status)
self:T(self.lid..text)
self:MissionCancel(mission)
end
end
-- Defaults:
@ -2176,7 +2176,7 @@ function FLIGHTGROUP:onafterRTB(From, Event, To, airbase, SpeedTo, SpeedHold, Sp
-- Clear all tasks.
-- Warning, looks like this can make DCS CRASH! Had this after calling RTB once passed the final waypoint.
--self:ClearTasks()
-- Just route the group. Respawn might happen when going from holding to final.
self:Route(wp, 1)
@ -2374,39 +2374,39 @@ function FLIGHTGROUP:onafterEngageTarget(From, Event, To, Target)
-- Check target object.
if Target:IsInstanceOf("UNIT") or Target:IsInstanceOf("STATIC") then
DCStask=self:GetGroup():TaskAttackUnit(Target, true)
elseif Target:IsInstanceOf("GROUP") then
DCStask=self:GetGroup():TaskAttackGroup(Target, nil, nil, nil, nil, nil, nil, true)
elseif Target:IsInstanceOf("SET_UNIT") then
local DCSTasks={}
for _,_unit in pairs(Target:GetSet()) do --detected by =HRP= Zero
local unit=_unit --Wrapper.Unit#UNIT
local task=self:GetGroup():TaskAttackUnit(unit, true)
table.insert(DCSTasks)
end
-- Task combo.
DCStask=self:GetGroup():TaskCombo(DCSTasks)
elseif Target:IsInstanceOf("SET_GROUP") then
local DCSTasks={}
for _,_unit in pairs(Target:GetSet()) do --detected by =HRP= Zero
local unit=_unit --Wrapper.Unit#UNIT
local task=self:GetGroup():TaskAttackGroup(Target, nil, nil, nil, nil, nil, nil, true)
table.insert(DCSTasks)
end
-- Task combo.
DCStask=self:GetGroup():TaskCombo(DCSTasks)
else
self:E("ERROR: unknown Target in EngageTarget! Needs to be a UNIT, STATIC, GROUP, SET_UNIT or SET_GROUP")
return
@ -2414,10 +2414,10 @@ function FLIGHTGROUP:onafterEngageTarget(From, Event, To, Target)
-- Create new task.The description "Engage_Target" is checked so do not change that lightly.
local Task=self:NewTaskScheduled(DCStask, 1, "Engage_Target", 0)
-- Backup ROE setting.
Task.backupROE=self:GetROE()
-- Switch ROE to open fire
self:SwitchROE(ENUMS.ROE.OpenFire)
@ -2428,7 +2428,7 @@ function FLIGHTGROUP:onafterEngageTarget(From, Event, To, Target)
end
-- Execute task.
self:TaskExecute(Task)
self:TaskExecute(Task)
end
@ -2501,9 +2501,9 @@ function FLIGHTGROUP:onafterFuelLow(From, Event, To)
local tanker=self.airwing:GetTankerForFlight(self)
if tanker then
self:I(self.lid..string.format("Send to refuel at tanker %s", tanker.flightgroup:GetName()))
-- Get a coordinate towards the tanker.
local coordinate=self:GetCoordinate():GetIntermediateCoordinate(tanker.flightgroup:GetCoordinate(), 0.75)
@ -2600,12 +2600,12 @@ function FLIGHTGROUP:onafterStop(From, Event, To)
self:UnHandleEvent(EVENTS.Ejection)
self:UnHandleEvent(EVENTS.Crash)
self:UnHandleEvent(EVENTS.RemoveUnit)
-- Call OPSGROUP function.
self:GetParent(self).onafterStop(self, From, Event, To)
-- Remove flight from data base.
_DATABASE.FLIGHTGROUPS[self.groupname]=nil
_DATABASE.FLIGHTGROUPS[self.groupname]=nil
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@ -2668,7 +2668,7 @@ function FLIGHTGROUP:_InitGroup()
self:E(self.lid.."WARNING: Group was already initialized!")
return
end
-- Group object.
local group=self.group --Wrapper.Group#GROUP
@ -2705,7 +2705,7 @@ function FLIGHTGROUP:_InitGroup()
self.radio.Freq=tonumber(self.template.frequency)
self.radio.Modu=tonumber(self.template.modulation)
self.radio.On=self.template.communication
-- Set callsign. Default is set on spawn if not modified by user.
local callsign=self.template.units[1].callsign
if type(callsign)=="number" then -- Sometimes callsign is just "101".
@ -2726,7 +2726,7 @@ function FLIGHTGROUP:_InitGroup()
else
self.optionDefault.Formation=ENUMS.Formation.FixedWing.EchelonLeft.Group
end
-- Default TACAN off.
self:SetDefaultTACAN(nil, nil, nil, nil, true)
self.tacan=UTILS.DeepCopy(self.tacanDefault)
@ -2870,7 +2870,7 @@ function FLIGHTGROUP:GetHomebaseFromWaypoints()
-- Get airbase ID depending on airbase category.
local airbaseID=nil
if wp.airdromeId then
airbaseID=wp.airdromeId
else
@ -2878,7 +2878,7 @@ function FLIGHTGROUP:GetHomebaseFromWaypoints()
end
local airbase=AIRBASE:FindByID(airbaseID)
return airbase
end
@ -3126,14 +3126,14 @@ function FLIGHTGROUP:InitWaypoints()
-- Template waypoints.
self.waypoints0=self.group:GetTemplateRoutePoints()
-- Waypoints
-- Waypoints
self.waypoints={}
for index,wp in pairs(self.waypoints0) do
local waypoint=self:_CreateWaypoint(wp)
local waypoint=self:_CreateWaypoint(wp)
self:_AddWaypoint(waypoint)
end
-- Get home and destination airbases from waypoints.
@ -3188,7 +3188,7 @@ function FLIGHTGROUP:AddWaypoint(Coordinate, Speed, AfterWaypointWithID, Altitud
-- Create waypoint data table.
local waypoint=self:_CreateWaypoint(wp)
-- Set altitude.
if Altitude then
waypoint.alt=UTILS.FeetToMeters(Altitude)
@ -3426,12 +3426,12 @@ end
function FLIGHTGROUP:GetClosestAirbase()
local group=self.group --Wrapper.Group#GROUP
local coord=group:GetCoordinate()
local coalition=self:GetCoalition()
local airbase=coord:GetClosestAirbase() --(nil, coalition)
return airbase
end

View File

@ -2646,7 +2646,7 @@ function OPSGROUP:onafterTaskExecute(From, Event, To, Task)
local TaskFinal=self.group:TaskCombo({TaskControlled, TaskDone})
-- Set task for group.
self:SetTask(TaskFinal, 1)
self:SetTask(TaskFinal)
end

View File

@ -1500,4 +1500,24 @@ function UTILS.GetOSTime()
end
return nil
end
end
--- Shuffle a table accoring to Fisher Yeates algorithm
--@param #table table to be shuffled
--@return #table
function UTILS.ShuffleTable(t)
if t == nil or type(t) ~= "table" then
BASE:I("Error in ShuffleTable: Missing or wrong tyåe of Argument")
return
end
math.random()
math.random()
math.random()
local TempTable = {}
for i = 1, #t do
local r = math.random(1,#t)
TempTable[i] = t[r]
table.remove(t,r)
end
return TempTable
end

View File

@ -1894,7 +1894,7 @@ do -- Patrol methods
local ToCoord = COORDINATE:NewFromVec2( { x = Waypoint.x, y = Waypoint.y } )
-- Create a "ground route point", which is a "point" structure that can be given as a parameter to a Task
local Route = {}
Route[#Route+1] = FromCoord:WaypointGround( 0 )
Route[#Route+1] = FromCoord:WaypointGround( Speed, Formation )
Route[#Route+1] = ToCoord:WaypointGround( Speed, Formation )
@ -1947,7 +1947,7 @@ do -- Patrol methods
-- Create a "ground route point", which is a "point" structure that can be given as a parameter to a Task
local Route = {}
Route[#Route+1] = FromCoord:WaypointGround( 20 )
Route[#Route+1] = FromCoord:WaypointGround( Speed, Formation )
Route[#Route+1] = ToCoord:WaypointGround( Speed, Formation )

View File

@ -1174,8 +1174,9 @@ end
--- Returns true if the UNIT is in the air.
-- @param #UNIT self
-- @param #boolean NoHeloCheck If true, no additonal checks for helos are performed.
-- @return #boolean Return true if in the air or #nil if the UNIT is not existing or alive.
function UNIT:InAir()
function UNIT:InAir(NoHeloCheck)
self:F2( self.UnitName )
-- Get DCS unit object.
@ -1185,14 +1186,14 @@ function UNIT:InAir()
-- Get DCS result of whether unit is in air or not.
local UnitInAir = DCSUnit:inAir()
-- Get unit category.
local UnitCategory = DCSUnit:getDesc().category
-- If DCS says that it is in air, check if this is really the case, since we might have landed on a building where inAir()=true but actually is not.
-- This is a workaround since DCS currently does not acknoledge that helos land on buildings.
-- Note however, that the velocity check will fail if the ground is moving, e.g. on an aircraft carrier!
if UnitInAir==true and UnitCategory == Unit.Category.HELICOPTER then
if UnitInAir==true and UnitCategory == Unit.Category.HELICOPTER and (not NoHeloCheck) then
local VelocityVec3 = DCSUnit:getVelocity()
local Velocity = UTILS.VecNorm(VelocityVec3)
local Coordinate = DCSUnit:getPoint()