From 6c0b6b3b9536f2fab2c43659240eaeef1a6575af Mon Sep 17 00:00:00 2001 From: Frank Date: Thu, 12 Mar 2020 12:37:09 +0100 Subject: [PATCH] Ops - First CAP version --- Moose Development/Moose/Ops/AirWing.lua | 139 +++++++++++++------- Moose Development/Moose/Ops/Auftrag.lua | 85 +++++++----- Moose Development/Moose/Ops/FlightGroup.lua | 82 +++++++----- Moose Development/Moose/Wrapper/Group.lua | 9 +- 4 files changed, 201 insertions(+), 114 deletions(-) diff --git a/Moose Development/Moose/Ops/AirWing.lua b/Moose Development/Moose/Ops/AirWing.lua index bc6fe6b29..ff6951852 100644 --- a/Moose Development/Moose/Ops/AirWing.lua +++ b/Moose Development/Moose/Ops/AirWing.lua @@ -78,13 +78,13 @@ AIRWING = { -- @field #number navail Number of available payloads of this type. -- @field #boolean unlimited If true, this payload is unlimited and does not get consumed. ---- CAP data. +--- Patrol data. -- @type AIRWING.PatrolData --- @field Core.Point#COORDINATE coord CAP coordinate. --- @field #number heading heading --- @field #number leg Leg. --- @field #number speed Speed. --- @field #boolean occupied Is currently occupied. +-- @field Core.Point#COORDINATE coord Patrol coordinate. +-- @field #number heading Heading in degrees. +-- @field #number leg Leg length in NM. +-- @field #number speed Speed in knots. +-- @field #number noccupied Number of flights on this patrol point. --- AIRWING class version. -- @field #string version @@ -133,6 +133,11 @@ function AIRWING:New(warehousename, airwingname) self:AddTransition("*", "MissionRequest", "*") -- Add a (mission) request to the warehouse. self:AddTransition("*", "MissionCancel", "*") -- Cancel mission. + -- Defaults: + self.nflightsCAP=0 + self.nflightsAWACS=0 + self.nflightsTANKER=0 + ------------------------ --- Pseudo Functions --- ------------------------ @@ -331,11 +336,11 @@ function AIRWING:AddAssetToSquadron(SquadronName, Group, Ngroups) self:AddAsset(Group, Ngroups, nil, nil, nil, nil, squadron.skill, squadron.livery, squadron.name) else - self:E("ERROR: Group does not exist!") + self:E(self.lid.."ERROR: Group does not exist!") end else - self:E("ERROR: Squadron does not exit!") + self:E(self.lid.."ERROR: Squadron does not exit!") end return self @@ -457,6 +462,7 @@ function AIRWING:NewPatrolPoint(Coordinate, Heading, LegLength, Altitude, Speed) cappoint.leg=LegLength or 15 cappoint.altitude=Altitude cappoint.speed=Speed or 350 + cappoint.noccupied=0 return cappoint end @@ -517,7 +523,7 @@ function AIRWING:onafterStatus(From, Event, To) local fsmstate=self:GetState() -- Check CAP missions. - --self:CheckCAP() + self:CheckCAP() --self:CheckTANKER() @@ -590,11 +596,12 @@ end -- @return #AIRWING.PatrolData function AIRWING:_GetPatrolData(PatrolPoints) + -- Sort wrt lowest number of flights on this point. local function sort(a,b) - return a.noccuied0 then -- Sort data wrt number of flights at that point. table.sort(PatrolPoints, sort) @@ -602,30 +609,32 @@ function AIRWING:_GetPatrolData(PatrolPoints) else - local point={} --#AIRWING.PatrolData + + local Coordinate=self:GetCoordinate() + local Heading=math.random(360) + local LegLength=math.random(10, 15) + local Altitude=math.random(10,15)*1000 + local Speed=math.random(250, 350) - point.coord=self:GetCoordinate() - point.speed=math.random(250, 350) - point.heading=math.random(360) - point.occupied=false - + return self:NewPatrolPoint(Coordinate,Heading,LegLength,Altitude,Speed) + end end ---- Get next mission. +--- Check how many CAP missions are assigned and add number of missing missions. -- @param #AIRWING self --- @return Ops.Auftrag#AUFTRAG Next mission or *nil*. +-- @return #AIRWING self function AIRWING:CheckCAP() - local Ncap=self:CountAssetsOnMission(AUFTRAG.Type.PATROL) + local Ncap=self:CountMissionsInQueue({AUFTRAG.Type.PATROL, AUFTRAG.Type.INTERCEPT}) for i=1,self.nflightsCAP-Ncap do local patrol=self:_GetPatrolData(self.cappoints) - local missionCAP=AUFTRAG:NewPATROL(patrol.coord, patrol.speed, patrol.heading, patrol.leg) + local missionCAP=AUFTRAG:NewPATROL(patrol.coord, patrol.speed, patrol.heading, patrol.leg, patrol.altitude) missionCAP.patroldata=patrol @@ -633,6 +642,7 @@ function AIRWING:CheckCAP() end + return self end @@ -788,8 +798,10 @@ function AIRWING:onafterMissionRequest(From, Event, To, Mission) if asset.spawned then if asset.flightgroup then - --TODO: cancel current mission if there is any! + + -- Add new mission. asset.flightgroup:AddMission(Mission) + else self:E(self.lid.."ERROR: flight group for asset does NOT exist!") end @@ -889,19 +901,6 @@ function AIRWING:onafterNewAsset(From, Event, To, asset, assignment) self:I(self.lid..string.format("Asset %s from squadron %s returned! asset.assignment=\"%s\", assignment=\"%s\"", asset.spawngroupname, squad.name, tostring(asset.assignment), tostring(assignment))) self:ReturnPayloadFromAsset(asset) - - -- Mission might already be removed from the queue! - --[[ - local mission=self:GetMissionByID(assignment) - - if mission then - local text=string.format("Asset %s returned from %s mission %s", asset.spawngroupname, mission.type, mission.name) - self:I(self.lid..text) - self:ReturnPayloadFromAsset(asset) - else - self:E(self.lid..string.format("ERROR: asset %s from squadron %s returned but could not find its mission! asset.assignment=\"%s\", assignment=\"%s\"", asset.spawngroupname, squad.name, tostring(asset.assignment), tostring(assignment))) - end - ]] end @@ -926,7 +925,13 @@ function AIRWING:onafterAssetSpawned(From, Event, To, group, asset, request) self:GetParent(self).onafterAssetSpawned(self, From, Event, To, group, asset, request) -- Create a flight group. - asset.flightgroup=self:_CreateFlightGroup(asset) + local flightgroup=self:_CreateFlightGroup(asset) + + -- Set RTB on fuel critical. + flightgroup:SetFuelCriticalThreshold(nil, true) + + -- Set asset flightgroup. + asset.flightgroup=flightgroup -- Not requested any more. asset.requested=nil @@ -936,6 +941,11 @@ function AIRWING:onafterAssetSpawned(From, Event, To, group, asset, request) -- Add mission to flightgroup queue. if mission then + + -- RTB on low fuel if on PATROL. + if mission.type==AUFTRAG.Type.PATROL then + flightgroup:SetFuelLowThreshold(nil, true) + end -- Add mission to flightgroup queue. asset.flightgroup:AddMission(mission) @@ -1103,13 +1113,13 @@ function AIRWING:SquadronCanMission(Squadron, MissionType, Nassets) -- This asset is already on a mission --- - --TODO: This only checks if it has an ORBIT mission. It could have others as well! + -- Check if this asset is currently on a PATROL mission (STARTED or EXECUTING). if self:IsAssetOnMission(asset, AUFTRAG.Type.PATROL) and MissionType~=AUFTRAG.Type.PATROL then -- Check if the payload of this asset is compatible with the mission. if self:CheckMissionType(MissionType, asset.payload.missiontypes) then -- TODO: Check if asset actually has weapons left. Difficult! - --table.insert(assets, asset) + table.insert(assets, asset) end end @@ -1121,10 +1131,22 @@ function AIRWING:SquadronCanMission(Squadron, MissionType, Nassets) --- if asset.spawned then - -- This asset is already spawned. Let's check if it has the right payload. - if self:CheckMissionType(MissionType, asset.payload.missiontypes) then - --table.insert(assets, asset) + + local combatready=false + local flightgroup=asset.flightgroup + if flightgroup then + + if (flightgroup:IsAirborne() or flightgroup:IsWaiting()) and not flightgroup:IsFuelLow() then + combatready=true + end + end + + -- This asset is "combatready". Let's check if it has the right payload. + if combatready and self:CheckMissionType(MissionType, asset.payload.missiontypes) then + table.insert(assets, asset) + end + else if not asset.requested then @@ -1153,7 +1175,7 @@ function AIRWING:SquadronCanMission(Squadron, MissionType, Nassets) return cando, assets end ---- Check if an asset is currently on a mission or has one in the queue. +--- Check if an asset is currently on a mission (STARTED or EXECUTING). -- @param #AIRWING self -- @param #AIRWING.SquadronAsset asset The asset. -- @param #table MissionTypes Types on mission to be checked. Default all. @@ -1177,8 +1199,8 @@ function AIRWING:IsAssetOnMission(asset, MissionTypes) local status=mission:GetFlightStatus(asset.flightgroup) - -- Only if mission is not already over. - if status~=AUFTRAG.FlightStatus.DONE and status~=AUFTRAG.FlightStatus.CANCELLED and self:CheckMissionType(mission.type, MissionTypes) then + -- Only if mission is started or executing. + if (status==AUFTRAG.FlightStatus.STARTED or status==AUFTRAG.FlightStatus.EXECUTING) and self:CheckMissionType(mission.type, MissionTypes) then return true end @@ -1187,6 +1209,7 @@ function AIRWING:IsAssetOnMission(asset, MissionTypes) end -- Alternative: run over all missions and compare to mission assets. + --[[ for _,_mission in pairs(self.missionqueue) do local mission=_mission --Ops.Auftrag#AUFTRAG @@ -1202,7 +1225,8 @@ function AIRWING:IsAssetOnMission(asset, MissionTypes) end end - + ]] + return false end @@ -1219,6 +1243,27 @@ function AIRWING:GetAssetCurrentMission(asset) return nil end +--- Count missions in mission queue. +-- @param #AIRWING self +-- @param #table MissionTypes Types on mission to be checked. Default *all* possible types `AUFTRAG.Type`. +-- @return #number Number of missions that are not over yet. +function AIRWING:CountMissionsInQueue(MissionTypes) + + MissionTypes=MissionTypes or AUFTRAG.Type + + local N=0 + for _,_mission in pairs(self.missionqueue) do + local mission=_mission --Ops.Auftrag#AUFTRAG + + -- Check if this mission type is requested. + if mission:IsNotOver() and self:CheckMissionType(mission.type, MissionTypes) then + N=N+1 + end + + end + + return N +end --- Count assets on mission. -- @param #AIRWING self @@ -1310,6 +1355,10 @@ end -- @return #boolean If true, the requested mission type is part of the possible mission types. function AIRWING:CheckMissionType(MissionType, PossibleTypes) + if type(PossibleTypes)=="string" then + PossibleTypes={PossibleTypes} + end + for _,canmission in pairs(PossibleTypes) do if canmission==MissionType then return true diff --git a/Moose Development/Moose/Ops/Auftrag.lua b/Moose Development/Moose/Ops/Auftrag.lua index 4d51a2aa6..a9808653a 100644 --- a/Moose Development/Moose/Ops/Auftrag.lua +++ b/Moose Development/Moose/Ops/Auftrag.lua @@ -258,6 +258,8 @@ function AUFTRAG:New(Type) self.missionRepeated=0 self.missionRepeatMax=0 + self.nassets=1 + -- FMS start state is PLANNED. self:SetStartState(self.status) @@ -273,13 +275,13 @@ function AUFTRAG:New(Type) self:AddTransition(AUFTRAG.Status.STARTED, "Executing", AUFTRAG.Status.EXECUTING) -- First asset is executing the mission. self:AddTransition("*", "Done", AUFTRAG.Status.DONE) -- All assets have reported that mission is done. - self:AddTransition("*", "Cancel", AUFTRAG.Status.CANCELLED) -- Command to cancel the mission. + self:AddTransition("*", "Cancel", "*") --AUFTRAG.Status.CANCELLED) -- Command to cancel the mission. self:AddTransition("*", "Success", AUFTRAG.Status.SUCCESS) self:AddTransition("*", "Failed", AUFTRAG.Status.FAILED) self:AddTransition("*", "Status", "*") - self:AddTransition("*", "Stop", "Stopped") + self:AddTransition("*", "Stop", "*") self:AddTransition("*", "Repeat", AUFTRAG.Status.PLANNED) @@ -322,19 +324,26 @@ end --- Create an ORBIT mission. -- @param #AUFTRAG self --- @param Core.Point#COORDINATE Coordinate Where to orbit. Altitude is also taken from the coordinate. --- @param #number Speed Orbit speed in knots. Default 350 kts. --- @param #number Heading Heading of race-track pattern in degrees. Default 270 (East to West). +-- @param Core.Point#COORDINATE Coordinate Where to orbit. +-- @param #number Speed Orbit speed in knots. Default 350 KIAS. +-- @param #number Heading Heading of race-track pattern in degrees. Default *random* in [1,360]. -- @param #number Leg Length of race-track in NM. Default 10 NM. +-- @param #number Altitude Orbit altitude in feet. Default is y component of `Coordinate`. -- @return #AUFTRAG self -function AUFTRAG:NewORBIT(Coordinate, Speed, Heading, Leg) +function AUFTRAG:NewORBIT(Coordinate, Speed, Heading, Leg, Altitude) local auftrag=AUFTRAG:New(AUFTRAG.Type.ORBIT) auftrag.orbitCoord = Coordinate - auftrag.orbitHeading = Heading or 270 + auftrag.orbitHeading = Heading or math.random(360) auftrag.orbitLeg = UTILS.NMToMeters(Leg or 10) - auftrag.orbitSpeed = UTILS.KnotsToMps(Speed or 350) + auftrag.orbitSpeed = UTILS.KnotsToMps(Speed or 350) + + if Altitude then + auftrag.orbitCoord.y=UTILS.FeetToMeters(Altitude) + end + + auftrag.missionAltitude=auftrag.orbitCoord.y*0.9 auftrag.DCStask=auftrag:GetDCSMissionTask() @@ -352,13 +361,9 @@ end function AUFTRAG:NewPATROL(OrbitCoordinate, OrbitSpeed, Heading, Leg, Altitude) -- Create ORBIT first. - local mission=self:NewORBIT(OrbitCoordinate, OrbitSpeed, Heading, Leg) - - if Altitude then - mission.orbitCoord.y=UTILS.FeetToMeters(Altitude) - end - - -- CAP paramters. + local mission=self:NewORBIT(OrbitCoordinate, OrbitSpeed, Heading, Leg, Altitude) + + -- Mission type PATROL. mission.type=AUFTRAG.Type.PATROL return mission @@ -544,6 +549,10 @@ function AUFTRAG:NewAUTO(EngageGroup) end end + + if mission then + mission:SetPriority(10, true) + end return mission end @@ -780,20 +789,28 @@ function AUFTRAG:onafterStatus(From, Event, To) -- Number of alive flights attached to this mission. local Nflights=self:CountFlightGroups() - -- Cancel mission if stop time passed. - if self.Tstop and timer.getAbsTime()>self.Tstop+10 then - self:Cancel() + -- Check if mission is not OVER yet. + if self:IsNotOver() then + + if self:CheckFlightsDone() then + + -- All flights have reported MISSON DONE. + self:Done() + + elseif self.Tstop and timer.getAbsTime()>self.Tstop+10 then + + -- Cancel mission if stop time passed. + self:Cancel() + + elseif self.Ntargets>0 and Ntargets==0 then + + -- Cancel mission if all targets were destroyed. + self:Cancel() + + end + end - -- Cancel mission if number of targest is 0 (and was >0 before as some missions, e.g. orbit, don't have any target). - if self:IsNotOver() and self.Ntargets>0 and Ntargets==0 then - self:Cancel() - end - - -- Check if ALL flights are done with their mission. - if self:IsNotOver() and self:CheckFlightsDone() then - self:Done() - end -- Current FSM state. local fsmstate=self:GetState() @@ -868,7 +885,7 @@ function AUFTRAG:SetFlightStatus(flightgroup, status) self:I(self.lid.."All flight done ==> mission DONE!") self:Done() else - self:I(self.lid.."Mission NOT DONE yet!") + self:T3(self.lid.."Mission NOT DONE yet!") end end @@ -877,7 +894,11 @@ end -- @param #AUFTRAG self -- @param Ops.FlightGroup#FLIGHTGROUP flightgroup The flight group. function AUFTRAG:GetFlightStatus(flightgroup) - return self.flightdata[flightgroup.groupname].status + if flightgroup then + return self.flightdata[flightgroup.groupname].status + else + return AUFTRAG.FlightStatus.DONE + end end @@ -1103,8 +1124,10 @@ end -- @param #string To To state. function AUFTRAG:onafterCancel(From, Event, To) - self.status=AUFTRAG.Status.CANCELLED - self:I(self.lid..string.format("New mission status=%s", self.status)) + --self.status=AUFTRAG.Status.CANCELLED + --self:I(self.lid..string.format("New mission status=%s", self.status)) + + self:I(self.lid..string.format("CANCELLING mission in status %s. Will wait for flights to report mission DONE before evaluation.", self.status)) if self.airwing then diff --git a/Moose Development/Moose/Ops/FlightGroup.lua b/Moose Development/Moose/Ops/FlightGroup.lua index 6632bc1da..b7555c91e 100644 --- a/Moose Development/Moose/Ops/FlightGroup.lua +++ b/Moose Development/Moose/Ops/FlightGroup.lua @@ -440,7 +440,7 @@ function FLIGHTGROUP:New(groupname, autostart) self:AddTransition("*", "PassingWaypoint", "*") -- Group passed a waypoint. self:AddTransition("*", "GotoWaypoint", "*") -- Group switches to a specific waypoint. - self:AddTransition("*", "Wait", "Waiting") -- Group is orbiting. + self:AddTransition("*", "Wait", "Waiting") -- Group is orbiting. self:AddTransition("*", "FuelLow", "*") -- Fuel state of group is low. Default ~25%. self:AddTransition("*", "FuelCritical", "*") -- Fuel state of group is critical. Default ~10%. @@ -932,6 +932,13 @@ function FLIGHTGROUP:IsAirborne() return self:Is("Airborne") end +--- Check if flight is waiting after passing final waypoint. +-- @param #FLIGHTGROUP self +-- @return #boolean If true, flight is waiting. +function FLIGHTGROUP:IsWaiting() + return self:Is("Waiting") +end + --- Check if flight is landing. -- @param #FLIGHTGROUP self -- @return #boolean If true, flight is landing, i.e. on final approach. @@ -1473,7 +1480,7 @@ function FLIGHTGROUP:onafterQueueUpdate(From, Event, To) -- Current mission but new mission is urgent with higher prio. if mission.urgent and mission.prio Update route possible. self:T3(self.lid.."Update route possible. Group is ALIVE and AIRBORNE") elseif self:IsDead() then @@ -2249,7 +2256,7 @@ function FLIGHTGROUP:onbeforeUpdateRoute(From, Event, To, n) local N=n or self.currentwp+1 if not N or N<1 then - self:T3(self.lid.."FF update route denied because N=nil or N<1") + self:E(self.lid.."FF update route denied because N=nil or N<1") self:__UpdateRoute(-1, n) allowed=false end @@ -2278,11 +2285,6 @@ function FLIGHTGROUP:onafterUpdateRoute(From, Event, To, n) -- TODO: what happens if currentwp=#waypoints n=n or self.currentwp+1 - - -- Debug info. - local text=string.format("Updating route n=%d for group %s", n, self.groupname) - MESSAGE:New(text, 10):ToAllIf(false) - self:I(self.lid..text) -- Update waypoint tasks, i.e. inject WP tasks into waypoint table. self:_UpdateWaypointTasks() @@ -2324,7 +2326,7 @@ function FLIGHTGROUP:onafterUpdateRoute(From, Event, To, n) -- Debug info. local hb=self.homebase and self.homebase:GetName() or "unknown" local db=self.destbase and self.destbase:GetName() or "unknown" - self:I(self.lid..string.format("Updating route for WP>=%d/%d (%d) homebase=%s destination=%s", n, #wp, #self.waypoints, hb, db)) + self:I(self.lid..string.format("Updating route for WP #%d-%d homebase=%s destination=%s", n, #wp, hb, db)) if #wp>1 then @@ -2479,7 +2481,7 @@ function FLIGHTGROUP:_CheckFlightDone(delay) self:__Wait(-1) end else - self:I(self.lid..string.format("Passed Final WP but still have current Tasks or Missions left to do")) + self:I(self.lid..string.format("Passed Final WP but still have current Tasks (%s) or Missions (%s) left to do", tostring(self.taskcurrent), tostring(self.currentmission))) end else self:I(self.lid.."Did NOT pass the final waypoint yet") @@ -2537,26 +2539,31 @@ function FLIGHTGROUP:onbeforeRTB(From, Event, To, airbase, SpeedTo, SpeedHold) self:E(self.lid.."ERROR: Wrong airbase coalition in RTB() call! We allow only same as group or neutral airbases.") allowed=false end - - -- Check if there are remaining tasks. - local Ntot,Nsched, Nwp=self:CountRemainingTasks() - - if self.taskcurrent>0 then - self:I(self.lid..string.format("WARNING: Got current task ==> RTB event is suspended for 10 sec.")) - Tsuspend=-10 - allowed=false - end - if Nsched>0 then - self:I(self.lid..string.format("WARNING: Still got %d SCHEDULED tasks in the queue ==> RTB event is suspended for 10 sec.", Nsched)) - Tsuspend=-10 - allowed=false - end + -- Only if fuel is not low or critical. + if not (self:IsFuelLow() or self:IsFuelCritical()) then - if Nwp>0 then - self:I(self.lid..string.format("WARNING: Still got %d WAYPOINT tasks in the queue ==> RTB event is suspended for 10 sec.", Nwp)) - Tsuspend=-10 - allowed=false + -- Check if there are remaining tasks. + local Ntot,Nsched, Nwp=self:CountRemainingTasks() + + if self.taskcurrent>0 then + self:I(self.lid..string.format("WARNING: Got current task ==> RTB event is suspended for 10 sec.")) + Tsuspend=-10 + allowed=false + end + + if Nsched>0 then + self:I(self.lid..string.format("WARNING: Still got %d SCHEDULED tasks in the queue ==> RTB event is suspended for 10 sec.", Nsched)) + Tsuspend=-10 + allowed=false + end + + if Nwp>0 then + self:I(self.lid..string.format("WARNING: Still got %d WAYPOINT tasks in the queue ==> RTB event is suspended for 10 sec.", Nwp)) + Tsuspend=-10 + allowed=false + end + end if Tsuspend and not allowed then @@ -3211,8 +3218,10 @@ function FLIGHTGROUP:onafterTaskDone(From, Event, To, Task) if Mission then + env.info("FF Task Done ==> Mission Done!") self:MissionDone(Mission) else + env.info("FF Task Done but NO mission found ==> _CheckFlightDone in 1 sec") self:_CheckFlightDone(1) end @@ -3267,6 +3276,7 @@ end function FLIGHTGROUP:onafterMissionStart(From, Event, To, Mission) local text=string.format("Starting Mission %s", tostring(Mission.name)) + self:I(self.lid..text) MESSAGE:New(text, 120, "DEBUG"):ToAllIf(true) -- Set current mission. @@ -3311,9 +3321,6 @@ end -- @param Ops.Auftrag#AUFTRAG Mission The mission to be cancelled. function FLIGHTGROUP:onafterMissionCancel(From, Event, To, Mission) - -- Set missin flight status. - Mission:SetFlightStatus(self, AUFTRAG.FlightStatus.CANCELLED) - if self.currentmission and Mission.auftragsnummer==self.currentmission then -- Get mission waypoint task. @@ -3328,15 +3335,18 @@ function FLIGHTGROUP:onafterMissionCancel(From, Event, To, Mission) self:TaskCancel(Task) -- Set current mission to nil. - self.currentmission=nil + --self.currentmission=nil else -- Not the current mission. -- TODO: remove mission from queue? + + -- Set mission flight status. + Mission:SetFlightStatus(self, AUFTRAG.FlightStatus.CANCELLED) -- Send flight RTB or WAIT if nothing left to do. - self:_CheckFlightDone() + self:_CheckFlightDone(1) end @@ -3417,7 +3427,7 @@ function FLIGHTGROUP._TaskExecute(group, flightgroup, task) -- Debug message. local text=string.format("_TaskExecute %s", task.description) - flightgroup:I(flightgroup.lid..text) + flightgroup:T3(flightgroup.lid..text) -- Set current task to nil so that the next in line can be executed. if flightgroup then @@ -3433,7 +3443,7 @@ function FLIGHTGROUP._TaskDone(group, flightgroup, task) -- Debug message. local text=string.format("_TaskDone %s", task.description) - flightgroup:I(flightgroup.lid..text) + flightgroup:T3(flightgroup.lid..text) -- Set current task to nil so that the next in line can be executed. if flightgroup then diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index 484dc160b..c042cd110 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -867,10 +867,15 @@ end --- Activates a late activated GROUP. -- @param #GROUP self +-- @param #number delay Delay in seconds, before the group is activated. -- @return #GROUP self -function GROUP:Activate() +function GROUP:Activate(delay) self:F2( { self.GroupName } ) - trigger.action.activateGroup( self:GetDCSObject() ) + if delay and delay>0 then + self:ScheduleOnce(delay, GROUP.Activate, self) + else + trigger.action.activateGroup( self:GetDCSObject() ) + end return self end