mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2026-08-16 16:06:44 +00:00
OPS ATIS
This commit is contained in:
@@ -1081,10 +1081,8 @@ do -- COORDINATE
|
|||||||
elseif AirbaseCategory == Airbase.Category.AIRDROME then
|
elseif AirbaseCategory == Airbase.Category.AIRDROME then
|
||||||
RoutePoint.airdromeId = AirbaseID
|
RoutePoint.airdromeId = AirbaseID
|
||||||
else
|
else
|
||||||
self:T("ERROR: Unknown airbase category in COORDINATE:WaypointAir()!")
|
self:E("ERROR: Unknown airbase category in COORDINATE:WaypointAir()!")
|
||||||
end
|
end
|
||||||
|
|
||||||
--self:MarkToAll(string.format("Landing waypoint at airbase %s, ID=%d, Category=%d", airbase:GetName(), AirbaseID, AirbaseCategory ))
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Time in minutes to stay at the airbase before resuming route.
|
-- Time in minutes to stay at the airbase before resuming route.
|
||||||
@@ -1104,7 +1102,7 @@ do -- COORDINATE
|
|||||||
--RoutePoint.formation_template=""
|
--RoutePoint.formation_template=""
|
||||||
|
|
||||||
-- Debug.
|
-- Debug.
|
||||||
self:T({RoutePoint=RoutePoint})
|
self:I({RoutePoint=RoutePoint})
|
||||||
|
|
||||||
-- Return waypoint.
|
-- Return waypoint.
|
||||||
return RoutePoint
|
return RoutePoint
|
||||||
|
|||||||
@@ -51,6 +51,8 @@ RADIOQUEUE = {
|
|||||||
-- @field #string filename Name of the file to be transmitted.
|
-- @field #string filename Name of the file to be transmitted.
|
||||||
-- @field #string path Path in miz file where the file is located.
|
-- @field #string path Path in miz file where the file is located.
|
||||||
-- @field #number duration Duration in seconds.
|
-- @field #number duration Duration in seconds.
|
||||||
|
-- @field #string subtitle Subtitle of the transmission.
|
||||||
|
-- @field #number subduration Duration of the subtitle being displayed.
|
||||||
-- @field #number Tstarted Mission time (abs) in seconds when the transmission started.
|
-- @field #number Tstarted Mission time (abs) in seconds when the transmission started.
|
||||||
-- @field #boolean isplaying If true, transmission is currently playing.
|
-- @field #boolean isplaying If true, transmission is currently playing.
|
||||||
-- @field #number Tplay Mission time (abs) in seconds when the transmission should be played.
|
-- @field #number Tplay Mission time (abs) in seconds when the transmission should be played.
|
||||||
@@ -96,7 +98,7 @@ function RADIOQUEUE:Start(delay, dt)
|
|||||||
|
|
||||||
dt=dt or 0.01
|
dt=dt or 0.01
|
||||||
|
|
||||||
self:I(self.lid..string.format("Starting RADIOQUEUE in %.1f seconds with interval dt=%.3f seconds.", delay, dt))
|
self:I(self.lid..string.format("Starting RADIOQUEUE on Frequency %.2f MHz [modulation=%d] in %.1f seconds (dt=%.3f sec)", self.frequency/1000000, self.modulation, delay, dt))
|
||||||
|
|
||||||
self.RQid=self.scheduler:Schedule(self, self._CheckRadioQueue, {}, delay, dt)
|
self.RQid=self.scheduler:Schedule(self, self._CheckRadioQueue, {}, delay, dt)
|
||||||
|
|
||||||
@@ -137,13 +139,17 @@ end
|
|||||||
-- @param #string filename The name of the sound file.
|
-- @param #string filename The name of the sound file.
|
||||||
-- @param #number duration The duration of the sound file in seconds.
|
-- @param #number duration The duration of the sound file in seconds.
|
||||||
-- @param #string path The directory within the miz file where the sound is located. Default "l10n/DEFAULT/".
|
-- @param #string path The directory within the miz file where the sound is located. Default "l10n/DEFAULT/".
|
||||||
|
-- @param #string subtitle Subtitle of the transmission.
|
||||||
|
-- @param #number subduration Duration [sec] of the subtitle being displayed. Default 5 sec.
|
||||||
-- @return #RADIOQUEUE self The RADIOQUEUE object.
|
-- @return #RADIOQUEUE self The RADIOQUEUE object.
|
||||||
function RADIOQUEUE:SetDigit(digit, filename, duration, path)
|
function RADIOQUEUE:SetDigit(digit, filename, duration, path, subtitle, subduration)
|
||||||
|
|
||||||
local transmission={} --#RADIOQUEUE.Transmission
|
local transmission={} --#RADIOQUEUE.Transmission
|
||||||
transmission.filename=filename
|
transmission.filename=filename
|
||||||
transmission.duration=duration
|
transmission.duration=duration
|
||||||
transmission.path=path or "l10n/DEFAULT/"
|
transmission.path=path or "l10n/DEFAULT/"
|
||||||
|
transmission.subtitle=nil
|
||||||
|
transmission.subduration=nil
|
||||||
|
|
||||||
-- Convert digit to string in case it is given as a number.
|
-- Convert digit to string in case it is given as a number.
|
||||||
if type(digit)=="number" then
|
if type(digit)=="number" then
|
||||||
@@ -182,8 +188,10 @@ end
|
|||||||
-- @param #number path Directory path inside the miz file where the sound file is located. Default "l10n/DEFAULT/".
|
-- @param #number path Directory path inside the miz file where the sound file is located. Default "l10n/DEFAULT/".
|
||||||
-- @param #number tstart Start time (abs) seconds. Default now.
|
-- @param #number tstart Start time (abs) seconds. Default now.
|
||||||
-- @param #number interval Interval in seconds after the last transmission finished.
|
-- @param #number interval Interval in seconds after the last transmission finished.
|
||||||
|
-- @param #string subtitle Subtitle of the transmission.
|
||||||
|
-- @param #number subduration Duration [sec] of the subtitle being displayed. Default 5 sec.
|
||||||
-- @return #RADIOQUEUE self The RADIOQUEUE object.
|
-- @return #RADIOQUEUE self The RADIOQUEUE object.
|
||||||
function RADIOQUEUE:NewTransmission(filename, duration, path, tstart, interval)
|
function RADIOQUEUE:NewTransmission(filename, duration, path, tstart, interval, subtitle, subduration)
|
||||||
|
|
||||||
-- Sanity checks.
|
-- Sanity checks.
|
||||||
if not filename then
|
if not filename then
|
||||||
@@ -210,6 +218,12 @@ function RADIOQUEUE:NewTransmission(filename, duration, path, tstart, interval)
|
|||||||
transmission.duration=duration
|
transmission.duration=duration
|
||||||
transmission.path=path or "l10n/DEFAULT/"
|
transmission.path=path or "l10n/DEFAULT/"
|
||||||
transmission.Tplay=tstart or timer.getAbsTime()
|
transmission.Tplay=tstart or timer.getAbsTime()
|
||||||
|
transmission.subtitle=subtitle
|
||||||
|
if transmission.subtitle then
|
||||||
|
transmission.subduration=subduration or 5
|
||||||
|
else
|
||||||
|
transmission.subduration=nil
|
||||||
|
end
|
||||||
|
|
||||||
-- Add transmission to queue.
|
-- Add transmission to queue.
|
||||||
self:AddTransmission(transmission)
|
self:AddTransmission(transmission)
|
||||||
@@ -276,13 +290,10 @@ function RADIOQUEUE:Broadcast(transmission)
|
|||||||
-- Construct file name.
|
-- Construct file name.
|
||||||
local filename=string.format("%s%s", transmission.path, transmission.filename)
|
local filename=string.format("%s%s", transmission.path, transmission.filename)
|
||||||
|
|
||||||
-- Create subtitle for transmission.
|
|
||||||
--local subtitle=self:_RadioSubtitle(radio, call, loud)
|
|
||||||
|
|
||||||
if sender then
|
if sender then
|
||||||
|
|
||||||
-- Broadcasting from aircraft. Only players tuned in to the right frequency will see the message.
|
-- Broadcasting from aircraft. Only players tuned in to the right frequency will see the message.
|
||||||
self:T(self.lid..string.format("Broadcasting from aircraft %s", sender:GetName()))
|
self:I(self.lid..string.format("Broadcasting from aircraft %s", sender:GetName()))
|
||||||
|
|
||||||
-- Command to set the Frequency for the transmission.
|
-- Command to set the Frequency for the transmission.
|
||||||
local commandFrequency={
|
local commandFrequency={
|
||||||
@@ -297,7 +308,7 @@ function RADIOQUEUE:Broadcast(transmission)
|
|||||||
id = "TransmitMessage",
|
id = "TransmitMessage",
|
||||||
params = {
|
params = {
|
||||||
file=filename,
|
file=filename,
|
||||||
duration=transmission.subduration or 5,
|
duration=transmission.subduration,
|
||||||
subtitle=transmission.subtitle or "",
|
subtitle=transmission.subtitle or "",
|
||||||
loop=false,
|
loop=false,
|
||||||
}}
|
}}
|
||||||
@@ -311,7 +322,7 @@ function RADIOQUEUE:Broadcast(transmission)
|
|||||||
else
|
else
|
||||||
|
|
||||||
-- Broadcasting from carrier. No subtitle possible. Need to send messages to players.
|
-- Broadcasting from carrier. No subtitle possible. Need to send messages to players.
|
||||||
self:T(self.lid..string.format("Broadcasting from carrier via trigger.action.radioTransmission()."))
|
self:I(self.lid..string.format("Broadcasting from carrier via trigger.action.radioTransmission()."))
|
||||||
|
|
||||||
-- Position from where to transmit.
|
-- Position from where to transmit.
|
||||||
local vec3=nil
|
local vec3=nil
|
||||||
@@ -331,8 +342,8 @@ function RADIOQUEUE:Broadcast(transmission)
|
|||||||
|
|
||||||
-- Transmit via trigger.
|
-- Transmit via trigger.
|
||||||
if vec3 then
|
if vec3 then
|
||||||
self:E("Sending")
|
self:T("Sending")
|
||||||
self:E( { filename = filename, vec3 = vec3, modulation = self.modulation, frequency = self.frequency, power = self.power } )
|
self:T( { filename = filename, vec3 = vec3, modulation = self.modulation, frequency = self.frequency, power = self.power } )
|
||||||
trigger.action.radioTransmission(filename, vec3, self.modulation, false, self.frequency, self.power)
|
trigger.action.radioTransmission(filename, vec3, self.modulation, false, self.frequency, self.power)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ __Moose.Include( 'Scripts/Moose/Ops/Skipper.lua' )
|
|||||||
__Moose.Include( 'Scripts/Moose/Ops/CarrierAirWing.lua' )
|
__Moose.Include( 'Scripts/Moose/Ops/CarrierAirWing.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/Ops/Squadron.lua' )
|
__Moose.Include( 'Scripts/Moose/Ops/Squadron.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/Ops/FlightGroup.lua' )
|
__Moose.Include( 'Scripts/Moose/Ops/FlightGroup.lua' )
|
||||||
|
__Moose.Include( 'Scripts/Moose/Ops/ATIS.lua' )
|
||||||
|
|
||||||
__Moose.Include( 'Scripts/Moose/AI/AI_Balancer.lua' )
|
__Moose.Include( 'Scripts/Moose/AI/AI_Balancer.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/AI/AI_Air.lua' )
|
__Moose.Include( 'Scripts/Moose/AI/AI_Air.lua' )
|
||||||
|
|||||||
@@ -0,0 +1,279 @@
|
|||||||
|
--- **Ops** - (R2.5) - Automatic Terminal Information Service.
|
||||||
|
--
|
||||||
|
-- **Main Features:**
|
||||||
|
--
|
||||||
|
-- * Broadcast
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### Author: **funkyfranky**
|
||||||
|
-- @module Ops.Atis
|
||||||
|
-- @image OPS_ATIS.png
|
||||||
|
|
||||||
|
|
||||||
|
--- ATIS class.
|
||||||
|
-- @type ATIS
|
||||||
|
-- @field #string ClassName Name of the class.
|
||||||
|
-- @field #boolean Debug Debug mode. Messages to all about status.
|
||||||
|
-- @field #string lid Class id string for output to DCS log file.
|
||||||
|
-- @field #string airbasename The name of the airbase.
|
||||||
|
-- @field Wrapper.Airbase#AIRBASE airbase The airbase object.
|
||||||
|
-- @field #number frequency Radio frequency in MHz.
|
||||||
|
-- @field #number modulation Radio modulation 0=AM or 1=FM.
|
||||||
|
-- @field Core.RadioQueue#RADIOQUEUE radioqueue Radio queue for broadcasing messages.
|
||||||
|
-- @field #string soundpath Path to sound files.
|
||||||
|
-- @extends Core.Fsm#FSM
|
||||||
|
|
||||||
|
--- Be surprised!
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
|
-- # The ATIS Concept
|
||||||
|
-- Automatic terminal information service, or ATIS, is a continuous broadcast of recorded aeronautical information in busier terminal areas, i.e. airports and their immediate surroundings.
|
||||||
|
-- ATIS broadcasts contain essential information, such as current weather information, active runways, and any other information required by the pilots.
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- @field #ATIS
|
||||||
|
ATIS = {
|
||||||
|
ClassName = "ATIS",
|
||||||
|
Debug = false,
|
||||||
|
lid = nil,
|
||||||
|
airbasename = nil,
|
||||||
|
airbase = nil,
|
||||||
|
frequency = nil,
|
||||||
|
modulation = nil,
|
||||||
|
radioqueue = nil,
|
||||||
|
soundpath = nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
--- ATIS class version.
|
||||||
|
-- @field #string version
|
||||||
|
ATIS.version="0.0.1"
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- TODO list
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- TODO: A lot!
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- Constructor
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- Create a new ATIS class object for a specific aircraft carrier unit.
|
||||||
|
-- @param #ATIS self
|
||||||
|
-- @param #string airbasename Name of the airbase.
|
||||||
|
-- @param #number frequency Radio frequency in MHz. Default 143.00 MHz.
|
||||||
|
-- @param #number modulation 0=AM, 1=FM. Default 0=AM.
|
||||||
|
-- @return #ATIS self
|
||||||
|
function ATIS:New(airbasename, frequency, modulation)
|
||||||
|
|
||||||
|
-- Inherit everything from WAREHOUSE class.
|
||||||
|
local self=BASE:Inherit(self, FSM:New()) -- #ATIS
|
||||||
|
|
||||||
|
self.airbasename=airbasename
|
||||||
|
self.airbase=AIRBASE:FindByName(airbasename)
|
||||||
|
|
||||||
|
self.frequency=frequency or 143.00
|
||||||
|
self.modulation=modulation or 0
|
||||||
|
|
||||||
|
-- Set some string id for output to DCS.log file.
|
||||||
|
self.lid=string.format("ATIS %s | ", self.airbasename)
|
||||||
|
|
||||||
|
-- Defaults:
|
||||||
|
self:SetSoundfilesPath()
|
||||||
|
|
||||||
|
-- Start State.
|
||||||
|
self:SetStartState("Stopped")
|
||||||
|
|
||||||
|
-- Add FSM transitions.
|
||||||
|
-- From State --> Event --> To State
|
||||||
|
self:AddTransition("Stopped", "Start", "Running") -- Start FSM.
|
||||||
|
self:AddTransition("*", "Status", "*") -- Update status.
|
||||||
|
self:AddTransition("*", "Broadcast", "*") -- Update status.
|
||||||
|
self:AddTransition("*", "CheckQueue", "*") -- Update status.
|
||||||
|
|
||||||
|
------------------------
|
||||||
|
--- Pseudo Functions ---
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
--- Triggers the FSM event "Start". Starts the ATIS.
|
||||||
|
-- @function [parent=#ATIS] Start
|
||||||
|
-- @param #ATIS self
|
||||||
|
|
||||||
|
--- Triggers the FSM event "Start" after a delay.
|
||||||
|
-- @function [parent=#ATIS] __Start
|
||||||
|
-- @param #ATIS self
|
||||||
|
-- @param #number delay Delay in seconds.
|
||||||
|
|
||||||
|
--- Triggers the FSM event "Stop". Stops the ATIS.
|
||||||
|
-- @param #ATIS self
|
||||||
|
|
||||||
|
--- Triggers the FSM event "Stop" after a delay.
|
||||||
|
-- @function [parent=#ATIS] __Stop
|
||||||
|
-- @param #ATIS self
|
||||||
|
-- @param #number delay Delay in seconds.
|
||||||
|
|
||||||
|
-- Debug trace.
|
||||||
|
if true then
|
||||||
|
self.Debug=true
|
||||||
|
BASE:TraceOnOff(true)
|
||||||
|
BASE:TraceClass(self.ClassName)
|
||||||
|
BASE:TraceLevel(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
self:__Start(1)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- User Functions
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- Set sound files folder within miz file.
|
||||||
|
-- @param #ATIS self
|
||||||
|
-- @param #string path Path for sound files. Default "ATIS Soundfiles".
|
||||||
|
-- @return #ATIS self
|
||||||
|
function ATIS:SetSoundfilesPath(path)
|
||||||
|
self.soundpath=tostring(path or "ATIS Soundfiles/")
|
||||||
|
self:I(self.lid..string.format("Setting sound files path to %s", self.soundpath))
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- Start & Status
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- Start ATIS FSM.
|
||||||
|
-- @param #ATIS self
|
||||||
|
function ATIS:onafterStart(From, Event, To)
|
||||||
|
|
||||||
|
-- Info.
|
||||||
|
self:I(self.lid..string.format("Starting ATIS v%s for airbase %s", ATIS.version, self.airbasename))
|
||||||
|
|
||||||
|
-- Start radio queue.
|
||||||
|
self.radioqueue=RADIOQUEUE:New(self.frequency, self.modulation)
|
||||||
|
|
||||||
|
self.radioqueue:SetSenderCoordinate(self.airbase:GetCoordinate())
|
||||||
|
|
||||||
|
self.radioqueue:Start(1, 0.01)
|
||||||
|
|
||||||
|
self.radioqueue:SetDigit(0, "0-continue.wav", 0.8, self.soundpath)
|
||||||
|
self.radioqueue:SetDigit(1, "1-continue.wav", 0.8, self.soundpath)
|
||||||
|
self.radioqueue:SetDigit(2, "2-continue.wav", 0.8, self.soundpath)
|
||||||
|
self.radioqueue:SetDigit(3, "3-continue.wav", 0.8, self.soundpath)
|
||||||
|
self.radioqueue:SetDigit(4, "4-continue.wav", 0.8, self.soundpath)
|
||||||
|
self.radioqueue:SetDigit(5, "5-continue.wav", 0.8, self.soundpath)
|
||||||
|
self.radioqueue:SetDigit(6, "6-continue.wav", 0.8, self.soundpath)
|
||||||
|
self.radioqueue:SetDigit(7, "7-continue.wav", 0.8, self.soundpath)
|
||||||
|
self.radioqueue:SetDigit(8, "8-continue.wav", 0.8, self.soundpath)
|
||||||
|
self.radioqueue:SetDigit(9, "9-continue.wav", 0.8, self.soundpath)
|
||||||
|
|
||||||
|
|
||||||
|
-- Init status updates.
|
||||||
|
self:__Status(-1)
|
||||||
|
self:__CheckQueue(-2)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Update status.
|
||||||
|
-- @param #ATIS self
|
||||||
|
function ATIS:onafterStatus(From, Event, To)
|
||||||
|
|
||||||
|
local fsmstate=self:GetState()
|
||||||
|
|
||||||
|
-- Info text.
|
||||||
|
local text=string.format("State %s", fsmstate)
|
||||||
|
self:I(self.lid..text)
|
||||||
|
|
||||||
|
self:__Status(-30)
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- FSM Events
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- Check if radio queue is empty. If so, start broadcasting the message again.
|
||||||
|
-- @param #ATIS self
|
||||||
|
function ATIS:onafterCheckQueue(From, Event, To)
|
||||||
|
|
||||||
|
if #self.radioqueue.queue==0 then
|
||||||
|
self:I(self.lid..string.format("Radio queue empty. Repeating message."))
|
||||||
|
self:Broadcast()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check back in 5 seconds.
|
||||||
|
self:__CheckQueue(-5)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Update status.
|
||||||
|
-- @param #ATIS self
|
||||||
|
function ATIS:onafterBroadcast(From, Event, To)
|
||||||
|
|
||||||
|
self.radioqueue:Number2Transmission("0123456789", 0, 0)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- Misc Functions
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- Get static weather of this mission from env.mission.weather.
|
||||||
|
-- @param #ATIS self
|
||||||
|
-- @param #table Clouds table which has entries "thickness", "density", "base", "iprecptns".
|
||||||
|
-- @param #number Visibility distance in meters.
|
||||||
|
-- @param #table Fog table, which has entries "thickness", "visibility" or nil if fog is disabled in the mission.
|
||||||
|
-- @param #number Dust density or nil if dust is disabled in the mission.
|
||||||
|
function ATIS:GetStaticWeather()
|
||||||
|
|
||||||
|
-- Weather data from mission file.
|
||||||
|
local weather=env.mission.weather
|
||||||
|
|
||||||
|
-- Clouds
|
||||||
|
--[[
|
||||||
|
["clouds"] =
|
||||||
|
{
|
||||||
|
["thickness"] = 430,
|
||||||
|
["density"] = 7,
|
||||||
|
["base"] = 0,
|
||||||
|
["iprecptns"] = 1,
|
||||||
|
}, -- end of ["clouds"]
|
||||||
|
]]
|
||||||
|
local clouds=weather.clouds
|
||||||
|
|
||||||
|
-- Visibilty distance in meters.
|
||||||
|
local visibility=weather.visibility.distance
|
||||||
|
|
||||||
|
-- Dust
|
||||||
|
--[[
|
||||||
|
["enable_dust"] = false,
|
||||||
|
["dust_density"] = 0,
|
||||||
|
]]
|
||||||
|
local dust=nil
|
||||||
|
if weather.enable_dust==true then
|
||||||
|
dust=weather.dust_density
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Fog
|
||||||
|
--[[
|
||||||
|
["enable_fog"] = false,
|
||||||
|
["fog"] =
|
||||||
|
{
|
||||||
|
["thickness"] = 0,
|
||||||
|
["visibility"] = 25,
|
||||||
|
}, -- end of ["fog"]
|
||||||
|
]]
|
||||||
|
local fog=nil
|
||||||
|
if weather.enable_fog==true then
|
||||||
|
fog=weather.fog
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
return clouds, visibility, fog, dust
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
@@ -249,7 +249,7 @@ function FLIGHTCONTROL:onafterStatus()
|
|||||||
self:_CheckQueues()
|
self:_CheckQueues()
|
||||||
|
|
||||||
-- Get runway.
|
-- Get runway.
|
||||||
local runway=self:_GetActiveRunway()
|
local runway=self:GetActiveRunway()
|
||||||
|
|
||||||
-- Get free parking spots.
|
-- Get free parking spots.
|
||||||
local nfree=self:_GetFreeParkingSpots()
|
local nfree=self:_GetFreeParkingSpots()
|
||||||
@@ -385,30 +385,24 @@ function FLIGHTCONTROL:_CheckQueues()
|
|||||||
local nholding=#self.Qwaiting
|
local nholding=#self.Qwaiting
|
||||||
|
|
||||||
-- Number of parking groups.
|
-- Number of parking groups.
|
||||||
local nparking=#self.Qparking
|
local nparking=#self.Qparking
|
||||||
|
|
||||||
-- Get next flight in holding queue.
|
local flight, isholding=self:_GetNextFight()
|
||||||
local flight=self:_GetNextFightHolding()
|
|
||||||
|
|
||||||
if flight then
|
|
||||||
|
if flight and ntakeoff==0 and nlanding==0 then
|
||||||
if nlanding==0 and ntakeoff==0 then
|
|
||||||
|
|
||||||
|
if isholding then
|
||||||
|
|
||||||
-- Message.
|
-- Message.
|
||||||
local text=string.format("Flight %s, you are cleared to taxi to runway.", flight.groupname)
|
local text=string.format("Flight %s, you are cleared to land.", flight.groupname)
|
||||||
MESSAGE:New(text, 5, "FLIGHTCONTROL"):ToAll()
|
MESSAGE:New(text, 5, "FLIGHTCONTROL"):ToAll()
|
||||||
|
|
||||||
flight:FlightLanding()
|
flight:FlightLanding()
|
||||||
self:_LandAI(flight)
|
self:_LandAI(flight)
|
||||||
end
|
|
||||||
|
|
||||||
else
|
|
||||||
|
|
||||||
-- Get next wairing flight.
|
|
||||||
local flight=self:_GetNextFightParking()
|
|
||||||
|
|
||||||
if flight and ntakeoff==0 and nlanding==0 then
|
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
-- Message.
|
-- Message.
|
||||||
local text=string.format("Flight %s, you are cleared to taxi to runway.", flight.groupname)
|
local text=string.format("Flight %s, you are cleared to taxi to runway.", flight.groupname)
|
||||||
MESSAGE:New(text, 5, "FLIGHTCONTROL"):ToAll()
|
MESSAGE:New(text, 5, "FLIGHTCONTROL"):ToAll()
|
||||||
@@ -418,12 +412,52 @@ function FLIGHTCONTROL:_CheckQueues()
|
|||||||
flight:_UpdateRoute(1)
|
flight:_UpdateRoute(1)
|
||||||
|
|
||||||
self:_RemoveFlightFromQueue(self.Qparking, flight, "parking")
|
self:_RemoveFlightFromQueue(self.Qparking, flight, "parking")
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Get next flight in line, either waiting for landing or waiting for takeoff.
|
||||||
|
-- @param #FLIGHTCONTROL self
|
||||||
|
-- @return Ops.FlightGroup#FLIGHTGROUP Marshal flight next in line and ready to enter the pattern. Or nil if no flight is ready.
|
||||||
|
-- @return #boolean If true, flight is holding and waiting for landing, if false, flight is parking and waiting for takeoff.
|
||||||
|
function FLIGHTCONTROL:_GetNextFight()
|
||||||
|
|
||||||
|
local flightholding=self:_GetNextFightHolding()
|
||||||
|
local flightparking=self:_GetNextFightParking()
|
||||||
|
|
||||||
|
-- If no flight is waiting for takeoff return the holding flight or nil.
|
||||||
|
if not flightparking then
|
||||||
|
return flightholding, true
|
||||||
|
end
|
||||||
|
|
||||||
|
-- If no flight is waiting for landing return the takeoff flight or nil.
|
||||||
|
if not flightholding then
|
||||||
|
return flightparking, false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- We got flights waiting for landing and for takeoff.
|
||||||
|
if flightholding and flightparking then
|
||||||
|
|
||||||
|
-- Return holding flight if fuel is low.
|
||||||
|
if flightholding.fuellow then
|
||||||
|
return flightholding, true
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Return the flight which is waiting longer.
|
||||||
|
if flightholding.Tholding<flightparking.Tparking then
|
||||||
|
return flightholding, true
|
||||||
|
else
|
||||||
|
return flightparking, false
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Get next flight waiting for landing clearance.
|
--- Get next flight waiting for landing clearance.
|
||||||
@@ -431,17 +465,46 @@ end
|
|||||||
-- @return Ops.FlightGroup#FLIGHTGROUP Marshal flight next in line and ready to enter the pattern. Or nil if no flight is ready.
|
-- @return Ops.FlightGroup#FLIGHTGROUP Marshal flight next in line and ready to enter the pattern. Or nil if no flight is ready.
|
||||||
function FLIGHTCONTROL:_GetNextFightHolding()
|
function FLIGHTCONTROL:_GetNextFightHolding()
|
||||||
|
|
||||||
|
if #self.Qwaiting==0 then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Sort flights by low fuel
|
||||||
|
local function _sortByFuel(a, b)
|
||||||
|
local flightA=a --Ops.FlightGroup#FLIGHTGROUP
|
||||||
|
local flightB=b --Ops.FlightGroup#FLIGHTGROUP
|
||||||
|
local fuelA=flightA.group:GetFuelMin()
|
||||||
|
local fuelB=flightB.group:GetFuelMin()
|
||||||
|
return fuelA<fuelB
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Sort flights by holding time.
|
||||||
|
local function _sortByTholding(a, b)
|
||||||
|
local flightA=a --Ops.FlightGroup#FLIGHTGROUP
|
||||||
|
local flightB=b --Ops.FlightGroup#FLIGHTGROUP
|
||||||
|
return flightA.Tholding<flightB.Tholding
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Sort flights by fuel.
|
||||||
|
table.sort(self.Qwaiting, _sortByFuel)
|
||||||
|
|
||||||
-- Loop over all marshal flights.
|
-- Loop over all marshal flights.
|
||||||
for _,_flight in pairs(self.Qwaiting) do
|
for _,_flight in pairs(self.Qwaiting) do
|
||||||
local flight=_flight --Ops.FlightGroup#FLIGHTGROUP
|
local flight=_flight --Ops.FlightGroup#FLIGHTGROUP
|
||||||
|
|
||||||
-- TODO: Sort by fuel, holding time.
|
-- Return flight that is lowest on fuel.
|
||||||
|
if flight.fuellow then
|
||||||
return flight
|
return flight
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Return flight waiting longest.
|
||||||
|
table.sort(self.Qwaiting, _sortByTholding)
|
||||||
|
return self.Qwaiting[1]
|
||||||
|
|
||||||
return nil
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -450,17 +513,21 @@ end
|
|||||||
-- @return Ops.FlightGroup#FLIGHTGROUP Marshal flight next in line and ready to enter the pattern. Or nil if no flight is ready.
|
-- @return Ops.FlightGroup#FLIGHTGROUP Marshal flight next in line and ready to enter the pattern. Or nil if no flight is ready.
|
||||||
function FLIGHTCONTROL:_GetNextFightParking()
|
function FLIGHTCONTROL:_GetNextFightParking()
|
||||||
|
|
||||||
-- Loop over all marshal flights.
|
if #self.Qparking==0 then
|
||||||
for _,_flight in pairs(self.Qparking) do
|
return nil
|
||||||
local flight=_flight --Ops.FlightGroup#FLIGHTGROUP
|
|
||||||
|
|
||||||
-- TODO: Sort by fuel, holding time.
|
|
||||||
|
|
||||||
return flight
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return nil
|
-- Sort flights parking time.
|
||||||
|
local function _sortByTholding(a, b)
|
||||||
|
local flightA=a --Ops.FlightGroup#FLIGHTGROUP
|
||||||
|
local flightB=b --Ops.FlightGroup#FLIGHTGROUP
|
||||||
|
return flightA.Tparking<flightB.Tparking
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Return flight waiting longest.
|
||||||
|
table.sort(self.Qwaiting, _sortByTholding)
|
||||||
|
return self.Qparking[1]
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Print queue.
|
--- Print queue.
|
||||||
@@ -533,6 +600,27 @@ function FLIGHTCONTROL:_RemoveFlightFromQueue(queue, flight, queuename)
|
|||||||
return false, nil
|
return false, nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Add flight to holding queue.
|
||||||
|
-- @param #FLIGHTCONTROL self
|
||||||
|
-- @param Ops.FlightGroup#FLIGHTGROUP flight Flight group.
|
||||||
|
-- @return #boolean If true, flight was added. False otherwise.
|
||||||
|
function FLIGHTCONTROL:_AddFlightToHoldingQueue(flight)
|
||||||
|
|
||||||
|
-- Check if already in queue.
|
||||||
|
if self:_InQueue(self.Qwaiting, flight.group) then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Add flight to table.
|
||||||
|
table.insert(self.Qwaiting, flight)
|
||||||
|
|
||||||
|
-- Flight is not holding any more.
|
||||||
|
flight.Tholding=timer.getAbsTime()
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Add flight to landing queue and set recovered to false for all elements of the flight and its section members.
|
--- Add flight to landing queue and set recovered to false for all elements of the flight and its section members.
|
||||||
-- @param #FLIGHTCONTROL self
|
-- @param #FLIGHTCONTROL self
|
||||||
-- @param Ops.FlightGroup#FLIGHTGROUP flight Flight group.
|
-- @param Ops.FlightGroup#FLIGHTGROUP flight Flight group.
|
||||||
@@ -553,6 +641,26 @@ function FLIGHTCONTROL:_AddFlightToLandingQueue(flight)
|
|||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Add flight to parking queue.
|
||||||
|
-- @param #FLIGHTCONTROL self
|
||||||
|
-- @param Ops.FlightGroup#FLIGHTGROUP flight Flight group.
|
||||||
|
-- @return #boolean If true, flight was added. False otherwise.
|
||||||
|
function FLIGHTCONTROL:_AddFlightToParkingQueue(flight)
|
||||||
|
|
||||||
|
-- Check if already in queue.
|
||||||
|
if self:_InQueue(self.Qparking, flight.group) then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Add flight to table.
|
||||||
|
table.insert(self.Qparking, flight)
|
||||||
|
|
||||||
|
-- Flight is not holding any more.
|
||||||
|
flight.Tparking=timer.getAbsTime()
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
--- Add flight to takeoff queue.
|
--- Add flight to takeoff queue.
|
||||||
-- @param #FLIGHTCONTROL self
|
-- @param #FLIGHTCONTROL self
|
||||||
-- @param Ops.FlightGroup#FLIGHTGROUP flight Flight group.
|
-- @param Ops.FlightGroup#FLIGHTGROUP flight Flight group.
|
||||||
@@ -567,8 +675,8 @@ function FLIGHTCONTROL:_AddFlightToTakeoffQueue(flight)
|
|||||||
-- Add flight to table.
|
-- Add flight to table.
|
||||||
table.insert(self.Qtakeoff, flight)
|
table.insert(self.Qtakeoff, flight)
|
||||||
|
|
||||||
-- New time stamp for time in pattern.
|
-- New time stamp for time waiting for takeoff.
|
||||||
flight.Tholding=timer.getAbsTime()
|
flight.Tparking=nil
|
||||||
|
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
@@ -652,13 +760,63 @@ function FLIGHTCONTROL:_InitRunwayData()
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Get wind.
|
||||||
|
-- @param #FLIGHTCONTROL self
|
||||||
|
-- @return #FLIGHTCONTROL.Runway Active runway.
|
||||||
|
function FLIGHTCONTROL:GetWindVector(altitude)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
--- Get the active runway based on current wind direction.
|
--- Get the active runway based on current wind direction.
|
||||||
-- @param #FLIGHTCONTROL self
|
-- @param #FLIGHTCONTROL self
|
||||||
-- @return #FLIGHTCONTROL.Runway Active runway.
|
-- @return #FLIGHTCONTROL.Runway Active runway.
|
||||||
function FLIGHTCONTROL:_GetActiveRunway()
|
function FLIGHTCONTROL:GetActiveRunway()
|
||||||
|
|
||||||
-- TODO: get runway.
|
-- TODO: get runway.
|
||||||
local i=math.max(self.activerwyno, #self.runways)
|
local iact=math.max(self.activerwyno, #self.runways)
|
||||||
return self.runways[i]
|
|
||||||
|
-- Get wind vector.
|
||||||
|
local Vwind=self:GetCoordinate():GetWindWithTurbulenceVec3()
|
||||||
|
local norm=UTILS.VecNorm(Vwind)
|
||||||
|
|
||||||
|
-- Check if wind is blowing (norm>0).
|
||||||
|
if norm>0 then
|
||||||
|
|
||||||
|
-- Normalize wind (not necessary).
|
||||||
|
Vwind.x=Vwind.x/norm
|
||||||
|
Vwind.y=0
|
||||||
|
Vwind.z=Vwind.z/norm
|
||||||
|
|
||||||
|
-- Debug.
|
||||||
|
self:T3({Vwind=Vwind})
|
||||||
|
|
||||||
|
-- Loop over runways.
|
||||||
|
local dotmin=nil
|
||||||
|
for i,_runway in pairs(self.runways) do
|
||||||
|
local runway=_runway --#FLIGHTCONTROL.Runway
|
||||||
|
|
||||||
|
-- Angle in rad.
|
||||||
|
local alpha=math.rad(runway.direction)
|
||||||
|
|
||||||
|
-- Runway vector.
|
||||||
|
local Vrunway={x=math.cos(alpha), y=0, z=math.sin(alpha)}
|
||||||
|
|
||||||
|
-- Dot product: parallel component of the two vectors.
|
||||||
|
local dot=UTILS.VecDot(Vwind, Vrunway)
|
||||||
|
|
||||||
|
-- Debug.
|
||||||
|
env.info(string.format("runway=%03d° dot=%.3f", runway.direction, dot))
|
||||||
|
|
||||||
|
-- New min?
|
||||||
|
if dotmin==nil or dot<dotmin then
|
||||||
|
dotmin=dot
|
||||||
|
iact=i
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return self.runways[iact]
|
||||||
end
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
@@ -1107,7 +1265,8 @@ function FLIGHTCONTROL:_LandAI(flight)
|
|||||||
self:I(self.lid..string.format("Landing AI flight %s.", flight.groupname))
|
self:I(self.lid..string.format("Landing AI flight %s.", flight.groupname))
|
||||||
|
|
||||||
-- Add flight to landing queue.
|
-- Add flight to landing queue.
|
||||||
table.insert(self.Qlanding, flight)
|
--table.insert(self.Qlanding, flight)
|
||||||
|
self:_AddFlightToLandingQueue(flight)
|
||||||
|
|
||||||
-- Give signal to land.
|
-- Give signal to land.
|
||||||
flight.flaghold:Set(1)
|
flight.flaghold:Set(1)
|
||||||
@@ -1124,7 +1283,7 @@ function FLIGHTCONTROL:_GetHoldingpoint(flight)
|
|||||||
|
|
||||||
local holdingpoint={} --#FLIGHTCONTROL.HoldingPoint
|
local holdingpoint={} --#FLIGHTCONTROL.HoldingPoint
|
||||||
|
|
||||||
local runway=self:_GetActiveRunway()
|
local runway=self:GetActiveRunway()
|
||||||
|
|
||||||
local hdg=runway.direction+90
|
local hdg=runway.direction+90
|
||||||
local dx=UTILS.NMToMeters(5)
|
local dx=UTILS.NMToMeters(5)
|
||||||
|
|||||||
@@ -41,6 +41,8 @@
|
|||||||
-- @field Ops.Squadron#SQUADRON squadron The squadron the flight group belongs to.
|
-- @field Ops.Squadron#SQUADRON squadron The squadron the flight group belongs to.
|
||||||
-- @field Ops.FlightControl#FLIGHTCONTROL flightcontrol The flightcontrol handling this group.
|
-- @field Ops.FlightControl#FLIGHTCONTROL flightcontrol The flightcontrol handling this group.
|
||||||
-- @field Core.UserFlag#USERFLAG flaghold Flag for holding.
|
-- @field Core.UserFlag#USERFLAG flaghold Flag for holding.
|
||||||
|
-- @field #number Tholding Abs. mission time stamp when the group reached the holding point.
|
||||||
|
-- @field #number Tparking Abs. mission time stamp when the group was spawned uncontrolled and is parking.
|
||||||
-- @extends Core.Fsm#FSM
|
-- @extends Core.Fsm#FSM
|
||||||
|
|
||||||
--- Be surprised!
|
--- Be surprised!
|
||||||
@@ -83,6 +85,8 @@ FLIGHTGROUP = {
|
|||||||
squadron = nil,
|
squadron = nil,
|
||||||
flightcontrol = nil,
|
flightcontrol = nil,
|
||||||
flaghold = nil,
|
flaghold = nil,
|
||||||
|
Tholding = nil,
|
||||||
|
Tparking = nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -593,6 +597,21 @@ function FLIGHTGROUP:IsDead()
|
|||||||
return self:Is("Dead")
|
return self:Is("Dead")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Check if flight low on fuel.
|
||||||
|
-- @param #FLIGHTGROUP self
|
||||||
|
-- @return #boolean If true, flight is low on fuel.
|
||||||
|
function FLIGHTGROUP:IsFuelLow()
|
||||||
|
return self.fuellow
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if flight critical on fuel
|
||||||
|
-- @param #FLIGHTGROUP self
|
||||||
|
-- @return #boolean If true, flight is critical on fuel.
|
||||||
|
function FLIGHTGROUP:IsFuelCritical()
|
||||||
|
return self.fuelcritical
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- Start & Status
|
-- Start & Status
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
@@ -1127,6 +1146,9 @@ function FLIGHTGROUP:onafterFlightParking(From, Event, To)
|
|||||||
local airbase=self.group:GetCoordinate():GetClosestAirbase()
|
local airbase=self.group:GetCoordinate():GetClosestAirbase()
|
||||||
|
|
||||||
local airbasename=airbase:GetName() or "unknown"
|
local airbasename=airbase:GetName() or "unknown"
|
||||||
|
|
||||||
|
-- Parking time stamp.
|
||||||
|
self.Tparking=timer.getAbsTime()
|
||||||
|
|
||||||
local flightcontrol=_DATABASE:GetFlightControl(airbasename)
|
local flightcontrol=_DATABASE:GetFlightControl(airbasename)
|
||||||
|
|
||||||
@@ -1135,7 +1157,8 @@ function FLIGHTGROUP:onafterFlightParking(From, Event, To)
|
|||||||
|
|
||||||
if self.flightcontrol then
|
if self.flightcontrol then
|
||||||
|
|
||||||
table.insert(self.flightcontrol.Qparking, self)
|
-- Add flight to parking queue, waiting for takeoff cleance.
|
||||||
|
self.flightcontrol:_AddFlightToParkingQueue(self)
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1150,12 +1173,19 @@ end
|
|||||||
-- @param #string To To state.
|
-- @param #string To To state.
|
||||||
function FLIGHTGROUP:onafterFlightTaxiing(From, Event, To)
|
function FLIGHTGROUP:onafterFlightTaxiing(From, Event, To)
|
||||||
self:I(self.sid..string.format("Flight is taxiing %s.", self.groupname))
|
self:I(self.sid..string.format("Flight is taxiing %s.", self.groupname))
|
||||||
|
|
||||||
|
-- Parking over.
|
||||||
|
self.Tparking=nil
|
||||||
|
|
||||||
-- TODO: need a better check for the airbase.
|
-- TODO: need a better check for the airbase.
|
||||||
local airbase=self.group:GetCoordinate():GetClosestAirbase(nil, self.group:GetCoalition())
|
local airbase=self.group:GetCoordinate():GetClosestAirbase(nil, self.group:GetCoalition())
|
||||||
|
|
||||||
if self.flightcontrol and airbase and self.flightcontrol.airbasename==airbase:GetName() then
|
if self.flightcontrol and airbase and self.flightcontrol.airbasename==airbase:GetName() then
|
||||||
|
-- Add flight to takeoff queue.
|
||||||
self.flightcontrol:_AddFlightToTakeoffQueue(self)
|
self.flightcontrol:_AddFlightToTakeoffQueue(self)
|
||||||
|
|
||||||
|
-- Remove flight from parking queue.
|
||||||
|
self.flightcontrol:_RemoveFlightFromQueue(self.flightcontrol.Qparking, self, "parking")
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -1189,7 +1219,7 @@ function FLIGHTGROUP:onafterFlightAirborne(From, Event, To, airbase)
|
|||||||
|
|
||||||
-- Remove flight from FC takeoff queue.
|
-- Remove flight from FC takeoff queue.
|
||||||
if self.flightcontrol and airbase and self.flightcontrol.airbasename==airbase:GetName() then
|
if self.flightcontrol and airbase and self.flightcontrol.airbasename==airbase:GetName() then
|
||||||
self.flightcontrol:_RemoveFlightFromQueue(self.flightcontrol.Qtakeoff, self, "takeoff")
|
--self.flightcontrol:_RemoveFlightFromQueue(self.flightcontrol.Qtakeoff, self, "takeoff")
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Update queue.
|
-- Update queue.
|
||||||
@@ -1197,7 +1227,7 @@ function FLIGHTGROUP:onafterFlightAirborne(From, Event, To, airbase)
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- On after "FlightLanded" event.
|
--- On after "FlightLanding" event.
|
||||||
-- @param #FLIGHTGROUP self
|
-- @param #FLIGHTGROUP self
|
||||||
-- @param #string From From state.
|
-- @param #string From From state.
|
||||||
-- @param #string Event Event.
|
-- @param #string Event Event.
|
||||||
@@ -1353,12 +1383,13 @@ end
|
|||||||
-- @param Wrapper.Airbase#AIRBASE airbase The airbase to hold at.
|
-- @param Wrapper.Airbase#AIRBASE airbase The airbase to hold at.
|
||||||
-- @param #number SpeedTo Speed used for travelling from current position to holding point in knots. Default 350 kts.
|
-- @param #number SpeedTo Speed used for travelling from current position to holding point in knots. Default 350 kts.
|
||||||
-- @param #number SpeedHold Holding speed in knots. Default 250 kts.
|
-- @param #number SpeedHold Holding speed in knots. Default 250 kts.
|
||||||
function FLIGHTGROUP:onafterHold(From, Event, To, airbase, SpeedTo, SpeedHold)
|
-- @param #number SpeedLand Landing speed in knots. Default 170 kts.
|
||||||
|
function FLIGHTGROUP:onafterHold(From, Event, To, airbase, SpeedTo, SpeedHold, SpeedLand)
|
||||||
|
|
||||||
-- Defaults:
|
-- Defaults:
|
||||||
SpeedTo=SpeedTo or 350
|
SpeedTo=SpeedTo or 350
|
||||||
SpeedHold=SpeedHold or 250
|
SpeedHold=SpeedHold or 250
|
||||||
local SpeedLand=190
|
local SpeedLand=170
|
||||||
|
|
||||||
-- Debug message.
|
-- Debug message.
|
||||||
local text=string.format("Flight group set to hold at airbase %s", airbase:GetName())
|
local text=string.format("Flight group set to hold at airbase %s", airbase:GetName())
|
||||||
@@ -1371,6 +1402,16 @@ function FLIGHTGROUP:onafterHold(From, Event, To, airbase, SpeedTo, SpeedHold)
|
|||||||
local p1=nil
|
local p1=nil
|
||||||
local wpap=nil
|
local wpap=nil
|
||||||
|
|
||||||
|
-- Altitude above ground for a glide slope of 3°.
|
||||||
|
local alpha=math.rad(3)
|
||||||
|
local x1=UTILS.NMToMeters(10)
|
||||||
|
local x2=UTILS.NMToMeters(5)
|
||||||
|
local h1=x1*math.tan(alpha)
|
||||||
|
local h2=x2*math.tan(alpha)
|
||||||
|
|
||||||
|
-- Get a landing point
|
||||||
|
local pland=airbase:GetZone():GetRandomCoordinate(x2,x1):SetAltitude(x2)
|
||||||
|
|
||||||
-- Do we have a flight control?
|
-- Do we have a flight control?
|
||||||
local fc=_DATABASE:GetFlightControl(airbase:GetName())
|
local fc=_DATABASE:GetFlightControl(airbase:GetName())
|
||||||
if fc then
|
if fc then
|
||||||
@@ -1379,21 +1420,23 @@ function FLIGHTGROUP:onafterHold(From, Event, To, airbase, SpeedTo, SpeedHold)
|
|||||||
p0=HoldingPoint.pos0
|
p0=HoldingPoint.pos0
|
||||||
p1=HoldingPoint.pos1
|
p1=HoldingPoint.pos1
|
||||||
|
|
||||||
p0:MarkToAll("P0")
|
-- Debug marks.
|
||||||
p1:MarkToAll("P1")
|
p0:MarkToAll("Holding point P0")
|
||||||
|
p1:MarkToAll("Holding point P1")
|
||||||
|
|
||||||
-- Get active runway.
|
-- Get active runway.
|
||||||
local runway=fc:_GetActiveRunway()
|
local runway=fc:GetActiveRunway()
|
||||||
|
|
||||||
|
-- Approach point: 10 NN in direction of runway.
|
||||||
|
local papp=airbase:GetCoordinate():Translate(x1, runway.direction-180):SetAltitude(h1)
|
||||||
|
papp:MarkToAll(string.format("Final Approach: d=%d m, h=%d m", x1, h1))
|
||||||
|
wpap=papp:WaypointAirTurningPoint(nil, UTILS.KnotsToKmph(SpeedLand), {}, "Final Approach")
|
||||||
|
|
||||||
-- TODO: make dependend on AC type helos etc.
|
-- TODO: make dependend on AC type helos etc.
|
||||||
|
|
||||||
-- Approach point: 10 NN in direction of runway.
|
-- Approach point: 10 NN in direction of runway.
|
||||||
local papproach=airbase:GetCoordinate():Translate(UTILS.NMToMeters(10), runway.direction-180):SetAltitude(UTILS.FeetToMeters(3000))
|
pland=airbase:GetCoordinate():Translate(x2, runway.direction-180):SetAltitude(h2)
|
||||||
|
pland:MarkToAll(string.format("Landing: d=%d m, h=%d m", x2, h2))
|
||||||
papproach:MarkToAll("Final Approach")
|
|
||||||
|
|
||||||
-- Approach waypoint.
|
|
||||||
wpap=papproach:WaypointAirTurningPoint(nil, UTILS.KnotsToKmph(SpeedLand), {}, "Final Approach")
|
|
||||||
|
|
||||||
-- Set flightcontrol for this flight.
|
-- Set flightcontrol for this flight.
|
||||||
self:SetFlightControl(fc)
|
self:SetFlightControl(fc)
|
||||||
@@ -1417,8 +1460,13 @@ function FLIGHTGROUP:onafterHold(From, Event, To, airbase, SpeedTo, SpeedHold)
|
|||||||
wp[#wp+1]= p0:WaypointAir(nil, COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.FlyoverPoint, UTILS.KnotsToKmph(SpeedTo), true , nil, {TaskArrived, TaskControlled}, "Holding Point")
|
wp[#wp+1]= p0:WaypointAir(nil, COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.FlyoverPoint, UTILS.KnotsToKmph(SpeedTo), true , nil, {TaskArrived, TaskControlled}, "Holding Point")
|
||||||
if wpap then
|
if wpap then
|
||||||
wp[#wp+1]=wpap
|
wp[#wp+1]=wpap
|
||||||
end
|
end
|
||||||
wp[#wp+1]=airbase:GetCoordinate():SetAltitude(UTILS.FeetToMeters(500)):WaypointAirLanding(UTILS.KnotsToKmph(SpeedLand), airbase, {}, "Landing")
|
|
||||||
|
-- Okay, it looks like it's best to specify the coordinates not at the airbase but a bit away. This causes a more direct landing approach.
|
||||||
|
wp[#wp+1]=pland:WaypointAirLanding(UTILS.KnotsToKmph(SpeedLand), airbase, {}, "Landing")
|
||||||
|
|
||||||
|
-- This is NOT good! It causes the AC to fly to the airbase and then start landing, i.e. go back.
|
||||||
|
--wp[#wp+1]=airbase:GetCoordinate():SetAltitude(UTILS.FeetToMeters(0)):WaypointAirLanding(UTILS.KnotsToKmph(SpeedLand), airbase, {}, "Landing")
|
||||||
|
|
||||||
local respawn=true
|
local respawn=true
|
||||||
|
|
||||||
@@ -1442,21 +1490,6 @@ function FLIGHTGROUP:onafterHold(From, Event, To, airbase, SpeedTo, SpeedHold)
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Function called when flight has reached the holding point.
|
|
||||||
-- @param Wrapper.Group#GROUP group Group object.
|
|
||||||
-- @param #FLIGHTGROUP flightgroup Flight group object.
|
|
||||||
function FLIGHTGROUP._ReachedHolding(group, flightgroup)
|
|
||||||
env.info(string.format("FF group %s reached holding point", group:GetName()))
|
|
||||||
group:GetCoordinate():MarkToAll("Holding Point Reached")
|
|
||||||
|
|
||||||
flightgroup.flaghold:Set(666)
|
|
||||||
|
|
||||||
-- Add flight to waiting/holding queue.
|
|
||||||
if flightgroup.flightcontrol then
|
|
||||||
table.insert(flightgroup.flightcontrol.Qwaiting, flightgroup)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--- On after TaskExecute event.
|
--- On after TaskExecute event.
|
||||||
-- @param #FLIGHTGROUP self
|
-- @param #FLIGHTGROUP self
|
||||||
-- @param #string From From state.
|
-- @param #string From From state.
|
||||||
@@ -1696,6 +1729,68 @@ function FLIGHTGROUP._TaskDone(group, flightgroup, task)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Function called when a group is passing a waypoint.
|
||||||
|
--@param Wrapper.Group#GROUP group Group that passed the waypoint
|
||||||
|
--@param #FLIGHTGROUP flightgroup Flightgroup object.
|
||||||
|
--@param #number i Waypoint number that has been reached.
|
||||||
|
function FLIGHTGROUP._PassingWaypoint(group, flightgroup, i)
|
||||||
|
|
||||||
|
local final=#flightgroup.waypoints or 1
|
||||||
|
|
||||||
|
-- Debug message.
|
||||||
|
local text=string.format("Group %s passing waypoint %d of %d.", group:GetName(), i, final)
|
||||||
|
|
||||||
|
-- Debug smoke and marker.
|
||||||
|
if flightgroup.Debug then
|
||||||
|
local pos=group:GetCoordinate()
|
||||||
|
--pos:SmokeRed()
|
||||||
|
local MarkerID=pos:MarkToAll(string.format("Group %s reached waypoint %d", group:GetName(), i))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Debug message.
|
||||||
|
--MESSAGE:New(text,10):ToAllIf(flightgroup.Debug)
|
||||||
|
flightgroup:T2(flightgroup.sid..text)
|
||||||
|
|
||||||
|
-- Set current waypoint.
|
||||||
|
flightgroup.currentwp=i
|
||||||
|
|
||||||
|
-- Passing Waypoint event.
|
||||||
|
flightgroup:PassingWaypoint(i, final)
|
||||||
|
|
||||||
|
-- If final waypoint reached, do route all over again.
|
||||||
|
if i==final and final>1 then
|
||||||
|
--TODO: final waypoint reached! what next?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Function called when flight has reached the holding point.
|
||||||
|
-- @param Wrapper.Group#GROUP group Group object.
|
||||||
|
-- @param #FLIGHTGROUP flightgroup Flight group object.
|
||||||
|
function FLIGHTGROUP._ReachedHolding(group, flightgroup)
|
||||||
|
env.info(string.format("FF group %s reached holding point", group:GetName()))
|
||||||
|
group:GetCoordinate():MarkToAll("Holding Point Reached")
|
||||||
|
|
||||||
|
flightgroup.flaghold:Set(666)
|
||||||
|
|
||||||
|
-- Add flight to waiting/holding queue.
|
||||||
|
if flightgroup.flightcontrol then
|
||||||
|
flightgroup.flightcontrol:_AddFlightToHoldingQueue(flightgroup)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Update route of group, e.g after new waypoints and/or waypoint tasks have been added.
|
||||||
|
-- @param Wrapper.Group#GROUP group The Moose group object.
|
||||||
|
-- @param #FLIGHTGROUP flightgroup The flight group object.
|
||||||
|
-- @param Wrapper.Airbase#AIRBASE destination Destination airbase
|
||||||
|
function FLIGHTGROUP._DestinationOverhead(group, flightgroup, destination)
|
||||||
|
|
||||||
|
-- Tell the flight to hold.
|
||||||
|
-- WARNING: This needs to be delayed or we get a CTD!
|
||||||
|
flightgroup:__Hold(1, destination)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Route flight group back to base.
|
--- Route flight group back to base.
|
||||||
-- @param #FLIGHTGROUP self
|
-- @param #FLIGHTGROUP self
|
||||||
-- @param Wrapper.Airbase#AIRBASE RTBAirbase
|
-- @param Wrapper.Airbase#AIRBASE RTBAirbase
|
||||||
@@ -1868,7 +1963,7 @@ function FLIGHTGROUP:GetHomebaseFromWaypoints()
|
|||||||
|
|
||||||
if wp then
|
if wp then
|
||||||
|
|
||||||
if wp and wp.action and wp.action==COORDINATE.WaypointAction.Landing then
|
if wp and wp.action and wp.action==COORDINATE.WaypointAction.FromParkingArea or wp.action==COORDINATE.WaypointAction.FromParkingAreaHot or wp.action==COORDINATE.WaypointAction.FromRunway then
|
||||||
|
|
||||||
-- Get airbase ID depending on airbase category.
|
-- Get airbase ID depending on airbase category.
|
||||||
local airbaseID=wp.airdromeId or wp.helipadId
|
local airbaseID=wp.airdromeId or wp.helipadId
|
||||||
@@ -2010,8 +2105,10 @@ function FLIGHTGROUP:_UpdateRoute(n)
|
|||||||
if self.destination and #wp>0 then
|
if self.destination and #wp>0 then
|
||||||
|
|
||||||
local TaskOverhead=self.group:TaskFunction("FLIGHTGROUP._DestinationOverhead", self, self.destination)
|
local TaskOverhead=self.group:TaskFunction("FLIGHTGROUP._DestinationOverhead", self, self.destination)
|
||||||
|
|
||||||
|
local coordoverhead=self.destination:GetZone():GetRandomCoordinate():SetAltitude(UTILS.FeetToMeters(6000))
|
||||||
|
|
||||||
local wpoverhead=self.destination:GetCoordinate():SetAltitude(3000):WaypointAir(nil, COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.FlyoverPoint, 500, false, nil, {TaskOverhead}, "Destination Overhead")
|
local wpoverhead=coordoverhead:WaypointAir(nil, COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.FlyoverPoint, 500, false, nil, {TaskOverhead}, "Destination Overhead")
|
||||||
self:I(self.sid..string.format("Adding overhead waypoint as #%d", #wp))
|
self:I(self.sid..string.format("Adding overhead waypoint as #%d", #wp))
|
||||||
table.insert(wp, #wp, wpoverhead)
|
table.insert(wp, #wp, wpoverhead)
|
||||||
end
|
end
|
||||||
@@ -2051,18 +2148,6 @@ function FLIGHTGROUP:_UpdateRoute(n)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Update route of group, e.g after new waypoints and/or waypoint tasks have been added.
|
|
||||||
-- @param Wrapper.Group#GROUP group The Moose group object.
|
|
||||||
-- @param #FLIGHTGROUP flightgroup The flight group object.
|
|
||||||
-- @param Wrapper.Airbase#AIRBASE destination Destination airbase
|
|
||||||
function FLIGHTGROUP._DestinationOverhead(group, flightgroup, destination)
|
|
||||||
|
|
||||||
-- Tell the flight to hold.
|
|
||||||
-- WARNING: This needs to be delayed or we get a CTD!
|
|
||||||
flightgroup:__Hold(1, destination)
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Initialize Mission Editor waypoints.
|
--- Initialize Mission Editor waypoints.
|
||||||
-- @param #FLIGHTGROUP self
|
-- @param #FLIGHTGROUP self
|
||||||
function FLIGHTGROUP:_UpdateWaypointTasks()
|
function FLIGHTGROUP:_UpdateWaypointTasks()
|
||||||
@@ -2149,43 +2234,6 @@ function FLIGHTGROUP:InitWaypoints(waypoints)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Function called when a group is passing a waypoint.
|
|
||||||
--@param Wrapper.Group#GROUP group Group that passed the waypoint
|
|
||||||
--@param #FLIGHTGROUP flightgroup Flightgroup object.
|
|
||||||
--@param #number i Waypoint number that has been reached.
|
|
||||||
function FLIGHTGROUP._PassingWaypoint(group, flightgroup, i)
|
|
||||||
|
|
||||||
local final=#flightgroup.waypoints or 1
|
|
||||||
|
|
||||||
-- Debug message.
|
|
||||||
local text=string.format("Group %s passing waypoint %d of %d.", group:GetName(), i, final)
|
|
||||||
|
|
||||||
-- Debug smoke and marker.
|
|
||||||
if flightgroup.Debug then
|
|
||||||
local pos=group:GetCoordinate()
|
|
||||||
--pos:SmokeRed()
|
|
||||||
local MarkerID=pos:MarkToAll(string.format("Group %s reached waypoint %d", group:GetName(), i))
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Debug message.
|
|
||||||
--MESSAGE:New(text,10):ToAllIf(flightgroup.Debug)
|
|
||||||
flightgroup:T2(flightgroup.sid..text)
|
|
||||||
|
|
||||||
-- Set current waypoint.
|
|
||||||
flightgroup.currentwp=i
|
|
||||||
|
|
||||||
-- Passing Waypoint event.
|
|
||||||
flightgroup:PassingWaypoint(i, final)
|
|
||||||
|
|
||||||
-- If final waypoint reached, do route all over again.
|
|
||||||
if i==final and final>1 then
|
|
||||||
--TODO: final waypoint reached! what next?
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- Check if a unit is and element of the flightgroup.
|
--- Check if a unit is and element of the flightgroup.
|
||||||
-- @param #FLIGHTGROUP self
|
-- @param #FLIGHTGROUP self
|
||||||
-- @param #string unitname Name of unit.
|
-- @param #string unitname Name of unit.
|
||||||
|
|||||||
@@ -13,6 +13,8 @@
|
|||||||
|
|
||||||
|
|
||||||
--- @type AIRBASE
|
--- @type AIRBASE
|
||||||
|
-- @field #string ClassName Name of the class, i.e. "AIRBASE".
|
||||||
|
-- @field #table CategoryName Names of airbase categories.
|
||||||
-- @extends Wrapper.Positionable#POSITIONABLE
|
-- @extends Wrapper.Positionable#POSITIONABLE
|
||||||
|
|
||||||
--- Wrapper class to handle the DCS Airbase objects:
|
--- Wrapper class to handle the DCS Airbase objects:
|
||||||
@@ -990,3 +992,8 @@ function AIRBASE._CheckTerminalType(Term_Type, termtype)
|
|||||||
|
|
||||||
return match
|
return match
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1097,8 +1097,6 @@ function UNIT:GetTemplate()
|
|||||||
|
|
||||||
for _,unit in pairs(template.units) do
|
for _,unit in pairs(template.units) do
|
||||||
|
|
||||||
self:I(string.format("FF template unit %s = %s", unit.name, name))
|
|
||||||
|
|
||||||
if unit.name==name then
|
if unit.name==name then
|
||||||
return UTILS.DeepCopy(unit)
|
return UTILS.DeepCopy(unit)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ Ops/RecoveryTanker.lua
|
|||||||
Ops/RescueHelo.lua
|
Ops/RescueHelo.lua
|
||||||
Ops/FlightControl.lua
|
Ops/FlightControl.lua
|
||||||
Ops/Skipper.lua
|
Ops/Skipper.lua
|
||||||
|
Ops/ATIS.lua
|
||||||
|
|
||||||
AI/AI_Balancer.lua
|
AI/AI_Balancer.lua
|
||||||
AI/AI_Air.lua
|
AI/AI_Air.lua
|
||||||
|
|||||||
Reference in New Issue
Block a user