diff --git a/Moose Development/Moose/Ops/Auftrag.lua b/Moose Development/Moose/Ops/Auftrag.lua index a58e933ff..1b3b11a74 100644 --- a/Moose Development/Moose/Ops/Auftrag.lua +++ b/Moose Development/Moose/Ops/Auftrag.lua @@ -93,6 +93,7 @@ -- @field #number engageWeaponType Weapon type used. -- @field #number engageWeaponExpend How many weapons are used. -- @field #boolean engageAsGroup Group attack. +-- @field #number engageLength Length of engage (carpet or strafing) in meters. -- @field #number engageMaxDistance Max engage distance. -- @field #number refuelSystem Refuel type (boom or probe) for TANKER missions. -- @@ -239,6 +240,10 @@ -- ## Bombing Carpet -- -- A carpet bombing mission can be created with the @{#AUFTRAG.NewBOMBCARPET}() function. +-- +-- ## Strafing +-- +-- A strafing mission can be created with the @{#AUFTRAG.NewSTRAFING}() function. -- -- ## CAP -- @@ -445,6 +450,7 @@ _AUFTRAGSNR=0 -- @field #string CAPTUREZONE Capture zone mission. -- @field #string NOTHING Nothing. -- @field #string PATROLRACETRACK Patrol Racetrack. +-- @field #string STRAFING Strafing run. AUFTRAG.Type={ ANTISHIP="Anti Ship", AWACS="AWACS", @@ -491,6 +497,7 @@ AUFTRAG.Type={ CAPTUREZONE="Capture Zone", NOTHING="Nothing", PATROLRACETRACK="Patrol Racetrack", + STRAFING="Strafing", } --- Special task description. @@ -1738,6 +1745,7 @@ function AUFTRAG:NewSTRIKE(Target, Altitude) end --- **[AIR]** Create a BOMBING mission. Flight will drop bombs a specified coordinate. +-- See [DCS task bombing](https://wiki.hoggitworld.com/view/DCS_task_bombing). -- @param #AUFTRAG self -- @param Core.Point#COORDINATE Target Target coordinate. Can also be specified as a GROUP, UNIT, STATIC or TARGET object. -- @param #number Altitude Engage altitude in feet. Default 25000 ft. @@ -1771,6 +1779,44 @@ function AUFTRAG:NewBOMBING(Target, Altitude) return mission end +--- **[AIR]** Create a STRAFING mission. Assigns a point on the ground for which the AI will do a strafing run with guns or rockets. +-- See [DCS task strafing](https://wiki.hoggitworld.com/view/DCS_task_strafing). +-- @param #AUFTRAG self +-- @param Core.Point#COORDINATE Target Target coordinate. Can also be specified as a GROUP, UNIT, STATIC or TARGET object. +-- @param #number Altitude Engage altitude in feet. Default 1000 ft. +-- @param #number Length The total length of the strafing target in meters. Default `nil`. +-- @return #AUFTRAG self +function AUFTRAG:NewSTRAFING(Target, Altitude, Length) + + local mission=AUFTRAG:New(AUFTRAG.Type.STRAFING) + + mission:_TargetFromObject(Target) + + -- DCS task options: + mission.engageWeaponType=805337088 -- Corresponds to guns/cannons (805306368) + any rocket (30720). This is the default when selecting this task in the ME. + mission.engageWeaponExpend=AI.Task.WeaponExpend.ALL + mission.engageAltitude=UTILS.FeetToMeters(Altitude or 1000) + mission.engageLength=Length + + -- Mission options: + mission.missionTask=ENUMS.MissionTask.GROUNDATTACK + mission.missionAltitude=mission.engageAltitude*0.8 + mission.missionFraction=0.5 + mission.optionROE=ENUMS.ROE.OpenFire + mission.optionROT=ENUMS.ROT.NoReaction -- No reaction is better. + + -- Evaluate result after 5 min. We might need time until the bombs have dropped and targets have been detroyed. + mission.dTevaluate=5*60 + + mission.categories={AUFTRAG.Category.AIRCRAFT} + + -- Get DCS task. + mission.DCStask=mission:GetDCSMissionTask() + + return mission +end + + --- **[AIR]** Create a BOMBRUNWAY mission. -- @param #AUFTRAG self -- @param Wrapper.Airbase#AIRBASE Airdrome The airbase to bomb. This must be an airdrome (not a FARP or ship) as these to not have a runway. @@ -1825,7 +1871,7 @@ function AUFTRAG:NewBOMBCARPET(Target, Altitude, CarpetLength) mission.engageWeaponType=ENUMS.WeaponFlag.Auto mission.engageWeaponExpend=AI.Task.WeaponExpend.ALL mission.engageAltitude=UTILS.FeetToMeters(Altitude or 25000) - mission.engageCarpetLength=CarpetLength or 500 + mission.engageLength=CarpetLength or 500 mission.engageAsGroup=false -- Looks like this must be false or the task is not executed. It is not available in the ME anyway but in the task of the mission file. mission.engageDirection=nil -- This is also not available in the ME. @@ -2615,6 +2661,8 @@ function AUFTRAG:NewFromTarget(Target, MissionType) mission=self:NewBOMBING(Target, Altitude) elseif MissionType==AUFTRAG.Type.BOMBRUNWAY then mission=self:NewBOMBRUNWAY(Target, Altitude) + elseif MissionType==AUFTRAG.Type.STRAFING then + mission=self:NewSTRAFING(Target, Altitude) elseif MissionType==AUFTRAG.Type.CAS then mission=self:NewCAS(ZONE_RADIUS:New(Target:GetName(),Target:GetVec2(),1000), Altitude, Speed, Target:GetAverageCoordinate(), Heading, Leg, TargetTypes) elseif MissionType==AUFTRAG.Type.CASENHANCED then @@ -5956,6 +6004,16 @@ function AUFTRAG:GetDCSMissionTask() local DCStask=CONTROLLABLE.TaskBombing(nil, self:GetTargetVec2(), self.engageAsGroup, self.engageWeaponExpend, self.engageQuantity, self.engageDirection, self.engageAltitude, self.engageWeaponType, Divebomb) table.insert(DCStasks, DCStask) + + elseif self.type==AUFTRAG.Type.STRAFING then + + ---------------------- + -- STRAFING Mission -- + ---------------------- + + local DCStask=CONTROLLABLE.TaskStrafing(nil,self:GetTargetVec2(), self.engageQuantity, self.engageLength,self.engageWeaponType,self.engageWeaponExpend,self.engageDirection,self.engageAsGroup) + + table.insert(DCStasks, DCStask) elseif self.type==AUFTRAG.Type.BOMBRUNWAY then @@ -5973,7 +6031,7 @@ function AUFTRAG:GetDCSMissionTask() -- BOMBCARPET Mission -- ------------------------ - local DCStask=CONTROLLABLE.TaskCarpetBombing(nil, self:GetTargetVec2(), self.engageAsGroup, self.engageWeaponExpend, self.engageQuantity, self.engageDirection, self.engageAltitude, self.engageWeaponType, self.engageCarpetLength) + local DCStask=CONTROLLABLE.TaskCarpetBombing(nil, self:GetTargetVec2(), self.engageAsGroup, self.engageWeaponExpend, self.engageQuantity, self.engageDirection, self.engageAltitude, self.engageWeaponType, self.engageLength) table.insert(DCStasks, DCStask) diff --git a/Moose Development/Moose/Ops/NavyGroup.lua b/Moose Development/Moose/Ops/NavyGroup.lua index 585b39d98..499ca6b12 100644 --- a/Moose Development/Moose/Ops/NavyGroup.lua +++ b/Moose Development/Moose/Ops/NavyGroup.lua @@ -44,6 +44,7 @@ -- @field #number pathCorridor Path corrdidor width in meters. -- @field #boolean ispathfinding If true, group is currently path finding. -- @field #NAVYGROUP.Target engage Engage target. +-- @field #boolean intowindold Use old calculation to determine heading into wind. -- @extends Ops.OpsGroup#OPSGROUP --- *Something must be left to chance; nothing is sure in a sea fight above all.* -- Horatio Nelson @@ -456,6 +457,18 @@ function NAVYGROUP:SetPathfindingOff() return self end +--- Set if old into wind calculation is used when carrier turns into the wind for a recovery. +-- @param #NAVYGROUP self +-- @param #boolean SwitchOn If `true` or `nil`, use old into wind calculation. +-- @return #NAVYGROUP self +function NAVYGROUP:SetIntoWindLegacy( SwitchOn ) + if SwitchOn==nil then + SwitchOn=true + end + self.intowindold=SwitchOn + return self +end + --- Add a *scheduled* task. -- @param #NAVYGROUP self @@ -601,6 +614,58 @@ function NAVYGROUP:AddTurnIntoWind(starttime, stoptime, speed, uturn, offset) return recovery end +--- Get "Turn Into Wind" data. You can specify a certain ID. +-- @param #NAVYGROUP self +-- @param #number TID (Optional) Turn Into wind ID. If not given, the currently open "Turn into Wind" data is return (if there is any). +-- @return #NAVYGROUP.IntoWind Turn into window data table. +function NAVYGROUP:GetTurnIntoWind(TID) + + if TID then + + -- Look for a specific ID. + for _,_turn in pairs(self.Qintowind) do + local turn=_turn --#NAVYGROUP.IntoWind + if turn.Id==TID then + return turn + end + end + + else + + -- Return currently open window. + return self.intowind + + end + + return nil +end + +--- Extend duration of turn into wind. +-- @param #NAVYGROUP self +-- @param #number Duration Duration in seconds. Default 300 sec. +-- @param #NAVYGROUP.IntoWind TurnIntoWind (Optional) Turn into window data table. If not given, the currently open one is used (if there is any). +-- @return #NAVYGROUP self +function NAVYGROUP:ExtendTurnIntoWind(Duration, TurnIntoWind) + + Duration=Duration or 300 + + -- ID of turn or nil + local TID=TurnIntoWind and TurnIntoWind.Id or nil + + -- Get turn data. + local turn=self:GetTurnIntoWind(TID) + + if turn then + turn.Tstop=turn.Tstop+Duration + self:T(self.lid..string.format("Extending turn into wind by %d seconds. New stop time is %s", Duration, UTILS.SecondsToClock(turn.Tstop))) + else + self:E(self.lid.."Could not get turn into wind to extend!") + end + + return self +end + + --- Remove steam into wind window from queue. If the window is currently active, it is stopped first. -- @param #NAVYGROUP self -- @param #NAVYGROUP.IntoWind IntoWindData Turn into window data table. @@ -2069,8 +2134,43 @@ end --- Get heading of group into the wind. -- @param #NAVYGROUP self -- @param #number Offset Offset angle in degrees, e.g. to account for an angled runway. +-- @param #number vdeck Desired wind speed on deck in Knots. -- @return #number Carrier heading in degrees. -function NAVYGROUP:GetHeadingIntoWind_old(Offset) +-- @return #number Carrier speed in knots. +function NAVYGROUP:GetHeadingIntoWind_old(Offset, vdeck) + + local function adjustDegreesForWindSpeed(windSpeed) + local degreesAdjustment = 0 + -- the windspeeds are in m/s + -- +0 degrees at 15m/s = 37kts + -- +0 degrees at 14m/s = 35kts + -- +0 degrees at 13m/s = 33kts + -- +4 degrees at 12m/s = 31kts + -- +4 degrees at 11m/s = 29kts + -- +4 degrees at 10m/s = 27kts + -- +4 degrees at 9m/s = 27kts + -- +4 degrees at 8m/s = 27kts + -- +8 degrees at 7m/s = 27kts + -- +8 degrees at 6m/s = 27kts + -- +8 degrees at 5m/s = 26kts + -- +20 degrees at 4m/s = 26kts + -- +20 degrees at 3m/s = 26kts + -- +30 degrees at 2m/s = 26kts 1s + + if windSpeed > 0 and windSpeed < 3 then + degreesAdjustment = 30 + elseif windSpeed >= 3 and windSpeed < 5 then + degreesAdjustment = 20 + elseif windSpeed >= 5 and windSpeed < 8 then + degreesAdjustment = 8 + elseif windSpeed >= 8 and windSpeed < 13 then + degreesAdjustment = 4 + elseif windSpeed >= 13 then + degreesAdjustment = 0 + end + + return degreesAdjustment + end Offset=Offset or 0 @@ -2078,7 +2178,7 @@ function NAVYGROUP:GetHeadingIntoWind_old(Offset) local windfrom, vwind=self:GetWind() -- Actually, we want the runway in the wind. - local intowind=windfrom-Offset + local intowind = windfrom - Offset + adjustDegreesForWindSpeed(vwind) -- If no wind, take current heading. if vwind<0.1 then @@ -2089,8 +2189,11 @@ function NAVYGROUP:GetHeadingIntoWind_old(Offset) if intowind<0 then intowind=intowind+360 end + + -- Speed of carrier in m/s but at least 4 knots. + local vtot = math.max(vdeck-UTILS.MpsToKnots(vwind), 4) - return intowind + return intowind, vtot end @@ -2100,7 +2203,8 @@ end -- @param #number Offset Offset angle in degrees, e.g. to account for an angled runway. -- @param #number vdeck Desired wind speed on deck in Knots. -- @return #number Carrier heading in degrees. -function NAVYGROUP:GetHeadingIntoWind(Offset, vdeck) +-- @return #number Carrier speed in knots. +function NAVYGROUP:GetHeadingIntoWind_new(Offset, vdeck) -- Default offset angle. Offset=Offset or 0 @@ -2181,6 +2285,25 @@ function NAVYGROUP:GetHeadingIntoWind(Offset, vdeck) return intowind, v end +--- Get heading of group into the wind. This minimizes the cross wind for an angled runway. +-- Implementation based on [Mags & Bami](https://magwo.github.io/carrier-cruise/) work. +-- @param #NAVYGROUP self +-- @param #number Offset Offset angle in degrees, e.g. to account for an angled runway. +-- @param #number vdeck Desired wind speed on deck in Knots. +-- @return #number Carrier heading in degrees. +-- @return #number Carrier speed in knots. +function NAVYGROUP:GetHeadingIntoWind(Offset, vdeck) + + if self.intowindold then + --env.info("FF use OLD into wind") + return self:GetHeadingIntoWind_old(Offset, vdeck) + else + --env.info("FF use NEW into wind") + return self:GetHeadingIntoWind_new(Offset, vdeck) + end + +end + --- Find free path to next waypoint. -- @param #NAVYGROUP self diff --git a/Moose Development/Moose/Wrapper/Controllable.lua b/Moose Development/Moose/Wrapper/Controllable.lua index a891a7ca6..e0b63e914 100644 --- a/Moose Development/Moose/Wrapper/Controllable.lua +++ b/Moose Development/Moose/Wrapper/Controllable.lua @@ -1148,10 +1148,10 @@ function CONTROLLABLE:TaskStrafing( Vec2, AttackQty, Length, WeaponType, WeaponE id = 'Strafing', params = { point = Vec2, -- req - weaponType = WeaponType or 1073741822, + weaponType = WeaponType or 805337088, -- Default 805337088 corresponds to guns/cannons (805306368) + any rocket (30720). You can set other types but then the AI uses even bombs for a strafing run! expend = WeaponExpend or "Auto", attackQty = AttackQty or 1, -- req - attackQtyLimit = AttackQty >1 and true or false, + attackQtyLimit = AttackQty~=nil and true or false, direction = Direction and math.rad(Direction) or 0, directionEnabled = Direction and true or false, groupAttack = GroupAttack or false,