Merge branch 'FF/Ops' into FF/OpsDev

This commit is contained in:
Frank 2025-10-26 15:20:48 +01:00
commit 386be19b8b
6 changed files with 941 additions and 30 deletions

View File

@ -191,5 +191,7 @@ __Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Navigation/Beacons.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Navigation/Point.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Navigation/Procedure.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Navigation/FlightPlan.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Navigation/Radios.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Navigation/Towns.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Globals.lua' )

View File

@ -180,5 +180,7 @@ __Moose.Include( 'Tasking\\Task_Capture_Dispatcher.lua' )
__Moose.Include( 'Navigation\\Point.lua' )
__Moose.Include( 'Navigation\\Beacons.lua' )
__Moose.Include( 'Navigation\\Radios.lua' )
__Moose.Include( 'Navigation\\Towns.lua' )
__Moose.Include( 'Globals.lua' )

View File

@ -2,7 +2,9 @@
--
-- **Main Features:**
--
-- * Beacons of the map
-- * Access beacons of the map
-- * Find closest beacon
-- * Get frequencies and channels
--
-- ===
--
@ -18,7 +20,6 @@
-- @module Navigation.Beacons
-- @image NAVIGATION_Beacons.png
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@ -32,45 +33,132 @@
--
-- @extends Core.Base#BASE
--- *A fleet of British ships at war are the best negotiators.* -- Horatio Nelson
--- *Hope is the beacon that guides lost ships back to the shore.*
--
-- ===
--
-- # The BEACONS Concept
--
-- The NAVFIX class has a great concept!
-- This class is desinged to make information about beacons of a map/theatre easier accessible. The information contains location, type and frequencies of all or specific beacons of the map.
--
-- Bla, bla...
-- **Note** that try to avoid hard coding stuff in Moose since DCS is updated frequently and things change. Therefore, the main source of information is either a file `beacons.lua` that can be
-- found in the installation directory of DCS for each map or a table that the user needs to provide.
--
-- # Basic Setup
--
-- A new `BEACONS` object can be created with the @{#BEACONS.New}() function.
-- A new `BEACONS` object can be created with the @{#BEACONS.NewFromFile}(*beacons_lua_file*) function.
--
-- local beacons=BEACONS:NewFromFile("<DCS_Install_Directory>\Mods\terrains\<Map_Name>\beacons.lua")
-- beacons:MarkerShow()
--
-- This will load the beacons from the `<DCS_Install_Directory>` for the specific map and place markers on the F10 map. This is the first step you should do to ensure that the file
-- you provided is correct and all relevant beacons are present.
--
-- # User Functions
--
-- ## F10 Map Markers
--
-- ## Position
--
-- ## Get Closest Beacon
--
-- local beacons=BEACONS:New("G:\Games\DCS World Testing\Mods\terrains\GermanyColdWar\beacons.lua")
--
-- This is how it works.
--
-- @field #BEACONS
BEACONS = {
ClassName = "BEACONS",
verbose = 0,
verbose = 1,
beacons = {},
}
--- Mission capability.
-- @type BEACONS.Beacon
-- @field #function display_name Function that returns the localized name.
-- @field #number type Beacon type.
-- @field #string beaconId Beacon ID.
-- @field #string callsign Call sign.
-- @field #number frequency Frequency in Hz.
-- @field #number channel TACAN, RSBN or PRMG channel depending on type.
-- @field #table position Position table.
-- @field #number direction Direction in degrees.
-- @field #table positionGeo Table with latitude and longitude.
-- @field #table sceneObjects Table with scenery objects, e.g. `{t:393396742}`.
-- @field #number chartOffsetX No idea what this offset is?!
-- @field DCS#Vec3 vec3 Position vector 3D.
-- @field #number markerID ID for the F10 marker.
-- @field #string typeName Name of becon type.
-- @field Wrapper.Scenery#SCENERY scenery The scenery object.
--- BEACONS class version.
-- @field #string version
BEACONS.version="0.0.0"
BEACONS.version="0.0.4"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- ToDo list
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO: A lot...
-- DONE: TACAN channel from frequency (was already in beacon.lua as channel)
-- DONE: Scenery object
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Constructor(s)
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Create a new BECAONS class instance from a given table.
-- @param #BEACONS self
-- @param #table BeaconTable Table with beacon info.
-- @return #BEACONS self
function BEACONS:NewFromTable(BeaconTable)
-- Inherit everything from BASE class.
self=BASE:Inherit(self, BASE:New()) -- #BEACONS
for _,_beacon in pairs(BeaconTable) do
local beacon=_beacon --#BEACONS.Beacon
-- Get 3D vector
beacon.vec3={x=beacon.position[1], y=beacon.position[2], z=beacon.position[3]}
-- Get coordinate
beacon.coordinate=COORDINATE:NewFromVec3(beacon.vec3)
-- Get type name
beacon.typeName=self:_GetTypeName(beacon.type)
-- Find closest scenery object from scan
beacon.scenery=beacon.coordinate:FindClosestScenery(20)
-- Debug stuff for scenery object
if false then
if beacon.scenery then
env.info(string.format("FF Beacon %s %s %s got scenery object %s, %s", beacon.callsign, beacon.beaconId, beacon.typeName, beacon.scenery:GetName(), beacon.scenery:GetTypeName() ))
UTILS.PrintTableToLog(beacon.scenery.SceneryObject)
UTILS.PrintTableToLog(beacon.sceneObjects)
else
env.info(string.format("FF NO scenery object %s %s %s ", beacon.callsign, beacon.beaconId, beacon.typeName))
end
end
-- Add to table
table.insert(self.beacons, beacon)
end
-- Debug output
self:I(string.format("Added %d beacons", #self.beacons))
if self.verbose > 0 then
local text="Beacon types:"
for typeName,typeID in pairs(BEACON.Type) do
local n=self:CountBeacons(typeID)
text=text..string.format("\n%s = %d", typeName, n)
end
self:I(text)
end
return self
end
--- Create a new BECAONS class instance from a given file.
-- @param #BEACONS self
-- @param #string FileName Full path to the file containing the map beacons.
@ -79,7 +167,20 @@ function BEACONS:NewFromFile(FileName)
-- Inherit everything from BASE class.
self=BASE:Inherit(self, BASE:New()) -- #BEACONS
local exists=UTILS.FileExists(FileName)
if exists==false then
self:E(string.format("ERROR: file with beacon info does not exist!"))
return nil
end
-- This will create a global table `beacons`
dofile(FileName)
-- Get beacons from table.
self=self:NewFromTable(beacons)
return self
end
@ -87,18 +188,141 @@ end
-- User Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Add marker all beacons on the F10 map.
--- Get 3D position vector of a specific beacon.
-- @param #BEACONS self
-- @param #BEACONS.Beacon beacon The beacon data structure.
-- @return DCS#Vec3 Position vector.
function BEACONS:GetVec3(beacon)
return beacon.vec3
end
--- Get COORDINATE of a specific beacon.
-- @param #BEACONS self
-- @param #BEACONS.Beacon beacon The beacon data structure.
-- @return Core.Point#COORDINATE The coordinate.
function BEACONS:GetCoordinate(beacon)
local coordinate=COORDINATE:NewFromVec3(beacon.vec3)
return coordinate
end
--- Find closest beacon to a given coordinate.
-- @param #BEACONS self
-- @param Core.Point#COORDINATE Coordinate The reference coordinate.
-- @param #number TypeID (Optional) Only search for specific beacon types, *e.g.* `BEACON.Type.TACAN`.
-- @param #number DistMax (Optional) Max search distance in meters.
-- @param #table ExcludeList (Optional) List of beacons to exclude.
-- @return #BEACONS.Beacon The closest beacon.
function BEACONS:GetClosestBeacon(Coordinate, TypeID, DistMax, ExcludeList)
local beacon=nil --#BEACONS.Beacon
local distmin=math.huge
ExcludeList=ExcludeList or {}
for _,_beacon in pairs(self.beacons) do
local bc=_beacon --#BEACONS.Beacon
if (TypeID==nil or TypeID==bc.type) and (not UTILS.IsInTable(ExcludeList, bc, "beaconId")) then
local dist=Coordinate:Get2DDistance(bc.vec3)
if dist<distmin and (DistMax==nil or dist<=DistMax) then
distmin=dist
beacon=bc
end
end
end
return beacon
end
--- Get table of all beacons, optionally of a given type.
-- @param #BEACONS self
-- @param #number TypeID (Optional) Only return specific beacon types, *e.g.* `BEACON.Type.TACAN`.
-- @return #table Table of beacons. Each element is of type #BEACON.Beacon.
function BEACONS:GetBeacons(TypeID)
local beacons={}
for _,_beacon in pairs(self.beacons) do
local bc=_beacon --#BEACONS.Beacon
if TypeID==nil or TypeID==bc.type then
table.insert(beacons, bc)
end
end
return beacons
end
--- Count beacons, optionally of a given type.
-- @param #BEACONS self
-- @param #number TypeID (Optional) Only count specific beacon types, *e.g.* `BEACON.Type.TACAN`.
-- @return #number Number of beacons.
function BEACONS:CountBeacons(TypeID)
local n=0
if TypeID then
for _,_beacon in pairs(self.beacons) do
local bc=_beacon --#BEACONS.Beacon
if TypeID==bc.type then
n=n+1
end
end
else
n=#self.beacons
end
return n
end
--- Add markers for all beacons on the F10 map. Optionally, only a specific beacon or a certain beacon type can be marked.
-- @param #BEACONS self
-- @param #BEACONS.Beacon Beacon (Optional) Only this specifc beacon.
-- @param #number TypeID (Optional) Only show specific beacon types, *e.g.* `BEACON.Type.TACAN`.
-- @return #BEACONS self
function BEACONS:MarkerShow()
function BEACONS:MarkerShow(Beacon, TypeID)
for _,_beacon in pairs(self.beacons) do
local beacon=_beacon --#BEACONS.Beacon
if Beacon==nil or Beacon.beaconId==beacon.beaconId then
if TypeID==nil or beacon.type==TypeID then
local text=self:_GetMarkerText(beacon)
local coord=COORDINATE:NewFromVec3(beacon.vec3)
if beacon.markerID then
UTILS.RemoveMark(beacon.markerID)
end
beacon.markerID=coord:MarkToAll(text)
end
end
end
return self
end
--- Remove markers of all beacons from the F10 map.
--- Remove markers of all beacons from the F10 map. Optionally, remove only marker of a specific beacon or a certain beacon type.
-- @param #BEACONS self
-- @param #BEACONS.Beacon Beacon (Optional) Only this specifc beacon.
-- @param #number TypeID (Optional) Only show specific beacon types, *e.g.* `BEACON.Type.TACAN`.
-- @return #BEACONS self
function BEACONS:MarkerRemove()
function BEACONS:MarkerRemove(Beacon, TypeID)
for _,_beacon in pairs(self.beacons) do
local beacon=_beacon --#BEACONS.Beacon
if Beacon==nil or Beacon.beaconId==beacon.beaconId then
if TypeID==nil or beacon.type==TypeID then
if beacon.markerID then
UTILS.RemoveMark(beacon.markerID)
beacon.markerID=nil
end
end
end
end
return self
end
@ -109,31 +333,63 @@ end
--- Get text displayed in the F10 marker.
-- @param #BEACONS self
-- @param #BEACONS.Beacon beacon The beacon data structure.
-- @return #string Marker text.
function BEACONS:_GetMarkerText(beacon)
local altmin=self.altMin and tostring(self.altMin) or ""
local altmax=self.altMax and tostring(self.altMax) or ""
local speedmin=self.speedMin and tostring(self.speedMin) or ""
local speedmax=self.speedMax and tostring(self.speedMax) or ""
local frequency, funit=self:_GetFrequency(beacon.frequency)
local direction=beacon.direction~=nil and beacon.direction or -1
local text=string.format("NAVFIX %s", self.name)
if self.isIAF then
text=text..string.format(" (IAF)")
local text=string.format("Beacon %s [ID=%s]", tostring(beacon.typeName), tostring(beacon.beaconId))
text=text..string.format("\nCallsign: %s", tostring(beacon.callsign))
if UTILS.IsInTable({BEACON.Type.TACAN, BEACON.Type.RSBN, BEACON.Type.PRMG_GLIDESLOPE, BEACON.Type.PRMG_LOCALIZER}, beacon.type) then
text=text..string.format("\nChannel: %s", tostring(beacon.channel))
end
if self.isIF then
text=text..string.format(" (IF)")
end
text=text..string.format("\nAltitude [ft]: %s - %s", altmin, altmax)
text=text..string.format("\nSpeed [knots]: %s - %s", speedmin, speedmax)
text=text..string.format("\nCompulsory: %s", tostring(self.isCompulsory))
text=text..string.format("\nFly Over: %s", tostring(self.isFlyover))
text=text..string.format("\nFrequency: %.3f %s", frequency, funit)
text=text..string.format("\nDirection: %.1f°", direction)
return text
end
--- Get converted frequency.
-- @param #BEACONS self
-- @param #number freq Frequency in Hz.
-- @return #number Frequency in better unit.
-- @return #string Unit ("Hz", "kHz", "MHz").
function BEACONS:_GetFrequency(freq)
freq=freq or 0
local unit="Hz"
if freq>=1e6 then
freq=freq/1e6
unit="MHz"
elseif freq>=1e3 then
freq=freq/1e3
unit="kHz"
end
return freq, unit
end
--- Get name of beacon type.
-- @param #BEACONS self
-- @param #number typeID Beacon type number.
-- @return #string Type name.
function BEACONS:_GetTypeName(typeID)
if typeID~=nil then
for typeName,_typeID in pairs(BEACON.Type) do
if _typeID==typeID then
return typeName
end
end
end
return "Unknown"
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

View File

@ -0,0 +1,330 @@
--- **NAVIGATION** - Airbase radios.
--
-- **Main Features:**
--
-- * Get radio frequencies of airbases
--
-- ===
--
-- ## Example Missions:
--
-- Demo missions can be found on [github](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/Navigation%20-%20Radios).
--
-- ===
--
-- ### Author: **funkyfranky**
--
-- ===
-- @module Navigation.Radios
-- @image NAVIGATION_Radios.png
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- RADIOS class.
-- @type RADIOS
--
-- @field #string ClassName Name of the class.
-- @field #number verbose Verbosity of output.
-- @field #table radios Radios.
--
-- @extends Core.Base#BASE
--- *It's not true I had nothing on, I had the radio on.* -- *Marilyn Monroe*
--
-- ===
--
-- # The RADIOS Concept
--
-- This class is desinged to make information about radios of a map/theatre easier accessible. The information contains mostly the frequencies of airbases of the map.
--
-- **Note** that try to avoid hard coding stuff in Moose since DCS is updated frequently and things change. Therefore, the main source of information is either a file `radio.lua` that can be
-- found in the installation directory of DCS for each map or a table that the user needs to provide.
--
-- # Basic Setup
--
-- A new `RADIOS` object can be created with the @{#RADIOS.NewFromFile}(*radio_lua_file*) function.
--
-- local radios=RADIOS:NewFromFile("<DCS_Install_Directory>\Mods\terrains\<Map_Name>\radios.lua")
-- radios:MarkerShow()
--
-- This will load the radios from the `<DCS_Install_Directory>` for the specific map and place markers on the F10 map. This is the first step you should do to ensure that the file
-- you provided is correct and all relevant radios are present.
--
-- # User Functions
--
-- ## F10 Map Markers
--
-- ## Position
--
-- ## Closest Radio
--
--
-- @field #RADIOS
RADIOS = {
ClassName = "RADIOS",
verbose = 0,
radios = {},
}
--- Radio item data structure.
-- @type RADIOS.Radio
-- @field #string radioId Radio ID.
-- @field #table role Roles of the radio (usually {"ground", "tower", "approach"}).
-- @field #table callsign Callsigns of the radio (usually the airbase name).
-- @field #table frequency Frequencies of the radios.
-- @field #table position Position table.
-- @field #table sceneObjects Scenery objects.
-- @field #string name Name of the airbase.
-- @field Wrapper.Airbase#AIRBASE airbase Airbase.
--- Radio item data structure.
-- @type RADIOS.Frequency
-- @field #number modu Modulation type.
-- @field #number freq Frequency in Hz.
--- RADIOS class version.
-- @field #string version
RADIOS.version="0.0.0"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- ToDo list
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO: A lot...
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Constructor(s)
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Create a new RADIOS class instance from a given table.
-- @param #RADIOS self
-- @param #table RadioTable Table with radios info.
-- @return #RADIOS self
function RADIOS:NewFromTable(RadioTable)
-- Inherit everything from BASE class.
self=BASE:Inherit(self, BASE:New()) -- #RADIOS
local airbasenames=AIRBASE.GetAllAirbaseNames()
for _,_radio in pairs(RadioTable) do
local radio=_radio --#RADIOS.Radio
--UTILS.PrintTableToLog(radio)
--UTILS.PrintTableToLog(radio.callsign)
-- The table structure of callsign is a bit awkward. We need to get the airbase name.
local cs=radio.callsign[1]
if cs and cs.common then
radio.name=cs.common[1]
elseif cs and cs.nato then
radio.name=cs.nato[1]
else
radio.name="Unknown"
end
--UTILS.PrintTableToLog(radio.callsign)
radio.name=self:_GetAirbaseName(airbasenames, radio.name)
radio.airbase=AIRBASE:FindByName(radio.name)
if radio.airbase then
radio.coordinate=radio.airbase:GetCoordinate()
end
-- Add to table
table.insert(self.radios, radio)
end
-- Debug output
self:I(string.format("Added %d radios", #self.radios))
return self
end
--- Create a new RADIOS class instance from a given file.
-- @param #RADIOS self
-- @param #string FileName Full path to the file containing the map radios.
-- @return #RADIOS self
function RADIOS:NewFromFile(FileName)
-- Inherit everything from BASE class.
self=BASE:Inherit(self, BASE:New()) -- #RADIOS
local exists=UTILS.FileExists(FileName)
if exists==false then
self:E(string.format("ERROR: file with radios info does not exist! File=%s", tostring(FileName)))
return nil
end
-- Backup DCS radio table
local radiobak=UTILS.DeepCopy(radio)
-- This will create a global table `radio`
dofile(FileName)
-- Get radios from table.
self=self:NewFromTable(radio)
-- Restore DCS radio table
radio=UTILS.DeepCopy(radiobak)
return self
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- User Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Get 3D position vector of a specific radio.
-- @param #RADIOS self
-- @param #RADIOS.Radio radio The radio data structure.
-- @return DCS#Vec3 Position vector.
function RADIOS:GetVec3(radio)
return radio.vec3
end
--- Get COORDINATE of a specific radio.
-- @param #RADIOS self
-- @param #RADIOS.Radio radio The radio data structure.
-- @return Core.Point#COORDINATE The coordinate.
function RADIOS:GetCoordinate(radio)
return radio.coordinate
end
--- Add markers for all radios on the F10 map.
-- @param #RADIOS self
-- @param #RADIOS.Radio Radio (Optional) Only this specifc radio.
-- @return #RADIOS self
function RADIOS:MarkerShow(Radio)
for _,_radio in pairs(self.radios) do
local radio=_radio --#RADIOS.Radio
if Radio==nil or Radio.radioId==radio.radioId then
local coord=self:GetCoordinate(radio)
if coord then
local text=self:_GetMarkerText(radio)
if radio.markerID then
UTILS.RemoveMark(radio.markerID)
end
radio.markerID=coord:MarkToAll(text)
end
end
end
return self
end
--- Remove markers of all radios from the F10 map.
-- @param #RADIOS self
-- @param #RADIOS.Radio Radio (Optional) Only this specifc radio.
-- @return #RADIOS self
function RADIOS:MarkerRemove(Radio)
for _,_radio in pairs(self.radios) do
local radio=_radio --#RADIOS.Radio
if Radio==nil or Radio.radioId==radio.radioId then
if radio.markerID then
UTILS.RemoveMark(radio.markerID)
radio.markerID=nil
end
end
end
return self
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Private Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Get text displayed in the F10 marker.
-- @param #RADIOS self
-- @param #RADIOS.Radio radio The radio data structure.
-- @return #string Marker text.
function RADIOS:_GetMarkerText(radio)
local text=string.format("Radio %s", tostring(radio.name))
for b,f in pairs(radio.frequency) do
local frequency=f --#RADIOS.Frequency
local mod=frequency[1]
local fre=frequency[2]
local freq, funit=self:_GetFrequency(fre)
--UTILS.PrintTableToLog(frequency)
local band=self:_GetBandName(b)
text=text..string.format("\n%s: %.3f %s", band, freq, funit)
end
return text
end
--- Get converted frequency.
-- @param #RADIOS self
-- @param #number freq Frequency in Hz.
-- @return #number Frequency in better unit.
-- @return #string Unit ("Hz", "kHz", "MHz").
function RADIOS:_GetFrequency(freq)
freq=freq or 0
local unit="Hz"
if freq>=1e6 then
freq=freq/1e6
unit="MHz"
elseif freq>=1e3 then
freq=freq/1e3
unit="kHz"
end
return freq, unit
end
--- Get name of frequency band.
-- @param #RADIOS self
-- @param #number BandNumber Band as number.
-- @return #string Band name.
function RADIOS:_GetBandName(BandNumber)
if BandNumber~=nil then
for bandName,bandNumber in pairs(ENUMS.FrequencyBand) do
if bandNumber==BandNumber then
return bandName
end
end
end
return "Unknown"
end
--- Get name of frequency band.
-- @param #RADIOS self
-- @param #table airbasenames Names of all airbases.
-- @param #string name Name of airbase.
-- @return #string Name of airbase
function RADIOS:_GetAirbaseName(airbasenames, name)
local airbase=AIRBASE:FindByName(name)
if airbase then
return name
else
for _,airbasename in pairs(airbasenames) do
if string.find(airbasename, name) then
return airbasename
end
end
end
return "Unknown"
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

View File

@ -0,0 +1,296 @@
--- **NAVIGATION** - Beacons of the map/theatre.
--
-- **Main Features:**
--
-- * Find towns of map
-- * Road and rail connections
--
-- ===
--
-- ## Example Missions:
--
-- Demo missions can be found on [github](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/Navigation%20-%20Towns).
--
-- ===
--
-- ### Author: **funkyfranky**
--
-- ===
-- @module Navigation.Towns
-- @image NAVIGATION_Towns.png
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- TOWNS class.
-- @type TOWNS
--
-- @field #string ClassName Name of the class.
-- @field #number verbose Verbosity of output.
-- @field #table towns Towns.
--
-- @extends Core.Base#BASE
--- *Hope is the beacon that guides lost ships back to the shore.*
--
-- ===
--
-- # The TOWNS Concept
--
-- This class is desinged to make information about towns of a map/theatre easier accessible. The information contains location and road/rail connections of the towns.
--
-- **Note** that try to avoid hard coding stuff in Moose since DCS is updated frequently and things change. Therefore, the main source of information is either a file `towns.lua` that can be
-- found in the installation directory of DCS for each map or a table that the user needs to provide.
--
-- # Basic Setup
--
-- A new `TOWNS` object can be created with the @{#TOWNS.NewFromFile}(*towns_lua_file*) function.
--
-- local towns=TOWNS:NewFromFile("<DCS_Install_Directory>\Mods\terrains\<Map_Name>\towns.lua")
-- towns:MarkerShow()
--
-- This will load the towns from the `<DCS_Install_Directory>` for the specific map and place markers on the F10 map. This is the first step you should do to ensure that the file
-- you provided is correct and all relevant towns are present.
--
-- # User Functions
--
-- ## F10 Map Markers
--
-- ## Position
--
-- ## Get Closest Town
--
--
-- @field #TOWNS
TOWNS = {
ClassName = "TOWNS",
verbose = 0,
towns = {},
}
--- Town data.
-- @type TOWNS.Town
-- @field #string display_name Displayed name.
-- @field #string name Name of the town.
-- @field #number latitude Latitude.
-- @field #number longitude Longitude
-- @field DCS#Vec3 vec3 Position vector 3D.
-- @field Core.Point#COORDINATE coordinate The coordinate.
-- @field Core.Point#COORDINATE coordRoad The coordinate of the closest road.
-- @field Core.Point#COORDINATE coordRail The coordinate of the closest railway.
-- @field #number markerID ID for the F10 marker.
--- TOWNS class version.
-- @field #string version
TOWNS.version="0.0.1"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- ToDo list
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO: A lot...
-- TODO: Road connection
-- TODO: Rail connection
-- TODO: Connection between towns
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Constructor(s)
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Create a new TOWNS class instance from a given table.
-- @param #TOWNS self
-- @param #table TownTable Table with all towns data.
-- @return #TOWNS self
function TOWNS:NewFromTable(TownTable)
-- Inherit everything from BASE class.
self=BASE:Inherit(self, BASE:New()) -- #TOWNS
for TownName,_town in pairs(TownTable) do
local town=_town --#TOWNS.Town
town.name=TownName
-- Get coordinate
town.coordinate=COORDINATE:NewFromLLDD(town.latitude, town.longitude)
-- Get coordinate of closest road
town.coordRoad=town.coordinate:GetClosestPointToRoad()
-- Get coordinate of closest rail
town.coordRail=town.coordinate:GetClosestPointToRoad(true)
-- Add to table
table.insert(self.towns, town)
end
-- Debug output
self:I(string.format("Added %d towns", #self.towns))
return self
end
--- Create a new TOWNS class instance from a given file.
-- @param #TOWNS self
-- @param #string FileName Full path to the file containing the towns data.
-- @return #TOWNS self
function TOWNS:NewFromFile(FileName)
-- Inherit everything from BASE class.
self=BASE:Inherit(self, BASE:New()) -- #TOWNS
local exists=UTILS.FileExists(FileName)
if exists==false then
self:E(string.format("ERROR: file with towns info does not exist!"))
return nil
end
-- This will create a global table `towns`
dofile(FileName)
-- Get towns from table.
self=self:NewFromTable(towns)
return self
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- User Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Get 3D position vector of a specific town.
-- @param #TOWNS self
-- @param #TOWNS.Town town The town data structure.
-- @return DCS#Vec3 Position vector.
function TOWNS:GetVec3(town)
return town.vec3
end
--- Get COORDINATE of a specific town.
-- @param #TOWNS self
-- @param #TOWNS.Town town The town data structure.
-- @return Core.Point#COORDINATE The coordinate.
function TOWNS:GetCoordinate(town)
return town.coordinate
end
--- Get closest road coordinate of a town.
-- @param #TOWNS self
-- @param #TOWNS.Town town The town data structure.
-- @return Core.Point#COORDINATE The closest road coordinate.
function TOWNS:GetCoordRoad(town)
return town.coordRoad
end
--- Get closest rail coordinate of a town.
-- @param #TOWNS self
-- @param #TOWNS.Town town The town data structure.
-- @return Core.Point#COORDINATE The closest rail coordinate.
function TOWNS:GetCoordRail(town)
return town.coordRail
end
--- Get road connection between two towns.
-- @param #TOWNS self
-- @param #TOWNS.Town townA The town data structure.
-- @param #TOWNS.Town townB The town data structure.
-- @return #table Table containing path coordinates.
function TOWNS:GetConnectionRoad(townA, townB)
local path=townA.coordRoad:GetPathOnRoad(townB.coordRoad)
return path
end
--- Find closest town to a given coordinate.
-- @param #TOWNS self
-- @param Core.Point#COORDINATE Coordinate The reference coordinate.
-- @return #TOWNS.Town The closest town.
function TOWNS:GetClosestTown(Coordinate)
local Town=nil --#TOWNS.Town
local distmin=math.huge
for _,_town in pairs(self.towns) do
local town=_town --#TOWNS.Town
local dist=Coordinate:Get2DDistance(town.coordinate)
if dist<distmin then
distmin=dist
Town=town
end
end
return Town
end
--- Get table of all towns, optionally of a given type.
-- @param #TOWNS self
-- @return #table Table of towns. Each element is of type #TOWN.Town.
function TOWNS:GetTowns()
return self.towns
end
--- Add markers for all towns on the F10 map.
-- @param #TOWNS self
-- @param #TOWNS.Town Town (Optional) Only this specifc town.
-- @return #TOWNS self
function TOWNS:MarkerShow(Town)
for _,_town in pairs(self.towns) do
local town=_town --#TOWNS.Town
if Town==nil or Town.name==town.name then
local text=self:_GetMarkerText(town)
local coord=town.coordinate
if town.markerID then
UTILS.RemoveMark(town.markerID)
end
town.markerID=coord:MarkToAll(text)
end
end
return self
end
--- Remove markers of all towns from the F10 map.
-- @param #TOWNS self
-- @param #TOWNS.Town Town (Optional) Only this specifc town.
-- @return #TOWNS self
function TOWNS:MarkerRemove(Town)
for _,_town in pairs(self.towns) do
local town=_town --#TOWNS.Town
if Town==nil or Town.name==town.name then
if town.markerID then
UTILS.RemoveMark(town.markerID)
town.markerID=nil
end
end
end
return self
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Private Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Get text displayed in the F10 marker.
-- @param #TOWNS self
-- @param #TOWNS.Town town The town data structure.
-- @return #string Marker text.
function TOWNS:_GetMarkerText(town)
local text=string.format("Town %s", town.name)
--text=text..string.format("\nCallsign: %s", tostring(beacon.callsign))
return text
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

View File

@ -1386,3 +1386,28 @@ ENUMS.FARPObjectTypeNamesAndShape ={
[ENUMS.FARPType.PADSINGLE] = { TypeName="FARP_SINGLE_01", ShapeName="FARP_SINGLE_01"},
}
--- Radio frequency bands (HF, VHF, UHF)
-- @type ENUMS.FrequencyBand
-- @field #number HF High frequency
-- @field #number VHF_LOW Very high frequency
-- @field #number VHF_HI Very high frequency
-- @field #number UHF Ultra high frequency
ENUMS.FrequencyBand = {
HF = 0,
VHF_LOW = 1,
VHF_HI = 2,
UHF = 3,
}
--- Radio modulation types (AM, FM)
-- @type ENUMS.ModulationType
-- @field #number AM Amplitude modulation
-- @field #number FM Frequency modulation
-- @field #number AMFM Amplitude and frequency modulation
-- @field #number DISCARD Discard modulation
ENUMS.ModulationType = {
AM = 0,
FM = 1,
AMFM = 2,
DISCARD = -1,
}