diff --git a/Moose Development/Moose/Ops/ArmyGroup.lua b/Moose Development/Moose/Ops/ArmyGroup.lua index 115607b46..f32dca574 100644 --- a/Moose Development/Moose/Ops/ArmyGroup.lua +++ b/Moose Development/Moose/Ops/ArmyGroup.lua @@ -3,7 +3,16 @@ -- **Main Features:** -- -- * Dynamically add and remove waypoints. --- +-- * Convenient checks when the group enters or leaves a zone. +-- * Sophisticated task queueing system. +-- * Compatible with AUFTRAG class. +-- * Easy change of ROE, alarm state, formation and other settings. +-- * Many additional events that the mission designer can hook into. +-- +-- **Example Missions:** +-- +-- Demo missions can be found on [github](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/OPS%20-%20Armygroup). +-- -- === -- -- ### Author: **funkyfranky** @@ -15,6 +24,7 @@ -- @type ARMYGROUP -- @field #boolean adinfinitum Resume route at first waypoint when final waypoint is reached. -- @field #boolean formationPerma Formation that is used permanently and overrules waypoint formations. +-- @field #boolean isMobile If true, group is mobile. -- @extends Ops.OpsGroup#OPSGROUP --- *Your soul may belong to Jesus, but your ass belongs to the marines.* -- Eugene B. Sledge @@ -46,7 +56,8 @@ ARMYGROUP.version="0.3.0" -- TODO list ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- TODO: A lot. +-- TODO: Check if group is mobile. +-- TODO: Rearm. Specify a point where to go and wait until ammo is full. ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- Constructor @@ -54,12 +65,12 @@ ARMYGROUP.version="0.3.0" --- Create a new ARMYGROUP class object. -- @param #ARMYGROUP self --- @param #string GroupName Name of the group. +-- @param Wrapper.Group#GROUP Group The group object. Can also be given by its group name as `#string`. -- @return #ARMYGROUP self -function ARMYGROUP:New(GroupName) +function ARMYGROUP:New(Group) -- Inherit everything from FSM class. - local self=BASE:Inherit(self, OPSGROUP:New(GroupName)) -- #ARMYGROUP + local self=BASE:Inherit(self, OPSGROUP:New(Group)) -- #ARMYGROUP -- Set some string id for output to DCS.log file. self.lid=string.format("ARMYGROUP %s | ", self.groupname) @@ -73,7 +84,10 @@ function ARMYGROUP:New(GroupName) -- Add FSM transitions. -- From State --> Event --> To State self:AddTransition("*", "FullStop", "Holding") -- Hold position. - self:AddTransition("*", "Cruise", "Cruising") -- Hold position. + self:AddTransition("*", "Cruise", "Cruising") -- Cruise along the given route of waypoints. + + self:AddTransition("*", "Rearm", "Rearming") -- Group is send to a coordinate and waits until ammo is refilled. + self:AddTransition("Rearming", "Rearmed", "Cruising") -- Group was rearmed. self:AddTransition("*", "Detour", "OnDetour") -- Make a detour to a coordinate and resume route afterwards. self:AddTransition("OnDetour", "DetourReached", "Cruising") -- Group reached the detour coordinate. @@ -224,11 +238,18 @@ end --- Check if the group is currently on a detour. -- @param #ARMYGROUP self --- @return #boolean If true, group is on a detour +-- @return #boolean If true, group is on a detour. function ARMYGROUP:IsOnDetour() return self:Is("OnDetour") end +--- Check if the group is currently rearming. +-- @param #ARMYGROUP self +-- @return #boolean If true, group is rearming. +function ARMYGROUP:IsRearming() + return self:Is("Rearming") +end + ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- Status ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -508,6 +529,26 @@ function ARMYGROUP:onafterDetour(From, Event, To, Coordinate, Speed, Formation, end +--- On after "Rearm" event. +-- @param #ARMYGROUP self +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +-- @param Core.Point#COORDINATE Coordinate Coordinate where to rearm. +-- @param #number Formation Formation of the group. +function ARMYGROUP:onafterRearm(From, Event, To, Coordinate, Formation) + + -- ID of current waypoint. + local uid=self:GetWaypointCurrent().uid + + -- Add waypoint after current. + local wp=self:AddWaypoint(Coordinate, nil, uid, Formation, true) + + -- Set if we want to resume route after reaching the detour waypoint. + wp.detour=0 + +end + --- On after "DetourReached" event. -- @param #ARMYGROUP self -- @param #string From From state. @@ -549,7 +590,7 @@ function ARMYGROUP:onafterCruise(From, Event, To, Speed, Formation) end ---- On after Start event. Starts the ARMYGROUP FSM and event handlers. +--- On after "Stop" event. -- @param #ARMYGROUP self -- @param #string From From state. -- @param #string Event Event. diff --git a/Moose Development/Moose/Ops/Auftrag.lua b/Moose Development/Moose/Ops/Auftrag.lua index 002509c7d..b6c030455 100644 --- a/Moose Development/Moose/Ops/Auftrag.lua +++ b/Moose Development/Moose/Ops/Auftrag.lua @@ -7,7 +7,7 @@ -- * Set mission start/stop times. -- * Set mission priority and urgency (can cancel running missions). -- * Specific mission options for ROE, ROT, formation, etc. --- * Interface to FLIGHTGROUP, AIRWING and WINGCOMMANDER classes. +-- * Interface to FLIGHTGROUP, NAVYGROUP, ARMYGROUP, AIRWING, WINGCOMMANDER and CHIEF classes. -- * FSM events when a mission is done, successful or failed. -- -- === diff --git a/Moose Development/Moose/Ops/FlightGroup.lua b/Moose Development/Moose/Ops/FlightGroup.lua index 81a8f4bf6..f7d394d96 100644 --- a/Moose Development/Moose/Ops/FlightGroup.lua +++ b/Moose Development/Moose/Ops/FlightGroup.lua @@ -50,7 +50,7 @@ -- -- @extends Ops.OpsGroup#OPSGROUP ---- *To invent an airplane is nothing. To build one is something. To fly is everything.* -- Otto Lilienthal +--- *To invent an airplane is nothing; to build one is something; to fly is everything.* -- Otto Lilienthal -- -- === -- @@ -210,7 +210,7 @@ FLIGHTGROUP.version="0.6.0" --- Create a new FLIGHTGROUP object and start the FSM. -- @param #FLIGHTGROUP self --- @param Wrapper.Group#GROUP group The group object. Can also be given as #string with the name of the group. +-- @param Wrapper.Group#GROUP Group The group object. Can also be given by its group name as `#string`. -- @return #FLIGHTGROUP self function FLIGHTGROUP:New(group) diff --git a/Moose Development/Moose/Ops/NavyGroup.lua b/Moose Development/Moose/Ops/NavyGroup.lua index ceb9b3f55..e180ae53f 100644 --- a/Moose Development/Moose/Ops/NavyGroup.lua +++ b/Moose Development/Moose/Ops/NavyGroup.lua @@ -5,8 +5,18 @@ -- * Dynamically add and remove waypoints. -- * Let the group steam into the wind. -- * Command a full stop. +-- * Automatic pathfinding, e.g. around islands. +-- * Collision warning, if group is heading towards a land mass. -- * Let a submarine dive and surface. --- +-- * Sophisticated task queueing system. +-- * Compatible with AUFTRAG class. +-- * Convenient checks when the group enters or leaves a zone. +-- * Many additional events that the mission designer can hook into. +-- +-- **Example Missions:** +-- +-- Demo missions can be found on [github](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/OPS%20-%20Navygroup) +-- -- === -- -- ### Author: **funkyfranky** @@ -19,6 +29,7 @@ -- @field #boolean turning If true, group is currently turning. -- @field #NAVYGROUP.IntoWind intowind Into wind info. -- @field #table Qintowind Queue of "into wind" turns. +-- @field #number intowindcounter Counter of into wind IDs. -- @field #number depth Ordered depth in meters. -- @field #boolean collisionwarning If true, collition warning. -- @field #boolean pathfindingOn If true, enable pathfining. @@ -74,7 +85,9 @@ NAVYGROUP.version="0.5.0" -- TODO list ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- TODO: Collision warning. +-- TODO: Extend, shorten turn into wind windows +-- TODO: Skipper menu. +-- DONE: Collision warning. -- DONE: Detour, add temporary waypoint and resume route. -- DONE: Stop and resume route. -- DONE: Add waypoints. @@ -109,6 +122,7 @@ function NAVYGROUP:New(GroupName) self:AddTransition("*", "Cruise", "Cruising") -- Hold position. self:AddTransition("*", "TurnIntoWind", "IntoWind") -- Command the group to turn into the wind. + self:AddTransition("IntoWind", "TurnedIntoWind", "IntoWind") -- Group turned into wind. self:AddTransition("IntoWind", "TurnIntoWindStop", "IntoWind") -- Stop a turn into wind. self:AddTransition("IntoWind", "TurnIntoWindOver", "Cruising") -- Turn into wind is over. @@ -355,7 +369,8 @@ end function NAVYGROUP:RemoveTurnIntoWind(IntoWindData) -- Check if this is a window currently open. - if self.intowind and self.intowind.id==IntoWindData.Id then + if self.intowind and self.intowind.Id==IntoWindData.Id then + --env.info("FF stop in remove") self:TurnIntoWindStop() return end @@ -363,6 +378,7 @@ function NAVYGROUP:RemoveTurnIntoWind(IntoWindData) for i,_tiw in pairs(self.Qintowind) do local tiw=_tiw --#NAVYGROUP.IntoWind if tiw.Id==IntoWindData.Id then + --env.info("FF removing window "..tiw.Id) table.remove(self.Qintowind, i) break end @@ -543,6 +559,37 @@ function NAVYGROUP:onafterStatus(From, Event, To) end + --- + -- Recovery Windows + --- + + if self.verbose>=2 then + + -- Debug output: + local text=string.format(self.lid.."Turn into wind time windows:") + + -- Handle case with no recoveries. + if #self.Qintowind==0 then + text=text.." none!" + end + + -- Loop over all slots. + for i,_recovery in pairs(self.Qintowind) do + local recovery=_recovery --#NAVYGROUP.IntoWind + + -- Get start/stop clock strings. + local Cstart=UTILS.SecondsToClock(recovery.Tstart) + local Cstop=UTILS.SecondsToClock(recovery.Tstop) + + -- Debug text. + text=text..string.format("\n[%d] ID=%d Start=%s Stop=%s Open=%s Over=%s", i, recovery.Id, Cstart, Cstop, tostring(recovery.Open), tostring(recovery.Over)) + end + + -- Debug output. + self:I(self.lid..text) + + end + --- -- Tasks & Missions @@ -794,7 +841,7 @@ end -- @param #string Event Event. -- @param #string To To state. function NAVYGROUP:onafterTurnIntoWindStop(From, Event, To) - self:TurnIntoWindOver() + self:TurnIntoWindOver(self.intowind) end --- On after "TurnIntoWindOver" event. @@ -802,28 +849,54 @@ end -- @param #string From From state. -- @param #string Event Event. -- @param #string To To state. -function NAVYGROUP:onafterTurnIntoWindOver(From, Event, To) +-- @param #NAVYGROUP.IntoWind IntoWindData Data table. +function NAVYGROUP:onafterTurnIntoWindOver(From, Event, To, IntoWindData) - -- Debug message. - self:T2(self.lid.."Turn Into Wind Over!") + if IntoWindData and self.intowind and IntoWindData.Id==self.intowind.Id then - self.intowind.Over=true - self.intowind.Open=false + -- Debug message. + self:T2(self.lid.."Turn Into Wind Over!") - -- Remove additional waypoint. - self:RemoveWaypointByID(self.intowind.waypoint.uid) + -- Window over and not open anymore. + self.intowind.Over=true + self.intowind.Open=false + + -- Remove additional waypoint. + self:RemoveWaypointByID(self.intowind.waypoint.uid) + + if self.intowind.Uturn then + + --- + -- U-turn ==> Go to coordinate where we left the route. + --- + + -- Detour to where we left the route. + self:I(self.lid.."FF Turn Into Wind Over ==> Uturn!") + self:Detour(self.intowind.Coordinate, self:GetSpeedCruise(), 0, true) + + else + + --- + -- Go directly to next waypoint. + --- + + -- Next waypoint index and speed. + local indx=self:GetWaypointIndexNext() + local speed=self:GetWaypointSpeed(indx) + + -- Update route. + self:I(self.lid..string.format("FF Turn Into Wind Over ==> Next WP Index=%d at %.1f knots via update route!", indx, speed)) + self:__UpdateRoute(-1, indx, speed) + + end + + -- Set current window to nil. + self.intowind=nil + + -- Remove window from queue. + self:RemoveTurnIntoWind(IntoWindData) - if self.intowind.Uturn then - self:T(self.lid.."Turn Into Wind Over ==> Uturn!") - self:Detour(self.intowind.Coordinate, self:GetSpeedCruise(), 0, true) - else - self:T(self.lid.."FF Turn Into Wind Over ==> Next WP!") - local indx=self:GetWaypointIndexNext() - local speed=self:GetWaypointSpeed(indx) - self:__UpdateRoute(-1, indx, speed) end - - self.intowind=nil end @@ -911,6 +984,11 @@ end function NAVYGROUP:onafterTurningStopped(From, Event, To) self.turning=false self.collisionwarning=false + + if self:IsSteamingIntoWind() then + self:TurnedIntoWind() + end + end --- On after "CollisionWarning" event. @@ -1343,66 +1421,60 @@ function NAVYGROUP:_CheckTurnsIntoWind() -- Get current abs time. local time=timer.getAbsTime() - local Cnow=UTILS.SecondsToClock(time) - -- Debug output: - local text=string.format(self.lid.."Recovery time windows:") + if self.intowind then - -- Handle case with no recoveries. - if #self.Qintowind==0 then - text=text.." none!" - end + -- Check if time is over. + if time>=self.intowind.Tstop then + self:TurnIntoWindOver(self.intowind) + end + + else + + -- Get next window. + local IntoWind=self:GetNextTurnIntoWind() - -- Sort windows wrt to start time. - table.sort(self.Qintowind, function(a, b) return a.Tstart=recovery.Tstart and time=self.intowind.Tstop then - self:TurnIntoWindOver() - end - end end ---- Check queued turns into wind. +--- Get the next turn into wind window, which is not yet running. -- @param #NAVYGROUP self --- @return #NAVYGROUP.IntoWind Next into wind data. -function NAVYGROUP:GetNextTurnIntoWind() +-- @return #NAVYGROUP.IntoWind Next into wind data. Could be `nil` if there is not next window. +function NAVYGROUP:GetTurnIntoWindNext() - -- Loop over all windows. - for _,_recovery in pairs(self.Qintowind) do - local recovery=_recovery --#NAVYGROUP.IntoWind - + if #self.Qintowind>0 then + + -- Get current abs time. + local time=timer.getAbsTime() + + -- Sort windows wrt to start time. + table.sort(self.Qintowind, function(a, b) return a.Tstart=recovery.Tstart and time