mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-08-15 10:47:21 +00:00
1755 lines
61 KiB
Lua
1755 lines
61 KiB
Lua
--- **Wrapper** -- AIRBASE is a wrapper class to handle the DCS Airbase objects.
|
|
--
|
|
-- ===
|
|
--
|
|
-- ### Author: **FlightControl**
|
|
--
|
|
-- ### Contributions: **funkyfranky**
|
|
--
|
|
-- ===
|
|
--
|
|
-- @module Wrapper.Airbase
|
|
-- @image Wrapper_Airbase.JPG
|
|
|
|
--- @type AIRBASE
|
|
-- @field #string ClassName Name of the class, i.e. "AIRBASE".
|
|
-- @field #table CategoryName Names of airbase categories.
|
|
-- @field #string AirbaseName Name of the airbase.
|
|
-- @field #number AirbaseID Airbase ID.
|
|
-- @field Core.Zone#ZONE AirbaseZone Circular zone around the airbase with a radius of 2500 meters. For ships this is a ZONE_UNIT object.
|
|
-- @field #number category Airbase category.
|
|
-- @field #table descriptors DCS descriptors.
|
|
-- @field #boolean isAirdrome Airbase is an airdrome.
|
|
-- @field #boolean isHelipad Airbase is a helipad.
|
|
-- @field #boolean isShip Airbase is a ship.
|
|
-- @field #table parking Parking spot data.
|
|
-- @field #table parkingByID Parking spot data table with ID as key.
|
|
-- @field #number activerwyno Active runway number (forced).
|
|
-- @field #table parkingWhitelist List of parking spot terminal IDs considered for spawning.
|
|
-- @field #table parkingBlacklist List of parking spot terminal IDs **not** considered for spawning.
|
|
-- @extends Wrapper.Positionable#POSITIONABLE
|
|
|
|
--- Wrapper class to handle the DCS Airbase objects:
|
|
--
|
|
-- * Support all DCS Airbase APIs.
|
|
-- * Enhance with Airbase specific APIs not in the DCS Airbase API set.
|
|
--
|
|
-- ## AIRBASE reference methods
|
|
--
|
|
-- For each DCS Airbase object alive within a running mission, a AIRBASE wrapper object (instance) will be created within the _@{DATABASE} object.
|
|
-- This is done at the beginning of the mission (when the mission starts).
|
|
--
|
|
-- The AIRBASE class **does not contain a :New()** method, rather it provides **:Find()** methods to retrieve the object reference
|
|
-- using the DCS Airbase or the DCS AirbaseName.
|
|
--
|
|
-- Another thing to know is that AIRBASE objects do not "contain" the DCS Airbase object.
|
|
-- The AIRBASE methods will reference the DCS Airbase object by name when it is needed during API execution.
|
|
-- If the DCS Airbase object does not exist or is nil, the AIRBASE methods will return nil and log an exception in the DCS.log file.
|
|
--
|
|
-- The AIRBASE class provides the following functions to retrieve quickly the relevant AIRBASE instance:
|
|
--
|
|
-- * @{#AIRBASE.Find}(): Find a AIRBASE instance from the _DATABASE object using a DCS Airbase object.
|
|
-- * @{#AIRBASE.FindByName}(): Find a AIRBASE instance from the _DATABASE object using a DCS Airbase name.
|
|
--
|
|
-- IMPORTANT: ONE SHOULD NEVER SANITIZE these AIRBASE OBJECT REFERENCES! (make the AIRBASE object references nil).
|
|
--
|
|
-- ## DCS Airbase APIs
|
|
--
|
|
-- The DCS Airbase APIs are used extensively within MOOSE. The AIRBASE class has for each DCS Airbase API a corresponding method.
|
|
-- To be able to distinguish easily in your code the difference between a AIRBASE API call and a DCS Airbase API call,
|
|
-- the first letter of the method is also capitalized. So, by example, the DCS Airbase method @{DCSWrapper.Airbase#Airbase.getName}()
|
|
-- is implemented in the AIRBASE class as @{#AIRBASE.GetName}().
|
|
--
|
|
-- @field #AIRBASE AIRBASE
|
|
AIRBASE = {
|
|
ClassName = "AIRBASE",
|
|
CategoryName = {
|
|
[Airbase.Category.AIRDROME] = "Airdrome",
|
|
[Airbase.Category.HELIPAD] = "Helipad",
|
|
[Airbase.Category.SHIP] = "Ship",
|
|
},
|
|
activerwyno = nil,
|
|
}
|
|
|
|
--- Enumeration to identify the airbases in the Caucasus region.
|
|
--
|
|
-- Airbases of the Caucasus map:
|
|
--
|
|
-- * AIRBASE.Caucasus.Gelendzhik
|
|
-- * AIRBASE.Caucasus.Krasnodar_Pashkovsky
|
|
-- * AIRBASE.Caucasus.Sukhumi_Babushara
|
|
-- * AIRBASE.Caucasus.Gudauta
|
|
-- * AIRBASE.Caucasus.Batumi
|
|
-- * AIRBASE.Caucasus.Senaki_Kolkhi
|
|
-- * AIRBASE.Caucasus.Kobuleti
|
|
-- * AIRBASE.Caucasus.Kutaisi
|
|
-- * AIRBASE.Caucasus.Tbilisi_Lochini
|
|
-- * AIRBASE.Caucasus.Soganlug
|
|
-- * AIRBASE.Caucasus.Vaziani
|
|
-- * AIRBASE.Caucasus.Anapa_Vityazevo
|
|
-- * AIRBASE.Caucasus.Krasnodar_Center
|
|
-- * AIRBASE.Caucasus.Novorossiysk
|
|
-- * AIRBASE.Caucasus.Krymsk
|
|
-- * AIRBASE.Caucasus.Maykop_Khanskaya
|
|
-- * AIRBASE.Caucasus.Sochi_Adler
|
|
-- * AIRBASE.Caucasus.Mineralnye_Vody
|
|
-- * AIRBASE.Caucasus.Nalchik
|
|
-- * AIRBASE.Caucasus.Mozdok
|
|
-- * AIRBASE.Caucasus.Beslan
|
|
--
|
|
-- @field Caucasus
|
|
AIRBASE.Caucasus = {
|
|
["Gelendzhik"] = "Gelendzhik",
|
|
["Krasnodar_Pashkovsky"] = "Krasnodar-Pashkovsky",
|
|
["Sukhumi_Babushara"] = "Sukhumi-Babushara",
|
|
["Gudauta"] = "Gudauta",
|
|
["Batumi"] = "Batumi",
|
|
["Senaki_Kolkhi"] = "Senaki-Kolkhi",
|
|
["Kobuleti"] = "Kobuleti",
|
|
["Kutaisi"] = "Kutaisi",
|
|
["Tbilisi_Lochini"] = "Tbilisi-Lochini",
|
|
["Soganlug"] = "Soganlug",
|
|
["Vaziani"] = "Vaziani",
|
|
["Anapa_Vityazevo"] = "Anapa-Vityazevo",
|
|
["Krasnodar_Center"] = "Krasnodar-Center",
|
|
["Novorossiysk"] = "Novorossiysk",
|
|
["Krymsk"] = "Krymsk",
|
|
["Maykop_Khanskaya"] = "Maykop-Khanskaya",
|
|
["Sochi_Adler"] = "Sochi-Adler",
|
|
["Mineralnye_Vody"] = "Mineralnye Vody",
|
|
["Nalchik"] = "Nalchik",
|
|
["Mozdok"] = "Mozdok",
|
|
["Beslan"] = "Beslan",
|
|
}
|
|
|
|
--- Airbases of the Nevada map:
|
|
--
|
|
-- * AIRBASE.Nevada.Creech_AFB
|
|
-- * AIRBASE.Nevada.Groom_Lake_AFB
|
|
-- * AIRBASE.Nevada.McCarran_International_Airport
|
|
-- * AIRBASE.Nevada.Nellis_AFB
|
|
-- * AIRBASE.Nevada.Beatty_Airport
|
|
-- * AIRBASE.Nevada.Boulder_City_Airport
|
|
-- * AIRBASE.Nevada.Echo_Bay
|
|
-- * AIRBASE.Nevada.Henderson_Executive_Airport
|
|
-- * AIRBASE.Nevada.Jean_Airport
|
|
-- * AIRBASE.Nevada.Laughlin_Airport
|
|
-- * AIRBASE.Nevada.Lincoln_County
|
|
-- * AIRBASE.Nevada.Mesquite
|
|
-- * AIRBASE.Nevada.Mina_Airport
|
|
-- * AIRBASE.Nevada.North_Las_Vegas
|
|
-- * AIRBASE.Nevada.Pahute_Mesa_Airstrip
|
|
-- * AIRBASE.Nevada.Tonopah_Airport
|
|
-- * AIRBASE.Nevada.Tonopah_Test_Range_Airfield
|
|
--
|
|
-- @field Nevada
|
|
AIRBASE.Nevada = {
|
|
["Creech_AFB"] = "Creech",
|
|
["Groom_Lake_AFB"] = "Groom Lake",
|
|
["McCarran_International_Airport"] = "McCarran International",
|
|
["Nellis_AFB"] = "Nellis",
|
|
["Beatty_Airport"] = "Beatty",
|
|
["Boulder_City_Airport"] = "Boulder City",
|
|
["Echo_Bay"] = "Echo Bay",
|
|
["Henderson_Executive_Airport"] = "Henderson Executive",
|
|
["Jean_Airport"] = "Jean",
|
|
["Laughlin_Airport"] = "Laughlin",
|
|
["Lincoln_County"] = "Lincoln County",
|
|
["Mesquite"] = "Mesquite",
|
|
["Mina_Airport"] = "Mina",
|
|
["North_Las_Vegas"] = "North Las Vegas",
|
|
["Pahute_Mesa_Airstrip"] = "Pahute Mesa",
|
|
["Tonopah_Airport"] = "Tonopah",
|
|
["Tonopah_Test_Range_Airfield"] = "Tonopah Test Range",
|
|
}
|
|
|
|
--- Airbases of the Normandy map:
|
|
--
|
|
-- * AIRBASE.Normandy.Saint_Pierre_du_Mont
|
|
-- * AIRBASE.Normandy.Lignerolles
|
|
-- * AIRBASE.Normandy.Cretteville
|
|
-- * AIRBASE.Normandy.Maupertus
|
|
-- * AIRBASE.Normandy.Brucheville
|
|
-- * AIRBASE.Normandy.Meautis
|
|
-- * AIRBASE.Normandy.Cricqueville_en_Bessin
|
|
-- * AIRBASE.Normandy.Lessay
|
|
-- * AIRBASE.Normandy.Sainte_Laurent_sur_Mer
|
|
-- * AIRBASE.Normandy.Biniville
|
|
-- * AIRBASE.Normandy.Cardonville
|
|
-- * AIRBASE.Normandy.Deux_Jumeaux
|
|
-- * AIRBASE.Normandy.Chippelle
|
|
-- * AIRBASE.Normandy.Beuzeville
|
|
-- * AIRBASE.Normandy.Azeville
|
|
-- * AIRBASE.Normandy.Picauville
|
|
-- * AIRBASE.Normandy.Le_Molay
|
|
-- * AIRBASE.Normandy.Longues_sur_Mer
|
|
-- * AIRBASE.Normandy.Carpiquet
|
|
-- * AIRBASE.Normandy.Bazenville
|
|
-- * AIRBASE.Normandy.Sainte_Croix_sur_Mer
|
|
-- * AIRBASE.Normandy.Beny_sur_Mer
|
|
-- * AIRBASE.Normandy.Rucqueville
|
|
-- * AIRBASE.Normandy.Sommervieu
|
|
-- * AIRBASE.Normandy.Lantheuil
|
|
-- * AIRBASE.Normandy.Evreux
|
|
-- * AIRBASE.Normandy.Chailey
|
|
-- * AIRBASE.Normandy.Needs_Oar_Point
|
|
-- * AIRBASE.Normandy.Funtington
|
|
-- * AIRBASE.Normandy.Tangmere
|
|
-- * AIRBASE.Normandy.Ford_AF
|
|
--
|
|
-- @field Normandy
|
|
AIRBASE.Normandy = {
|
|
["Saint_Pierre_du_Mont"] = "Saint Pierre du Mont",
|
|
["Lignerolles"] = "Lignerolles",
|
|
["Cretteville"] = "Cretteville",
|
|
["Maupertus"] = "Maupertus",
|
|
["Brucheville"] = "Brucheville",
|
|
["Meautis"] = "Meautis",
|
|
["Cricqueville_en_Bessin"] = "Cricqueville-en-Bessin",
|
|
["Lessay"] = "Lessay",
|
|
["Sainte_Laurent_sur_Mer"] = "Sainte-Laurent-sur-Mer",
|
|
["Biniville"] = "Biniville",
|
|
["Cardonville"] = "Cardonville",
|
|
["Deux_Jumeaux"] = "Deux Jumeaux",
|
|
["Chippelle"] = "Chippelle",
|
|
["Beuzeville"] = "Beuzeville",
|
|
["Azeville"] = "Azeville",
|
|
["Picauville"] = "Picauville",
|
|
["Le_Molay"] = "Le Molay",
|
|
["Longues_sur_Mer"] = "Longues-sur-Mer",
|
|
["Carpiquet"] = "Carpiquet",
|
|
["Bazenville"] = "Bazenville",
|
|
["Sainte_Croix_sur_Mer"] = "Sainte-Croix-sur-Mer",
|
|
["Beny_sur_Mer"] = "Beny-sur-Mer",
|
|
["Rucqueville"] = "Rucqueville",
|
|
["Sommervieu"] = "Sommervieu",
|
|
["Lantheuil"] = "Lantheuil",
|
|
["Evreux"] = "Evreux",
|
|
["Chailey"] = "Chailey",
|
|
["Needs_Oar_Point"] = "Needs Oar Point",
|
|
["Funtington"] = "Funtington",
|
|
["Tangmere"] = "Tangmere",
|
|
["Ford_AF"] = "Ford_AF",
|
|
["Goulet"] = "Goulet",
|
|
["Argentan"] = "Argentan",
|
|
["Vrigny"] = "Vrigny",
|
|
["Essay"] = "Essay",
|
|
["Hauterive"] = "Hauterive",
|
|
["Barville"] = "Barville",
|
|
["Conches"] = "Conches",
|
|
}
|
|
|
|
--- Airbases of the Persion Gulf Map:
|
|
--
|
|
-- * AIRBASE.PersianGulf.Abu_Dhabi_International_Airport
|
|
-- * AIRBASE.PersianGulf.Abu_Musa_Island_Airport
|
|
-- * AIRBASE.PersianGulf.Al-Bateen_Airport
|
|
-- * AIRBASE.PersianGulf.Al_Ain_International_Airport
|
|
-- * AIRBASE.PersianGulf.Al_Dhafra_AB
|
|
-- * AIRBASE.PersianGulf.Al_Maktoum_Intl
|
|
-- * AIRBASE.PersianGulf.Al_Minhad_AB
|
|
-- * AIRBASE.PersianGulf.Bandar_e_Jask_airfield
|
|
-- * AIRBASE.PersianGulf.Bandar_Abbas_Intl
|
|
-- * AIRBASE.PersianGulf.Bandar_Lengeh
|
|
-- * AIRBASE.PersianGulf.Dubai_Intl
|
|
-- * AIRBASE.PersianGulf.Fujairah_Intl
|
|
-- * AIRBASE.PersianGulf.Havadarya
|
|
-- * AIRBASE.PersianGulf.Jiroft_Airport
|
|
-- * AIRBASE.PersianGulf.Kerman_Airport
|
|
-- * AIRBASE.PersianGulf.Khasab
|
|
-- * AIRBASE.PersianGulf.Kish_International_Airport
|
|
-- * AIRBASE.PersianGulf.Lar_Airbase
|
|
-- * AIRBASE.PersianGulf.Lavan_Island_Airport
|
|
-- * AIRBASE.PersianGulf.Liwa_Airbase
|
|
-- * AIRBASE.PersianGulf.Qeshm_Island
|
|
-- * AIRBASE.PersianGulf.Ras_Al_Khaimah_International_Airport
|
|
-- * AIRBASE.PersianGulf.Sas_Al_Nakheel_Airport
|
|
-- * AIRBASE.PersianGulf.Sharjah_Intl
|
|
-- * AIRBASE.PersianGulf.Shiraz_International_Airport
|
|
-- * AIRBASE.PersianGulf.Sir_Abu_Nuayr
|
|
-- * AIRBASE.PersianGulf.Sirri_Island
|
|
-- * AIRBASE.PersianGulf.Tunb_Island_AFB
|
|
-- * AIRBASE.PersianGulf.Tunb_Kochak
|
|
--
|
|
-- @field PersianGulf
|
|
AIRBASE.PersianGulf = {
|
|
["Abu_Dhabi_International_Airport"] = "Abu Dhabi Intl",
|
|
["Abu_Musa_Island_Airport"] = "Abu Musa Island",
|
|
["Al_Ain_International_Airport"] = "Al Ain Intl",
|
|
["Al_Bateen_Airport"] = "Al-Bateen",
|
|
["Al_Dhafra_AB"] = "Al Dhafra AFB",
|
|
["Al_Maktoum_Intl"] = "Al Maktoum Intl",
|
|
["Al_Minhad_AB"] = "Al Minhad AFB",
|
|
["Bandar_Abbas_Intl"] = "Bandar Abbas Intl",
|
|
["Bandar_Lengeh"] = "Bandar Lengeh",
|
|
["Bandar_e_Jask_airfield"] = "Bandar-e-Jask",
|
|
["Dubai_Intl"] = "Dubai Intl",
|
|
["Fujairah_Intl"] = "Fujairah Intl",
|
|
["Havadarya"] = "Havadarya",
|
|
["Jiroft_Airport"] = "Jiroft",
|
|
["Kerman_Airport"] = "Kerman",
|
|
["Khasab"] = "Khasab",
|
|
["Kish_International_Airport"] = "Kish Intl",
|
|
["Lar_Airbase"] = "Lar",
|
|
["Lavan_Island_Airport"] = "Lavan Island",
|
|
["Liwa_Airbase"] = "Liwa AFB",
|
|
["Qeshm_Island"] = "Qeshm Island",
|
|
["Ras_Al_Khaimah"] = "Ras Al Khaimah Intl",
|
|
["Sas_Al_Nakheel_Airport"] = "Sas Al Nakheel",
|
|
["Sharjah_Intl"] = "Sharjah Intl",
|
|
["Shiraz_International_Airport"] = "Shiraz Intl",
|
|
["Sir_Abu_Nuayr"] = "Sir Abu Nuayr",
|
|
["Sirri_Island"] = "Sirri Island",
|
|
["Tunb_Island_AFB"] = "Tunb Island AFB",
|
|
["Tunb_Kochak"] = "Tunb Kochak",
|
|
}
|
|
|
|
--- Airbases of The Channel Map:
|
|
--
|
|
-- * AIRBASE.TheChannel.Abbeville_Drucat
|
|
-- * AIRBASE.TheChannel.Merville_Calonne
|
|
-- * AIRBASE.TheChannel.Saint_Omer_Longuenesse
|
|
-- * AIRBASE.TheChannel.Dunkirk_Mardyck
|
|
-- * AIRBASE.TheChannel.Manston
|
|
-- * AIRBASE.TheChannel.Hawkinge
|
|
-- * AIRBASE.TheChannel.Lympne
|
|
-- * AIRBASE.TheChannel.Detling
|
|
-- * AIRBASE.TheChannel.High_Halden
|
|
-- * AIRBASE.TheChannel.Biggin_Hill
|
|
-- * AIRBASE.TheChannel.Eastchurch
|
|
-- * AIRBASE.TheChannel.Headcorn
|
|
--
|
|
-- @field TheChannel
|
|
AIRBASE.TheChannel = {
|
|
["Abbeville_Drucat"] = "Abbeville Drucat",
|
|
["Merville_Calonne"] = "Merville Calonne",
|
|
["Saint_Omer_Longuenesse"] = "Saint Omer Longuenesse",
|
|
["Dunkirk_Mardyck"] = "Dunkirk Mardyck",
|
|
["Manston"] = "Manston",
|
|
["Hawkinge"] = "Hawkinge",
|
|
["Lympne"] = "Lympne",
|
|
["Detling"] = "Detling",
|
|
["High_Halden"] = "High Halden",
|
|
["Biggin_Hill"] = "Biggin Hill",
|
|
["Eastchurch"] = "Eastchurch",
|
|
["Headcorn"] = "Headcorn",
|
|
}
|
|
|
|
--- Airbases of the Syria map:
|
|
--
|
|
-- * AIRBASE.Syria.Kuweires
|
|
-- * AIRBASE.Syria.Marj_Ruhayyil
|
|
-- * AIRBASE.Syria.Kiryat_Shmona
|
|
-- * AIRBASE.Syria.Marj_as_Sultan_North
|
|
-- * AIRBASE.Syria.Eyn_Shemer
|
|
-- * AIRBASE.Syria.Incirlik
|
|
-- * AIRBASE.Syria.Damascus
|
|
-- * AIRBASE.Syria.Bassel_Al_Assad
|
|
-- * AIRBASE.Syria.Rosh_Pina
|
|
-- * AIRBASE.Syria.Aleppo
|
|
-- * AIRBASE.Syria.Al_Qusayr
|
|
-- * AIRBASE.Syria.Wujah_Al_Hajar
|
|
-- * AIRBASE.Syria.Al_Dumayr
|
|
-- * AIRBASE.Syria.Gazipasa
|
|
-- * AIRBASE.Syria.Hatay
|
|
-- * AIRBASE.Syria.Nicosia
|
|
-- * AIRBASE.Syria.Pinarbashi
|
|
-- * AIRBASE.Syria.Paphos
|
|
-- * AIRBASE.Syria.Kingsfield
|
|
-- * AIRBASE.Syria.Thalah
|
|
-- * AIRBASE.Syria.Haifa
|
|
-- * AIRBASE.Syria.Khalkhalah
|
|
-- * AIRBASE.Syria.Megiddo
|
|
-- * AIRBASE.Syria.Lakatamia
|
|
-- * AIRBASE.Syria.Rayak
|
|
-- * AIRBASE.Syria.Larnaca
|
|
-- * AIRBASE.Syria.Mezzeh
|
|
-- * AIRBASE.Syria.Gecitkale
|
|
-- * AIRBASE.Syria.Akrotiri
|
|
-- * AIRBASE.Syria.Naqoura
|
|
-- * AIRBASE.Syria.Gaziantep
|
|
-- * AIRBASE.Syria.Sayqal
|
|
-- * AIRBASE.Syria.Tiyas
|
|
-- * AIRBASE.Syria.Shayrat
|
|
-- * AIRBASE.Syria.Taftanaz
|
|
-- * AIRBASE.Syria.H4
|
|
-- * AIRBASE.Syria.King_Hussein_Air_College
|
|
-- * AIRBASE.Syria.Rene_Mouawad
|
|
-- * AIRBASE.Syria.Jirah
|
|
-- * AIRBASE.Syria.Ramat_David
|
|
-- * AIRBASE.Syria.Qabr_as_Sitt
|
|
-- * AIRBASE.Syria.Minakh
|
|
-- * AIRBASE.Syria.Adana_Sakirpasa
|
|
-- * AIRBASE.Syria.Palmyra
|
|
-- * AIRBASE.Syria.Hama
|
|
-- * AIRBASE.Syria.Ercan
|
|
-- * AIRBASE.Syria.Marj_as_Sultan_South
|
|
-- * AIRBASE.Syria.Tabqa
|
|
-- * AIRBASE.Syria.Beirut_Rafic_Hariri
|
|
-- * AIRBASE.Syria.An_Nasiriyah
|
|
-- * AIRBASE.Syria.Abu_al_Duhur
|
|
-- * AIRBASE.Syria.At_Tanf
|
|
-- * AIRBASE.Syria.H3
|
|
-- * AIRBASE.Syria.H3_Northwest
|
|
-- * AIRBASE.Syria.H3_Southwest
|
|
-- * AIRBASE.Syria.Kharab_Ishk
|
|
-- * AIRBASE.Syria.Raj_al_Issa_East
|
|
-- * AIRBASE.Syria.Raj_al_Issa_West
|
|
-- * AIRBASE.Syria.Ruwayshid
|
|
-- * AIRBASE.Syria.Sanliurfa
|
|
-- * AIRBASE.Syria.Tal_Siman
|
|
-- * AIRBASE.Syria.Deir_ez_Zor
|
|
--
|
|
--@field Syria
|
|
AIRBASE.Syria={
|
|
["Kuweires"]="Kuweires",
|
|
["Marj_Ruhayyil"]="Marj Ruhayyil",
|
|
["Kiryat_Shmona"]="Kiryat Shmona",
|
|
["Marj_as_Sultan_North"]="Marj as Sultan North",
|
|
["Eyn_Shemer"]="Eyn Shemer",
|
|
["Incirlik"]="Incirlik",
|
|
["Damascus"]="Damascus",
|
|
["Bassel_Al_Assad"]="Bassel Al-Assad",
|
|
["Rosh_Pina"]="Rosh Pina",
|
|
["Aleppo"]="Aleppo",
|
|
["Al_Qusayr"]="Al Qusayr",
|
|
["Wujah_Al_Hajar"]="Wujah Al Hajar",
|
|
["Al_Dumayr"]="Al-Dumayr",
|
|
["Gazipasa"]="Gazipasa",
|
|
-- ["Ru_Convoy_4"]="Ru Convoy-4",
|
|
["Hatay"]="Hatay",
|
|
["Nicosia"]="Nicosia",
|
|
["Pinarbashi"]="Pinarbashi",
|
|
["Paphos"]="Paphos",
|
|
["Kingsfield"]="Kingsfield",
|
|
["Thalah"]="Tha'lah",
|
|
["Haifa"]="Haifa",
|
|
["Khalkhalah"]="Khalkhalah",
|
|
["Megiddo"]="Megiddo",
|
|
["Lakatamia"]="Lakatamia",
|
|
["Rayak"]="Rayak",
|
|
["Larnaca"]="Larnaca",
|
|
["Mezzeh"]="Mezzeh",
|
|
["Gecitkale"]="Gecitkale",
|
|
["Akrotiri"]="Akrotiri",
|
|
["Naqoura"]="Naqoura",
|
|
["Gaziantep"]="Gaziantep",
|
|
["Sayqal"]="Sayqal",
|
|
["Tiyas"]="Tiyas",
|
|
["Shayrat"]="Shayrat",
|
|
["Taftanaz"]="Taftanaz",
|
|
["H4"]="H4",
|
|
["King_Hussein_Air_College"]="King Hussein Air College",
|
|
["Rene_Mouawad"]="Rene Mouawad",
|
|
["Jirah"]="Jirah",
|
|
["Ramat_David"]="Ramat David",
|
|
["Qabr_as_Sitt"]="Qabr as Sitt",
|
|
["Minakh"]="Minakh",
|
|
["Adana_Sakirpasa"]="Adana Sakirpasa",
|
|
["Palmyra"]="Palmyra",
|
|
["Hama"]="Hama",
|
|
["Ercan"]="Ercan",
|
|
["Marj_as_Sultan_South"]="Marj as Sultan South",
|
|
["Tabqa"]="Tabqa",
|
|
["Beirut_Rafic_Hariri"]="Beirut-Rafic Hariri",
|
|
["An_Nasiriyah"]="An Nasiriyah",
|
|
["Abu_al_Duhur"]="Abu al-Duhur",
|
|
["At_Tanf"]="At Tanf",
|
|
["H3"]="H3",
|
|
["H3_Northwest"]="H3 Northwest",
|
|
["H3_Southwest"]="H3 Southwest",
|
|
["Kharab_Ishk"]="Kharab Ishk",
|
|
["Raj_al_Issa_East"]="Raj al Issa East",
|
|
["Raj_al_Issa_West"]="Raj al Issa West",
|
|
["Ruwayshid"]="Ruwayshid",
|
|
["Sanliurfa"]="Sanliurfa",
|
|
["Tal_Siman"]="Tal Siman",
|
|
["Deir_ez_Zor"] = "Deir ez-Zor",
|
|
}
|
|
|
|
--- Airbases of the Mariana Islands map:
|
|
--
|
|
-- * AIRBASE.MarianaIslands.Rota_Intl
|
|
-- * AIRBASE.MarianaIslands.Andersen_AFB
|
|
-- * AIRBASE.MarianaIslands.Antonio_B_Won_Pat_Intl
|
|
-- * AIRBASE.MarianaIslands.Saipan_Intl
|
|
-- * AIRBASE.MarianaIslands.Tinian_Intl
|
|
-- * AIRBASE.MarianaIslands.Olf_Orote
|
|
--
|
|
-- @field MarianaIslands
|
|
AIRBASE.MarianaIslands = {
|
|
["Rota_Intl"] = "Rota Intl",
|
|
["Andersen_AFB"] = "Andersen AFB",
|
|
["Antonio_B_Won_Pat_Intl"] = "Antonio B. Won Pat Intl",
|
|
["Saipan_Intl"] = "Saipan Intl",
|
|
["Tinian_Intl"] = "Tinian Intl",
|
|
["Olf_Orote"] = "Olf Orote",
|
|
}
|
|
|
|
--- Airbases of the South Atlantic map:
|
|
--
|
|
-- * AIRBASE.SouthAtlantic.Port_Stanley
|
|
-- * AIRBASE.SouthAtlantic.Mount_Pleasant
|
|
-- * AIRBASE.SouthAtlantic.San_Carlos_FOB
|
|
-- * AIRBASE.SouthAtlantic.Rio_Grande
|
|
-- * AIRBASE.SouthAtlantic.Rio_Gallegos
|
|
-- * AIRBASE.SouthAtlantic.Ushuaia
|
|
-- * AIRBASE.SouthAtlantic.Ushuaia_Helo_Port
|
|
-- * AIRBASE.SouthAtlantic.Punta_Arenas
|
|
--
|
|
--@field MarianaIslands
|
|
AIRBASE.SouthAtlantic={
|
|
["Port_Stanley"]="Port Stanley",
|
|
["Mount_Pleasant"]="Mount Pleasant",
|
|
["San_Carlos_FOB"]="San Carlos FOB",
|
|
["Rio_Grande"]="Rio Grande",
|
|
["Rio_Gallegos"]="Rio Gallegos",
|
|
["Ushuaia"]="Ushuaia",
|
|
["Ushuaia_Helo_Port"]="Ushuaia Helo Port",
|
|
["Punta_Arenas"]="Punta Arenas",
|
|
}
|
|
|
|
--- AIRBASE.ParkingSpot ".Coordinate, ".TerminalID", ".TerminalType", ".TOAC", ".Free", ".TerminalID0", ".DistToRwy".
|
|
-- @type AIRBASE.ParkingSpot
|
|
-- @field Core.Point#COORDINATE Coordinate Coordinate of the parking spot.
|
|
-- @field #number TerminalID Terminal ID of the spot. Generally, this is not the same number as displayed in the mission editor.
|
|
-- @field #AIRBASE.TerminalType TerminalType Type of the spot, i.e. for which type of aircraft it can be used.
|
|
-- @field #boolean TOAC Takeoff or landing aircarft. I.e. this stop is occupied currently by an aircraft until it took of or until it landed.
|
|
-- @field #boolean Free This spot is currently free, i.e. there is no alive aircraft on it at the present moment.
|
|
-- @field #number TerminalID0 Unknown what this means. If you know, please tell us!
|
|
-- @field #number DistToRwy Distance to runway in meters. Currently bugged and giving the same number as the TerminalID.
|
|
|
|
--- Terminal Types of parking spots. See also https://wiki.hoggitworld.com/view/DCS_func_getParking
|
|
--
|
|
-- Supported types are:
|
|
--
|
|
-- * AIRBASE.TerminalType.Runway = 16: Valid spawn points on runway.
|
|
-- * AIRBASE.TerminalType.HelicopterOnly = 40: Special spots for Helicopers.
|
|
-- * AIRBASE.TerminalType.Shelter = 68: Hardened Air Shelter. Currently only on Caucaus map.
|
|
-- * AIRBASE.TerminalType.OpenMed = 72: Open/Shelter air airplane only.
|
|
-- * AIRBASE.TerminalType.OpenBig = 104: Open air spawn points. Generally larger but does not guarantee large aircraft are capable of spawning there.
|
|
-- * AIRBASE.TerminalType.OpenMedOrBig = 176: Combines OpenMed and OpenBig spots.
|
|
-- * AIRBASE.TerminalType.HelicopterUsable = 216: Combines HelicopterOnly, OpenMed and OpenBig.
|
|
-- * AIRBASE.TerminalType.FighterAircraft = 244: Combines Shelter. OpenMed and OpenBig spots. So effectively all spots usable by fixed wing aircraft.
|
|
--
|
|
-- @type AIRBASE.TerminalType
|
|
-- @field #number Runway 16: Valid spawn points on runway.
|
|
-- @field #number HelicopterOnly 40: Special spots for Helicopers.
|
|
-- @field #number Shelter 68: Hardened Air Shelter. Currently only on Caucaus map.
|
|
-- @field #number OpenMed 72: Open/Shelter air airplane only.
|
|
-- @field #number OpenBig 104: Open air spawn points. Generally larger but does not guarantee large aircraft are capable of spawning there.
|
|
-- @field #number OpenMedOrBig 176: Combines OpenMed and OpenBig spots.
|
|
-- @field #number HelicopterUsable 216: Combines HelicopterOnly, OpenMed and OpenBig.
|
|
-- @field #number FighterAircraft 244: Combines Shelter. OpenMed and OpenBig spots. So effectively all spots usable by fixed wing aircraft.
|
|
AIRBASE.TerminalType = {
|
|
Runway = 16,
|
|
HelicopterOnly = 40,
|
|
Shelter = 68,
|
|
OpenMed = 72,
|
|
OpenBig = 104,
|
|
OpenMedOrBig = 176,
|
|
HelicopterUsable = 216,
|
|
FighterAircraft = 244,
|
|
}
|
|
|
|
--- Runway data.
|
|
-- @type AIRBASE.Runway
|
|
-- @field #number heading Heading of the runway in degrees.
|
|
-- @field #string idx Runway ID: heading 070° ==> idx="07".
|
|
-- @field #number length Length of runway in meters.
|
|
-- @field Core.Point#COORDINATE position Position of runway start.
|
|
-- @field Core.Point#COORDINATE endpoint End point of runway.
|
|
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
-- Registration
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
--- Create a new AIRBASE from DCSAirbase.
|
|
-- @param #AIRBASE self
|
|
-- @param #string AirbaseName The name of the airbase.
|
|
-- @return #AIRBASE self
|
|
function AIRBASE:Register( AirbaseName )
|
|
|
|
-- Inherit everything from positionable.
|
|
local self = BASE:Inherit( self, POSITIONABLE:New( AirbaseName ) ) -- #AIRBASE
|
|
|
|
-- Set airbase name.
|
|
self.AirbaseName = AirbaseName
|
|
|
|
-- Set airbase ID.
|
|
self.AirbaseID = self:GetID( true )
|
|
|
|
-- Get descriptors.
|
|
self.descriptors = self:GetDesc()
|
|
|
|
-- Category.
|
|
self.category = self.descriptors and self.descriptors.category or Airbase.Category.AIRDROME
|
|
|
|
-- Set category.
|
|
if self.category == Airbase.Category.AIRDROME then
|
|
self.isAirdrome = true
|
|
elseif self.category == Airbase.Category.HELIPAD then
|
|
self.isHelipad = true
|
|
elseif self.category == Airbase.Category.SHIP then
|
|
self.isShip = true
|
|
-- DCS bug: Oil rigs and gas platforms have category=2 (ship). Also they cannot be retrieved by coalition.getStaticObjects()
|
|
if self.descriptors.typeName == "Oil rig" or self.descriptors.typeName == "Ga" then
|
|
self.isHelipad = true
|
|
self.isShip = false
|
|
self.category = Airbase.Category.HELIPAD
|
|
_DATABASE:AddStatic( AirbaseName )
|
|
end
|
|
else
|
|
self:E( "ERROR: Unknown airbase category!" )
|
|
end
|
|
|
|
self:_InitParkingSpots()
|
|
|
|
local vec2 = self:GetVec2()
|
|
|
|
-- Init coordinate.
|
|
self:GetCoordinate()
|
|
|
|
if vec2 then
|
|
if self.isShip then
|
|
local unit = UNIT:FindByName( AirbaseName )
|
|
if unit then
|
|
self.AirbaseZone = ZONE_UNIT:New( AirbaseName, unit, 2500 )
|
|
end
|
|
else
|
|
self.AirbaseZone = ZONE_RADIUS:New( AirbaseName, vec2, 2500 )
|
|
end
|
|
else
|
|
self:E( string.format( "ERROR: Cound not get position Vec2 of airbase %s", AirbaseName ) )
|
|
end
|
|
|
|
return self
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
-- Reference methods
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
--- Finds a AIRBASE from the _DATABASE using a DCSAirbase object.
|
|
-- @param #AIRBASE self
|
|
-- @param DCS#Airbase DCSAirbase An existing DCS Airbase object reference.
|
|
-- @return Wrapper.Airbase#AIRBASE self
|
|
function AIRBASE:Find( DCSAirbase )
|
|
|
|
local AirbaseName = DCSAirbase:getName()
|
|
local AirbaseFound = _DATABASE:FindAirbase( AirbaseName )
|
|
return AirbaseFound
|
|
end
|
|
|
|
--- Find a AIRBASE in the _DATABASE using the name of an existing DCS Airbase.
|
|
-- @param #AIRBASE self
|
|
-- @param #string AirbaseName The Airbase Name.
|
|
-- @return #AIRBASE self
|
|
function AIRBASE:FindByName( AirbaseName )
|
|
|
|
local AirbaseFound = _DATABASE:FindAirbase( AirbaseName )
|
|
return AirbaseFound
|
|
end
|
|
|
|
--- Find a AIRBASE in the _DATABASE by its ID.
|
|
-- @param #AIRBASE self
|
|
-- @param #number id Airbase ID.
|
|
-- @return #AIRBASE self
|
|
function AIRBASE:FindByID( id )
|
|
|
|
for name, _airbase in pairs( _DATABASE.AIRBASES ) do
|
|
local airbase = _airbase -- #AIRBASE
|
|
|
|
local aid = tonumber( airbase:GetID( true ) )
|
|
|
|
if aid == id then
|
|
return airbase
|
|
end
|
|
|
|
end
|
|
|
|
return nil
|
|
end
|
|
|
|
--- Get the DCS object of an airbase
|
|
-- @param #AIRBASE self
|
|
-- @return DCS#Airbase DCS airbase object.
|
|
function AIRBASE:GetDCSObject()
|
|
|
|
-- Get the DCS object.
|
|
local DCSAirbase = Airbase.getByName( self.AirbaseName )
|
|
|
|
if DCSAirbase then
|
|
return DCSAirbase
|
|
end
|
|
|
|
return nil
|
|
end
|
|
|
|
--- Get the airbase zone.
|
|
-- @param #AIRBASE self
|
|
-- @return Core.Zone#ZONE_RADIUS The zone radius of the airbase.
|
|
function AIRBASE:GetZone()
|
|
return self.AirbaseZone
|
|
end
|
|
|
|
--- Get all airbases of the current map. This includes ships and FARPS.
|
|
-- @param DCS#Coalition coalition (Optional) Return only airbases belonging to the specified coalition. By default, all airbases of the map are returned.
|
|
-- @param #number category (Optional) Return only airbases of a certain category, e.g. Airbase.Category.FARP
|
|
-- @return #table Table containing all airbase objects of the current map.
|
|
function AIRBASE.GetAllAirbases( coalition, category )
|
|
|
|
local airbases = {}
|
|
for _, _airbase in pairs( _DATABASE.AIRBASES ) do
|
|
local airbase = _airbase -- #AIRBASE
|
|
if coalition == nil or airbase:GetCoalition() == coalition then
|
|
if category == nil or category == airbase:GetAirbaseCategory() then
|
|
table.insert( airbases, airbase )
|
|
end
|
|
end
|
|
end
|
|
|
|
return airbases
|
|
end
|
|
|
|
--- Get all airbase names of the current map. This includes ships and FARPS.
|
|
-- @param DCS#Coalition coalition (Optional) Return only airbases belonging to the specified coalition. By default, all airbases of the map are returned.
|
|
-- @param #number category (Optional) Return only airbases of a certain category, e.g. `Airbase.Category.HELIPAD`.
|
|
-- @return #table Table containing all airbase names of the current map.
|
|
function AIRBASE.GetAllAirbaseNames( coalition, category )
|
|
|
|
local airbases = {}
|
|
for airbasename, _airbase in pairs( _DATABASE.AIRBASES ) do
|
|
local airbase = _airbase -- #AIRBASE
|
|
if coalition == nil or airbase:GetCoalition() == coalition then
|
|
if category == nil or category == airbase:GetAirbaseCategory() then
|
|
table.insert( airbases, airbasename )
|
|
end
|
|
end
|
|
end
|
|
|
|
return airbases
|
|
end
|
|
|
|
--- Get ID of the airbase.
|
|
-- @param #AIRBASE self
|
|
-- @param #boolean unique (Optional) If true, ships will get a negative sign as the unit ID might be the same as an airbase ID. Default off!
|
|
-- @return #number The airbase ID.
|
|
function AIRBASE:GetID( unique )
|
|
|
|
if self.AirbaseID then
|
|
|
|
return unique and self.AirbaseID or math.abs( self.AirbaseID )
|
|
|
|
else
|
|
|
|
for DCSAirbaseId, DCSAirbase in ipairs( world.getAirbases() ) do
|
|
|
|
-- Get the airbase name.
|
|
local AirbaseName = DCSAirbase:getName()
|
|
|
|
-- This gives the incorrect value to be inserted into the airdromeID for DCS 2.5.6!
|
|
local airbaseID = tonumber( DCSAirbase:getID() )
|
|
|
|
local airbaseCategory = self:GetAirbaseCategory()
|
|
|
|
if AirbaseName == self.AirbaseName then
|
|
if airbaseCategory == Airbase.Category.SHIP or airbaseCategory == Airbase.Category.HELIPAD then
|
|
-- Ships get a negative sign as their unit number might be the same as the ID of another airbase.
|
|
return unique and -airbaseID or airbaseID
|
|
else
|
|
return airbaseID
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return nil
|
|
end
|
|
|
|
--- Set parking spot whitelist. Only these spots will be considered for spawning.
|
|
-- Black listed spots overrule white listed spots.
|
|
-- **NOTE** that terminal IDs are not necessarily the same as those displayed in the mission editor!
|
|
-- @param #AIRBASE self
|
|
-- @param #table TerminalIdBlacklist Table of white listed terminal IDs.
|
|
-- @return #AIRBASE self
|
|
-- @usage AIRBASE:FindByName("Batumi"):SetParkingSpotWhitelist({2, 3, 4}) --Only allow terminal IDs 2, 3, 4
|
|
function AIRBASE:SetParkingSpotWhitelist( TerminalIdWhitelist )
|
|
|
|
if TerminalIdWhitelist == nil then
|
|
self.parkingWhitelist = {}
|
|
return self
|
|
end
|
|
|
|
-- Ensure we got a table.
|
|
if type( TerminalIdWhitelist ) ~= "table" then
|
|
TerminalIdWhitelist = { TerminalIdWhitelist }
|
|
end
|
|
|
|
self.parkingWhitelist = TerminalIdWhitelist
|
|
|
|
return self
|
|
end
|
|
|
|
--- Set parking spot blacklist. These parking spots will *not* be used for spawning.
|
|
-- Black listed spots overrule white listed spots.
|
|
-- **NOTE** that terminal IDs are not necessarily the same as those displayed in the mission editor!
|
|
-- @param #AIRBASE self
|
|
-- @param #table TerminalIdBlacklist Table of black listed terminal IDs.
|
|
-- @return #AIRBASE self
|
|
-- @usage AIRBASE:FindByName("Batumi"):SetParkingSpotBlacklist({2, 3, 4}) --Forbit terminal IDs 2, 3, 4
|
|
function AIRBASE:SetParkingSpotBlacklist( TerminalIdBlacklist )
|
|
|
|
if TerminalIdBlacklist == nil then
|
|
self.parkingBlacklist = {}
|
|
return self
|
|
end
|
|
|
|
-- Ensure we got a table.
|
|
if type( TerminalIdBlacklist ) ~= "table" then
|
|
TerminalIdBlacklist = { TerminalIdBlacklist }
|
|
end
|
|
|
|
self.parkingBlacklist = TerminalIdBlacklist
|
|
|
|
return self
|
|
end
|
|
|
|
--- Get category of airbase.
|
|
-- @param #AIRBASE self
|
|
-- @return #number Category of airbase from GetDesc().category.
|
|
function AIRBASE:GetAirbaseCategory()
|
|
return self.category
|
|
end
|
|
|
|
--- Check if airbase is an airdrome.
|
|
-- @param #AIRBASE self
|
|
-- @return #boolean If true, airbase is an airdrome.
|
|
function AIRBASE:IsAirdrome()
|
|
return self.isAirdrome
|
|
end
|
|
|
|
--- Check if airbase is a helipad.
|
|
-- @param #AIRBASE self
|
|
-- @return #boolean If true, airbase is a helipad.
|
|
function AIRBASE:IsHelipad()
|
|
return self.isHelipad
|
|
end
|
|
|
|
--- Check if airbase is a ship.
|
|
-- @param #AIRBASE self
|
|
-- @return #boolean If true, airbase is a ship.
|
|
function AIRBASE:IsShip()
|
|
return self.isShip
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
-- Parking
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
--- Returns a table of parking data for a given airbase. If the optional parameter *available* is true only available parking will be returned, otherwise all parking at the base is returned. Term types have the following enumerated values:
|
|
--
|
|
-- * 16 : Valid spawn points on runway
|
|
-- * 40 : Helicopter only spawn
|
|
-- * 68 : Hardened Air Shelter
|
|
-- * 72 : Open/Shelter air airplane only
|
|
-- * 104: Open air spawn
|
|
--
|
|
-- Note that only Caucuses will return 68 as it is the only map currently with hardened air shelters.
|
|
-- 104 are also generally larger, but does not guarantee a large aircraft like the B-52 or a C-130 are capable of spawning there.
|
|
--
|
|
-- Table entries:
|
|
--
|
|
-- * Term_index is the id for the parking
|
|
-- * vTerminal pos is its vec3 position in the world
|
|
-- * fDistToRW is the distance to the take-off position for the active runway from the parking.
|
|
--
|
|
-- @param #AIRBASE self
|
|
-- @param #boolean available If true, only available parking spots will be returned.
|
|
-- @return #table Table with parking data. See https://wiki.hoggitworld.com/view/DCS_func_getParking
|
|
function AIRBASE:GetParkingData( available )
|
|
self:F2( available )
|
|
|
|
-- Get DCS airbase object.
|
|
local DCSAirbase = self:GetDCSObject()
|
|
|
|
-- Get parking data.
|
|
local parkingdata = nil
|
|
if DCSAirbase then
|
|
parkingdata = DCSAirbase:getParking( available )
|
|
end
|
|
|
|
self:T2( { parkingdata = parkingdata } )
|
|
return parkingdata
|
|
end
|
|
|
|
--- Get number of parking spots at an airbase. Optionally, a specific terminal type can be requested.
|
|
-- @param #AIRBASE self
|
|
-- @param #AIRBASE.TerminalType termtype Terminal type of which the number of spots is counted. Default all spots but spawn points on runway.
|
|
-- @return #number Number of parking spots at this airbase.
|
|
function AIRBASE:GetParkingSpotsNumber( termtype )
|
|
|
|
-- Get free parking spots data.
|
|
local parkingdata = self:GetParkingData( false )
|
|
|
|
local nspots = 0
|
|
for _, parkingspot in pairs( parkingdata ) do
|
|
if AIRBASE._CheckTerminalType( parkingspot.Term_Type, termtype ) then
|
|
nspots = nspots + 1
|
|
end
|
|
end
|
|
|
|
return nspots
|
|
end
|
|
|
|
--- Get number of free parking spots at an airbase.
|
|
-- @param #AIRBASE self
|
|
-- @param #AIRBASE.TerminalType termtype Terminal type.
|
|
-- @param #boolean allowTOAC If true, spots are considered free even though TO_AC is true. Default is off which is saver to avoid spawning aircraft on top of each other. Option might be enabled for FARPS and ships.
|
|
-- @return #number Number of free parking spots at this airbase.
|
|
function AIRBASE:GetFreeParkingSpotsNumber( termtype, allowTOAC )
|
|
|
|
-- Get free parking spots data.
|
|
local parkingdata = self:GetParkingData( true )
|
|
|
|
local nfree = 0
|
|
for _, parkingspot in pairs( parkingdata ) do
|
|
-- Spots on runway are not counted unless explicitly requested.
|
|
if AIRBASE._CheckTerminalType( parkingspot.Term_Type, termtype ) then
|
|
if (allowTOAC and allowTOAC == true) or parkingspot.TO_AC == false then
|
|
nfree = nfree + 1
|
|
end
|
|
end
|
|
end
|
|
|
|
return nfree
|
|
end
|
|
|
|
--- Get the coordinates of free parking spots at an airbase.
|
|
-- @param #AIRBASE self
|
|
-- @param #AIRBASE.TerminalType termtype Terminal type.
|
|
-- @param #boolean allowTOAC If true, spots are considered free even though TO_AC is true. Default is off which is saver to avoid spawning aircraft on top of each other. Option might be enabled for FARPS and ships.
|
|
-- @return #table Table of coordinates of the free parking spots.
|
|
function AIRBASE:GetFreeParkingSpotsCoordinates( termtype, allowTOAC )
|
|
|
|
-- Get free parking spots data.
|
|
local parkingdata = self:GetParkingData( true )
|
|
|
|
-- Put coordinates of free spots into table.
|
|
local spots = {}
|
|
for _, parkingspot in pairs( parkingdata ) do
|
|
-- Coordinates on runway are not returned unless explicitly requested.
|
|
if AIRBASE._CheckTerminalType( parkingspot.Term_Type, termtype ) then
|
|
if (allowTOAC and allowTOAC == true) or parkingspot.TO_AC == false then
|
|
table.insert( spots, COORDINATE:NewFromVec3( parkingspot.vTerminalPos ) )
|
|
end
|
|
end
|
|
end
|
|
|
|
return spots
|
|
end
|
|
|
|
--- Get the coordinates of all parking spots at an airbase. Optionally only those of a specific terminal type. Spots on runways are excluded if not explicitly requested by terminal type.
|
|
-- @param #AIRBASE self
|
|
-- @param #AIRBASE.TerminalType termtype (Optional) Terminal type. Default all.
|
|
-- @return #table Table of coordinates of parking spots.
|
|
function AIRBASE:GetParkingSpotsCoordinates( termtype )
|
|
|
|
-- Get all parking spots data.
|
|
local parkingdata = self:GetParkingData( false )
|
|
|
|
-- Put coordinates of free spots into table.
|
|
local spots = {}
|
|
for _, parkingspot in ipairs( parkingdata ) do
|
|
|
|
-- Coordinates on runway are not returned unless explicitly requested.
|
|
if AIRBASE._CheckTerminalType( parkingspot.Term_Type, termtype ) then
|
|
|
|
-- Get coordinate from Vec3 terminal position.
|
|
local _coord = COORDINATE:NewFromVec3( parkingspot.vTerminalPos )
|
|
|
|
-- Add to table.
|
|
table.insert( spots, _coord )
|
|
end
|
|
|
|
end
|
|
|
|
return spots
|
|
end
|
|
|
|
--- Get a table containing the coordinates, terminal index and terminal type of free parking spots at an airbase.
|
|
-- @param #AIRBASE self
|
|
-- @return#AIRBASE self
|
|
function AIRBASE:_InitParkingSpots()
|
|
|
|
-- Get parking data of all spots (free or occupied)
|
|
local parkingdata = self:GetParkingData( false )
|
|
|
|
-- Init table.
|
|
self.parking = {}
|
|
self.parkingByID = {}
|
|
|
|
self.NparkingTotal = 0
|
|
self.NparkingTerminal = {}
|
|
for _, terminalType in pairs( AIRBASE.TerminalType ) do
|
|
self.NparkingTerminal[terminalType] = 0
|
|
end
|
|
|
|
-- Put coordinates of parking spots into table.
|
|
for _, spot in pairs( parkingdata ) do
|
|
|
|
-- New parking spot.
|
|
local park = {} -- #AIRBASE.ParkingSpot
|
|
park.Vec3 = spot.vTerminalPos
|
|
park.Coordinate = COORDINATE:NewFromVec3( spot.vTerminalPos )
|
|
park.DistToRwy = spot.fDistToRW
|
|
park.Free = nil
|
|
park.TerminalID = spot.Term_Index
|
|
park.TerminalID0 = spot.Term_Index_0
|
|
park.TerminalType = spot.Term_Type
|
|
park.TOAC = spot.TO_AC
|
|
|
|
self.NparkingTotal = self.NparkingTotal + 1
|
|
|
|
for _, terminalType in pairs( AIRBASE.TerminalType ) do
|
|
if self._CheckTerminalType( terminalType, park.TerminalType ) then
|
|
self.NparkingTerminal[terminalType] = self.NparkingTerminal[terminalType] + 1
|
|
end
|
|
end
|
|
|
|
self.parkingByID[park.TerminalID] = park
|
|
table.insert( self.parking, park )
|
|
end
|
|
|
|
return self
|
|
end
|
|
|
|
--- Get a table containing the coordinates, terminal index and terminal type of free parking spots at an airbase.
|
|
-- @param #AIRBASE self
|
|
-- @param #number TerminalID Terminal ID.
|
|
-- @return #AIRBASE.ParkingSpot Parking spot.
|
|
function AIRBASE:_GetParkingSpotByID( TerminalID )
|
|
return self.parkingByID[TerminalID]
|
|
end
|
|
|
|
--- Get a table containing the coordinates, terminal index and terminal type of free parking spots at an airbase.
|
|
-- @param #AIRBASE self
|
|
-- @param #AIRBASE.TerminalType termtype Terminal type.
|
|
-- @return #table Table free parking spots. Table has the elements ".Coordinate, ".TerminalID", ".TerminalType", ".TOAC", ".Free", ".TerminalID0", ".DistToRwy".
|
|
function AIRBASE:GetParkingSpotsTable( termtype )
|
|
|
|
-- Get parking data of all spots (free or occupied)
|
|
local parkingdata = self:GetParkingData( false )
|
|
|
|
-- Get parking data of all free spots.
|
|
local parkingfree = self:GetParkingData( true )
|
|
|
|
-- Function to ckeck if any parking spot is free.
|
|
local function _isfree( _tocheck )
|
|
for _, _spot in pairs( parkingfree ) do
|
|
if _spot.Term_Index == _tocheck.Term_Index then
|
|
return true
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
-- Put coordinates of parking spots into table.
|
|
local spots = {}
|
|
for _, _spot in pairs( parkingdata ) do
|
|
|
|
if AIRBASE._CheckTerminalType( _spot.Term_Type, termtype ) then
|
|
|
|
local spot = self:_GetParkingSpotByID( _spot.Term_Index )
|
|
|
|
if spot then
|
|
|
|
spot.Free = _isfree( _spot ) -- updated
|
|
spot.TOAC = _spot.TO_AC -- updated
|
|
|
|
table.insert( spots, spot )
|
|
|
|
else
|
|
|
|
self:E( string.format( "ERROR: Parking spot %s is nil!", tostring( _spot.Term_Index ) ) )
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return spots
|
|
end
|
|
|
|
--- Get a table containing the coordinates, terminal index and terminal type of free parking spots at an airbase.
|
|
-- @param #AIRBASE self
|
|
-- @param #AIRBASE.TerminalType termtype Terminal type.
|
|
-- @param #boolean allowTOAC If true, spots are considered free even though TO_AC is true. Default is off which is saver to avoid spawning aircraft on top of each other. Option might be enabled for FARPS and ships.
|
|
-- @return #table Table free parking spots. Table has the elements ".Coordinate, ".TerminalID", ".TerminalType", ".TOAC", ".Free", ".TerminalID0", ".DistToRwy".
|
|
function AIRBASE:GetFreeParkingSpotsTable( termtype, allowTOAC )
|
|
|
|
-- Get parking data of all free spots.
|
|
local parkingfree = self:GetParkingData( true )
|
|
|
|
-- Put coordinates of free spots into table.
|
|
local freespots = {}
|
|
for _, _spot in pairs( parkingfree ) do
|
|
if AIRBASE._CheckTerminalType( _spot.Term_Type, termtype ) and _spot.Term_Index > 0 then
|
|
if (allowTOAC and allowTOAC == true) or _spot.TO_AC == false then
|
|
|
|
local spot = self:_GetParkingSpotByID( _spot.Term_Index )
|
|
|
|
spot.Free = true -- updated
|
|
spot.TOAC = _spot.TO_AC -- updated
|
|
|
|
table.insert( freespots, spot )
|
|
|
|
end
|
|
end
|
|
end
|
|
|
|
return freespots
|
|
end
|
|
|
|
--- Get a table containing the coordinates, terminal index and terminal type of free parking spots at an airbase.
|
|
-- @param #AIRBASE self
|
|
-- @param #number TerminalID The terminal ID of the parking spot.
|
|
-- @return #AIRBASE.ParkingSpot Table free parking spots. Table has the elements ".Coordinate, ".TerminalID", ".TerminalType", ".TOAC", ".Free", ".TerminalID0", ".DistToRwy".
|
|
function AIRBASE:GetParkingSpotData( TerminalID )
|
|
|
|
-- Get parking data.
|
|
local parkingdata = self:GetParkingSpotsTable()
|
|
|
|
for _, _spot in pairs( parkingdata ) do
|
|
local spot = _spot -- #AIRBASE.ParkingSpot
|
|
self:T( { TerminalID = spot.TerminalID, TerminalType = spot.TerminalType } )
|
|
if TerminalID == spot.TerminalID then
|
|
return spot
|
|
end
|
|
end
|
|
|
|
self:E( "ERROR: Could not find spot with Terminal ID=" .. tostring( TerminalID ) )
|
|
return nil
|
|
end
|
|
|
|
--- Place markers of parking spots on the F10 map.
|
|
-- @param #AIRBASE self
|
|
-- @param #AIRBASE.TerminalType termtype Terminal type for which marks should be placed.
|
|
-- @param #boolean mark If false, do not place markers but only give output to DCS.log file. Default true.
|
|
function AIRBASE:MarkParkingSpots( termtype, mark )
|
|
|
|
-- Default is true.
|
|
if mark == nil then
|
|
mark = true
|
|
end
|
|
|
|
-- Get parking data from getParking() wrapper function.
|
|
local parkingdata = self:GetParkingSpotsTable( termtype )
|
|
|
|
-- Get airbase name.
|
|
local airbasename = self:GetName()
|
|
self:E( string.format( "Parking spots at %s for terminal type %s:", airbasename, tostring( termtype ) ) )
|
|
|
|
for _, _spot in pairs( parkingdata ) do
|
|
|
|
-- Mark text.
|
|
local _text = string.format( "Term Index=%d, Term Type=%d, Free=%s, TOAC=%s, Term ID0=%d, Dist2Rwy=%.1f m", _spot.TerminalID, _spot.TerminalType, tostring( _spot.Free ), tostring( _spot.TOAC ), _spot.TerminalID0, _spot.DistToRwy )
|
|
|
|
-- Create mark on the F10 map.
|
|
if mark then
|
|
_spot.Coordinate:MarkToAll( _text )
|
|
end
|
|
|
|
-- Info to DCS.log file.
|
|
local _text = string.format( "%s, Term Index=%3d, Term Type=%03d, Free=%5s, TOAC=%5s, Term ID0=%3d, Dist2Rwy=%.1f m", airbasename, _spot.TerminalID, _spot.TerminalType, tostring( _spot.Free ), tostring( _spot.TOAC ), _spot.TerminalID0, _spot.DistToRwy )
|
|
self:E( _text )
|
|
end
|
|
end
|
|
|
|
--- Seach unoccupied parking spots at the airbase for a specific group of aircraft. The routine also optionally checks for other unit, static and scenery options in a certain radius around the parking spot.
|
|
-- The dimension of the spawned aircraft and of the potential obstacle are taken into account. Note that the routine can only return so many spots that are free.
|
|
-- @param #AIRBASE self
|
|
-- @param Wrapper.Group#GROUP group Aircraft group for which the parking spots are requested.
|
|
-- @param #AIRBASE.TerminalType terminaltype (Optional) Only search spots at a specific terminal type. Default is all types execpt on runway.
|
|
-- @param #number scanradius (Optional) Radius in meters around parking spot to scan for obstacles. Default 50 m.
|
|
-- @param #boolean scanunits (Optional) Scan for units as obstacles. Default true.
|
|
-- @param #boolean scanstatics (Optional) Scan for statics as obstacles. Default true.
|
|
-- @param #boolean scanscenery (Optional) Scan for scenery as obstacles. Default false. Can cause problems with e.g. shelters.
|
|
-- @param #boolean verysafe (Optional) If true, wait until an aircraft has taken off until the parking spot is considered to be free. Defaul false.
|
|
-- @param #number nspots (Optional) Number of freeparking spots requested. Default is the number of aircraft in the group.
|
|
-- @param #table parkingdata (Optional) Parking spots data table. If not given it is automatically derived from the GetParkingSpotsTable() function.
|
|
-- @return #table Table of coordinates and terminal IDs of free parking spots. Each table entry has the elements .Coordinate and .TerminalID.
|
|
function AIRBASE:FindFreeParkingSpotForAircraft( group, terminaltype, scanradius, scanunits, scanstatics, scanscenery, verysafe, nspots, parkingdata )
|
|
|
|
-- Init default
|
|
scanradius = scanradius or 50
|
|
if scanunits == nil then
|
|
scanunits = true
|
|
end
|
|
if scanstatics == nil then
|
|
scanstatics = true
|
|
end
|
|
if scanscenery == nil then
|
|
scanscenery = false
|
|
end
|
|
if verysafe == nil then
|
|
verysafe = false
|
|
end
|
|
|
|
-- Function calculating the overlap of two (square) objects.
|
|
local function _overlap( object1, object2, dist )
|
|
local pos1 = object1 -- Wrapper.Positionable#POSITIONABLE
|
|
local pos2 = object2 -- Wrapper.Positionable#POSITIONABLE
|
|
local r1 = pos1:GetBoundingRadius()
|
|
local r2 = pos2:GetBoundingRadius()
|
|
if r1 and r2 then
|
|
local safedist = (r1 + r2) * 1.1
|
|
local safe = (dist > safedist)
|
|
self:T2( string.format( "r1=%.1f r2=%.1f s=%.1f d=%.1f ==> safe=%s", r1, r2, safedist, dist, tostring( safe ) ) )
|
|
return safe
|
|
else
|
|
return true
|
|
end
|
|
end
|
|
|
|
-- Get airport name.
|
|
local airport = self:GetName()
|
|
|
|
-- Get parking spot data table. This contains free and "non-free" spots.
|
|
-- Note that there are three major issues with the DCS getParking() function:
|
|
-- 1. A spot is considered as NOT free until an aircraft that is present has finally taken off. This might be a bit long especiall at smaller airports.
|
|
-- 2. A "free" spot does not take the aircraft size into accound. So if two big aircraft are spawned on spots next to each other, they might overlap and get destroyed.
|
|
-- 3. The routine return a free spot, if there a static objects placed on the spot.
|
|
parkingdata = parkingdata or self:GetParkingSpotsTable( terminaltype )
|
|
|
|
-- Get the aircraft size, i.e. it's longest side of x,z.
|
|
local aircraft = nil -- fix local problem below
|
|
local _aircraftsize, ax, ay, az
|
|
if group and group.ClassName == "GROUP" then
|
|
aircraft = group:GetUnit( 1 )
|
|
_aircraftsize, ax, ay, az = aircraft:GetObjectSize()
|
|
else
|
|
-- SU27 dimensions
|
|
_aircraftsize = 23
|
|
ax = 23 -- length
|
|
ay = 7 -- height
|
|
az = 17 -- width
|
|
end
|
|
|
|
-- Number of spots we are looking for. Note that, e.g. grouping can require a number different from the group size!
|
|
local _nspots = nspots or group:GetSize()
|
|
|
|
-- Debug info.
|
|
self:E( string.format( "%s: Looking for %d parking spot(s) for aircraft of size %.1f m (x=%.1f,y=%.1f,z=%.1f) at terminal type %s.", airport, _nspots, _aircraftsize, ax, ay, az, tostring( terminaltype ) ) )
|
|
|
|
-- Table of valid spots.
|
|
local validspots = {}
|
|
local nvalid = 0
|
|
|
|
-- Test other stuff if no parking spot is available.
|
|
local _test = false
|
|
if _test then
|
|
return validspots
|
|
end
|
|
|
|
-- Mark all found obstacles on F10 map for debugging.
|
|
local markobstacles = false
|
|
|
|
-- Loop over all known parking spots
|
|
for _, parkingspot in pairs( parkingdata ) do
|
|
|
|
-- Coordinate of the parking spot.
|
|
local _spot = parkingspot.Coordinate -- Core.Point#COORDINATE
|
|
local _termid = parkingspot.TerminalID
|
|
|
|
-- Check terminal type and black/white listed parking spots.
|
|
if AIRBASE._CheckTerminalType( parkingspot.TerminalType, terminaltype ) and self:_CheckParkingLists( _termid ) then
|
|
|
|
-- Very safe uses the DCS getParking() info to check if a spot is free. Unfortunately, the function returns free=false until the aircraft has actually taken-off.
|
|
if verysafe and (parkingspot.Free == false or parkingspot.TOAC == true) then
|
|
|
|
-- DCS getParking() routine returned that spot is not free.
|
|
self:T( string.format( "%s: Parking spot id %d NOT free (or aircraft has not taken off yet). Free=%s, TOAC=%s.", airport, parkingspot.TerminalID, tostring( parkingspot.Free ), tostring( parkingspot.TOAC ) ) )
|
|
|
|
else
|
|
|
|
-- Scan a radius of 50 meters around the spot.
|
|
local _, _, _, _units, _statics, _sceneries = _spot:ScanObjects( scanradius, scanunits, scanstatics, scanscenery )
|
|
|
|
-- Loop over objects within scan radius.
|
|
local occupied = false
|
|
|
|
-- Check all units.
|
|
for _, unit in pairs( _units ) do
|
|
local _coord = unit:GetCoordinate()
|
|
local _dist = _coord:Get2DDistance( _spot )
|
|
local _safe = _overlap( aircraft, unit, _dist )
|
|
|
|
if markobstacles then
|
|
local l, x, y, z = unit:GetObjectSize()
|
|
_coord:MarkToAll( string.format( "Unit %s\nx=%.1f y=%.1f z=%.1f\nl=%.1f d=%.1f\nspot %d safe=%s", unit:GetName(), x, y, z, l, _dist, _termid, tostring( _safe ) ) )
|
|
end
|
|
|
|
if scanunits and not _safe then
|
|
occupied = true
|
|
end
|
|
end
|
|
|
|
-- Check all statics.
|
|
for _, static in pairs( _statics ) do
|
|
local _static = STATIC:Find( static )
|
|
local _vec3 = static:getPoint()
|
|
local _coord = COORDINATE:NewFromVec3( _vec3 )
|
|
local _dist = _coord:Get2DDistance( _spot )
|
|
local _safe = _overlap( aircraft, _static, _dist )
|
|
|
|
if markobstacles then
|
|
local l, x, y, z = _static:GetObjectSize()
|
|
_coord:MarkToAll( string.format( "Static %s\nx=%.1f y=%.1f z=%.1f\nl=%.1f d=%.1f\nspot %d safe=%s", static:getName(), x, y, z, l, _dist, _termid, tostring( _safe ) ) )
|
|
end
|
|
|
|
if scanstatics and not _safe then
|
|
occupied = true
|
|
end
|
|
end
|
|
|
|
-- Check all scenery.
|
|
for _, scenery in pairs( _sceneries ) do
|
|
local _scenery = SCENERY:Register( scenery:getTypeName(), scenery )
|
|
local _vec3 = scenery:getPoint()
|
|
local _coord = COORDINATE:NewFromVec3( _vec3 )
|
|
local _dist = _coord:Get2DDistance( _spot )
|
|
local _safe = _overlap( aircraft, _scenery, _dist )
|
|
|
|
if markobstacles then
|
|
local l, x, y, z = scenery:GetObjectSize( scenery )
|
|
_coord:MarkToAll( string.format( "Scenery %s\nx=%.1f y=%.1f z=%.1f\nl=%.1f d=%.1f\nspot %d safe=%s", scenery:getTypeName(), x, y, z, l, _dist, _termid, tostring( _safe ) ) )
|
|
end
|
|
|
|
if scanscenery and not _safe then
|
|
occupied = true
|
|
end
|
|
end
|
|
|
|
-- Now check the already given spots so that we do not put a large aircraft next to one we already assigned a nearby spot.
|
|
for _, _takenspot in pairs( validspots ) do
|
|
local _dist = _takenspot.Coordinate:Get2DDistance( _spot )
|
|
local _safe = _overlap( aircraft, aircraft, _dist )
|
|
if not _safe then
|
|
occupied = true
|
|
end
|
|
end
|
|
|
|
-- _spot:MarkToAll(string.format("Parking spot %d free=%s", parkingspot.TerminalID, tostring(not occupied)))
|
|
if occupied then
|
|
self:I( string.format( "%s: Parking spot id %d occupied.", airport, _termid ) )
|
|
else
|
|
self:I( string.format( "%s: Parking spot id %d free.", airport, _termid ) )
|
|
if nvalid < _nspots then
|
|
table.insert( validspots, { Coordinate = _spot, TerminalID = _termid } )
|
|
end
|
|
nvalid = nvalid + 1
|
|
self:I( string.format( "%s: Parking spot id %d free. Nfree=%d/%d.", airport, _termid, nvalid, _nspots ) )
|
|
end
|
|
|
|
end -- loop over units
|
|
|
|
-- We found enough spots.
|
|
if nvalid >= _nspots then
|
|
return validspots
|
|
end
|
|
end -- check terminal type
|
|
end
|
|
|
|
-- Retrun spots we found, even if there were not enough.
|
|
return validspots
|
|
|
|
end
|
|
|
|
--- Check black and white lists.
|
|
-- @param #AIRBASE self
|
|
-- @param #number TerminalID Terminal ID to check.
|
|
-- @return #boolean `true` if this is a valid spot.
|
|
function AIRBASE:_CheckParkingLists( TerminalID )
|
|
|
|
-- First check the black list. If we find a match, this spot is forbidden!
|
|
if self.parkingBlacklist and #self.parkingBlacklist > 0 then
|
|
for _, terminalID in pairs( self.parkingBlacklist or {} ) do
|
|
if terminalID == TerminalID then
|
|
-- This is a invalid spot.
|
|
return false
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Check if a whitelist was defined.
|
|
if self.parkingWhitelist and #self.parkingWhitelist > 0 then
|
|
for _, terminalID in pairs( self.parkingWhitelist or {} ) do
|
|
if terminalID == TerminalID then
|
|
-- This is a valid spot.
|
|
return true
|
|
end
|
|
end
|
|
-- No match ==> invalid spot
|
|
return false
|
|
end
|
|
|
|
-- Neither black nor white lists were defined or spot is not in black list.
|
|
return true
|
|
end
|
|
|
|
--- Helper function to check for the correct terminal type including "artificial" ones.
|
|
-- @param #number Term_Type Termial type from getParking routine.
|
|
-- @param #AIRBASE.TerminalType termtype Terminal type from AIRBASE.TerminalType enumerator.
|
|
-- @return #boolean True if terminal types match.
|
|
function AIRBASE._CheckTerminalType( Term_Type, termtype )
|
|
|
|
-- Nill check for Term_Type.
|
|
if Term_Type == nil then
|
|
return false
|
|
end
|
|
|
|
-- If no terminal type is requested, we return true. BUT runways are excluded unless explicitly requested.
|
|
if termtype == nil then
|
|
if Term_Type == AIRBASE.TerminalType.Runway then
|
|
return false
|
|
else
|
|
return true
|
|
end
|
|
end
|
|
|
|
-- Init no match.
|
|
local match = false
|
|
|
|
-- Standar case.
|
|
if Term_Type == termtype then
|
|
match = true
|
|
end
|
|
|
|
-- Artificial cases. Combination of terminal types.
|
|
if termtype == AIRBASE.TerminalType.OpenMedOrBig then
|
|
if Term_Type == AIRBASE.TerminalType.OpenMed or Term_Type == AIRBASE.TerminalType.OpenBig then
|
|
match = true
|
|
end
|
|
elseif termtype == AIRBASE.TerminalType.HelicopterUsable then
|
|
if Term_Type == AIRBASE.TerminalType.OpenMed or Term_Type == AIRBASE.TerminalType.OpenBig or Term_Type == AIRBASE.TerminalType.HelicopterOnly then
|
|
match = true
|
|
end
|
|
elseif termtype == AIRBASE.TerminalType.FighterAircraft then
|
|
if Term_Type == AIRBASE.TerminalType.OpenMed or Term_Type == AIRBASE.TerminalType.OpenBig or Term_Type == AIRBASE.TerminalType.Shelter then
|
|
match = true
|
|
end
|
|
end
|
|
|
|
return match
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
-- Runway
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
--- Get runways data. Only for airdromes!
|
|
-- @param #AIRBASE self
|
|
-- @param #number magvar (Optional) Magnetic variation in degrees.
|
|
-- @param #boolean mark (Optional) Place markers with runway data on F10 map.
|
|
-- @return #table Runway data.
|
|
function AIRBASE:GetRunwayData( magvar, mark )
|
|
|
|
-- Runway table.
|
|
local runways = {}
|
|
|
|
if self:GetAirbaseCategory() ~= Airbase.Category.AIRDROME then
|
|
return {}
|
|
end
|
|
|
|
-- Get spawn points on runway. These can be used to determine the runway heading.
|
|
local runwaycoords = self:GetParkingSpotsCoordinates( AIRBASE.TerminalType.Runway )
|
|
|
|
-- Debug: For finding the numbers of the spawn points belonging to each runway.
|
|
if false then
|
|
for i, _coord in pairs( runwaycoords ) do
|
|
local coord = _coord -- Core.Point#COORDINATE
|
|
coord:Translate( 100, 0 ):MarkToAll( "Runway i=" .. i )
|
|
end
|
|
end
|
|
|
|
-- Magnetic declination.
|
|
magvar = magvar or UTILS.GetMagneticDeclination()
|
|
|
|
-- Number of runways.
|
|
local N = #runwaycoords
|
|
local N2 = N / 2
|
|
local exception = false
|
|
|
|
-- Airbase name.
|
|
local name = self:GetName()
|
|
|
|
-- Exceptions
|
|
if name == AIRBASE.Nevada.Jean_Airport or
|
|
name == AIRBASE.Nevada.Creech_AFB or
|
|
name == AIRBASE.PersianGulf.Abu_Dhabi_International_Airport or
|
|
name == AIRBASE.PersianGulf.Dubai_Intl or
|
|
name == AIRBASE.PersianGulf.Shiraz_International_Airport or
|
|
name == AIRBASE.PersianGulf.Kish_International_Airport or
|
|
name == AIRBASE.MarianaIslands.Andersen_AFB then
|
|
|
|
-- 1-->4, 2-->3, 3-->2, 4-->1
|
|
exception = 1
|
|
|
|
elseif UTILS.GetDCSMap() == DCSMAP.Syria and N >= 2 and
|
|
name ~= AIRBASE.Syria.Minakh and
|
|
name ~= AIRBASE.Syria.Damascus and
|
|
name ~= AIRBASE.Syria.Khalkhalah and
|
|
name ~= AIRBASE.Syria.Marj_Ruhayyil and
|
|
name ~= AIRBASE.Syria.Beirut_Rafic_Hariri then
|
|
|
|
-- 1-->3, 2-->4, 3-->1, 4-->2
|
|
exception = 2
|
|
|
|
end
|
|
|
|
--- Function returning the index of the runway coordinate belonding to the given index i.
|
|
local function f( i )
|
|
|
|
local j
|
|
|
|
if exception == 1 then
|
|
|
|
j = N - (i - 1) -- 1-->4, 2-->3
|
|
|
|
elseif exception == 2 then
|
|
|
|
if i <= N2 then
|
|
j = i + N2 -- 1-->3, 2-->4
|
|
else
|
|
j = i - N2 -- 3-->1, 4-->3
|
|
end
|
|
|
|
else
|
|
|
|
if i % 2 == 0 then
|
|
j = i - 1 -- even 2-->1, 4-->3
|
|
else
|
|
j = i + 1 -- odd 1-->2, 3-->4
|
|
end
|
|
|
|
end
|
|
|
|
-- Special case where there is no obvious order.
|
|
if name == AIRBASE.Syria.Beirut_Rafic_Hariri then
|
|
if i == 1 then
|
|
j = 3
|
|
elseif i == 2 then
|
|
j = 6
|
|
elseif i == 3 then
|
|
j = 1
|
|
elseif i == 4 then
|
|
j = 5
|
|
elseif i == 5 then
|
|
j = 4
|
|
elseif i == 6 then
|
|
j = 2
|
|
end
|
|
end
|
|
|
|
if name == AIRBASE.Syria.Ramat_David then
|
|
if i == 1 then
|
|
j = 4
|
|
elseif i == 2 then
|
|
j = 6
|
|
elseif i == 3 then
|
|
j = 5
|
|
elseif i == 4 then
|
|
j = 1
|
|
elseif i == 5 then
|
|
j = 3
|
|
elseif i == 6 then
|
|
j = 2
|
|
end
|
|
end
|
|
|
|
return j
|
|
end
|
|
|
|
for i = 1, N do
|
|
|
|
-- Get the other spawn point coordinate.
|
|
local j = f( i )
|
|
|
|
-- Debug info.
|
|
-- env.info(string.format("Runway i=%s j=%s (N=%d #runwaycoord=%d)", tostring(i), tostring(j), N, #runwaycoords))
|
|
|
|
-- Coordinates of the two runway points.
|
|
local c1 = runwaycoords[i] -- Core.Point#COORDINATE
|
|
local c2 = runwaycoords[j] -- Core.Point#COORDINATE
|
|
|
|
-- Heading of runway.
|
|
local hdg = c1:HeadingTo( c2 )
|
|
|
|
-- Runway ID: heading=070° ==> idx="07"
|
|
local idx = string.format( "%02d", UTILS.Round( (hdg - magvar) / 10, 0 ) )
|
|
|
|
-- Runway table.
|
|
local runway = {} -- #AIRBASE.Runway
|
|
runway.heading = hdg
|
|
runway.idx = idx
|
|
runway.length = c1:Get2DDistance( c2 )
|
|
runway.position = c1
|
|
runway.endpoint = c2
|
|
|
|
-- Debug info.
|
|
-- self:I(string.format("Airbase %s: Adding runway id=%s, heading=%03d, length=%d m i=%d j=%d", self:GetName(), runway.idx, runway.heading, runway.length, i, j))
|
|
|
|
-- Debug mark
|
|
if mark then
|
|
runway.position:MarkToAll( string.format( "Runway %s: true heading=%03d (magvar=%d), length=%d m, i=%d, j=%d", runway.idx, runway.heading, magvar, runway.length, i, j ) )
|
|
end
|
|
|
|
-- Add runway.
|
|
table.insert( runways, runway )
|
|
|
|
end
|
|
|
|
return runways
|
|
end
|
|
|
|
--- Set the active runway in case it cannot be determined by the wind direction.
|
|
-- @param #AIRBASE self
|
|
-- @param #number iactive Number of the active runway in the runway data table.
|
|
function AIRBASE:SetActiveRunway( iactive )
|
|
self.activerwyno = iactive
|
|
end
|
|
|
|
--- Get the active runway based on current wind direction.
|
|
-- @param #AIRBASE self
|
|
-- @param #number magvar (Optional) Magnetic variation in degrees.
|
|
-- @return #AIRBASE.Runway Active runway data table.
|
|
function AIRBASE:GetActiveRunway( magvar )
|
|
|
|
-- Get runways data (initialize if necessary).
|
|
local runways = self:GetRunwayData( magvar )
|
|
|
|
-- Return user forced active runway if it was set.
|
|
if self.activerwyno then
|
|
return runways[self.activerwyno]
|
|
end
|
|
|
|
-- Get wind vector.
|
|
local Vwind = self:GetCoordinate():GetWindWithTurbulenceVec3()
|
|
local norm = UTILS.VecNorm( Vwind )
|
|
|
|
-- Active runway number.
|
|
local iact = 1
|
|
|
|
-- 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
|
|
|
|
-- Loop over runways.
|
|
local dotmin = nil
|
|
for i, _runway in pairs( runways ) do
|
|
local runway = _runway -- #AIRBASE.Runway
|
|
|
|
-- Angle in rad.
|
|
local alpha = math.rad( runway.heading )
|
|
|
|
-- 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.heading, dot))
|
|
|
|
-- New min?
|
|
if dotmin == nil or dot < dotmin then
|
|
dotmin = dot
|
|
iact = i
|
|
end
|
|
|
|
end
|
|
else
|
|
self:E( "WARNING: Norm of wind is zero! Cannot determine active runway based on wind direction." )
|
|
end
|
|
|
|
return runways[iact]
|
|
end
|
|
|
|
--- Function that checks if at leat one unit of a group has been spawned close to a spawn point on the runway.
|
|
-- @param #AIRBASE self
|
|
-- @param Wrapper.Group#GROUP group Group to be checked.
|
|
-- @param #number radius Radius around the spawn point to be checked. Default is 50 m.
|
|
-- @param #boolean despawn If true, the group is destroyed.
|
|
-- @return #boolean True if group is within radius around spawn points on runway.
|
|
function AIRBASE:CheckOnRunWay( group, radius, despawn )
|
|
|
|
-- Default radius.
|
|
radius = radius or 50
|
|
|
|
-- We only check at real airbases (not FARPS or ships).
|
|
if self:GetAirbaseCategory() ~= Airbase.Category.AIRDROME then
|
|
return false
|
|
end
|
|
|
|
if group and group:IsAlive() then
|
|
|
|
-- Debug.
|
|
self:T( string.format( "%s, checking if group %s is on runway?", self:GetName(), group:GetName() ) )
|
|
|
|
-- Get coordinates on runway.
|
|
local runwaypoints = self:GetParkingSpotsCoordinates( AIRBASE.TerminalType.Runway )
|
|
|
|
-- Get units of group.
|
|
local units = group:GetUnits()
|
|
|
|
-- Loop over units.
|
|
for _, _unit in pairs( units ) do
|
|
|
|
local unit = _unit -- Wrapper.Unit#UNIT
|
|
|
|
-- Check if unit is alive and not in air.
|
|
if unit and unit:IsAlive() and not unit:InAir() then
|
|
self:T( string.format( "%s, checking if unit %s is on runway?", self:GetName(), unit:GetName() ) )
|
|
|
|
-- Loop over runway spawn points.
|
|
for _i, _coord in pairs( runwaypoints ) do
|
|
|
|
-- Distance between unit and spawn pos.
|
|
local dist = unit:GetCoordinate():Get2DDistance( _coord )
|
|
|
|
-- Mark unit spawn points for debugging.
|
|
-- unit:GetCoordinate():MarkToAll(string.format("unit %s distance to rwy %d = %d",unit:GetName(),_i, dist))
|
|
|
|
-- Check if unit is withing radius.
|
|
if dist < radius then
|
|
self:E( string.format( "%s, unit %s of group %s was spawned on runway #%d. Distance %.1f < radius %.1f m. Despawn = %s.", self:GetName(), unit:GetName(), group:GetName(), _i, dist, radius, tostring( despawn ) ) )
|
|
-- unit:FlareRed()
|
|
if despawn then
|
|
group:Destroy( true )
|
|
end
|
|
return true
|
|
else
|
|
self:T( string.format( "%s, unit %s of group %s was NOT spawned on runway #%d. Distance %.1f > radius %.1f m. Despawn = %s.", self:GetName(), unit:GetName(), group:GetName(), _i, dist, radius, tostring( despawn ) ) )
|
|
-- unit:FlareGreen()
|
|
end
|
|
|
|
end
|
|
else
|
|
self:T( string.format( "%s, checking if unit %s of group %s is on runway. Unit is NOT alive.", self:GetName(), unit:GetName(), group:GetName() ) )
|
|
end
|
|
end
|
|
else
|
|
self:T( string.format( "%s, checking if group %s is on runway. Group is NOT alive.", self:GetName(), group:GetName() ) )
|
|
end
|
|
|
|
return false
|
|
end
|