Merge pull request #1154 from FlightControl-Master/FF/Develop

MISC
This commit is contained in:
Frank 2019-05-07 22:06:42 +02:00 committed by GitHub
commit 32ff4db36a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 600 additions and 15 deletions

View File

@ -19,7 +19,7 @@
-- * Your sound files need to be encoded in **.ogg** or .wav,
-- * Your sound files should be **as tiny as possible**. It is suggested you encode in .ogg with low bitrate and sampling settings,
-- * They need to be added in .\l10n\DEFAULT\ in you .miz file (wich can be decompressed like a .zip file),
-- * For simplicty sake, you can **let DCS' Mission Editor add the file** itself, by creating a new Trigger with the action "Sound to Country", and choosing your sound file and a country you don't use in your mission.
-- * For simplicity sake, you can **let DCS' Mission Editor add the file** itself, by creating a new Trigger with the action "Sound to Country", and choosing your sound file and a country you don't use in your mission.
--
-- Due to weird DCS quirks, **radio communications behave differently** if sent by a @{Wrapper.Unit#UNIT} or a @{Wrapper.Group#GROUP} or by any other @{Wrapper.Positionable#POSITIONABLE}
--
@ -28,7 +28,7 @@
--
-- Note that obviously, the **frequency** and the **modulation** of the transmission are important only if the players are piloting an **Advanced System Modelling** enabled aircraft,
-- like the A10C or the Mirage 2000C. They will **hear the transmission** if they are tuned on the **right frequency and modulation** (and if they are close enough - more on that below).
-- If a FC3 airacraft is used, it will **hear every communication, whatever the frequency and the modulation** is set to. The same is true for TACAN beacons. If your aircaft isn't compatible,
-- If an FC3 aircraft is used, it will **hear every communication, whatever the frequency and the modulation** is set to. The same is true for TACAN beacons. If your aircraft isn't compatible,
-- you won't hear/be able to use the TACAN beacon informations.
--
-- ===
@ -39,7 +39,7 @@
-- @image Core_Radio.JPG
--- Models the radio capabilty.
--- Models the radio capability.
--
-- ## RADIO usage
--
@ -56,12 +56,12 @@
-- * @{#RADIO.SetModulation}() : Sets the modulation of your transmission.
-- * @{#RADIO.SetLoop}() : Choose if you want the transmission to be looped. If you need your transmission to be looped, you might need a @{#BEACON} instead...
--
-- Additional Methods to set relevant parameters if the transmiter is a @{Wrapper.Unit#UNIT} or a @{Wrapper.Group#GROUP}
-- Additional Methods to set relevant parameters if the transmitter is a @{Wrapper.Unit#UNIT} or a @{Wrapper.Group#GROUP}
--
-- * @{#RADIO.SetSubtitle}() : Set both the subtitle and its duration,
-- * @{#RADIO.NewUnitTransmission}() : Shortcut to set all the relevant parameters in one method call
--
-- Additional Methods to set relevant parameters if the transmiter is any other @{Wrapper.Positionable#POSITIONABLE}
-- Additional Methods to set relevant parameters if the transmitter is any other @{Wrapper.Positionable#POSITIONABLE}
--
-- * @{#RADIO.SetPower}() : Sets the power of the antenna in Watts
-- * @{#RADIO.NewGenericTransmission}() : Shortcut to set all the relevant parameters in one method call
@ -797,3 +797,470 @@ function BEACON:_TACANToFrequency(TACANChannel, TACANMode)
return (A + TACANChannel - B) * 1000000
end
--- Manages radio transmissions.
--
-- @type RADIOQUEUE
-- @field #string ClassName Name of the class "RADIOQUEUE".
-- @field #string lid ID for dcs.log.
-- @field #number frequency The radio frequency in Hz.
-- @field #number modulation The radio modulation. Either radio.modulation.AM or radio.modulation.FM.
-- @field Core.Scheduler#SCHEDULER scheduler The scheduler.
-- @field #string RQid The radio queue scheduler ID.
-- @field #table queue The queue of transmissions.
-- @field #number Tlast Time (abs) when the last transmission finished.
-- @field Core.Point#COORDINATE sendercoord Coordinate from where transmissions are broadcasted.
-- @field #number sendername Name of the sending unit or static.
-- @field Wrapper.Positionable#POSITIONABLE positionable The positionable to broadcast the message.
-- @field #number power Power of radio station in Watts. Default 100 W.
-- @field #table numbers Table of number transmission parameters.
-- @extends Core.Base#BASE
RADIOQUEUE = {
ClassName = "RADIOQUEUE",
lid=nil,
frequency=nil,
modulation=nil,
scheduler=nil,
RQid=nil,
queue={},
Tlast=nil,
sendercoord=nil,
sendername=nil,
positionable=nil,
power=100,
numbers={},
}
--- Radio queue transmission data.
-- @type RADIOQUEUE.Transmission
-- @field #string filename Name of the file to be transmitted.
-- @field #string path Path in miz file where the file is located.
-- @field #number duration Duration in seconds.
-- @field #number Tstarted Mission time (abs) in seconds when the transmission started.
-- @field #boolean isplaying If true, transmission is currently playing.
-- @field #number Tplay Mission time (abs) in seconds when the transmission should be played.
--- Create a new RADIOQUEUE object for a given radio frequency/modulation.
-- @param #RADIOQUEUE self
-- @param #number frequency The radio frequency in MHz.
-- @param #number modulation (Optional) The radio modulation. Default radio.modulation.AM.
-- @return #RADIOQUEUE self The RADIOQUEUE object.
function RADIOQUEUE:New(frequency, modulation)
-- Inherit base
local self=BASE:Inherit(self, BASE:New()) -- Core.Radio#RADIOQUEUE
self.lid="RADIOQUEUE | "
if frequency==nil then
self:E(self.lid.."ERROR: No frequency specified as first parameter!")
return nil
end
-- Frequency in Hz.
self.frequency=frequency*1000000
-- Modulation.
self.modulation=modulation or radio.modulation.AM
-- Scheduler
self.scheduler=SCHEDULER:New()
return self
end
--- Start the radio queue.
-- @param #RADIOQUEUE self
-- @param #number delay (Optional) Delay in seconds, before the radio queue is started. Default 1 sec.
-- @param #number dt (Optional) Time step in seconds for checking the queue. Default 0.01 sec.
-- @return #RADIOQUEUE self The RADIOQUEUE object.
function RADIOQUEUE:Start(delay, dt)
delay=delay or 1
dt=dt or 0.01
self:I(self.lid..string.format("Starting RADIOQUEUE in %.1f seconds with interval dt=%.3f seconds.", delay, dt))
self.RQid=self.scheduler:Schedule(self, self._CheckRadioQueue, {}, delay, dt)
return self
end
--- Stop the radio queue. Stop scheduler and delete queue.
-- @param #RADIOQUEUE self
-- @return #RADIOQUEUE self The RADIOQUEUE object.
function RADIOQUEUE:Stop()
self:I(self.lid.."Stopping RADIOQUEUE.")
self.scheduler:Stop(self.RQid)
self.queue={}
return self
end
--- Set coordinate from where the transmission is broadcasted.
-- @param #RADIOQUEUE self
-- @param Core.Point#COORDINATE coordinate Coordinate of the sender.
-- @return #RADIOQUEUE self The RADIOQUEUE object.
function RADIOQUEUE:SetSenderCoordinate(coordinate)
self.sendercoord=coordinate
return self
end
--- Set name of unit or static from which transmissions are made.
-- @param #RADIOQUEUE self
-- @param #string name Name of the unit or static used for transmissions.
-- @return #RADIOQUEUE self The RADIOQUEUE object.
function RADIOQUEUE:SetSenderUnitName(name)
self.sendername=name
return self
end
--- Set parameters of a digit.
-- @param #RADIOQUEUE self
-- @param #number digit The digit 0-9.
-- @param #string filename The name of the sound file.
-- @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/".
-- @return #RADIOQUEUE self The RADIOQUEUE object.
function RADIOQUEUE:SetDigit(digit, filename, duration, path)
local transmission={} --#RADIOQUEUE.Transmission
transmission.filename=filename
transmission.duration=duration
transmission.path=path or "l10n/DEFAULT/"
-- Convert digit to string in case it is given as a number.
if type(digit)=="number" then
digit=tostring(digit)
end
-- Set transmission.
self.numbers[digit]=transmission
return self
end
--- Add a transmission to the radio queue.
-- @param #RADIOQUEUE self
-- @param #RADIOQUEUE.Transmission transmission The transmission data table.
-- @return #RADIOQUEUE self The RADIOQUEUE object.
function RADIOQUEUE:AddTransmission(transmission)
self:F({transmission=transmission})
-- Init.
transmission.isplaying=false
transmission.Tstarted=nil
-- Add to queue.
table.insert(self.queue, transmission)
return self
end
--- Add a transmission to the radio queue.
-- @param #RADIOQUEUE self
-- @param #string filename Name of the sound file. Usually an ogg or wav file type.
-- @param #number duration Duration in seconds the file lasts.
-- @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 interval Interval in seconds after the last transmission finished.
-- @return #RADIOQUEUE self The RADIOQUEUE object.
function RADIOQUEUE:NewTransmission(filename, duration, path, tstart, interval)
-- Sanity checks.
if not filename then
self:E(self.lid.."ERROR: No filename specified.")
return nil
end
if type(filename)~="string" then
self:E(self.lid.."ERROR: Filename specified is NOT a string.")
return nil
end
if not duration then
self:E(self.lid.."ERROR: No duration of transmission specified.")
return nil
end
if type(duration)~="number" then
self:E(self.lid.."ERROR: Duration specified is NOT a number.")
return nil
end
local transmission={} --#RADIOQUEUE.Transmission
transmission.filename=filename
transmission.duration=duration
transmission.path=path or "l10n/DEFAULT/"
transmission.Tplay=tstart or timer.getAbsTime()
-- Add transmission to queue.
self:AddTransmission(transmission)
return self
end
--- Convert a number (as string) into a radio transmission.
-- E.g. for board number or headings.
-- @param #RADIOQUEUE self
-- @param #string number Number string, e.g. "032" or "183".
-- @param #number delay Delay before transmission in seconds.
-- @param #number interval Interval between the next call.
-- @return #number Duration of the call in seconds.
function RADIOQUEUE:Number2Transmission(number, delay, interval)
--- Split string into characters.
local function _split(str)
local chars={}
for i=1,#str do
local c=str:sub(i,i)
table.insert(chars, c)
end
return chars
end
-- Split string into characters.
local numbers=_split(number)
local wait=0
for i=1,#numbers do
-- Current number
local n=numbers[i]
-- Radio call.
local transmission=UTILS.DeepCopy(self.numbers[n]) --#RADIOQUEUE.Transmission
transmission.Tplay=timer.getAbsTime()+(delay or 0)
if interval and i==1 then
transmission.interval=interval
end
self:AddTransmission(transmission)
-- Add up duration of the number.
wait=wait+transmission.duration
end
-- Return the total duration of the call.
return wait
end
--- Broadcast radio message.
-- @param #RADIOQUEUE self
-- @param #RADIOQUEUE.Transmission transmission The transmission.
function RADIOQUEUE:Broadcast(transmission)
-- Get unit sending the transmission.
local sender=self:_GetRadioSender()
-- Construct file name.
local filename=string.format("%s%s", transmission.path, transmission.filename)
-- Create subtitle for transmission.
--local subtitle=self:_RadioSubtitle(radio, call, loud)
if sender then
-- 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()))
-- Command to set the Frequency for the transmission.
local commandFrequency={
id="SetFrequency",
params={
frequency=self.frequency, -- Frequency in Hz.
modulation=self.modulation,
}}
-- Command to tranmit the call.
local commandTransmit={
id = "TransmitMessage",
params = {
file=filename,
duration=transmission.subduration or 5,
subtitle=transmission.subtitle or "",
loop=false,
}}
-- Set commend for frequency
sender:SetCommand(commandFrequency)
-- Set command for radio transmission.
sender:SetCommand(commandTransmit)
else
-- 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()."))
-- Position from where to transmit.
local vec3=nil
-- Try to get positon from sender unit/static.
if self.sendername then
local coord=self:_GetRadioSenderCoord()
if coord then
vec3=coord:GetVec3()
end
end
-- Try to get fixed positon.
if self.sendercoord and not vec3 then
vec3=self.sendercoord:GetVec3()
end
-- Transmit via trigger.
if vec3 then
trigger.action.radioTransmission(filename, vec3, self.modulation, false, self.frequency, self.power)
end
end
end
--- Check radio queue for transmissions to be broadcasted.
-- @param #RADIOQUEUE self
function RADIOQUEUE:_CheckRadioQueue()
-- Check if queue is empty.
if #self.queue==0 then
return
end
-- Get current abs time.
local time=timer.getAbsTime()
local playing=false
local next=nil --#RADIOQUEUE.Transmission
local remove=nil
for i,_transmission in ipairs(self.queue) do
local transmission=_transmission --#RADIOQUEUE.Transmission
-- Check if transmission time has passed.
if time>=transmission.Tplay then
-- Check if transmission is currently playing.
if transmission.isplaying then
-- Check if transmission is finished.
if time>=transmission.Tstarted+transmission.duration then
-- Transmission over.
transmission.isplaying=false
-- Remove ith element in queue.
remove=i
-- Store time last transmission finished.
self.Tlast=time
else -- still playing
-- Transmission is still playing.
playing=true
end
else -- not playing yet
local Tlast=self.Tlast
if transmission.interval==nil then
-- Not playing ==> this will be next.
if next==nil then
next=transmission
end
else
if time-Tlast>=transmission.interval then
next=transmission
else
end
end
-- We got a transmission or one with an interval that is not due yet. No need for anything else.
if next or Tlast then
break
end
end
else
-- Transmission not due yet.
end
end
-- Found a new transmission.
if next~=nil and not playing then
self:Broadcast(next)
next.isplaying=true
next.Tstarted=time
end
-- Remove completed calls from queue.
if remove then
table.remove(self.queue, remove)
end
end
--- Get unit from which we want to transmit a radio message. This has to be an aircraft for subtitles to work.
-- @param #RADIOQUEUE self
-- @return Wrapper.Unit#UNIT Sending aircraft unit or nil if was not setup, is not an aircraft or is not alive.
function RADIOQUEUE:_GetRadioSender()
-- Check if we have a sending aircraft.
local sender=nil --Wrapper.Unit#UNIT
-- Try the general default.
if self.sendername then
-- First try to find a unit
sender=UNIT:FindByName(self.sendername)
-- Check that sender is alive and an aircraft.
if sender and sender:IsAlive() and sender:IsAir() then
return sender
end
end
return nil
end
--- Get unit from which we want to transmit a radio message. This has to be an aircraft for subtitles to work.
-- @param #RADIOQUEUE self
-- @return Core.Point#COORDINATE Coordinate of the sender unit.
function RADIOQUEUE:_GetRadioSenderCoord()
local vec3=nil
-- Try the general default.
if self.sendername then
-- First try to find a unit
local sender=UNIT:FindByName(self.sendername)
-- Check that sender is alive and an aircraft.
if sender and sender:IsAlive() then
return sender:GetCoodinate()
end
-- Now try a static.
local sender=STATIC:FindByName(self.sendername)
-- Check that sender is alive and an aircraft.
if sender then
return sender:GetCoodinate()
end
end
return nil
end

View File

@ -52,6 +52,7 @@
-- @field #table bombingTargets Table of targets to bomb.
-- @field #number nbombtargets Number of bombing targets.
-- @field #number nstrafetargets Number of strafing targets.
-- @field #boolean messages Globally enable/disable all messages to players.
-- @field #table MenuAddedTo Table for monitoring which players already got an F10 menu.
-- @field #table planes Table for administration.
-- @field #table strafeStatus Table containing the current strafing target a player as assigned to.
@ -217,6 +218,7 @@ RANGE={
id=nil,
rangename=nil,
location=nil,
messages=true,
rangeradius=5000,
rangezone=nil,
strafeTargets={},
@ -286,9 +288,11 @@ RANGE.TargetType={
-- @field #number smokecolor Color of smoke.
-- @field #number flarecolor Color of flares.
-- @field #boolean messages Display info messages.
-- @field Wrapper.Client#CLIENT client Client object of player.
-- @field #string unitname Name of player aircraft unit.
-- @field #string playername Name of player.
-- @field #string airframe Aircraft type name.
-- @field #boolean inzone If true, player is inside the range zone.
--- Bomb target data.
-- @type RANGE.BombTarget
@ -336,7 +340,7 @@ RANGE.MenuF10Root=nil
--- Range script version.
-- @field #string version
RANGE.version="2.0.0"
RANGE.version="2.1.0"
--TODO list:
--TODO: Verbosity level for messages.
@ -388,6 +392,8 @@ function RANGE:New(rangename)
self:AddTransition("Stopped", "Start", "Running") -- Start RANGE script.
self:AddTransition("*", "Status", "*") -- Status of RANGE script.
self:AddTransition("*", "Impact", "*") -- Impact of bomb/rocket/missile.
self:AddTransition("*", "EnterRange", "*") -- Player enters the range.
self:AddTransition("*", "ExitRange", "*") -- Player leaves the range.
self:AddTransition("*", "Save", "*") -- Save player results.
self:AddTransition("*", "Load", "*") -- Load player results.
@ -443,6 +449,44 @@ function RANGE:New(rangename)
-- @param #RANGE.BombResult result Data of the bombing run.
-- @param #RANGE.Playerdata player Data of player settings etc.
--- Triggers the FSM event "EnterRange".
-- @function [parent=#RANGE] EnterRange
-- @param #RANGE self
-- @param #RANGE.Playerdata player Data of player settings etc.
--- Triggers the FSM delayed event "EnterRange".
-- @function [parent=#RANGE] __EnterRange
-- @param #RANGE self
-- @param #number delay Delay in seconds before the function is called.
-- @param #RANGE.Playerdata player Data of player settings etc.
--- On after "EnterRange" event user function. Called when a player enters the range zone.
-- @function [parent=#RANGE] OnAfterEnterRange
-- @param #RANGE self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param #RANGE.Playerdata player Data of player settings etc.
--- Triggers the FSM event "ExitRange".
-- @function [parent=#RANGE] ExitRange
-- @param #RANGE self
-- @param #RANGE.Playerdata player Data of player settings etc.
--- Triggers the FSM delayed event "ExitRange".
-- @function [parent=#RANGE] __ExitRange
-- @param #RANGE self
-- @param #number delay Delay in seconds before the function is called.
-- @param #RANGE.Playerdata player Data of player settings etc.
--- On after "ExitRange" event user function. Called when a player leaves the range zone.
-- @function [parent=#RANGE] OnAfterExitRange
-- @param #RANGE self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param #RANGE.Playerdata player Data of player settings etc.
-- Return object.
return self
end
@ -721,6 +765,23 @@ function RANGE:DebugOFF()
return self
end
--- Disable ALL messages to players.
-- @param #RANGE self
-- @return #RANGE self
function RANGE:SetMessagesOFF()
self.messages=false
return self
end
--- Enable messages to players. This is the default
-- @param #RANGE self
-- @return #RANGE self
function RANGE:SetMessagesON()
self.messages=true
return self
end
--- Enables tracking of all bomb types. Note that this is the default setting.
-- @param #RANGE self
-- @return #RANGE self
@ -1253,9 +1314,11 @@ function RANGE:OnEventBirth(EventData)
self.PlayerSettings[_playername].flarecolor=FLARECOLOR.Red
self.PlayerSettings[_playername].delaysmoke=true
self.PlayerSettings[_playername].messages=true
self.PlayerSettings[_playername].client=CLIENT:FindByName(_unitName, nil, true)
self.PlayerSettings[_playername].unitname=_unitName
self.PlayerSettings[_playername].playername=_playername
self.PlayerSettings[_playername].airframe=EventData.IniUnit:GetTypeName()
self.PlayerSettings[_playername].inzone=false
-- Start check in zone timer.
if self.planes[_uid] ~= true then
@ -1580,16 +1643,19 @@ end
-- @param #string To To state.
function RANGE:onafterStatus(From, Event, To)
-- Check range status.
self:I(self.id..string.format("Range status: %s", self:GetState()))
--self:_CheckMissileStatus()
-- Check player status.
self:_CheckPlayers()
-- Save results.
if self.autosafe then
self:Save()
end
self:__Status(-60)
-- Check back in ~10 seconds.
self:__Status(-10)
end
@ -2245,6 +2311,47 @@ end
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Timer Functions
--- Check status of players.
-- @param #RANGE self
-- @param #string _unitName Name of player unit.
function RANGE:_CheckPlayers()
for playername,_playersettings in pairs(self.PlayerSettings) do
local playersettings=_playersettings --#RANGE.PlayerData
local unitname=playersettings.unitname
local unit=UNIT:FindByName(unitname)
if unit and unit:IsAlive() then
if unit:IsInZone(self.rangezone) then
------------------------------
-- Player INSIDE Range Zone --
------------------------------
if not playersettings.inzone then
self:EnterRange(playersettings)
playersettings.inzone=true
end
else
-------------------------------
-- Player OUTSIDE Range Zone --
-------------------------------
if playersettings.inzone==true then
self:ExitRange(playersettings)
playersettings.inzone=false
end
end
end
end
end
--- Check if player is inside a strafing zone. If he is, we start looking for hits. If he was and left the zone again, the result is stored.
-- @param #RANGE self
-- @param #string _unitName Name of player unit.
@ -2727,6 +2834,11 @@ function RANGE:_DisplayMessageToGroup(_unit, _text, _time, _clear, display)
_clear=true
end
-- Messages globally disabled.
if self.messages==false then
return
end
-- Check if unit is alive.
if _unit and _unit:IsAlive() then

View File

@ -1733,7 +1733,7 @@ _WAREHOUSEDB = {
--- Warehouse class version.
-- @field #string version
WAREHOUSE.version="0.6.9"
WAREHOUSE.version="0.7.0"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO: Warehouse todo list.
@ -7669,7 +7669,13 @@ function WAREHOUSE:_PrintQueue(queue, name)
end
self:I(self.wid..text)
if #queue==0 then
self:T(self.wid..text)
else
if total~="Empty" then
self:I(self.wid..text)
end
end
end
--- Display status of warehouse.
@ -8109,28 +8115,28 @@ function WAREHOUSE:_GetFlightplan(asset, departure, destination)
--- Departure/Take-off
c[#c+1]=Pdeparture
wp[#wp+1]=Pdeparture:WaypointAir("RADIO", COORDINATE.WaypointType.TakeOffParking, COORDINATE.WaypointAction.FromParkingArea, VxClimb, true, departure, nil, "Departure")
wp[#wp+1]=Pdeparture:WaypointAir("RADIO", COORDINATE.WaypointType.TakeOffParking, COORDINATE.WaypointAction.FromParkingArea, VxClimb*3.6, true, departure, nil, "Departure")
--- Begin of Cruise
local Pcruise=Pdeparture:Translate(d_climb, heading)
Pcruise.y=FLcruise
c[#c+1]=Pcruise
wp[#wp+1]=Pcruise:WaypointAir("BARO", COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint, VxCruise, true, nil, nil, "Cruise")
wp[#wp+1]=Pcruise:WaypointAir("BARO", COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint, VxCruise*3.6, true, nil, nil, "Cruise")
--- Descent
local Pdescent=Pcruise:Translate(d_cruise, heading)
Pdescent.y=FLcruise
c[#c+1]=Pdescent
wp[#wp+1]=Pdescent:WaypointAir("BARO", COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint, VxDescent, true, nil, nil, "Descent")
wp[#wp+1]=Pdescent:WaypointAir("BARO", COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint, VxDescent*3.6, true, nil, nil, "Descent")
--- Holding point
Pholding.y=H_holding+h_holding
c[#c+1]=Pholding
wp[#wp+1]=Pholding:WaypointAir("BARO", COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint, VxHolding, true, nil, nil, "Holding")
wp[#wp+1]=Pholding:WaypointAir("BARO", COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint, VxHolding*3.6, true, nil, nil, "Holding")
--- Final destination.
c[#c+1]=Pdestination
wp[#wp+1]=Pdestination:WaypointAir("RADIO", COORDINATE.WaypointType.Land, COORDINATE.WaypointAction.Landing, VxFinal, true, destination, nil, "Final Destination")
wp[#wp+1]=Pdestination:WaypointAir("RADIO", COORDINATE.WaypointType.Land, COORDINATE.WaypointAction.Landing, VxFinal*3.6, true, destination, nil, "Final Destination")
-- Mark points at waypoints for debugging.