From fb6ebc42a5243fb868a54e317971f11d4c036561 Mon Sep 17 00:00:00 2001 From: Frank Date: Mon, 10 Aug 2020 23:45:52 +0200 Subject: [PATCH] Ops --- Moose Development/Moose/Ops/ArmyGroup.lua | 12 + Moose Development/Moose/Ops/Auftrag.lua | 270 ++++++++++++++------ Moose Development/Moose/Ops/FlightGroup.lua | 2 +- Moose Development/Moose/Ops/OpsGroup.lua | 5 - 4 files changed, 202 insertions(+), 87 deletions(-) diff --git a/Moose Development/Moose/Ops/ArmyGroup.lua b/Moose Development/Moose/Ops/ArmyGroup.lua index 0c6d1577d..3ced05e52 100644 --- a/Moose Development/Moose/Ops/ArmyGroup.lua +++ b/Moose Development/Moose/Ops/ArmyGroup.lua @@ -428,6 +428,17 @@ 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 + + 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)) @@ -705,6 +716,7 @@ function ARMYGROUP:AddWaypoint(Coordinate, Speed, AfterWaypointWithID, Formation -- Get closest point to road. waypoint.roadcoord=Coordinate:GetClosestPointToRoad(false) + waypoint.roadist=Coordinate:Get2DDistance(waypoint.roadcoord) -- 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)) diff --git a/Moose Development/Moose/Ops/Auftrag.lua b/Moose Development/Moose/Ops/Auftrag.lua index 4c02e8cb7..d22d07960 100644 --- a/Moose Development/Moose/Ops/Auftrag.lua +++ b/Moose Development/Moose/Ops/Auftrag.lua @@ -21,6 +21,7 @@ -- @type AUFTRAG -- @field #string ClassName Name of the class. -- @field #boolean Debug Debug mode. Messages to all about status. +-- @field #number verbose Verbosity level. -- @field #string lid Class id string for output to DCS log file. -- @field #number auftragsnummer Auftragsnummer. -- @field #string type Mission type. @@ -255,6 +256,7 @@ AUFTRAG = { ClassName = "AUFTRAG", Debug = false, + verbose = 2, lid = nil, auftragsnummer = nil, groupdata = {}, @@ -627,7 +629,8 @@ function AUFTRAG:NewORBIT_RACETRACK(Coordinate, Altitude, Speed, Heading, Leg) return mission end ---- Create a GCCAP mission. +--- Create a Ground Controlled CAP (GCCAP) mission. Flights with this task are considered for A2A INTERCEPT missions by the CHIEF class. They will perform a compat air patrol but not engage by +-- themselfs. They wait for the CHIEF to tell them whom to engage. -- @param #AUFTRAG self -- @param Core.Point#COORDINATE Coordinate Where to orbit. -- @param #number Altitude Orbit altitude in feet. Default is y component of `Coordinate`. @@ -1178,6 +1181,96 @@ function AUFTRAG:NewTARGET(Target) end + +--- Create a mission to attack a group. Mission type is automatically chosen from the group category. +-- @param #AUFTRAG self +-- @param Wrapper.Positionable#POSITIONABLE Target Target object. +-- @return #string Auftrag type, e.g. `AUFTRAG.Type.BAI` (="BAI"). +function AUFTRAG:_DetermineAuftragType(Target) + + local group=nil --Wrapper.Group#GROUP + local airbase=nil --Wrapper.Airbase#AIRBASE + local scenery=nil --Wrapper.Scenery#SCENERY + local coordinate=nil --Core.Point#COORDINATE + local auftrag=nil + + if Target:IsInstanceOf("GROUP") then + group=Target --Target is already a group. + elseif Target:IsInstanceOf("UNIT") then + group=Target:GetGroup() + elseif Target:IsInstanceOf("AIRBASE") then + airbase=Target + elseif Target:IsInstanceOf("SCENERY") then + scenery=Target + end + + if group then + + local category=group:GetCategory() + local attribute=group:GetAttribute() + + if category==Group.Category.AIRPLANE or category==Group.Category.HELICOPTER then + + --- + -- A2A: Intercept + --- + + auftrag=AUFTRAG.Type.INTERCEPT + + elseif category==Group.Category.GROUND or category==Group.Category.TRAIN then + + --- + -- GROUND + --- + + if attribute==GROUP.Attribute.GROUND_SAM then + + -- SEAD/DEAD + + auftrag=AUFTRAG.Type.SEAD + + elseif attribute==GROUP.Attribute.GROUND_AAA then + + auftrag=AUFTRAG.Type.BAI + + elseif attribute==GROUP.Attribute.GROUND_ARTILLERY then + + auftrag=AUFTRAG.Type.BAI + + elseif attribute==GROUP.Attribute.GROUND_INFANTRY then + + auftrag=AUFTRAG.Type.BAI + + else + + auftrag=AUFTRAG.Type.BAI + + end + + + elseif category==Group.Category.SHIP then + + --- + -- NAVAL + --- + + auftrag=AUFTRAG.Type.ANTISHIP + + else + self:E(self.lid.."ERROR: Unknown Group category!") + end + + elseif airbase then + auftrag=AUFTRAG.Type.BOMBRUNWAY + elseif scenery then + auftrag=AUFTRAG.Type.STRIKE + elseif coordinate then + auftrag=AUFTRAG.Type.BOMBING + end + + return auftrag +end + --- Create a mission to attack a group. Mission type is automatically chosen from the group category. -- @param #AUFTRAG self -- @param Wrapper.Group#GROUP EngageGroup Group to be engaged. @@ -1186,66 +1279,54 @@ function AUFTRAG:NewAUTO(EngageGroup) local mission=nil --#AUFTRAG - local group=EngageGroup + local Target=EngageGroup - if group and group:IsAlive() then + local auftrag=self:_DetermineAuftragType(EngageGroup) - local category=group:GetCategory() - local attribute=group:GetAttribute() - local threatlevel=group:GetThreatLevel() + if auftrag==AUFTRAG.Type.ANTISHIP then + mission=AUFTRAG:NewANTISHIP(Target) + elseif auftrag==AUFTRAG.Type.ARTY then + mission=AUFTRAG:NewARTY(Target) + elseif auftrag==AUFTRAG.Type.AWACS then + mission=AUFTRAG:NewAWACS(Coordinate,Altitude,Speed,Heading,Leg) + elseif auftrag==AUFTRAG.Type.BAI then + mission=AUFTRAG:NewBAI(Target,Altitude) + elseif auftrag==AUFTRAG.Type.BOMBING then + mission=AUFTRAG:NewBOMBING(Target,Altitude) + elseif auftrag==AUFTRAG.Type.BOMBRUNWAY then + mission=AUFTRAG:NewBOMBRUNWAY(Airdrome,Altitude) + elseif auftrag==AUFTRAG.Type.BOMBCARPET then + mission=AUFTRAG:NewBOMBCARPET(Target,Altitude,CarpetLength) + elseif auftrag==AUFTRAG.Type.CAP then + mission=AUFTRAG:NewCAP(ZoneCAP,Altitude,Speed,Coordinate,Heading,Leg,TargetTypes) + elseif auftrag==AUFTRAG.Type.CAS then + mission=AUFTRAG:NewCAS(ZoneCAS,Altitude,Speed,Coordinate,Heading,Leg,TargetTypes) + elseif auftrag==AUFTRAG.Type.ESCORT then + mission=AUFTRAG:NewESCORT(EscortGroup,OffsetVector,EngageMaxDistance,TargetTypes) + elseif auftrag==AUFTRAG.Type.FACA then + mission=AUFTRAG:NewFACA(Target,Designation,DataLink,Frequency,Modulation) + elseif auftrag==AUFTRAG.Type.FERRY then + -- Not implemented yet. + elseif auftrag==AUFTRAG.Type.GCCAP then + mission=AUFTRAG:NewGCCAP(Coordinate,Altitude,Speed,Heading,Leg) + elseif auftrag==AUFTRAG.Type.INTERCEPT then + mission=AUFTRAG:NewINTERCEPT(Target) + elseif auftrag==AUFTRAG.Type.ORBIT then + mission=AUFTRAG:NewORBIT(Coordinate,Altitude,Speed,Heading,Leg) + elseif auftrag==AUFTRAG.Type.RECON then + -- Not implemented yet. + elseif auftrag==AUFTRAG.Type.RESCUEHELO then + mission=AUFTRAG:NewRESCUEHELO(Carrier) + elseif auftrag==AUFTRAG.Type.SEAD then + mission=AUFTRAG:NewSEAD(Target,Altitude) + elseif auftrag==AUFTRAG.Type.STRIKE then + mission=AUFTRAG:NewSTRIKE(Target,Altitude) + elseif auftrag==AUFTRAG.Type.TANKER then + mission=AUFTRAG:NewTANKER(Coordinate,Altitude,Speed,Heading,Leg,RefuelSystem) + elseif auftrag==AUFTRAG.Type.TROOPTRANSPORT then + mission=AUFTRAG:NewTROOPTRANSPORT(TransportGroupSet,DropoffCoordinate,PickupCoordinate) + else - if category==Group.Category.AIRPLANE or category==Group.Category.HELICOPTER then - - --- - -- AIR - --- - - mission=AUFTRAG:NewINTERCEPT(group) - - elseif category==Group.Category.GROUND then - - --- - -- GROUND - --- - - --TODO: action depends on type - -- AA/SAM ==> SEAD - -- Tanks ==> - -- Artillery ==> - -- Infantry ==> - -- - - if attribute==GROUP.Attribute.GROUND_AAA or attribute==GROUP.Attribute.GROUND_SAM then - - -- SEAD/DEAD - - -- TODO: Attack radars first? Attack launchers? - - mission=AUFTRAG:NewSEAD(group) - - elseif attribute==GROUP.Attribute.GROUND_ARTILLERY then - - mission=AUFTRAG:NewBAI(group) - - elseif attribute==GROUP.Attribute.GROUND_INFANTRY then - - mission=AUFTRAG:NewBAI(group) - - else - - mission=AUFTRAG:NewBAI(group) - - end - - elseif category==Group.Category.SHIP then - - --- - -- NAVAL - --- - - mission=AUFTRAG:NewANTISHIP(group) - - end end if mission then @@ -1255,7 +1336,19 @@ function AUFTRAG:NewAUTO(EngageGroup) return mission end +--- Create a mission to attack a group. Mission type is automatically chosen from the group category. +-- @param #AUFTRAG self +-- @param Ops.Target#TARGET Target Target to engage. +-- @return #AUFTRAG self +function AUFTRAG:NewTARGET(Target) + for _,_target in pairs(Target) do + local target=_target --Ops.Target#TARGET.Object + a=target.Object + end + + return mission +end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- User API Functions @@ -1414,6 +1507,15 @@ function AUFTRAG:SetMissionAltitude(Altitude) return self end +--- Set mission speed. That is the speed the group uses to get to the mission waypoint. +-- @param #AUFTRAG self +-- @param #string Speed Mission speed in knots. +-- @return #AUFTRAG self +function AUFTRAG:SetMissionSpeed(Speed) + self.missionSpeed=Speed and UTILS.KnotsToKmph(Speed) or nil + return self +end + --- Set max engage range. -- @param #AUFTRAG self -- @param #number Range Max range in NM. Default 100 NM. @@ -1823,6 +1925,9 @@ end -- @param #string To To state. function AUFTRAG:onafterStatus(From, Event, To) + -- Current abs. mission time. + local Tnow=timer.getAbsTime() + -- Number of alive mission targets. local Ntargets=self:CountMissionTargets() @@ -1837,7 +1942,7 @@ function AUFTRAG:onafterStatus(From, Event, To) -- All groups have reported MISSON DONE. self:Done() - elseif (self.Tstop and timer.getAbsTime()>self.Tstop+10) or (self.Ntargets>0 and Ntargets==0) then + elseif (self.Tstop and Tnow>self.Tstop+10) or (self.Ntargets>0 and Ntargets==0) then -- Cancel mission if stop time passed. self:Cancel() @@ -1845,36 +1950,39 @@ function AUFTRAG:onafterStatus(From, Event, To) end end - - + -- Current FSM state. local fsmstate=self:GetState() - local Tnow=timer.getAbsTime() - -- Mission start stop time. - local Cstart=UTILS.SecondsToClock(self.Tstart, true) - local Cstop=self.Tstop and UTILS.SecondsToClock(self.Tstop, true) or "INF" - - local targetname=self:GetTargetName() or "unknown" - - local airwing=self.airwing and self.airwing.alias or "N/A" - local commander=self.wingcommander and tostring(self.wingcommander.coalition) or "N/A" - - -- Info message. - self:I(self.lid..string.format("Status %s: Target=%s, T=%s-%s, assets=%d, groups=%d, targets=%d, wing=%s, commander=%s", self.status, targetname, Cstart, Cstop, #self.assets, Ngroups, Ntargets, airwing, commander)) - -- Check for error. if fsmstate~=self.status then self:E(self.lid..string.format("ERROR: FSM state %s != %s mission status!", fsmstate, self.status)) end - - -- Data on assigned groups. - local text="Group data:" - for groupname,_groupdata in pairs(self.groupdata) do - local groupdata=_groupdata --#AUFTRAG.GroupData - text=text..string.format("\n- %s: status mission=%s opsgroup=%s", groupname, groupdata.status, groupdata.opsgroup and groupdata.opsgroup:GetState() or "N/A") + + if self.verbose>=1 then + + -- Mission start stop time. + local Cstart=UTILS.SecondsToClock(self.Tstart, true) + local Cstop=self.Tstop and UTILS.SecondsToClock(self.Tstop, true) or "INF" + + local targetname=self:GetTargetName() or "unknown" + + local airwing=self.airwing and self.airwing.alias or "N/A" + local commander=self.wingcommander and tostring(self.wingcommander.coalition) or "N/A" + + -- Info message. + self:I(self.lid..string.format("Status %s: Target=%s, T=%s-%s, assets=%d, groups=%d, targets=%d, wing=%s, commander=%s", self.status, targetname, Cstart, Cstop, #self.assets, Ngroups, Ntargets, airwing, commander)) + end + + if self.verbose>=2 then + -- Data on assigned groups. + local text="Group data:" + for groupname,_groupdata in pairs(self.groupdata) do + local groupdata=_groupdata --#AUFTRAG.GroupData + text=text..string.format("\n- %s: status mission=%s opsgroup=%s", groupname, groupdata.status, groupdata.opsgroup and groupdata.opsgroup:GetState() or "N/A") + end + self:I(self.lid..text) end - self:T(self.lid..text) -- Ready to evaluate mission outcome? local ready2evaluate=self.Tover and Tnow-self.Tover>=self.dTevaluate or false diff --git a/Moose Development/Moose/Ops/FlightGroup.lua b/Moose Development/Moose/Ops/FlightGroup.lua index b4b3e0ce9..77dbfa768 100644 --- a/Moose Development/Moose/Ops/FlightGroup.lua +++ b/Moose Development/Moose/Ops/FlightGroup.lua @@ -2184,7 +2184,7 @@ function FLIGHTGROUP:onafterRefuel(From, Event, To, Coordinate) local wp0=coordinate:WaypointAir("BARO", COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint, Speed, true) local wp9=Coordinate:WaypointAir("BARO", COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint, Speed, true, nil, DCSTasks, "Refuel") - self:Route({wp0, wp9}) + self:Route({wp0, wp9}, 1) end diff --git a/Moose Development/Moose/Ops/OpsGroup.lua b/Moose Development/Moose/Ops/OpsGroup.lua index 14b8db4e8..e2cdffa2e 100644 --- a/Moose Development/Moose/Ops/OpsGroup.lua +++ b/Moose Development/Moose/Ops/OpsGroup.lua @@ -757,17 +757,12 @@ function OPSGROUP:GetWaypointIndexNext(cyclic) cyclic=self.adinfinitum end - --env.info("FF cyclic = "..tostring(cyclic)) - local N=#self.waypoints local n=math.min(self.currentwp+1, N) - --env.info("FF n = "..tostring(n)) - if cyclic and self.currentwp==N then n=1 - --env.info("FF cyclic n = "..tostring(n)) end return n