RECOVERYTANKER v0.9.9

RESCUEHELO v0.9.8
This commit is contained in:
Frank
2018-12-16 16:59:53 +01:00
parent 1559f14f11
commit d576573cf8
6 changed files with 205 additions and 179 deletions

View File

@@ -1052,7 +1052,7 @@ do -- COORDINATE
self:T("ERROR: Unknown airbase category in COORDINATE:WaypointAir()!") self:T("ERROR: Unknown airbase category in COORDINATE:WaypointAir()!")
end end
self:MarkToAll(string.format("Landing waypoint at airbase %s", airbase:GetName())) --self:MarkToAll(string.format("Landing waypoint at airbase %s", airbase:GetName()))
end end
-- Waypoint tasks. -- Waypoint tasks.

View File

@@ -35,7 +35,7 @@
-- === -- ===
-- --
-- @module Functional.Warehouse -- @module Functional.Warehouse
-- @image MOOSE.JPG -- @image Warehouse.JPG
--- WAREHOUSE class. --- WAREHOUSE class.
-- @type WAREHOUSE -- @type WAREHOUSE

View File

@@ -390,9 +390,9 @@
-- --
-- # AI Handling -- # AI Handling
-- --
-- The implementation allows to handle incoming AI units and integrate them into the marshal and landing pattern. -- The AIRBOSS class allows to handle incoming AI units and integrate them into the marshal and landing pattern.
-- --
-- By default, incoming carrier capable aircraft which are detecting inside the CCZ and approach the carrier by more than 5 NM are automatically guided to the holding zone. -- By default, incoming carrier capable aircraft which are detecting inside the CCZ and approach the carrier by more than 10 NM are automatically guided to the holding zone.
-- Each AI group gets its own marshal stack in the holding pattern. Once a recovery window opens, the AI group of the lowest stack is transitioning to the landing pattern -- Each AI group gets its own marshal stack in the holding pattern. Once a recovery window opens, the AI group of the lowest stack is transitioning to the landing pattern
-- and the Marshal stack collapses. -- and the Marshal stack collapses.
-- --
@@ -1767,9 +1767,11 @@ function AIRBOSS:_CheckAIStatus()
-- Pilot: "405, Hornet Ball, 3.2" -- Pilot: "405, Hornet Ball, 3.2"
-- TODO: Voice over. -- TODO: Voice over.
local text=string.format("%s Ball, %.1f.", self:_GetACNickname(unit:GetTypeName()), self:_GetFuelState(unit)/1000) local text=string.format("%s Ball, %.1f.", self:_GetACNickname(unit:GetTypeName()), self:_GetFuelState(unit)/1000)
self:MessageToPattern(text, element.onboard, "", 3, false, 0, true) self:MessageToPattern(text, element.onboard, "", 3, false, 0, true)
MESSAGE:New(text, 15):ToAll()
-- Debug message.
MESSAGE:New(string.format("%s, %s", element.onboard..text), 15, "DEBUG"):ToAllIf(self.Debug)
-- Paddles: Roger ball after 3 seconds. -- Paddles: Roger ball after 3 seconds.
self:RadioTransmission(self.LSORadio, AIRBOSS.LSOCall.ROGERBALL, false, 3) self:RadioTransmission(self.LSORadio, AIRBOSS.LSOCall.ROGERBALL, false, 3)
@@ -2749,13 +2751,13 @@ function AIRBOSS:_ScanCarrierZone()
-- Debug info. -- Debug info.
self:T3(self.lid..string.format("Known AI flight group %s closed in by %.1f NM", knownflight.groupname, UTILS.MetersToNM(closein))) self:T3(self.lid..string.format("Known AI flight group %s closed in by %.1f NM", knownflight.groupname, UTILS.MetersToNM(closein)))
-- Send AI flight to marshal stack if group closes in more than 2.5 and has initial flag value. -- Send AI flight to marshal stack if group closes in more than 5 and has initial flag value.
if closein>UTILS.NMToMeters(2.5) and knownflight.flag:Get()==-100 then if closein>UTILS.NMToMeters(5) and knownflight.flag:Get()==-100 then
-- Check that we do not add a recovery tanker for marshaling. -- Check that we do not add a recovery tanker for marshaling.
if self.tanker and self.tanker.tanker:GetName()==groupname then if self.tanker and self.tanker.tanker:GetName()==groupname then
-- Don't touch the recovery thanker! -- Don't touch the recovery tanker!
else else
@@ -2788,7 +2790,7 @@ function AIRBOSS:_ScanCarrierZone()
end end
end end
-- Remove flight groups. -- Remove flight groups outside CCA.
for _,group in pairs(remove) do for _,group in pairs(remove) do
self:_RemoveFlightGroup(group) self:_RemoveFlightGroup(group)
end end
@@ -5152,17 +5154,20 @@ end
-- @param #number dx Correction. -- @param #number dx Correction.
function AIRBOSS:_GetWire(Ccoord, Lcoord, dx) function AIRBOSS:_GetWire(Ccoord, Lcoord, dx)
-- Heading of carrier (true).
local hdg=self.carrier:GetHeading() local hdg=self.carrier:GetHeading()
-- Stern coordinate (sterndist<0) -- Final bearing (true).
local Scoord=Ccoord:Translate(self.carrierparam.sterndist, hdg) local FB=self:GetFinalBearing()
-- Distance to landing coord -- Stern coordinate (sterndist<0). Also translate 10 meters starboard wrt Final bearing.
local Scoord=Ccoord:Translate(self.carrierparam.sterndist, hdg):Translate(10, FB+90)
-- Distance to landing coord.
local Ldist=Lcoord:Get2DDistance(Scoord) local Ldist=Lcoord:Get2DDistance(Scoord)
-- Little offset for the exact wire positions. -- Little offset for the exact wire positions.
dx=dx or self.carrierparam.wireoffset -- TODO: Maybe add little offset depending on aircraft type.
dx=self.carrierparam.wireoffset dx=self.carrierparam.wireoffset
-- Corrected distance. -- Corrected distance.
@@ -5183,8 +5188,7 @@ function AIRBOSS:_GetWire(Ccoord, Lcoord, dx)
end end
if self.Debug then if self.Debug then
local FB=self:GetFinalBearing(false)
local w1=Scoord:Translate(self.carrierparam.wire1+self.carrierparam.wireoffset, FB) local w1=Scoord:Translate(self.carrierparam.wire1+self.carrierparam.wireoffset, FB)
local w2=Scoord:Translate(self.carrierparam.wire2+self.carrierparam.wireoffset, FB) local w2=Scoord:Translate(self.carrierparam.wire2+self.carrierparam.wireoffset, FB)
local w3=Scoord:Translate(self.carrierparam.wire3+self.carrierparam.wireoffset, FB) local w3=Scoord:Translate(self.carrierparam.wire3+self.carrierparam.wireoffset, FB)
@@ -7485,16 +7489,15 @@ function AIRBOSS:_AddF10Commands(_unitName)
-- Get group and ID. -- Get group and ID.
local group=_unit:GetGroup() local group=_unit:GetGroup()
local gid=group:GetID() local gid=group:GetID()
-- Player Data. if group and gid then
local playerData=self.players[playername]
if group and gid and playerData then
if not self.menuadded[gid] then if not self.menuadded[gid] then
-- Enable switch so we don't do this twice. -- Enable switch so we don't do this twice.
self.menuadded[gid]=true self.menuadded[gid]=true
env.info("FF menu")
-- Main F10 menu: F10/Airboss/<Carrier Name>/ -- Main F10 menu: F10/Airboss/<Carrier Name>/
if AIRBOSS.MenuF10[gid]==nil then if AIRBOSS.MenuF10[gid]==nil then
@@ -7551,10 +7554,10 @@ function AIRBOSS:_AddF10Commands(_unitName)
missionCommands.addCommandForGroup(gid, "Request Refueling", _rootPath, self._RequestRefueling, self, _unitName) -- F5 missionCommands.addCommandForGroup(gid, "Request Refueling", _rootPath, self._RequestRefueling, self, _unitName) -- F5
end end
else else
self:T(self.lid.."Could not find group or group ID in AddF10Menu() function. Unit name: ".._unitName) self:E(self.lid..string.format("ERROR: Could not find group or group ID in AddF10Menu() function. Unit name: %s.", _unitName))
end end
else else
self:T(self.lid.."Player unit does not exist in AddF10Menu() function. Unit name: ".._unitName) self:E(self.lid..string.format("ERROR: Player unit does not exist in AddF10Menu() function. Unit name: %s.", _unitName))
end end
end end
@@ -7712,12 +7715,7 @@ function AIRBOSS:_RequestCommence(_unitName)
local text local text
if _unit:IsInZone(self.zoneCCA) then if _unit:IsInZone(self.zoneCCA) then
if self:_InQueue(self.Qmarshal, playerData.group) then if self:_InQueue(self.Qpattern, playerData.group) then
-- Flight group is already in marhal queue.
text=string.format("%s, you are already in the Marshal queue. Commence request denied!", playerData.name)
elseif self:_InQueue(self.Qpattern, playerData.group) then
-- Flight group is already in pattern queue. -- Flight group is already in pattern queue.
text=string.format("%s, you are already in the Pattern queue. Commence request denied!", playerData.name) text=string.format("%s, you are already in the Pattern queue. Commence request denied!", playerData.name)
@@ -7742,10 +7740,13 @@ function AIRBOSS:_RequestCommence(_unitName)
local _,npattern=self:_GetQueueInfo(self.Qpattern) local _,npattern=self:_GetQueueInfo(self.Qpattern)
-- Check if pattern is already full. -- Check if pattern is already full.
if npattern>=self.Nmaxpattern then if npattern>=self.Nmaxpattern then
-- Patern is full! -- Patern is full!
text=string.format("Negative ghostrider, pattern is full!\nThere are %d aircraft currently in the pattern.", npattern) text=string.format("Negative ghostrider, pattern is full!\nThere are %d aircraft currently in the pattern.", npattern)
else else
-- Positive response. -- Positive response.
if playerData.case==1 then if playerData.case==1 then
text="Proceed to initial." text="Proceed to initial."
@@ -7861,9 +7862,9 @@ function AIRBOSS:_SetSection(_unitName)
-- Check if player is in Marshal or pattern queue already. -- Check if player is in Marshal or pattern queue already.
local text local text
if self:_InQueue(self.Qmarshal,playerData.group) then if self:_InQueue(self.Qmarshal,playerData.group) then
text=string.format("You are already in the Marshal queue. Setting section no possible any more!") text=string.format("You are already in the Marshal queue. Setting section not possible any more!")
elseif self:_InQueue(self.Qpattern, playerData.group) then elseif self:_InQueue(self.Qpattern, playerData.group) then
text=string.format("You are already in the Pattern queue. Setting section no possible any more!") text=string.format("You are already in the Pattern queue. Setting section not possible any more!")
else else
-- Init array -- Init array

View File

@@ -1,14 +1,15 @@
--- **Ops** - (R2.5) - Carrier recovery tanker. --- **Ops** - (R2.5) - Recovery tanker for carrier operations.
-- --
-- Tanker aircraft flying a racetrack pattern overhead an aircraft carrier. -- Tanker aircraft flying a racetrack pattern overhead an aircraft carrier.
-- --
-- **Main Features:** -- **Main Features:**
-- --
-- * Regular pattern update with respect to carrier positon. -- * Regular pattern update with respect to carrier positon.
-- * No restrictions regarding carrier waypoints and heading.
-- * Automatic respawning when tanker runs out of fuel for 24/7 operations. -- * Automatic respawning when tanker runs out of fuel for 24/7 operations.
-- * Tanker can be spawned cold or hot on the carrier or at any other airbase or directly in air. -- * Tanker can be spawned cold or hot on the carrier or at any other airbase or directly in air.
-- * Automatic AA TACAN beacon setting. -- * Automatic AA TACAN beacon setting.
-- * Multiple tanker at different carriers due to object oriented approach. -- * Multiple tankers at different carriers due to object oriented approach.
-- * Finite State Machine (FSM) implementation, which allows the mission designer to hook into certain events. -- * Finite State Machine (FSM) implementation, which allows the mission designer to hook into certain events.
-- --
-- === -- ===
@@ -36,8 +37,8 @@
-- @field #boolean TACANon If true, TACAN is automatically activated. If false, TACAN is disabled. -- @field #boolean TACANon If true, TACAN is automatically activated. If false, TACAN is disabled.
-- @field #number speed Tanker speed when flying pattern. -- @field #number speed Tanker speed when flying pattern.
-- @field #number altitude Tanker orbit pattern altitude. -- @field #number altitude Tanker orbit pattern altitude.
-- @field #number distStern Race-track distance astern. -- @field #number distStern Race-track distance astern. distStern is <0.
-- @field #number distBow Race-track distance bow. -- @field #number distBow Race-track distance bow. distBow is >0.
-- @field #number Dupdate Pattern update when carrier changes its position by more than this distance (meters). -- @field #number Dupdate Pattern update when carrier changes its position by more than this distance (meters).
-- @field #number Hupdate Pattern update when carrier changes its heading by more than this number (degrees). -- @field #number Hupdate Pattern update when carrier changes its heading by more than this number (degrees).
-- @field #number dTupdate Minimum time interval in seconds before the next pattern update can happen. -- @field #number dTupdate Minimum time interval in seconds before the next pattern update can happen.
@@ -50,18 +51,17 @@
-- @field DCS#Vec3 orientation Orientation of the carrier. Used to monitor changes and update the pattern if heading changes significantly. -- @field DCS#Vec3 orientation Orientation of the carrier. Used to monitor changes and update the pattern if heading changes significantly.
-- @field DCS#Vec3 orientlast Orientation of the carrier for checking if carrier is currently turning. -- @field DCS#Vec3 orientlast Orientation of the carrier for checking if carrier is currently turning.
-- @field Core.Point#COORDINATE position Positon of carrier. Used to monitor if carrier significantly changed its position and then update the tanker pattern. -- @field Core.Point#COORDINATE position Positon of carrier. Used to monitor if carrier significantly changed its position and then update the tanker pattern.
-- @field Core.Zone#ZONE_UNIT zoneUpdate Moving zone relative to carrier. Each time the tanker is in this zone, its pattern is updated.
-- @extends Core.Fsm#FSM -- @extends Core.Fsm#FSM
--- Recovery Tanker. --- Recovery Tanker.
-- --
-- === -- ===
-- --
-- ![Banner Image](..\Presentations\RECOVERYTANKER\RecoveryTanker_Main.jpg) -- ![Banner Image](..\Presentations\RECOVERYTANKER\RecoveryTanker_Main.png)
-- --
-- # Recovery Tanker -- # Recovery Tanker
-- --
-- A recovery tanker acts as refueling unit flying overhead an aircraft carrier in order to supply incoming flights with gas if they go "Bingo on the Ball". -- A recovery tanker acts as refueling unit flying overhead an aircraft carrier in order to supply incoming flights with gas if they go "*Bingo on the Ball*".
-- --
-- # Simple Script -- # Simple Script
-- --
@@ -76,18 +76,25 @@
-- --
-- The first line will create a new RECOVERYTANKER object and the second line starts the process. -- The first line will create a new RECOVERYTANKER object and the second line starts the process.
-- --
-- With this setup, the tanker will be spawned on the USS Stennis with running engines. After it takes off, it will fly a position astern of the boat and from there start its -- With this setup, the tanker will be spawned on the USS Stennis with running engines. After it takes off, it will fly a position ~10 NM astern of the boat and from there start its
-- pattern. This is a counter clockwise racetrack pattern at angels 6. -- pattern. This is a counter clockwise racetrack pattern at angels 6.
-- --
-- A TACAN beacon will be automatically activated at channel 1Y with morse code "TKR". See below how to change this setting.
--
-- Note that the Tanker entry in the F10 radio menu will appear once the tanker is on station and not before. If you spawn the tanker cold or hot on the carrier, this will take ~10 minutes.
--
-- Also note, that currently the only carrier capable aircraft in DCS is the S-3B Viking (tanker version). If you want to use another refueling aircraft, you need to activate air spawn
-- or set a different land based airport of the map. This will be explained below.
--
-- ![Banner Image](..\Presentations\RECOVERYTANKER\RecoveryTanker_Pattern.jpg) -- ![Banner Image](..\Presentations\RECOVERYTANKER\RecoveryTanker_Pattern.jpg)
-- --
-- The "downwind" leg of the pattern is normally used for refueling. -- The "downwind" leg of the pattern is normally used for refueling.
-- --
-- Once the tanker runs out of fuel itself, it will return to the carrier and be respawned. -- Once the tanker runs out of fuel itself, it will return to the carrier, respawn with full fuel and take up its pattern again.
-- --
-- # Options and Fine Tuning -- # Options and Fine Tuning
-- --
-- Several parameters can be customized by the mission designer. -- Several parameters can be customized by the mission designer via user API functions.
-- --
-- ## Takeoff Type -- ## Takeoff Type
-- --
@@ -96,7 +103,7 @@
-- --
-- * @{#RECOVERYTANKER.SetTakeoffHot}(): Will set the takeoff to hot, which is also the default. -- * @{#RECOVERYTANKER.SetTakeoffHot}(): Will set the takeoff to hot, which is also the default.
-- * @{#RECOVERYTANKER.SetTakeoffCold}(): Will set the takeoff type to cold, i.e. with engines off. -- * @{#RECOVERYTANKER.SetTakeoffCold}(): Will set the takeoff type to cold, i.e. with engines off.
-- * @{#RECOVERYTANKER.SetTakeoffAir}(): Will set the takeoff type to air, i.e. the tanker will be spawned in air relatively far behind the carrier. -- * @{#RECOVERYTANKER.SetTakeoffAir}(): Will set the takeoff type to air, i.e. the tanker will be spawned in air ~10 NM astern the carrier.
-- --
-- For example, -- For example,
-- TexacoStennis=RECOVERYTANKER:New(UNIT:FindByName("USS Stennis"), "Texaco") -- TexacoStennis=RECOVERYTANKER:New(UNIT:FindByName("USS Stennis"), "Texaco")
@@ -118,8 +125,18 @@
-- The racetrack pattern parameters can be fine tuned via the following functions: -- The racetrack pattern parameters can be fine tuned via the following functions:
-- --
-- * @{#RECOVERYTANKER.SetAltitude}(*altitude*), where *altitude* is the pattern altitude in feet. Default 6000 ft. -- * @{#RECOVERYTANKER.SetAltitude}(*altitude*), where *altitude* is the pattern altitude in feet. Default 6000 ft.
-- * @{#RECOVERYTANKER.SetSpeed}(*speed*), where *speed* is the pattern speed in knots. Default is 272 knots. -- * @{#RECOVERYTANKER.SetSpeed}(*speed*), where *speed* is the pattern speed in knots. Default is 274 knots TAS which results in ~250 KIAS.
-- * @{#RECOVERYTANKER.SetRacetrackDistances}(*distbow*, *diststern*), where *distbow* and *diststern* are the distances ahead and astern the boat, respectively. -- * @{#RECOVERYTANKER.SetRacetrackDistances}(*distbow*, *diststern*), where *distbow* and *diststern* are the distances ahead and astern the boat (default 10 and 4 NM), respectively.
-- In principle, these number should be more like 8 and 6 NM but since the carrier is moving, we give translate the pattern points a bit forward.
--
-- ## Home Base
--
-- The home base is the airbase where the tanker is spawned (if not in air) and where it will go once it is running out of fuel. The default home base is the carrier itself.
-- The home base can be changed via the @{#RECOVERYTANKER.SetHomeBase}(*airbase*) function, where *airbase* can be a MOOSE @{Wrapper.Airbase#AIRBASE} object or simply the
-- name of the airbase passed as string.
--
-- Note that only the S3B Viking is a refueling aircraft that is carrier capable. You can use other tanker aircraft types, e.g. the KC-130, but in this case you must either
-- set an airport of the map as home base or activate spawning in air via @{#RECOVERYTANKER.SetTakeoffAir}.
-- --
-- ## TACAN -- ## TACAN
-- --
@@ -141,14 +158,14 @@
-- --
-- The pattern of the tanker is updated if at least one of the two following conditions apply: -- The pattern of the tanker is updated if at least one of the two following conditions apply:
-- --
-- * The aircraft carrier changes its position by more than ~10 km (see @{#RECOVERYTANKER.SetPatternUpdateDistance}) and/or -- * The aircraft carrier changes its position by more than 5 NM (see @{#RECOVERYTANKER.SetPatternUpdateDistance}) and/or
-- * The aircraft carrier changes its heading by more than 5 degrees (see @{#RECOVERYTANKER.SetPatternUpdateHeading}) -- * The aircraft carrier changes its heading by more than 5 degrees (see @{#RECOVERYTANKER.SetPatternUpdateHeading})
-- --
-- **Note** that updating the pattern always leads to a small disruption in the perfect racetrack pattern of the tanker. This is because a new waypoint and new racetrack points -- **Note** that updating the pattern often leads to a more or less small disruption of the perfect racetrack pattern of the tanker. This is because a new waypoint and new racetrack points
-- need to be set as DCS task. This is also the reason why the pattern is not contantly updated but rather when the position or heading of the carrier changes significantly. -- need to be set as DCS task. This is the reason why the pattern is not contantly updated but rather when the position or heading of the carrier changes significantly.
-- --
-- The maximum update frequency is set to 10 minutes. You can adjust this by @{#RECOVERYTANKER.SetPatternUpdateInterval}. -- The maximum update frequency is set to 10 minutes. You can adjust this by @{#RECOVERYTANKER.SetPatternUpdateInterval}.
-- Also the pattern will not be updated while the carrier is turning or the tanker is currently refuelling another unit. -- Also the pattern will not be updated whilst the carrier is turning or the tanker is currently refueling another unit.
-- --
-- # Finite State Machine -- # Finite State Machine
-- --
@@ -216,19 +233,18 @@ RECOVERYTANKER = {
orientation = nil, orientation = nil,
orientlast = nil, orientlast = nil,
position = nil, position = nil,
zoneUpdate = nil,
} }
--- Class version. --- Class version.
-- @field #string version -- @field #string version
RECOVERYTANKER.version="0.9.8" RECOVERYTANKER.version="0.9.9"
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list -- TODO list
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO: Seamless change of position update. Get good updated waypoint and update position if tanker position is right!
-- TODO: Is alive check for tanker necessary? -- TODO: Is alive check for tanker necessary?
-- DONE: Seamless change of position update. Get good updated waypoint and update position if tanker position is right. Not really possiple atm.
-- DONE: Check if TACAN mode "X" is allowed for AA TACAN stations. Nope -- DONE: Check if TACAN mode "X" is allowed for AA TACAN stations. Nope
-- DONE: Check if tanker is going back to "Running" state after RTB and respawn. -- DONE: Check if tanker is going back to "Running" state after RTB and respawn.
-- DONE: Write documenation. -- DONE: Write documenation.
@@ -275,7 +291,7 @@ function RECOVERYTANKER:New(carrierunit, tankergroupname)
-- Init default parameters. -- Init default parameters.
self:SetAltitude() self:SetAltitude()
self:SetSpeed() self:SetSpeed()
self:SetRacetrackDistances(6, 8) self:SetRacetrackDistances()
self:SetHomeBase(AIRBASE:FindByName(self.carrier:GetName())) self:SetHomeBase(AIRBASE:FindByName(self.carrier:GetName()))
self:SetTakeoffHot() self:SetTakeoffHot()
self:SetLowFuelThreshold() self:SetLowFuelThreshold()
@@ -285,10 +301,12 @@ function RECOVERYTANKER:New(carrierunit, tankergroupname)
self:SetPatternUpdateHeading() self:SetPatternUpdateHeading()
self:SetPatternUpdateInterval() self:SetPatternUpdateInterval()
-- Moving zone: Zone 1 NM astern the carrier with radius of 1 NM. --[[
--self.zoneUpdate=ZONE_UNIT:New("Pattern Update Zone", self.carrier, UTILS.NMToMeters(1), {dx=-UTILS.NMToMeters(1), dy=0, relative_to_unit=true}) BASE:TraceOnOff(true)
--self.zoneUpdate:SmokeZone(SMOKECOLOR.White, 45) BASE:TraceClass(self.ClassName)
BASE:TraceLevel(1)
]]
----------------------- -----------------------
--- FSM Transitions --- --- FSM Transitions ---
----------------------- -----------------------
@@ -421,10 +439,10 @@ end
--- Set the speed the tanker flys in its orbit pattern. --- Set the speed the tanker flys in its orbit pattern.
-- @param #RECOVERYTANKER self -- @param #RECOVERYTANKER self
-- @param #number speed Tanker speed in knots. Default 272 knots. -- @param #number speed True air speed (TAS) in knots. Default 274 knots, which results in ~250 KIAS.
-- @return #RECOVERYTANKER self -- @return #RECOVERYTANKER self
function RECOVERYTANKER:SetSpeed(speed) function RECOVERYTANKER:SetSpeed(speed)
self.speed=UTILS.KnotsToMps(speed or 272) self.speed=UTILS.KnotsToMps(speed or 274)
return self return self
end end
@@ -439,12 +457,12 @@ end
--- Set race-track distances. --- Set race-track distances.
-- @param #RECOVERYTANKER self -- @param #RECOVERYTANKER self
-- @param #number distbow Distance [NM] in front of the carrier. Default 6 NM. -- @param #number distbow Distance [NM] in front of the carrier. Default 10 NM.
-- @param #number diststern Distance [NM] behind the carrier. Default 8 NM. -- @param #number diststern Distance [NM] behind the carrier. Default 4 NM.
-- @return #RECOVERYTANKER self -- @return #RECOVERYTANKER self
function RECOVERYTANKER:SetRacetrackDistances(distbow, diststern) function RECOVERYTANKER:SetRacetrackDistances(distbow, diststern)
self.distBow=UTILS.NMToMeters(distbow or 6) self.distBow=UTILS.NMToMeters(distbow or 10)
self.distStern=-UTILS.NMToMeters(diststern or 8) self.distStern=-UTILS.NMToMeters(diststern or 4)
return self return self
end end
@@ -457,16 +475,16 @@ function RECOVERYTANKER:SetPatternUpdateInterval(interval)
return self return self
end end
--- Set pattern update distance. Tanker will update its pattern when the carrier changes its position by more than this distance. --- Set pattern update distance threshold. Tanker will update its pattern when the carrier changes its position by more than this distance.
-- @param #RECOVERYTANKER self -- @param #RECOVERYTANKER self
-- @param #number distancechange Distance threshold in km. Default 9.62 km (= 5 NM). -- @param #number distancechange Distance threshold in NM. Default 5 NM (=9.62 km).
-- @return #RECOVERYTANKER self -- @return #RECOVERYTANKER self
function RECOVERYTANKER:SetPatternUpdateDistance(distancechange) function RECOVERYTANKER:SetPatternUpdateDistance(distancechange)
self.Dupdate=(distancechange or 9.62)*1000 self.Dupdate=UTILS.NMToMeters(distancechange or 5)
return self return self
end end
--- Set pattern update heading. Tanker will update its pattern when the carrier changes its heading by more than this value. --- Set pattern update heading threshold. Tanker will update its pattern when the carrier changes its heading by more than this value.
-- @param #RECOVERYTANKER self -- @param #RECOVERYTANKER self
-- @param #number headingchange Heading threshold in degrees. Default 5 degrees. -- @param #number headingchange Heading threshold in degrees. Default 5 degrees.
-- @return #RECOVERYTANKER self -- @return #RECOVERYTANKER self
@@ -477,19 +495,26 @@ end
--- Set low fuel state of tanker. When fuel is below this threshold, the tanker will RTB or be respawned if takeoff type is in air. --- Set low fuel state of tanker. When fuel is below this threshold, the tanker will RTB or be respawned if takeoff type is in air.
-- @param #RECOVERYTANKER self -- @param #RECOVERYTANKER self
-- @param #number fuelthreshold Low fuel threshold in percent. Default 10 %. -- @param #number fuelthreshold Low fuel threshold in percent. Default 10 % of max fuel.
-- @return #RECOVERYTANKER self -- @return #RECOVERYTANKER self
function RECOVERYTANKER:SetLowFuelThreshold(fuelthreshold) function RECOVERYTANKER:SetLowFuelThreshold(fuelthreshold)
self.lowfuel=fuelthreshold or 10 self.lowfuel=fuelthreshold or 10
return self return self
end end
--- Set home airbase of the tanker. Default is the carrier. --- Set home airbase of the tanker. This is the airbase where the tanker will go when it is out of fuel.
-- @param #RECOVERYTANKER self -- @param #RECOVERYTANKER self
-- @param Wrapper.Airbase#AIRBASE airbase -- @param Wrapper.Airbase#AIRBASE airbase The home airbase. Can be the airbase name or a Moose AIRBASE object.
-- @return #RECOVERYTANKER self -- @return #RECOVERYTANKER self
function RECOVERYTANKER:SetHomeBase(airbase) function RECOVERYTANKER:SetHomeBase(airbase)
self.airbase=airbase if type(airbase)=="string" then
self.airbase=AIRBASE:FindByName(airbase)
else
self.airbase=airbase
end
if not self.airbase then
self:E(self.lid.."ERROR: Airbase is nil!")
end
return self return self
end end
@@ -518,7 +543,7 @@ function RECOVERYTANKER:SetTakeoffCold()
return self return self
end end
--- Set takeoff in air at the defined pattern altitude and 20 NM astern the carrier. --- Set takeoff in air at the defined pattern altitude and ~10 NM astern the carrier.
-- @param #RECOVERYTANKER self -- @param #RECOVERYTANKER self
-- @return #RECOVERYTANKER self -- @return #RECOVERYTANKER self
function RECOVERYTANKER:SetTakeoffAir() function RECOVERYTANKER:SetTakeoffAir()
@@ -566,7 +591,7 @@ function RECOVERYTANKER:SetRespawnInAir()
end end
--- Use an uncontrolled aircraft already present in the mission rather than spawning a new tanker as initial recovery thanker. --- Use an uncontrolled aircraft already present in the mission rather than spawning a new tanker as initial recovery thanker.
-- This can be useful when interfaced with, e.g., a warehouse. -- This can be useful when interfaced with, e.g., a MOOSE @{Functional.Warehouse#WAREHOUSE}.
-- The group name is the one specified in the @{#RECOVERYTANKER.New} function. -- The group name is the one specified in the @{#RECOVERYTANKER.New} function.
-- @param #RECOVERYTANKER self -- @param #RECOVERYTANKER self
-- @return #RECOVERYTANKER self -- @return #RECOVERYTANKER self
@@ -597,7 +622,7 @@ function RECOVERYTANKER:SetTACAN(channel, morse)
return self return self
end end
--- Activate debug mode. Marks of pattern on F10 map etc. --- Activate debug mode. Marks of pattern on F10 map and debug messages displayed on screen.
-- @param #RECOVERYTANKER self -- @param #RECOVERYTANKER self
-- @return #RECOVERYTANKER self -- @return #RECOVERYTANKER self
function RECOVERYTANKER:SetDebugModeON() function RECOVERYTANKER:SetDebugModeON()
@@ -660,8 +685,11 @@ function RECOVERYTANKER:onafterStart(From, Event, To)
self:HandleEvent(EVENTS.Refueling, self._RefuelingStart) --Need explcit functions sice OnEventRefueling and OnEventRefuelingStop did not hook. self:HandleEvent(EVENTS.Refueling, self._RefuelingStart) --Need explcit functions sice OnEventRefueling and OnEventRefuelingStop did not hook.
self:HandleEvent(EVENTS.RefuelingStop, self._RefuelingStop) self:HandleEvent(EVENTS.RefuelingStop, self._RefuelingStop)
-- Spawn tanker. -- Set unique alias for spawn from tanker group name and carrier unit name.
local Spawn=SPAWN:New(self.tankergroupname):InitUnControlled(false) local tankergroupalias=string.format("%s_%s", self.tankergroupname, self.carrier:GetName())
-- Spawn tanker. We need to introduce an alias in case this class is used twice. This would confuse the spawn routine.
local Spawn=SPAWN:NewWithAlias(self.tankergroupname, tankergroupalias)
-- Spawn on carrier. -- Spawn on carrier.
if self.takeoff==SPAWN.Takeoff.Air then if self.takeoff==SPAWN.Takeoff.Air then
@@ -670,13 +698,13 @@ function RECOVERYTANKER:onafterStart(From, Event, To)
local hdg=self.carrier:GetHeading() local hdg=self.carrier:GetHeading()
-- Spawn distance behind the carrier. -- Spawn distance behind the carrier.
local dist=UTILS.NMToMeters(20) local dist=-self.distStern+UTILS.NMToMeters(4)
-- Coordinate behind the carrier -- Coordinate behind the carrier and slightly port.
local Carrier=self.carrier:GetCoordinate():SetAltitude(self.altitude):Translate(-dist, hdg) local Carrier=self.carrier:GetCoordinate():SetAltitude(self.altitude):Translate(dist, hdg+190)
-- Orientation of spawned group. -- Orientation of spawned group.
Spawn:InitHeading(hdg) Spawn:InitHeading(hdg+10)
-- Spawn at coordinate. -- Spawn at coordinate.
self.tanker=Spawn:SpawnFromCoordinate(Carrier) self.tanker=Spawn:SpawnFromCoordinate(Carrier)
@@ -709,8 +737,9 @@ function RECOVERYTANKER:onafterStart(From, Event, To)
end end
-- Initialize route. -- Initialize route. self.distStern<0!
self:_InitRoute(15, 1) SCHEDULER:New(self, self._InitRoute, {-self.distStern+UTILS.NMToMeters(3)}, 1)
--self:_InitRoute(-self.distStern+UTILS.NMToMeters(3), 1)
-- Create tanker beacon. -- Create tanker beacon.
if self.TACANon then if self.TACANon then
@@ -741,19 +770,6 @@ function RECOVERYTANKER:onafterStatus(From, Event, To)
local fuel=self.tanker:GetFuel()*100 local fuel=self.tanker:GetFuel()*100
local text=string.format("Recovery tanker %s: state=%s fuel=%.1f", self.tanker:GetName(), self:GetState(), fuel) local text=string.format("Recovery tanker %s: state=%s fuel=%.1f", self.tanker:GetName(), self:GetState(), fuel)
self:T(self.lid..text) self:T(self.lid..text)
-- Check if tanker flies through pattern update zone.
-- TODO: Check if this can be used to update the pattern without too much disruption.
-- Could be a problem when carrier changes course since the tanker might not fligh through the zone any more.
--[[
if self.Debug and self.zoneUpdate then
local inupdatezone=self.tanker:GetUnit(1):IsInZone(self.zoneUpdate)
if inupdatezone then
local clock=UTILS.SecondsToClock(timer.getAbsTime())
self:T(string.format("Recovery tanker is in pattern update zone! Time=%s", clock))
end
end
]]
-- Check if tanker is running and not RTBing or refueling. -- Check if tanker is running and not RTBing or refueling.
if self:IsRunning() then if self:IsRunning() then
@@ -837,7 +853,9 @@ function RECOVERYTANKER:onafterPatternUpdate(From, Event, To)
local Carrier=self.carrier:GetCoordinate() local Carrier=self.carrier:GetCoordinate()
-- Define race-track pattern. -- Define race-track pattern.
local p0=self.tanker:GetCoordinate():Translate(3000, self.tanker:GetHeading()) local p0=self.tanker:GetCoordinate():Translate(UTILS.NMToMeters(1), self.tanker:GetHeading())
-- Racetrack pattern points.
local p1=Carrier:SetAltitude(self.altitude):Translate(self.distStern, hdg) local p1=Carrier:SetAltitude(self.altitude):Translate(self.distStern, hdg)
local p2=Carrier:SetAltitude(self.altitude):Translate(self.distBow, hdg) local p2=Carrier:SetAltitude(self.altitude):Translate(self.distBow, hdg)
@@ -858,8 +876,6 @@ function RECOVERYTANKER:onafterPatternUpdate(From, Event, To)
wp[1]=self.tanker:GetCoordinate():WaypointAirTurningPoint(nil , UTILS.MpsToKmph(self.speed), {}, "Current Position") wp[1]=self.tanker:GetCoordinate():WaypointAirTurningPoint(nil , UTILS.MpsToKmph(self.speed), {}, "Current Position")
wp[2]=p0:WaypointAirTurningPoint(nil, UTILS.MpsToKmph(self.speed), {taskorbit}, "Tanker Orbit") wp[2]=p0:WaypointAirTurningPoint(nil, UTILS.MpsToKmph(self.speed), {taskorbit}, "Tanker Orbit")
--local wp=self:_Pattern()
-- Initialize WP and route tanker. -- Initialize WP and route tanker.
self.tanker:WayPointInitialize(wp) self.tanker:WayPointInitialize(wp)
@@ -876,47 +892,6 @@ function RECOVERYTANKER:onafterPatternUpdate(From, Event, To)
self.Tupdate=timer.getTime() self.Tupdate=timer.getTime()
end end
--- Self made race track pattern. (not used)
-- @param #RECOVERYTANKER self
-- @return #table Table of pattern waypoints.
function RECOVERYTANKER:_Pattern()
-- Carrier heading.
local hdg=self.carrier:GetHeading()
-- Pattern altitude
local alt=self.altitude
-- Carrier position.
local Carrier=self.carrier:GetCoordinate()
local width=UTILS.NMToMeters(8)
-- Not working as desired, since tanker changes course too rapidly after each waypoint.
-- Define race-track pattern.
local p={}
p[1]=self.tanker:GetCoordinate() -- Tanker position
p[2]=Carrier:SetAltitude(alt) -- Carrier position
p[3]=p[2]:Translate(self.distBow, hdg) -- In front of carrier
p[4]=p[3]:Translate(width/math.sqrt(2), hdg-45) -- Middle front for smoother curve
-- Probably need one more to make it go -hdg at the waypoint.
p[5]=p[3]:Translate(width, hdg-90) -- In front on port
p[6]=p[5]:Translate(self.distStern-self.distBow, hdg) -- Behind on port (sterndist<0!)
p[7]=p[2]:Translate(self.distStern, hdg) -- Behind carrier
local wp={}
for i=1,#p do
local coord=p[i] --Core.Point#COORDINATE
coord:MarkToAll(string.format("Waypoint %d", i))
--table.insert(wp, coord:WaypointAirFlyOverPoint(nil , self.speed))
table.insert(wp, coord:WaypointAirTurningPoint(nil , UTILS.MpsToKmph(self.speed)))
end
return wp
end
--- On after "RTB" event. Send tanker back to carrier. --- On after "RTB" event. Send tanker back to carrier.
-- @param #RECOVERYTANKER self -- @param #RECOVERYTANKER self
-- @param #string From From state. -- @param #string From From state.
@@ -929,16 +904,19 @@ function RECOVERYTANKER:onafterRTB(From, Event, To, airbase)
airbase=airbase or self.airbase airbase=airbase or self.airbase
-- Debug message. -- Debug message.
local text=string.format("Recoery tanker %s returning to airbase %s.", self.tanker:GetName(), airbase:GetName()) local text=string.format("Recovery tanker %s returning to airbase %s.", self.tanker:GetName(), airbase:GetName())
MESSAGE:New(text, 10, "DEBUG"):ToAllIf(self.Debug) MESSAGE:New(text, 10, "DEBUG"):ToAllIf(self.Debug)
self:T(self.lid..text) self:T(self.lid..text)
-- Waypoint array. -- Waypoint array.
local wp={} local wp={}
-- Set speed ot 75% max.
local speed=self.tanker:GetSpeedMax()*0.75
-- Set landing waypoint. -- Set landing waypoint.
wp[1]=self.tanker:GetCoordinate():WaypointAirTurningPoint(nil, 300, {}, "Current Position") wp[1]=self.tanker:GetCoordinate():WaypointAirTurningPoint(nil, speed, {}, "Current Position")
wp[2]=airbase:GetCoordinate():SetAltitude(500):WaypointAirLanding(300, airbase, nil, "Land at airbase") wp[2]=airbase:GetCoordinate():SetAltitude(500):WaypointAirLanding(speed, airbase, nil, "Land at airbase")
-- Initialize WP and route tanker. -- Initialize WP and route tanker.
self.tanker:WayPointInitialize(wp) self.tanker:WayPointInitialize(wp)
@@ -956,7 +934,6 @@ function RECOVERYTANKER:onafterStop(From, Event, To)
self:UnHandleEvent(EVENTS.EngineShutdown) self:UnHandleEvent(EVENTS.EngineShutdown)
self:UnHandleEvent(EVENTS.Refueling) self:UnHandleEvent(EVENTS.Refueling)
self:UnHandleEvent(EVENTS.RefuelingStop) self:UnHandleEvent(EVENTS.RefuelingStop)
--self:UnHandleEvent(EVENTS.Land)
end end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -969,22 +946,23 @@ end
-- @param Core.Event#EVENTDATA EventData Event data. -- @param Core.Event#EVENTDATA EventData Event data.
function RECOVERYTANKER:OnEventEngineShutdown(EventData) function RECOVERYTANKER:OnEventEngineShutdown(EventData)
-- Group that shut down the engine.
local group=EventData.IniGroup --Wrapper.Group#GROUP local group=EventData.IniGroup --Wrapper.Group#GROUP
-- Check if group is alive and should be respawned. -- Check if group is alive.
if group:IsAlive() and self.respawn then if group:IsAlive() then
-- Group name. When spawning it will have #001 attached. -- Group name. When spawning it will have #001 attached.
local groupname=group:GetName() local groupname=group:GetName()
if groupname:match(self.tankergroupname) then -- Check that we have the right group and that it should be respawned.
if groupname==self.tanker:GetName() and self.respawn then
-- Debug info. -- Debug info.
local text=string.format("Respawning recovery tanker group %s.", group:GetName()) local text=string.format("Respawning recovery tanker group %s.", group:GetName())
MESSAGE:New(text, 10, "DEBUG"):ToAllIf(self.Debug) MESSAGE:New(text, 10, "DEBUG"):ToAllIf(self.Debug)
self:T(self.lid..text) self:T(self.lid..text)
-- Respawn tanker. -- Respawn tanker.
self.tanker=group:RespawnAtCurrentAirbase() self.tanker=group:RespawnAtCurrentAirbase()
@@ -994,7 +972,8 @@ function RECOVERYTANKER:OnEventEngineShutdown(EventData)
end end
-- Initial route. -- Initial route.
self:_InitRoute(15, 1) SCHEDULER:New(self, self._InitRoute, {-self.distStern+UTILS.NMToMeters(3)}, 1)
--self:_InitRoute(-self.distStern+UTILS.NMToMeters(3), 1)
end end
end end
@@ -1084,14 +1063,14 @@ function RECOVERYTANKER:_InitPatternTaskFunction()
end end
--- Init waypoint after spawn. --- Init waypoint after spawn. Tanker is first guided to a position astern the carrier and starts its racetrack pattern from there.
-- @param #RECOVERYTANKER self -- @param #RECOVERYTANKER self
-- @param #number dist Distance [NM] of initial waypoint astern carrier. Default 15 NM. -- @param #number dist Distance [NM] of initial waypoint astern carrier. Default 8 NM.
-- @param #number delay Delay before routing in seconds. Default 1 second. -- @param #number delay Delay before routing in seconds. Default 1 second.
function RECOVERYTANKER:_InitRoute(dist, delay) function RECOVERYTANKER:_InitRoute(dist, delay)
-- Defaults. -- Defaults.
dist=UTILS.NMToMeters(dist or 15) dist=dist or UTILS.NMToMeters(8)
delay=delay or 1 delay=delay or 1
-- Debug message. -- Debug message.
@@ -1103,12 +1082,19 @@ function RECOVERYTANKER:_InitRoute(dist, delay)
-- Carrier heading. -- Carrier heading.
local hdg=self.carrier:GetHeading() local hdg=self.carrier:GetHeading()
-- First waypoint is ~15 NM behind the boat. -- First waypoint is ~10 NM behind and slightly port the boat.
local p=Carrier:Translate(-dist, hdg):SetAltitude(self.altitude) local p=Carrier:Translate(dist, hdg+190):SetAltitude(self.altitude)
-- Speed for waypoints in km/h.
-- This causes a problem, because the tanker might not be alive yet ==> We schedule the call of _InitRoute
local speed=self.tanker:GetSpeedMax()*0.8
-- Set to 280 knots and convert to km/h.
--local speed=280/0.539957
-- Debug mark. -- Debug mark.
if self.Debug then if self.Debug then
p:MarkToAll(string.format("Init WP: alt=%d ft, speed=%d kts", UTILS.MetersToFeet(self.altitude), UTILS.MpsToKnots(self.speed))) p:MarkToAll(string.format("Enter Pattern WP: alt=%d ft, speed=%d kts", UTILS.MetersToFeet(self.altitude), speed*0.539957))
end end
-- Task to update pattern when wp 2 is reached. -- Task to update pattern when wp 2 is reached.
@@ -1117,11 +1103,11 @@ function RECOVERYTANKER:_InitRoute(dist, delay)
-- Waypoints. -- Waypoints.
local wp={} local wp={}
if self.takeoff==SPAWN.Takeoff.Air then if self.takeoff==SPAWN.Takeoff.Air then
wp[#wp+1]=self.tanker:GetCoordinate():SetAltitude(self.altitude):WaypointAirTurningPoint(nil, UTILS.MpsToKmph(self.speed), {}, "Spawn Position") wp[#wp+1]=self.tanker:GetCoordinate():SetAltitude(self.altitude):WaypointAirTurningPoint(nil, speed, {}, "Spawn Position")
else else
wp[#wp+1]=Carrier:WaypointAirTakeOffParking() wp[#wp+1]=Carrier:WaypointAirTakeOffParking()
end end
wp[#wp+1]=p:WaypointAirTurningPoint(nil, UTILS.MpsToKmph(self.speed), {task}, "Begin Pattern") wp[#wp+1]=p:WaypointAirTurningPoint(nil, speed, {task}, "Enter Pattern")
-- Set route. -- Set route.
self.tanker:Route(wp, delay) self.tanker:Route(wp, delay)
@@ -1181,7 +1167,7 @@ function RECOVERYTANKER:_CheckPatternUpdate(dt)
-- Get distance to saved position. -- Get distance to saved position.
local dist=pos:Get2DDistance(self.position) local dist=pos:Get2DDistance(self.position)
-- Check if carrier moved more than ~10 km. -- Check if carrier moved more than ~5 NM.
local Dchange=false local Dchange=false
if dist>self.Dupdate then if dist>self.Dupdate then
self:T(self.lid..string.format("Carrier position changed by %.1f NM. Turning=%s.", UTILS.MetersToNM(dist), tostring(turning))) self:T(self.lid..string.format("Carrier position changed by %.1f NM. Turning=%s.", UTILS.MetersToNM(dist), tostring(turning)))
@@ -1191,13 +1177,13 @@ function RECOVERYTANKER:_CheckPatternUpdate(dt)
-- Assume no update necessary. -- Assume no update necessary.
local update=false local update=false
-- No update if currently turning! Also must be running (not RTB or refuelling) and T>~10 min since last position update. -- No update if currently turning! Also must be running (not RTB or refueling) and T>~10 min since last position update.
if self:IsRunning() and dt>self.dTupdate and not turning then if self:IsRunning() and dt>self.dTupdate and not turning then
-- Update if heading or distance changed. -- Update if heading or distance changed.
if Hchange or Dchange then if Hchange or Dchange then
-- Debug message. -- Debug message.
local text=string.format("Updating tanker %s pattern due to carrier change.", self.tanker:GetName()) local text=string.format("Updating tanker %s pattern due to carrier position=%s or heading=%s change.", self.tanker:GetName(), tostring(Dchange), tostring(Hchange))
MESSAGE:New(text, 10, "DEBUG"):ToAllIf(self.Debug) MESSAGE:New(text, 10, "DEBUG"):ToAllIf(self.Debug)
self:T(self.lid..text) self:T(self.lid..text)
@@ -1220,7 +1206,7 @@ function RECOVERYTANKER:_ActivateTACAN(delay)
if delay and delay>0 then if delay and delay>0 then
-- Schedule TACAN activation. -- Schedule TACAN activation.
SCHEDULER:New(nil,self._ActivateTACAN, {self}, delay) SCHEDULER:New(nil, self._ActivateTACAN, {self}, delay)
else else
@@ -1247,6 +1233,44 @@ function RECOVERYTANKER:_ActivateTACAN(delay)
end end
--- Self made race track pattern. Not working as desired, since tanker changes course too rapidly after each waypoint.
-- @param #RECOVERYTANKER self
-- @return #table Table of pattern waypoints.
function RECOVERYTANKER:_Pattern()
-- Carrier heading.
local hdg=self.carrier:GetHeading()
-- Pattern altitude
local alt=self.altitude
-- Carrier position.
local Carrier=self.carrier:GetCoordinate()
local width=UTILS.NMToMeters(8)
-- Define race-track pattern.
local p={}
p[1]=self.tanker:GetCoordinate() -- Tanker position
p[2]=Carrier:SetAltitude(alt) -- Carrier position
p[3]=p[2]:Translate(self.distBow, hdg) -- In front of carrier
p[4]=p[3]:Translate(width/math.sqrt(2), hdg-45) -- Middle front for smoother curve
-- Probably need one more to make it go -hdg at the waypoint.
p[5]=p[3]:Translate(width, hdg-90) -- In front on port
p[6]=p[5]:Translate(self.distStern-self.distBow, hdg) -- Behind on port (sterndist<0!)
p[7]=p[2]:Translate(self.distStern, hdg) -- Behind carrier
local wp={}
for i=1,#p do
local coord=p[i] --Core.Point#COORDINATE
coord:MarkToAll(string.format("Waypoint %d", i))
--table.insert(wp, coord:WaypointAirFlyOverPoint(nil , self.speed))
table.insert(wp, coord:WaypointAirTurningPoint(nil , UTILS.MpsToKmph(self.speed)))
end
return wp
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

View File

@@ -5,16 +5,16 @@
-- **Main Features:** -- **Main Features:**
-- --
-- * Close formation with carrier. -- * Close formation with carrier.
-- * Carrier can have any number of waypoints. -- * No restrictions regarding carrier waypoints and heading.
-- * Automatic respawning on empty fuel for 24/7 operations. -- * Automatic respawning on empty fuel for 24/7 operations.
-- * Automatic rescuing of crashed or ejected units in the vicinity. -- * Automatic rescuing of crashed or ejected pilots in the vicinity of the carrier.
-- * Multiple helos at different carriers due to object oriented approach. -- * Multiple helos at different carriers due to object oriented approach.
-- * Finite State Machine (FSM) implementation. -- * Finite State Machine (FSM) implementation.
-- --
-- === -- ===
-- --
-- ### Author: **funkyfranky** -- ### Author: **funkyfranky**
-- ### Contributions: Flightcontrol (@{#AI_FORMATION} class) -- ### Contributions: Flightcontrol (@{AI.#AI_FORMATION} class)
-- --
-- @module Ops.RescueHelo -- @module Ops.RescueHelo
-- @image MOOSE.JPG -- @image MOOSE.JPG
@@ -27,7 +27,6 @@
-- @field Wrapper.Unit#UNIT carrier The carrier the helo is attached to. -- @field Wrapper.Unit#UNIT carrier The carrier the helo is attached to.
-- @field #string carriertype Carrier type. -- @field #string carriertype Carrier type.
-- @field #string helogroupname Name of the late activated helo template group. -- @field #string helogroupname Name of the late activated helo template group.
-- @field #string helogroupalias Spawn alias name of the group. Necessary for multiple RESCUEHELO objects in one mission. Uses groupname plus carrier name.
-- @field Wrapper.Group#GROUP helo Helo group. -- @field Wrapper.Group#GROUP helo Helo group.
-- @field #number takeoff Takeoff type. -- @field #number takeoff Takeoff type.
-- @field Wrapper.Airbase#AIRBASE airbase The airbase object acting as home base of the helo. -- @field Wrapper.Airbase#AIRBASE airbase The airbase object acting as home base of the helo.
@@ -54,7 +53,7 @@
-- --
-- === -- ===
-- --
-- ![Banner Image](..\Presentations\RESCUEHELO\RescueHelo_Main.jpg) -- ![Banner Image](..\Presentations\RESCUEHELO\RescueHelo_Main.png)
-- --
-- # Recue Helo -- # Recue Helo
-- --
@@ -191,7 +190,6 @@ RESCUEHELO = {
carrier = nil, carrier = nil,
carriertype = nil, carriertype = nil,
helogroupname = nil, helogroupname = nil,
helogroupalias = nil,
helo = nil, helo = nil,
airbase = nil, airbase = nil,
takeoff = nil, takeoff = nil,
@@ -216,7 +214,7 @@ RESCUEHELO = {
--- Class version. --- Class version.
-- @field #string version -- @field #string version
RESCUEHELO.version="0.9.7" RESCUEHELO.version="0.9.8"
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list -- TODO list
@@ -396,12 +394,19 @@ function RESCUEHELO:SetLowFuelThreshold(threshold)
return self return self
end end
--- Set home airbase of the helo. Default is the carrier. --- Set home airbase of the helo. This is the airbase where the helo is spawned (if not in air) and will go when it is out of fuel.
-- @param #RESCUEHELO self -- @param #RESCUEHELO self
-- @param Wrapper.Airbase#AIRBASE airbase Homebase of helo. -- @param Wrapper.Airbase#AIRBASE airbase The home airbase. Can be the airbase name (passed as a string) or a Moose AIRBASE object.
-- @return #RESCUEHELO self -- @return #RESCUEHELO self
function RESCUEHELO:SetHomeBase(airbase) function RESCUEHELO:SetHomeBase(airbase)
self.airbase=airbase if type(airbase)=="string" then
self.airbase=AIRBASE:FindByName(airbase)
else
self.airbase=airbase
end
if not self.airbase then
self:E(self.lid.."ERROR: Airbase is nil!")
end
return self return self
end end
@@ -755,10 +760,10 @@ function RESCUEHELO:onafterStart(From, Event, To)
local delay=120 local delay=120
-- Set unique alias for spawn. -- Set unique alias for spawn.
self.helogroupalias=string.format("%s_%s", self.helogroupname, self.carrier:GetName()) local helogroupalias=string.format("%s_%s", self.helogroupname, self.carrier:GetName())
-- Spawn helo. We need to introduce an alias in case this class is used twice. This would confuse the spawn routine. -- Spawn helo. We need to introduce an alias in case this class is used twice. This would confuse the spawn routine.
local Spawn=SPAWN:NewWithAlias(self.helogroupname, self.helogroupalias) local Spawn=SPAWN:NewWithAlias(self.helogroupname, helogroupalias)
-- Spawn in air or at airbase. -- Spawn in air or at airbase.
if self.takeoff==SPAWN.Takeoff.Air then if self.takeoff==SPAWN.Takeoff.Air then
@@ -789,9 +794,6 @@ function RESCUEHELO:onafterStart(From, Event, To)
-- Use an uncontrolled aircraft group. -- Use an uncontrolled aircraft group.
self.helo=GROUP:FindByName(self.helogroupname) self.helo=GROUP:FindByName(self.helogroupname)
-- Also set the alias just in case.
self.helogroupalias=self.helogroupname
if self.helo:IsAlive() then if self.helo:IsAlive() then
-- Start uncontrolled group. -- Start uncontrolled group.

View File

@@ -1912,8 +1912,7 @@ do -- Route methods
--local PointAirbase=RTBAirbase:GetCoordinate():SetAltitude(coord.y):WaypointAirTurningPoint(nil ,Speed) --local PointAirbase=RTBAirbase:GetCoordinate():SetAltitude(coord.y):WaypointAirTurningPoint(nil ,Speed)
-- Landing waypoint. More general than prev version since it should also work with FAPRS and ships. -- Landing waypoint. More general than prev version since it should also work with FAPRS and ships.
local PointLanding=RTBAirbase:GetCoordinate():WaypointAirLanding(Speed, RTBAirbase) local PointLanding=RTBAirbase:GetCoordinate():WaypointAirLanding(Speed, RTBAirbase)
-- Waypoint table. -- Waypoint table.
local Points={PointFrom, PointLanding} local Points={PointFrom, PointLanding}