diff --git a/Moose Development/Moose/Ops/ArmyGroup.lua b/Moose Development/Moose/Ops/ArmyGroup.lua index 3ced05e52..1674f9c97 100644 --- a/Moose Development/Moose/Ops/ArmyGroup.lua +++ b/Moose Development/Moose/Ops/ArmyGroup.lua @@ -21,7 +21,7 @@ -- -- === -- --- ![Banner Image](..\Presentations\ARMYGROUP\NavyGroup_Main.jpg) +-- ![Banner Image](..\Presentations\ARMYGROUP\ArmyGroup_Main.jpg) -- -- # The ARMYGROUP Concept -- @@ -33,12 +33,12 @@ ARMYGROUP = { formationPerma = nil, } ---- Navy group element. +--- Army group element. -- @type ARMYGROUP.Element -- @field #string name Name of the element, i.e. the unit. -- @field #string typename Type name. ---- NavyGroup version. +--- Army Group version. -- @field #string version ARMYGROUP.version="0.0.1" @@ -151,8 +151,7 @@ end --- Get coordinate of the closest road. -- @param #ARMYGROUP self --- @param #boolean switch If true or nil, patrol until the end of time. If false, go along the waypoints once and stop. --- @return #ARMYGROUP self +-- @return Core.Point#COORDINATE Coordinate of a road closest to the group. function ARMYGROUP:GetClosestRoad() return self:GetCoordinate():GetClosestPointToRoad() end @@ -174,6 +173,24 @@ function ARMYGROUP:AddTaskFireAtPoint(Coordinate, Radius, Nshots, WeaponType, Cl end +--- Add a *waypoint* task. +-- @param #ARMYGROUP self +-- @param Core.Point#COORDINATE Coordinate Coordinate of the target. +-- @param Ops.OpsGroup#OPSGROUP.Waypoint Waypoint Where the task is executed. Default is next waypoint. +-- @param #number Radius Radius in meters. Default 100 m. +-- @param #number Nshots Number of shots to fire. Default 3. +-- @param #number WeaponType Type of weapon. Default auto. +-- @param #number Prio Priority of the task. +function ARMYGROUP:AddTaskWaypointFireAtPoint(Coordinate, Waypoint, Radius, Nshots, WeaponType, Prio) + + Waypoint=Waypoint or self:GetWaypointNext() + + local DCStask=CONTROLLABLE.TaskFireAtPoint(nil, Coordinate:GetVec2(), Radius, Nshots, WeaponType) + + self:AddTaskWaypoint(DCStask, Waypoint, nil, Prio) + +end + --- Add a *scheduled* task. -- @param #ARMYGROUP self -- @param Wrapper.Group#GROUP TargetGroup Target group. @@ -189,6 +206,8 @@ function ARMYGROUP:AddTaskAttackGroup(TargetGroup, WeaponExpend, WeaponType, Clo end + + ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- Status ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -251,60 +270,11 @@ function ARMYGROUP:onafterStatus(From, Event, To) --- - -- Tasks + -- Tasks & Missions --- - - -- Task queue. - if #self.taskqueue>0 and self.verbose>1 then - local text=string.format("Tasks #%d", #self.taskqueue) - for i,_task in pairs(self.taskqueue) do - local task=_task --Ops.OpsGroup#OPSGROUP.Task - local name=task.description - local taskid=task.dcstask.id or "unknown" - local status=task.status - local clock=UTILS.SecondsToClock(task.time, true) - local eta=task.time-timer.getAbsTime() - local started=task.timestamp and UTILS.SecondsToClock(task.timestamp, true) or "N/A" - local duration=-1 - if task.duration then - duration=task.duration - if task.timestamp then - -- Time the task is running. - duration=task.duration-(timer.getAbsTime()-task.timestamp) - else - -- Time the task is supposed to run. - duration=task.duration - end - end - -- Output text for element. - if task.type==OPSGROUP.TaskType.SCHEDULED then - text=text..string.format("\n[%d] %s (%s): status=%s, scheduled=%s (%d sec), started=%s, duration=%d", i, taskid, name, status, clock, eta, started, duration) - elseif task.type==OPSGROUP.TaskType.WAYPOINT then - text=text..string.format("\n[%d] %s (%s): status=%s, waypoint=%d, started=%s, duration=%d, stopflag=%d", i, taskid, name, status, task.waypoint, started, duration, task.stopflag:Get()) - end - end - self:I(self.lid..text) - end - - --- - -- Missions - --- - - -- Current mission name. - if self.verbose>0 then - local Mission=self:GetMissionByID(self.currentmission) - - -- Current status. - local text=string.format("Missions %d, Current: %s", self:CountRemainingMissison(), Mission and Mission.name or "none") - for i,_mission in pairs(self.missionqueue) do - local mission=_mission --Ops.Auftrag#AUFTRAG - local Cstart= UTILS.SecondsToClock(mission.Tstart, true) - local Cstop = mission.Tstop and UTILS.SecondsToClock(mission.Tstop, true) or "INF" - text=text..string.format("\n[%d] %s (%s) status=%s (%s), Time=%s-%s, prio=%d wp=%s targets=%d", - i, tostring(mission.name), mission.type, mission:GetGroupStatus(self), tostring(mission.status), Cstart, Cstop, mission.prio, tostring(mission:GetGroupWaypointIndex(self)), mission:CountMissionTargets()) - end - self:I(self.lid..text) - end + + self:_PrintTaskAndMissionStatus() + self:__Status(-30) end @@ -350,11 +320,29 @@ function ARMYGROUP:onafterSpawned(From, Event, To) if self.ai then - -- Set default ROE option. - self:SwitchROE(self.option.ROE) + -- Set default ROE. + if self.option.ROE then + self:SwitchROE(self.option.ROE) + else + self:SwitchROE(ENUMS.ROE.ReturnFire) + end - -- Set default Alarm State option. - self:SwitchAlarmstate(self.option.Alarm) + -- Set default Alarm State. + if self.option.Alarm then + self:SwitchAlarmstate(self.option.Alarm) + else + self:SwitchAlarmstate(0) + end + + -- Turn TACAN beacon on. + if self.tacan.On then + self:_SwitchTACAN(self.tacan) + end + + -- Turn on the radio. + if self.radio.On then + self:SwitchRadio(self.radio.Freq, self.radio.Modu) + end end @@ -384,9 +372,12 @@ function ARMYGROUP:onafterUpdateRoute(From, Event, To, n, Speed, Formation) -- Waypoints. local waypoints={} + + -- Total number of waypoints + local N=#self.waypoints -- Add remaining waypoints to route. - for i=n, #self.waypoints do + for i=n, N do -- Copy waypoint. local wp=UTILS.DeepCopy(self.waypoints[i]) --Ops.OpsGroup#OPSGROUP.Waypoint @@ -404,7 +395,9 @@ function ARMYGROUP:onafterUpdateRoute(From, Event, To, n, Speed, Formation) end if self.formationPerma then - wp.action=self.formationPerma + --if self.formationPerma==ENUMS.Formation.Vehicle.OnRoad then + wp.action=self.formationPerma + --end elseif Formation then wp.action=Formation end @@ -428,17 +421,27 @@ function ARMYGROUP:onafterUpdateRoute(From, Event, To, n, Speed, Formation) end end - - - if formation==ENUMS.Formation.Vehicle.OnRoad then - local wpnext=self:GetWaypointNext() - - if wpnext.action~=ENUMS.Formation.Vehicle.OnRoad then - - end + if wp.roaddist>100 and wp.action==ENUMS.Formation.Vehicle.OnRoad then + env.info("FF Adding ON road waypoint") + --wp.roadcoord:MarkToAll("Added Road waypoint") + -- Waypoint is actually off road! + wp.action=ENUMS.Formation.Vehicle.OffRoad + + -- Add "On Road" waypoint in between. + local wproad=wp.roadcoord:WaypointGround(wp.speed, ENUMS.Formation.Vehicle.OnRoad) + table.insert(waypoints, wproad) + end + + --if wp.formation==ENUMS.Formation.Vehicle.OnRoad and wp.action~=ENUMS.Formation.Vehicle.OnRoad then --and not self.formationPerma~=ENUMS.Formation.Vehicle.OnRoad then + --[[ + if wp.action==ENUMS.Formation.Vehicle.OnRoad and wp.roaddist>100 then + env.info("FF Adding ON road waypoint") + local wproad=wp.roadcoord:WaypointGround(wp.speed, ENUMS.Formation.Vehicle.OnRoad) + table.insert(waypoints, wproad) end + ]] -- Debug info. self:I(string.format("WP %d %s: Speed=%d m/s, alt=%d m, Action=%s", i, wp.type, wp.speed, wp.alt, wp.action)) @@ -716,10 +719,24 @@ function ARMYGROUP:AddWaypoint(Coordinate, Speed, AfterWaypointWithID, Formation -- Get closest point to road. waypoint.roadcoord=Coordinate:GetClosestPointToRoad(false) - waypoint.roadist=Coordinate:Get2DDistance(waypoint.roadcoord) + if waypoint.roadcoord then + waypoint.roaddist=Coordinate:Get2DDistance(waypoint.roadcoord) + else + waypoint.roaddist=1000*1000 --1000 km. + end + + --[[ + if waypoint.roaddist>100 and waypoint.action==ENUMS.Formation.Vehicle.OnRoad then + waypoint.formation=ENUMS.Formation.Vehicle.OnRoad + waypoint.action=ENUMS.Formation.Vehicle.OffRoad + else + waypoint.formation=waypoint.action + end + ]] + -- Debug info. - self:T(self.lid..string.format("Adding GROUND waypoint #%d, speed=%.1f knots. Last waypoint passed was #%s. Total waypoints #%d", wpnumber, Speed, self.currentwp, #self.waypoints)) + self:I(self.lid..string.format("Adding waypoint UID=%d (index=%d), Speed=%.1f knots, Dist2Road=%d m, Action=%s", waypoint.uid, wpnumber, Speed, waypoint.roaddist, waypoint.action)) -- Update route. if Updateroute==nil or Updateroute==true then @@ -771,7 +788,7 @@ function ARMYGROUP:_InitGroup() self.position=self:GetCoordinate() -- Radio parameters from template. - self.radioOn=false -- Radio is always OFF for ground. + self.radio.On=false -- Radio is always OFF for ground. self.radio.Freq=133 self.radio.Modu=radio.modulation.AM @@ -810,13 +827,13 @@ function ARMYGROUP:_InitGroup() self.actype=unit:GetTypeName() -- Debug info. - local text=string.format("Initialized Navy Group %s:\n", self.groupname) + local text=string.format("Initialized Army Group %s:\n", self.groupname) text=text..string.format("AC type = %s\n", self.actype) text=text..string.format("Speed max = %.1f Knots\n", UTILS.KmphToKnots(self.speedmax)) text=text..string.format("Speed cruise = %.1f Knots\n", UTILS.KmphToKnots(self.speedCruise)) text=text..string.format("Elements = %d\n", #self.elements) text=text..string.format("Waypoints = %d\n", #self.waypoints) - text=text..string.format("Radio = %.1f MHz %s %s\n", self.radio.Freq, UTILS.GetModulationName(self.radio.Modu), tostring(self.radioOn)) + text=text..string.format("Radio = %.1f MHz %s %s\n", self.radio.Freq, UTILS.GetModulationName(self.radio.Modu), tostring(self.radio.On)) text=text..string.format("Ammo = %d (G=%d/R=%d/M=%d)\n", self.ammo.Total, self.ammo.Guns, self.ammo.Rockets, self.ammo.Missiles) text=text..string.format("FSM state = %s\n", self:GetState()) text=text..string.format("Is alive = %s\n", tostring(self:IsAlive())) diff --git a/Moose Development/Moose/Ops/FlightGroup.lua b/Moose Development/Moose/Ops/FlightGroup.lua index 77dbfa768..fdbcae847 100644 --- a/Moose Development/Moose/Ops/FlightGroup.lua +++ b/Moose Development/Moose/Ops/FlightGroup.lua @@ -824,60 +824,10 @@ function FLIGHTGROUP:onafterStatus(From, Event, To) end --- - -- Tasks + -- Tasks & Missions --- - -- Task queue. - if self.verbose>1 and #self.taskqueue>0 then - local text=string.format("Tasks #%d", #self.taskqueue) - for i,_task in pairs(self.taskqueue) do - local task=_task --Ops.OpsGroup#OPSGROUP.Task - local name=task.description - local taskid=task.dcstask.id or "unknown" - local status=task.status - local clock=UTILS.SecondsToClock(task.time, true) - local eta=task.time-timer.getAbsTime() - local started=task.timestamp and UTILS.SecondsToClock(task.timestamp, true) or "N/A" - local duration=-1 - if task.duration then - duration=task.duration - if task.timestamp then - -- Time the task is running. - duration=task.duration-(timer.getAbsTime()-task.timestamp) - else - -- Time the task is supposed to run. - duration=task.duration - end - end - -- Output text for element. - if task.type==OPSGROUP.TaskType.SCHEDULED then - text=text..string.format("\n[%d] %s (%s): status=%s, scheduled=%s (%d sec), started=%s, duration=%d", i, taskid, name, status, clock, eta, started, duration) - elseif task.type==OPSGROUP.TaskType.WAYPOINT then - text=text..string.format("\n[%d] %s (%s): status=%s, waypoint=%d, started=%s, duration=%d, stopflag=%d", i, taskid, name, status, task.waypoint, started, duration, task.stopflag:Get()) - end - end - self:I(self.lid..text) - end - - --- - -- Missions - --- - - -- Current mission name. - if self.verbose>0 then - local Mission=self:GetMissionByID(self.currentmission) - - -- Current status. - local text=string.format("Missions %d, Current: %s", self:CountRemainingMissison(), Mission and Mission.name or "none") - for i,_mission in pairs(self.missionqueue) do - local mission=_mission --Ops.Auftrag#AUFTRAG - local Cstart= UTILS.SecondsToClock(mission.Tstart, true) - local Cstop = mission.Tstop and UTILS.SecondsToClock(mission.Tstop, true) or "INF" - text=text..string.format("\n[%d] %s (%s) status=%s (%s), Time=%s-%s, prio=%d wp=%s targets=%d", - i, tostring(mission.name), mission.type, mission:GetGroupStatus(self), tostring(mission.status), Cstart, Cstop, mission.prio, tostring(mission:GetGroupWaypointIndex(self)), mission:CountMissionTargets()) - end - self:I(self.lid..text) - end + self:_PrintTaskAndMissionStatus() --- -- Fuel State @@ -1415,35 +1365,35 @@ function FLIGHTGROUP:onafterSpawned(From, Event, To) if self.ai then - -- Set default ROE and ROT options. - self:SwitchROE(self.option.ROE) - self:SwitchROT(self.option.ROT) - - -- Turn TACAN beacon on. - if self.tacanDefault then - self:SwitchTACAN(self.tacanDefault.Channel, self.tacanDefault.Morse, self.tacanDefault.BeaconName, self.tacanDefault.Band) + -- Set default ROE. + if self.option.ROE then + self:SwitchROE(self.option.ROE) + else + self:SwitchROE(ENUMS.ROE.ReturnFire) end - -- Turn on the radio. - if self.radioDefault then - self:SwitchRadio(self.radioDefault.Freq, self.radioDefault.Modu) + -- Set default ROT. + if self.option.ROT then + self:SwitchROT(self.option.ROT) else - self:SetDefaultRadio(self.radio.Freq, self.radio.Modu) + self:SwitchROE(ENUMS.ROT.PassiveDefense) + end + + -- Turn TACAN beacon on. + if self.tacan.On then + self:_SwitchTACAN(self.tacan) end - -- Set callsign. - if self.callsignDefault then - self:SwitchCallsign(self.callsignDefault.NumberSquad, self.callsignDefault.NumberGroup) - else - self:SetDefaultCallsign(self.callsign.NumberSquad, self.callsign.NumberGroup) + -- Turn on the radio. + if self.radio.On then + self:SwitchRadio(self.radio.Freq, self.radio.Modu) end -- TODO: make this input. self.group:SetOption(AI.Option.Air.id.PROHIBIT_JETT, true) - self.group:SetOption(AI.Option.Air.id.PROHIBIT_AB, true) -- Does not seem to work. AI still used the after burner. + self.group:SetOption(AI.Option.Air.id.PROHIBIT_AB, true) -- Does not seem to work. AI still used the after burner. self.group: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) @@ -2554,7 +2504,7 @@ function FLIGHTGROUP:_InitGroup() self.position=self:GetCoordinate() -- Radio parameters from template. - self.radioOn=self.template.communication + self.radio.On=self.template.communication self.radio.Freq=self.template.frequency self.radio.Modu=self.template.modulation @@ -2614,7 +2564,7 @@ function FLIGHTGROUP:_InitGroup() text=text..string.format("Helicopter = %s\n", tostring(self.group:IsHelicopter())) text=text..string.format("Elements = %d\n", #self.elements) text=text..string.format("Waypoints = %d\n", #self.waypoints) - text=text..string.format("Radio = %.1f MHz %s %s\n", self.radio.Freq, UTILS.GetModulationName(self.radio.Modu), tostring(self.radioOn)) + text=text..string.format("Radio = %.1f MHz %s %s\n", self.radio.Freq, UTILS.GetModulationName(self.radio.Modu), tostring(self.radio.On)) text=text..string.format("Ammo = %d (G=%d/R=%d/B=%d/M=%d)\n", self.ammo.Total, self.ammo.Guns, self.ammo.Rockets, self.ammo.Bombs, self.ammo.Missiles) text=text..string.format("FSM state = %s\n", self:GetState()) text=text..string.format("Is alive = %s\n", tostring(self.group:IsAlive())) diff --git a/Moose Development/Moose/Ops/NavyGroup.lua b/Moose Development/Moose/Ops/NavyGroup.lua index 8cf2a117a..940fcf4b2 100644 --- a/Moose Development/Moose/Ops/NavyGroup.lua +++ b/Moose Development/Moose/Ops/NavyGroup.lua @@ -95,8 +95,8 @@ function NAVYGROUP:New(GroupName) self.lid=string.format("NAVYGROUP %s | ", self.groupname) -- Defaults - self:SetDefaultROE() - self:SetDefaultAlarmstate() + --self:SetDefaultROE() + --self:SetDefaultAlarmstate() self:SetDetection() self:SetPatrolAdInfinitum(true) @@ -205,6 +205,27 @@ function NAVYGROUP:AddTaskFireAtPoint(Coordinate, Radius, Nshots, WeaponType, Cl return task end +--- Add a *waypoint* task. +-- @param #NAVYGROUP self +-- @param Core.Point#COORDINATE Coordinate Coordinate of the target. +-- @param Ops.OpsGroup#OPSGROUP.Waypoint Waypoint Where the task is executed. Default is next waypoint. +-- @param #number Radius Radius in meters. Default 100 m. +-- @param #number Nshots Number of shots to fire. Default 3. +-- @param #number WeaponType Type of weapon. Default auto. +-- @param #number Prio Priority of the task. +-- @return Ops.OpsGroup#OPSGROUP.Task The task table. +function NAVYGROUP:AddTaskWaypointFireAtPoint(Coordinate, Waypoint, Radius, Nshots, WeaponType, Prio) + + Waypoint=Waypoint or self:GetWaypointNext() + + local DCStask=CONTROLLABLE.TaskFireAtPoint(nil, Coordinate:GetVec2(), Radius, Nshots, WeaponType) + + local task=self:AddTaskWaypoint(DCStask, Waypoint, nil, Prio) + + return task +end + + --- Add a *scheduled* task. -- @param #NAVYGROUP self -- @param Wrapper.Group#GROUP TargetGroup Target group. @@ -408,14 +429,16 @@ function NAVYGROUP:onafterStatus(From, Event, To) -- Check free path ahead. freepath=self:_CheckFreePath(freepath, 100) - if freepath<5000 then + if freepath<5000 and not self.collisionwarning then + + -- Issue a collision warning event. self:CollisionWarning() end if not self.ispathfinding then if freepath<5000 then - --self.ispathfinding=self:_FindPathToNextWaypoint() + self.ispathfinding=self:_FindPathToNextWaypoint() end end @@ -464,60 +487,10 @@ function NAVYGROUP:onafterStatus(From, Event, To) --- - -- Tasks + -- Tasks & Missions --- - - -- Task queue. - if self.verbose>-1 and #self.taskqueue>0 then - local text=string.format("Tasks #%d", #self.taskqueue) - for i,_task in pairs(self.taskqueue) do - local task=_task --Ops.OpsGroup#OPSGROUP.Task - local name=task.description - local taskid=task.dcstask.id or "unknown" - local status=task.status - local clock=UTILS.SecondsToClock(task.time, true) - local eta=task.time-timer.getAbsTime() - local started=task.timestamp and UTILS.SecondsToClock(task.timestamp, true) or "N/A" - local duration=-1 - if task.duration then - duration=task.duration - if task.timestamp then - -- Time the task is running. - duration=task.duration-(timer.getAbsTime()-task.timestamp) - else - -- Time the task is supposed to run. - duration=task.duration - end - end - -- Output text for element. - if task.type==OPSGROUP.TaskType.SCHEDULED then - text=text..string.format("\n[%d] %s (%s): status=%s, scheduled=%s (%d sec), started=%s, duration=%d", i, taskid, name, status, clock, eta, started, duration) - elseif task.type==OPSGROUP.TaskType.WAYPOINT then - text=text..string.format("\n[%d] %s (%s): status=%s, waypoint=%d, started=%s, duration=%d, stopflag=%d", i, taskid, name, status, task.waypoint, started, duration, task.stopflag:Get()) - end - end - self:I(self.lid..text) - end - - --- - -- Missions - --- - - -- Current mission name. - if self.verbose>0 then - local Mission=self:GetMissionByID(self.currentmission) - - -- Current status. - local text=string.format("Missions %d, Current: %s", self:CountRemainingMissison(), Mission and Mission.name or "none") - for i,_mission in pairs(self.missionqueue) do - local mission=_mission --Ops.Auftrag#AUFTRAG - local Cstart= UTILS.SecondsToClock(mission.Tstart, true) - local Cstop = mission.Tstop and UTILS.SecondsToClock(mission.Tstop, true) or "INF" - text=text..string.format("\n[%d] %s (%s) status=%s (%s), Time=%s-%s, prio=%d wp=%s targets=%d", - i, tostring(mission.name), mission.type, mission:GetGroupStatus(self), tostring(mission.status), Cstart, Cstop, mission.prio, tostring(mission:GetGroupWaypointIndex(self)), mission:CountMissionTargets()) - end - self:I(self.lid..text) - end + + self:_PrintTaskAndMissionStatus() -- Next status update in 30 seconds. @@ -564,28 +537,36 @@ function NAVYGROUP:onafterSpawned(From, Event, To) self:I(self.lid..string.format("Group spawned!")) if self.ai then - + -- Set default ROE. - self:SwitchROE(self.option.ROE) + if self.option.ROE then + self:SwitchROE(self.option.ROE) + else + self:SwitchROE(ENUMS.ROE.ReturnFire) + end -- Set default Alarm State. - self:SwitchAlarmstate(self.option.Alarm) + if self.option.Alarm then + self:SwitchAlarmstate(self.option.Alarm) + else + self:SwitchAlarmstate(0) + end -- Turn TACAN beacon on. - if self.tacanDefault then - self:SwitchTACAN(self.tacanDefault.Channel, self.tacanDefault.Morse, self.tacanDefault.BeaconName, self.tacanDefault.Band) + if self.tacan.On then + self:_SwitchTACAN(self.tacan) end -- Turn ICLS on. - if self.iclsDefault then - self:SwitchICLS(self.iclsDefault.Channel, self.iclsDefault.Morse, self.iclsDefault.BeaconName) + if self.icls.On then + self:_SwitchICLS(self.icls) end -- Turn on the radio. - if self.radioDefault then - self:SwitchRadio(self.radioDefault.Freq, self.radioDefault.Modu) + if self.radio.On then + self:SwitchRadio(self.radio.Freq, self.radio.Modu) else - self:SetDefaultRadio(self.radio.Freq, self.radio.Modu) + self.radio.On=true -- Radio is always on for ships. If not set, it is default. end end @@ -776,7 +757,7 @@ function NAVYGROUP:onafterTurnIntoWind(From, Event, To, IntoWind) IntoWind.waypoint=wptiw - if IntoWind.Uturn then + if IntoWind.Uturn and self.Debug then IntoWind.Coordinate:MarkToAll("Return coord") end @@ -880,6 +861,34 @@ function NAVYGROUP:onafterSurface(From, Event, To, Speed) end +--- On after "TurningStarted" event. +-- @param #NAVYGROUP self +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +function NAVYGROUP:onafterTurningStarted(From, Event, To) + self.turning=true +end + +--- On after "TurningStarted" event. +-- @param #NAVYGROUP self +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +function NAVYGROUP:onafterTurningStopped(From, Event, To) + self.turning=false + self.collisionwarning=false +end + +--- On after "CollisionWarning" event. +-- @param #NAVYGROUP self +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +function NAVYGROUP:onafterCollisionWarning(From, Event, To) + self.collisionwarning=true +end + --- On after "Dead" event. -- @param #NAVYGROUP self -- @param #string From From state. @@ -1029,6 +1038,16 @@ end -- @param #boolean Updateroute If true or nil, call UpdateRoute. If false, no call. -- @return Ops.OpsGroup#OPSGROUP.Waypoint Waypoint table. function NAVYGROUP:AddWaypoint(Coordinate, Speed, AfterWaypointWithID, Depth, Updateroute) + + if not Coordinate:IsInstanceOf("COORDINATE") then + if Coordinate:IsInstanceOf("POSITIONABLE") then + self:I(self.lid.."WARNING: Coordinate is not a COORDINATE but a POSITIONABLE. Trying to get coordinate") + Coordinate=Coordinate:GetCoordinate() + else + self:E(self.lid.."ERROR: Coordinate is neither a COORDINATE nor any POSITIONABLE!") + return nil + end + end -- Set waypoint index. local wpnumber=self:GetWaypointIndexAfterID(AfterWaypointWithID) @@ -1107,7 +1126,7 @@ function NAVYGROUP:_InitGroup() self.position=self:GetCoordinate() -- Radio parameters from template. - self.radioOn=true -- Radio is always on for ships. + self.radio.On=false -- Radio is always on for ships but we set it to false to check if it has been changed before spawn. self.radio.Freq=tonumber(self.template.units[1].frequency)/1000000 self.radio.Modu=tonumber(self.template.units[1].modulation) @@ -1152,7 +1171,7 @@ function NAVYGROUP:_InitGroup() text=text..string.format("Speed cruise = %.1f Knots\n", UTILS.KmphToKnots(self.speedCruise)) text=text..string.format("Elements = %d\n", #self.elements) text=text..string.format("Waypoints = %d\n", #self.waypoints) - text=text..string.format("Radio = %.1f MHz %s %s\n", self.radio.Freq, UTILS.GetModulationName(self.radio.Modu), tostring(self.radioOn)) + text=text..string.format("Radio = %.1f MHz %s %s\n", self.radio.Freq, UTILS.GetModulationName(self.radio.Modu), tostring(self.radio.On)) text=text..string.format("Ammo = %d (G=%d/R=%d/M=%d/T=%d)\n", self.ammo.Total, self.ammo.Guns, self.ammo.Rockets, self.ammo.Missiles, self.ammo.Torpedos) text=text..string.format("FSM state = %s\n", self:GetState()) text=text..string.format("Is alive = %s\n", tostring(self.group:IsAlive())) @@ -1190,7 +1209,13 @@ function NAVYGROUP:_CheckFreePath(DistanceMax, dx) return distance end - local offsetY=1 + -- Offset above sea level. + local offsetY=0.1 + + -- Current bug on Caucasus. LoS returns false. + if UTILS.GetDCSMap()==DCSMAP.Caucasus then + offsetY=5.01 + end -- Current coordinate. local coordinate=self:GetCoordinate():SetAltitude(offsetY, true) @@ -1199,7 +1224,7 @@ function NAVYGROUP:_CheckFreePath(DistanceMax, dx) local heading=self:GetHeading() -- Check from 500 meters in front. - coordinate=coordinate:Translate(500, heading, true) + --coordinate=coordinate:Translate(500, heading, true) local function LoS(dist) local checkcoord=coordinate:Translate(dist, heading, true) @@ -1534,7 +1559,7 @@ function NAVYGROUP:_FindPathToNextWaypoint() local delta=dist/10 -- Create a grid of nodes. We only want nodes of surface type water. - astar:CreateGrid({land.SurfaceType.WATER}, boxwidth, spacex, delta, delta*2, false) + astar:CreateGrid({land.SurfaceType.WATER}, boxwidth, spacex, delta, delta*2, self.Debug) -- Valid neighbour nodes need to have line of sight. astar:SetValidNeighbourLoS(400) diff --git a/Moose Development/Moose/Ops/OpsGroup.lua b/Moose Development/Moose/Ops/OpsGroup.lua index e2cdffa2e..1a83902b8 100644 --- a/Moose Development/Moose/Ops/OpsGroup.lua +++ b/Moose Development/Moose/Ops/OpsGroup.lua @@ -58,16 +58,13 @@ -- -- @field #OPSGROUP.Radio radio Current radio settings. -- @field #OPSGROUP.Radio radioDefault Default radio settings. --- @field #boolean radioOn If true, radio is currently turned on. -- @field Core.RadioQueue#RADIOQUEUE radioQueue Radio queue. -- -- @field #OPSGROUP.Beacon tacan Current TACAN settings. -- @field #OPSGROUP.Beacon tacanDefault Default TACAN settings. --- @field #boolean tacanOn If true, TACAN is currently active. -- -- @field #OPSGROUP.Beacon icls Current ICLS settings. -- @field #OPSGROUP.Beacon iclsDefault Default ICLS settings. --- @field #boolean iclsOn If true, ICLS is currently active. -- -- @field #OPSGROUP.Option option Current optional settings. -- @field #OPSGROUP.Option optionDefault Default option settings. @@ -202,11 +199,13 @@ OPSGROUP.TaskType={ -- @field #string Band Band "X" or "Y" for TACAN beacon. -- @field #string BeaconName Name of the unit acting as beacon. -- @field Wrapper.Unit#UNIT BeaconUnit Unit object acting as beacon. +-- @field #boolean On If true, beacon is on, if false, beacon is turned off. If nil, has not been used yet. --- Radio data. -- @type OPSGROUP.Radio -- @field #number Freq Frequency -- @field #number Modu Modulation. +-- @field #boolean On If true, radio is on, if false, radio is turned off. If nil, has not been used yet. --- Callsign data. -- @type OPSGROUP.Callsign @@ -255,7 +254,9 @@ OPSGROUP.TaskType={ -- @field #boolean astar If true, this waypint was found by A* pathfinding algorithm. -- @field Core.Point#COORDINATE coordinate Waypoint coordinate. -- @field Core.Point#COORDINATE roadcoord Closest point to road. +-- @field #number roaddist Distance to closest point on road. -- @field Wrapper.Marker#MARKER marker Marker on the F10 map. +-- @field #string formation Ground formation. Similar to action but on/off road. --- NavyGroup version. -- @field #string version @@ -864,6 +865,14 @@ end --- Get unique ID of waypoint. -- @param #OPSGROUP self +-- @param #OPSGROUP.Waypoint waypoint The waypoint data table. +-- @return #number Unique ID. +function OPSGROUP:GetWaypointUID(waypoint) + return waypoint.uid +end + +--- Get unique ID of waypoint given its index. +-- @param #OPSGROUP self -- @param #number indx Waypoint index. -- @return #number Unique ID. function OPSGROUP:GetWaypointID(indx) @@ -1213,7 +1222,7 @@ function OPSGROUP:AddTaskWaypoint(task, Waypoint, description, prio, duration) -- Task data structure. local newtask={} --#OPSGROUP.Task - newtask.description=description + newtask.description=description or string.format("Task #%d", self.taskcounter) newtask.status=OPSGROUP.TaskStatus.SCHEDULED newtask.dcstask=task newtask.prio=prio or 50 @@ -2592,6 +2601,72 @@ function OPSGROUP:_CheckGroupDone(delay) end +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Status Info Common to Air, Land and Sea +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- Print info on mission and task status to DCS log file. +-- @param #OPSGROUP self +function OPSGROUP:_PrintTaskAndMissionStatus() + + --- + -- Tasks: verbose >= 2 + --- + + -- Task queue. + if #self.taskqueue>0 and self.verbose>=2 then + local text=string.format("Tasks #%d", #self.taskqueue) + for i,_task in pairs(self.taskqueue) do + local task=_task --Ops.OpsGroup#OPSGROUP.Task + local name=task.description + local taskid=task.dcstask.id or "unknown" + local status=task.status + local clock=UTILS.SecondsToClock(task.time, true) + local eta=task.time-timer.getAbsTime() + local started=task.timestamp and UTILS.SecondsToClock(task.timestamp, true) or "N/A" + local duration=-1 + if task.duration then + duration=task.duration + if task.timestamp then + -- Time the task is running. + duration=task.duration-(timer.getAbsTime()-task.timestamp) + else + -- Time the task is supposed to run. + duration=task.duration + end + end + -- Output text for element. + if task.type==OPSGROUP.TaskType.SCHEDULED then + text=text..string.format("\n[%d] %s (%s): status=%s, scheduled=%s (%d sec), started=%s, duration=%d", i, taskid, name, status, clock, eta, started, duration) + elseif task.type==OPSGROUP.TaskType.WAYPOINT then + text=text..string.format("\n[%d] %s (%s): status=%s, waypoint=%d, started=%s, duration=%d, stopflag=%d", i, taskid, name, status, task.waypoint, started, duration, task.stopflag:Get()) + end + end + self:I(self.lid..text) + end + + --- + -- Missions: verbose>=1 + --- + + -- Current mission name. + if self.verbose>0 then + local Mission=self:GetMissionByID(self.currentmission) + + -- Current status. + local text=string.format("Missions %d, Current: %s", self:CountRemainingMissison(), Mission and Mission.name or "none") + for i,_mission in pairs(self.missionqueue) do + local mission=_mission --Ops.Auftrag#AUFTRAG + local Cstart= UTILS.SecondsToClock(mission.Tstart, true) + local Cstop = mission.Tstop and UTILS.SecondsToClock(mission.Tstop, true) or "INF" + text=text..string.format("\n[%d] %s (%s) status=%s (%s), Time=%s-%s, prio=%d wp=%s targets=%d", + i, tostring(mission.name), mission.type, mission:GetGroupStatus(self), tostring(mission.status), Cstart, Cstop, mission.prio, tostring(mission:GetGroupWaypointIndex(self)), mission:CountMissionTargets()) + end + self:I(self.lid..text) + end + +end + ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- Waypoints & Routing ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -2653,9 +2728,13 @@ function OPSGROUP:InitWaypoints() for index,wp in pairs(self.waypoints0) do - local waypoint=self:_CreateWaypoint(wp) + --local waypoint=self:_CreateWaypoint(wp) + --self:_AddWaypoint(waypoint) - self:_AddWaypoint(waypoint) + local coordinate=COORDINATE:New(wp.x, wp.alt, wp.y) + local speedknots=UTILS.MpsToKnots(wp.speed) + + self:AddWaypoint(coordinate, speedknots, index-1, nil, false) end @@ -2871,19 +2950,26 @@ end --- Set current ROE for the group. -- @param #OPSGROUP self --- @param #string roe ROE of group. Default is the value defined by :SetDefaultROE(). +-- @param #string roe ROE of group. Default is `ENUMS.ROE.ReturnFire`. -- @return #OPSGROUP self function OPSGROUP:SwitchROE(roe) + + if self:IsAlive() or self:IsInUtero() then - self.option.ROE=roe or self.optionDefault.ROE + self.option.ROE=roe or ENUMS.ROE.ReturnFire - if self:IsAlive() then - - self.group:OptionROE(self.option.ROE) + if self:IsInUtero() then + self:I(self.lid..string.format("Setting current ROE=%d when GROUP is SPAWNED", self.option.ROE)) + else + + self.group:OptionROE(roe) + + self:I(self.lid..string.format("Setting current ROE=%d (0=WeaponFree, 1=OpenFireWeaponFree, 2=OpenFire, 3=ReturnFire, 4=WeaponHold)", self.option.ROE)) + end + - self:I(self.lid..string.format("Setting current ROE=%d (0=WeaponFree, 1=OpenFireWeaponFree, 2=OpenFire, 3=ReturnFire, 4=WeaponHold)", self.option.ROE)) else - -- TODO WARNING + self:E(self.lid.."WARNING: Cannot switch ROE! Group is not alive") end return self @@ -2907,19 +2993,26 @@ end --- Set ROT for the group. -- @param #OPSGROUP self --- @param #string rot ROT of group. Default is the value defined by :SetDefaultROT(). +-- @param #string rot ROT of group. Default is `ENUMS.ROT.PassiveDefense`. -- @return #OPSGROUP self function OPSGROUP:SwitchROT(rot) - - self.option.ROT=rot or self.optionDefault.ROT - if self:IsAlive() then + if self:IsAlive() or self:IsInUtero() then - self.group:OptionROT(self.option.ROT) + self.option.ROT=rot or ENUMS.ROT.PassiveDefense + + if self:IsInUtero() then + self:I(self.lid..string.format("Setting current ROT=%d when GROUP is SPAWNED", self.option.ROT)) + else - self:T2(self.lid..string.format("Setting current ROT=%d (0=NoReaction, 1=Passive, 2=Evade, 3=ByPass, 4=AllowAbort)", self.option.ROT)) + self.group:OptionROT(self.option.ROT) + + self:I(self.lid..string.format("Setting current ROT=%d (0=NoReaction, 1=Passive, 2=Evade, 3=ByPass, 4=AllowAbort)", self.option.ROT)) + end + + else - -- TODO WARNING + self:E(self.lid.."WARNING: Cannot switch ROT! Group is not alive") end return self @@ -2943,29 +3036,41 @@ function OPSGROUP:SetDefaultAlarmstate(alarmstate) end --- Set current Alarm State of the group. +-- +-- * 0 = "Auto" +-- * 1 = "Green" +-- * 2 = "Red" +-- -- @param #OPSGROUP self --- @param #string alarmstate Alarm state of group. Default is the value defined by :SetDefaultAlarmstate(). +-- @param #number alarmstate Alarm state of group. Default is 0="Auto". -- @return #OPSGROUP self function OPSGROUP:SwitchAlarmstate(alarmstate) - - self.option.Alarm=alarmstate or self.optionDefault.Alarm - if self:IsAlive() then + if self:IsAlive() or self:IsInUtero() then - if self.option.Alarm==0 then - self.group:OptionAlarmStateAuto() - elseif self.option.Alarm==1 then - self.group:OptionAlarmStateGreen() - elseif self.option.Alarm==2 then - self.group:OptionAlarmStateRed() - else - self:E("ERROR: Unknown Alarm State! Setting to AUTO.") - self.group:OptionAlarmStateAuto() - end + self.option.Alarm=alarmstate or 0 - self:I(self.lid..string.format("Setting current Alarm State=%d (0=Auto, 1=Green, 2=Red)", self.option.Alarm)) + if self:IsInUtero() then + self:I(self.lid..string.format("Setting current Alarm State=%d when GROUP is SPAWNED", self.option.Alarm)) + else + + if self.option.Alarm==0 then + self.group:OptionAlarmStateAuto() + elseif self.option.Alarm==1 then + self.group:OptionAlarmStateGreen() + elseif self.option.Alarm==2 then + self.group:OptionAlarmStateRed() + else + self:E("ERROR: Unknown Alarm State! Setting to AUTO") + self.group:OptionAlarmStateAuto() + self.option.Alarm=0 + end + + self:I(self.lid..string.format("Setting current Alarm State=%d (0=Auto, 1=Green, 2=Red)", self.option.Alarm)) + + end else - -- TODO WARNING + self:E(self.lid.."WARNING: Cannot switch Alarm State! Group is not alive.") end return self @@ -2996,6 +3101,15 @@ function OPSGROUP:SetDefaultTACAN(Channel, Morse, UnitName, Band) return self end + +--- Activate/switch TACAN beacon settings. +-- @param #OPSGROUP self +-- @param #OPSGROUP.Beacon Tacan Tacan data table. +-- @return #OPSGROUP self +function OPSGROUP:_SwitchTACAN(Tacan) + self:SwitchTACAN(Tacan.Channel, Tacan.Morse, Tacan.BeaconName, Tacan.Band) +end + --- Activate/switch TACAN beacon settings. -- @param #OPSGROUP self -- @param #number Channel TACAN Channel. @@ -3005,7 +3119,7 @@ end -- @return #OPSGROUP self function OPSGROUP:SwitchTACAN(Channel, Morse, UnitName, Band) - if self:IsAlive() then + if self:IsAlive() or self:IsInUtero() then local unit=self.group:GetUnit(1) --Wrapper.Unit#UNIT @@ -3022,15 +3136,10 @@ function OPSGROUP:SwitchTACAN(Channel, Morse, UnitName, Band) unit=self.group:GetUnit(1) end - if not Channel then - Channel=self.tacanDefault and self.tacanDefault.Channel or nil - end + Channel=Channel or 74 + Morse=Morse or "XXX" - if not Morse then - Morse=self.tacanDefault and self.tacanDefault.Morse or "XXX" - end - - if unit and unit:IsAlive() and Channel then + if unit and unit:IsAlive() or self:IsInUtero() then local UnitID=unit:GetID() @@ -3039,7 +3148,7 @@ function OPSGROUP:SwitchTACAN(Channel, Morse, UnitName, Band) if self.isAircraft then System=BEACON.System.TACAN_TANKER_Y - Band=Band or "Y" + Band=Band or "Y" else System=BEACON.System.TACAN Band=Band or "X" @@ -3048,26 +3157,31 @@ function OPSGROUP:SwitchTACAN(Channel, Morse, UnitName, Band) -- Tacan frequency. local Frequency=UTILS.TACANToFrequency(Channel, Band) - -- Activate beacon. - unit:CommandActivateBeacon(Type, System, Frequency, UnitID, Channel, Band, true, Morse, true) - -- Update info. - self.tacan={} self.tacan.Channel=Channel self.tacan.Morse=Morse self.tacan.Band=Band self.tacan.BeaconName=unit:GetName() self.tacan.BeaconUnit=unit + self.tacan.On=true - -- TACAN is now on. - self.tacanOn=true - - self:I(self.lid..string.format("Switching TACAN to Channel %d%s Morse %s on unit %s", self.tacan.Channel, self.tacan.Band, tostring(self.tacan.Morse), self.tacan.BeaconName)) + if self:IsInUtero() then + self:I(self.lid..string.format("Switching TACAN to Channel %d%s Morse %s on unit %s when GROUP is SPAWNED", self.tacan.Channel, self.tacan.Band, tostring(self.tacan.Morse), self.tacan.BeaconName)) + else + + -- Activate beacon. + unit:CommandActivateBeacon(Type, System, Frequency, UnitID, Channel, Band, true, Morse, true) + + self:I(self.lid..string.format("Switching TACAN to Channel %d%s Morse %s on unit %s", self.tacan.Channel, self.tacan.Band, tostring(self.tacan.Morse), self.tacan.BeaconName)) + end + else - self:E(self.lid.."ERROR: Cound not set TACAN! Unit is not alive.") + self:E(self.lid.."ERROR: Cound not set TACAN! Unit is not alive") end + else + self:E(self.lid.."ERROR: Cound not set TACAN! Group is not alive") end return self @@ -3107,13 +3221,21 @@ end --- Activate/switch ICLS beacon settings. -- @param #OPSGROUP self --- @param #number Channel ICLS Channel. --- @param #string Morse ICLS morse code. Default is the value set in @{#OPSGROUP.SetDefaultICLS} or if not set "XXX". +-- @param #OPSGROUP.Beacon Icls ICLS data table. +-- @return #OPSGROUP self +function OPSGROUP:_SwitchICLS(Icls) + self:SwitchICLS(Icls.Channel, Icls.Morse, Icls.BeaconName) +end + +--- Activate/switch ICLS beacon settings. +-- @param #OPSGROUP self +-- @param #number Channel ICLS Channel. Default is 1. +-- @param #string Morse ICLS morse code. Default is "XXX". -- @param #string UnitName Name of the unit in the group which should activate the ICLS beacon. Can also be given as #number to specify the unit number. Default is the first unit of the group. -- @return #OPSGROUP self function OPSGROUP:SwitchICLS(Channel, Morse, UnitName) - if self:IsAlive() then + if self:IsAlive() or self:IsInUtero() then local unit=self.group:GetUnit(1) --Wrapper.Unit#UNIT @@ -3130,33 +3252,32 @@ function OPSGROUP:SwitchICLS(Channel, Morse, UnitName) unit=self.group:GetUnit(1) end - if not Channel then - Channel=self.iclsDefault and self.iclsDefault.Channel or nil - end - - if not Morse then - Morse=self.iclsDefault and self.iclsDefault.Morse or "XXX" - end + Channel=Channel or 1 + Morse=Morse or "XXX" - if unit and unit:IsAlive() and Channel then + if unit and unit:IsAlive() or self:IsInUtero() then local UnitID=unit:GetID() - - -- Activate beacon. - unit:CommandActivateICLS(Channel, UnitID, Morse) - + -- Update info. - self.icls={} self.icls.Channel=Channel self.icls.Morse=Morse - self.icls.Band=Band + self.icls.Band=nil self.icls.BeaconName=unit:GetName() self.icls.BeaconUnit=unit + self.icls.On=true + - -- ICLS is now on. - self.iclsOn=true + if self:IsInUtero() then + self:I(self.lid..string.format("Switching ICLS to Channel %d Morse %s on unit %s when GROUP is SPAWNED", self.icls.Channel, tostring(self.icls.Morse), self.icls.BeaconName)) + else - self:I(self.lid..string.format("Switching ICLS to Channel %d Morse %s on unit %s", self.icls.Channel, tostring(self.icls.Morse), self.icls.BeaconName)) + -- Activate beacon. + unit:CommandActivateICLS(Channel, UnitID, Morse) + + self:I(self.lid..string.format("Switching ICLS to Channel %d Morse %s on unit %s", self.icls.Channel, tostring(self.icls.Morse), self.icls.BeaconName)) + + end else self:E(self.lid.."ERROR: Cound not set ICLS! Unit is not alive.") @@ -3204,33 +3325,42 @@ function OPSGROUP:GetRadio() return self.radio.Freq, self.radio.Modu end ---- Turn radio on. +--- Turn radio on or switch frequency/modulation. -- @param #OPSGROUP self --- @param #number Frequency Radio frequency in MHz. +-- @param #number Frequency Radio frequency in MHz. Default is 127.5 MHz. -- @param #number Modulation Radio modulation. Default `radio.Modulation.AM`. -- @return #OPSGROUP self function OPSGROUP:SwitchRadio(Frequency, Modulation) - if self:IsAlive() and Frequency then + if self:IsAlive() or self:IsInUtero() then - Modulation=Modulation or self.radioDefault.Modu + Frequency=Frequency or 127.5 + Modulation=Modulation or radio.modulation.AM local group=self.group --Wrapper.Group#GROUP - if self.isAircraft and not self.radioOn then + if self.isAircraft and not self.radio.On then group:SetOption(AI.Option.Air.id.SILENCE, false) end - group:CommandSetFrequency(Frequency, Modulation) - + -- Set radio self.radio.Freq=Frequency self.radio.Modu=Modulation + self.radio.On=true - -- Radio is on. - self.radioOn=true - - self:I(self.lid..string.format("Switching radio to frequency %.3f MHz %s", self.radio.Freq, UTILS.GetModulationName(self.radio.Modu))) + if self:IsInUtero() then + self:I(self.lid..string.format("Switching radio to frequency %.3f MHz %s when GROUP is SPAWNED", self.radio.Freq, UTILS.GetModulationName(self.radio.Modu))) + else + -- Give command + group:CommandSetFrequency(Frequency, Modulation) + + self:I(self.lid..string.format("Switching radio to frequency %.3f MHz %s", self.radio.Freq, UTILS.GetModulationName(self.radio.Modu))) + + end + + else + self:E(self.lid.."ERROR: Cound not set Radio! Group is not alive") end return self @@ -3252,11 +3382,11 @@ function OPSGROUP:TurnOffRadio() --self.radio.Modu=nil -- Radio is off. - self.radioOn=false + self.radio.On=false self:I(self.lid..string.format("Switching radio OFF")) else - self:E(self.lid.."ERROR radio can only be turned off for aircraft!") + self:E(self.lid.."ERROR: Radio can only be turned off for aircraft!") end end diff --git a/Moose Development/Moose/Ops/Squadron.lua b/Moose Development/Moose/Ops/Squadron.lua index 0c1939570..ac57544e4 100644 --- a/Moose Development/Moose/Ops/Squadron.lua +++ b/Moose Development/Moose/Ops/Squadron.lua @@ -156,8 +156,10 @@ function SQUADRON:New(TemplateGroupName, Ngroups, SquadronName) -- From State --> Event --> To State self:AddTransition("Stopped", "Start", "OnDuty") -- Start FSM. self:AddTransition("*", "Status", "*") -- Status update. + self:AddTransition("OnDuty", "Pause", "Paused") -- Pause squadron. self:AddTransition("Paused", "Unpause", "OnDuty") -- Unpause squadron. + self:AddTransition("*", "Stop", "Stopped") -- Stop squadron.