mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-10-29 16:58:06 +00:00
Merge branch 'develop' into FF/OpsDev
This commit is contained in:
@@ -64,6 +64,11 @@
|
||||
-- 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}().
|
||||
--
|
||||
-- ## Note on the "H" heli pads in the Syria map:
|
||||
--
|
||||
-- As of the time of writing (Oct 2024, DCS DCS 2.9.8.1107), these 143 objects have the **same name and object ID**, which makes them unusable in Moose, e.g. you cannot find a specific one for spawning etc.
|
||||
-- Waiting for Ugra and ED to fix this issue.
|
||||
--
|
||||
-- @field #AIRBASE AIRBASE
|
||||
AIRBASE = {
|
||||
@@ -250,6 +255,9 @@ AIRBASE.Nevada = {
|
||||
-- * AIRBASE.Normandy.Villacoublay
|
||||
-- * AIRBASE.Normandy.Vrigny
|
||||
-- * AIRBASE.Normandy.West_Malling
|
||||
-- * AIRBASE.Normandy.Eastchurch
|
||||
-- * AIRBASE.Normandy.Headcorn
|
||||
-- * AIRBASE.Normandy.Hawkinge
|
||||
--
|
||||
-- @field Normandy
|
||||
AIRBASE.Normandy = {
|
||||
@@ -332,6 +340,9 @@ AIRBASE.Normandy = {
|
||||
["Villacoublay"] = "Villacoublay",
|
||||
["Vrigny"] = "Vrigny",
|
||||
["West_Malling"] = "West Malling",
|
||||
["Eastchurch"] = "Eastchurch",
|
||||
["Headcorn"] = "Headcorn",
|
||||
["Hawkinge"] = "Hawkinge",
|
||||
}
|
||||
|
||||
--- Airbases of the Persion Gulf Map:
|
||||
@@ -452,6 +463,7 @@ AIRBASE.TheChannel = {
|
||||
-- * AIRBASE.Syria.Gaziantep
|
||||
-- * AIRBASE.Syria.Gazipasa
|
||||
-- * AIRBASE.Syria.Gecitkale
|
||||
-- * AIRBASE.Syria.H
|
||||
-- * AIRBASE.Syria.H3
|
||||
-- * AIRBASE.Syria.H3_Northwest
|
||||
-- * AIRBASE.Syria.H3_Southwest
|
||||
@@ -499,6 +511,10 @@ AIRBASE.TheChannel = {
|
||||
-- * AIRBASE.Syria.Tha_lah
|
||||
-- * AIRBASE.Syria.Tiyas
|
||||
-- * AIRBASE.Syria.Wujah_Al_Hajar
|
||||
-- * AIRBASE.Syria.Ben_Gurion
|
||||
-- * AIRBASE.Syria.Hatzor
|
||||
-- * AIRBASE.Syria.Palmashim
|
||||
-- * AIRBASE.Syria.Tel_Nof
|
||||
--
|
||||
--@field Syria
|
||||
AIRBASE.Syria={
|
||||
@@ -520,6 +536,7 @@ AIRBASE.Syria={
|
||||
["Gaziantep"] = "Gaziantep",
|
||||
["Gazipasa"] = "Gazipasa",
|
||||
["Gecitkale"] = "Gecitkale",
|
||||
["H"] = "H",
|
||||
["H3"] = "H3",
|
||||
["H3_Northwest"] = "H3 Northwest",
|
||||
["H3_Southwest"] = "H3 Southwest",
|
||||
@@ -567,6 +584,10 @@ AIRBASE.Syria={
|
||||
["Tha_lah"] = "Tha'lah",
|
||||
["Tiyas"] = "Tiyas",
|
||||
["Wujah_Al_Hajar"] = "Wujah Al Hajar",
|
||||
["Ben_Gurion"] = "Ben Gurion",
|
||||
["Hatzor"] = "Hatzor",
|
||||
["Palmashim"] = "Palmashim",
|
||||
["Tel_Nof"] = "Tel Nof",
|
||||
}
|
||||
|
||||
--- Airbases of the Mariana Islands map:
|
||||
@@ -595,7 +616,6 @@ AIRBASE.MarianaIslands = {
|
||||
--- Airbases of the South Atlantic map:
|
||||
--
|
||||
-- * AIRBASE.SouthAtlantic.Almirante_Schroeders
|
||||
-- * AIRBASE.SouthAtlantic.Caleta_Tortel
|
||||
-- * AIRBASE.SouthAtlantic.Comandante_Luis_Piedrabuena
|
||||
-- * AIRBASE.SouthAtlantic.Cullen
|
||||
-- * AIRBASE.SouthAtlantic.El_Calafate
|
||||
@@ -626,7 +646,6 @@ AIRBASE.MarianaIslands = {
|
||||
--@field SouthAtlantic
|
||||
AIRBASE.SouthAtlantic={
|
||||
["Almirante_Schroeders"] = "Almirante Schroeders",
|
||||
["Caleta_Tortel"] = "Caleta Tortel",
|
||||
["Comandante_Luis_Piedrabuena"] = "Comandante Luis Piedrabuena",
|
||||
["Cullen"] = "Cullen",
|
||||
["El_Calafate"] = "El Calafate",
|
||||
@@ -659,100 +678,237 @@ AIRBASE.SouthAtlantic={
|
||||
--
|
||||
-- * AIRBASE.Sinai.Abu_Rudeis
|
||||
-- * AIRBASE.Sinai.Abu_Suwayr
|
||||
-- * AIRBASE.Sinai.Al_Bahr_al_Ahmar
|
||||
-- * AIRBASE.Sinai.Al_Ismailiyah
|
||||
-- * AIRBASE.Sinai.Al_Khatatbah
|
||||
-- * AIRBASE.Sinai.Al_Mansurah
|
||||
-- * AIRBASE.Sinai.Al_Rahmaniyah_Air_Base
|
||||
-- * AIRBASE.Sinai.As_Salihiyah
|
||||
-- * AIRBASE.Sinai.AzZaqaziq
|
||||
-- * AIRBASE.Sinai.Baluza
|
||||
-- * AIRBASE.Sinai.Ben_Gurion
|
||||
-- * AIRBASE.Sinai.Beni_Suef
|
||||
-- * AIRBASE.Sinai.Bilbeis_Air_Base
|
||||
-- * AIRBASE.Sinai.Bir_Hasanah
|
||||
-- * AIRBASE.Sinai.Birma_Air_Base
|
||||
-- * AIRBASE.Sinai.Borj_El_Arab_International_Airport
|
||||
-- * AIRBASE.Sinai.Cairo_International_Airport
|
||||
-- * AIRBASE.Sinai.Cairo_West
|
||||
-- * AIRBASE.Sinai.Difarsuwar_Airfield
|
||||
-- * AIRBASE.Sinai.El_Arish
|
||||
-- * AIRBASE.Sinai.El_Gora
|
||||
-- * AIRBASE.Sinai.El_Minya
|
||||
-- * AIRBASE.Sinai.Fayed
|
||||
-- * AIRBASE.Sinai.Gebel_El_Basur_Air_Base
|
||||
-- * AIRBASE.Sinai.Hatzerim
|
||||
-- * AIRBASE.Sinai.Hatzor
|
||||
-- * AIRBASE.Sinai.Hurghada_International_Airport
|
||||
-- * AIRBASE.Sinai.Inshas_Airbase
|
||||
-- * AIRBASE.Sinai.Jiyanklis_Air_Base
|
||||
-- * AIRBASE.Sinai.Kedem
|
||||
-- * AIRBASE.Sinai.Kibrit_Air_Base
|
||||
-- * AIRBASE.Sinai.Kom_Awshim
|
||||
-- * AIRBASE.Sinai.Melez
|
||||
-- * AIRBASE.Sinai.Nevatim
|
||||
-- * AIRBASE.Sinai.Ovda
|
||||
-- * AIRBASE.Sinai.Palmahim
|
||||
-- * AIRBASE.Sinai.Palmachim
|
||||
-- * AIRBASE.Sinai.Quwaysina
|
||||
-- * AIRBASE.Sinai.Ramon_Airbase
|
||||
-- * AIRBASE.Sinai.Ramon_International_Airport
|
||||
-- * AIRBASE.Sinai.Sde_Dov
|
||||
-- * AIRBASE.Sinai.Sharm_El_Sheikh_International_Airport
|
||||
-- * AIRBASE.Sinai.St_Catherine
|
||||
-- * AIRBASE.Sinai.Tel_Nof
|
||||
-- * AIRBASE.Sinai.Wadi_Abu_Rish
|
||||
-- * AIRBASE.Sinai.Wadi_al_Jandali
|
||||
--
|
||||
-- @field Sinai
|
||||
AIRBASE.Sinai = {
|
||||
["Abu_Rudeis"] = "Abu Rudeis",
|
||||
["Abu_Suwayr"] = "Abu Suwayr",
|
||||
["Al_Bahr_al_Ahmar"] = "Al Bahr al Ahmar",
|
||||
["Al_Ismailiyah"] = "Al Ismailiyah",
|
||||
["Al_Khatatbah"] = "Al Khatatbah",
|
||||
["Al_Mansurah"] = "Al Mansurah",
|
||||
["Al_Rahmaniyah_Air_Base"] = "Al Rahmaniyah Air Base",
|
||||
["As_Salihiyah"] = "As Salihiyah",
|
||||
["AzZaqaziq"] = "AzZaqaziq",
|
||||
["Baluza"] = "Baluza",
|
||||
["Ben_Gurion"] = "Ben-Gurion",
|
||||
["Beni_Suef"] = "Beni Suef",
|
||||
["Bilbeis_Air_Base"] = "Bilbeis Air Base",
|
||||
["Bir_Hasanah"] = "Bir Hasanah",
|
||||
["Birma_Air_Base"] = "Birma Air Base",
|
||||
["Borj_El_Arab_International_Airport"] = "Borj El Arab International Airport",
|
||||
["Cairo_International_Airport"] = "Cairo International Airport",
|
||||
["Cairo_West"] = "Cairo West",
|
||||
["Difarsuwar_Airfield"] = "Difarsuwar Airfield",
|
||||
["El_Arish"] = "El Arish",
|
||||
["El_Gora"] = "El Gora",
|
||||
["El_Minya"] = "El Minya",
|
||||
["Fayed"] = "Fayed",
|
||||
["Gebel_El_Basur_Air_Base"] = "Gebel El Basur Air Base",
|
||||
["Hatzerim"] = "Hatzerim",
|
||||
["Hatzor"] = "Hatzor",
|
||||
["Hurghada_International_Airport"] = "Hurghada International Airport",
|
||||
["Inshas_Airbase"] = "Inshas Airbase",
|
||||
["Jiyanklis_Air_Base"] = "Jiyanklis Air Base",
|
||||
["Kedem"] = "Kedem",
|
||||
["Kibrit_Air_Base"] = "Kibrit Air Base",
|
||||
["Kom_Awshim"] = "Kom Awshim",
|
||||
["Melez"] = "Melez",
|
||||
["Nevatim"] = "Nevatim",
|
||||
["Ovda"] = "Ovda",
|
||||
["Palmahim"] = "Palmahim",
|
||||
["Palmachim"] = "Palmachim",
|
||||
["Quwaysina"] = "Quwaysina",
|
||||
["Ramon_Airbase"] = "Ramon Airbase",
|
||||
["Ramon_International_Airport"] = "Ramon International Airport",
|
||||
["Sde_Dov"] = "Sde Dov",
|
||||
["Sharm_El_Sheikh_International_Airport"] = "Sharm El Sheikh International Airport",
|
||||
["St_Catherine"] = "St Catherine",
|
||||
["Tel_Nof"] = "Tel Nof",
|
||||
["Wadi_Abu_Rish"] = "Wadi Abu Rish",
|
||||
["Wadi_al_Jandali"] = "Wadi al Jandali",
|
||||
}
|
||||
|
||||
--- Airbases of the Kola map
|
||||
--
|
||||
-- * AIRBASE.Kola.Banak
|
||||
-- * AIRBASE.Kola.Bas_100
|
||||
-- * AIRBASE.Kola.Bodo
|
||||
-- * AIRBASE.Kola.Ivalo
|
||||
-- * AIRBASE.Kola.Jokkmokk
|
||||
-- * AIRBASE.Kola.Kalixfors
|
||||
-- * AIRBASE.Kola.Kallax
|
||||
-- * AIRBASE.Kola.Kemi_Tornio
|
||||
-- * AIRBASE.Kola.Kirkenes
|
||||
-- * AIRBASE.Kola.Kiruna
|
||||
-- * AIRBASE.Kola.Kuusamo
|
||||
-- * AIRBASE.Kola.Monchegorsk
|
||||
-- * AIRBASE.Kola.Murmansk_International
|
||||
-- * AIRBASE.Kola.Olenya
|
||||
-- * AIRBASE.Kola.Rovaniemi
|
||||
-- * AIRBASE.Kola.Severomorsk_1
|
||||
-- * AIRBASE.Kola.Severomorsk_3
|
||||
--
|
||||
-- * AIRBASE.Kola.Vidsel
|
||||
-- * AIRBASE.Kola.Vuojarvi
|
||||
-- * AIRBASE.Kola.Andoya
|
||||
-- * AIRBASE.Kola.Alakourtti
|
||||
-- * AIRBASE.Kola.Kittila
|
||||
-- * AIRBASE.Kola.Bardufoss
|
||||
--
|
||||
-- @field Kola
|
||||
AIRBASE.Kola = {
|
||||
["Banak"] = "Banak",
|
||||
["Bas_100"] = "Bas 100",
|
||||
["Bodo"] = "Bodo",
|
||||
["Ivalo"] = "Ivalo",
|
||||
["Jokkmokk"] = "Jokkmokk",
|
||||
["Kalixfors"] = "Kalixfors",
|
||||
["Kallax"] = "Kallax",
|
||||
["Kemi_Tornio"] = "Kemi Tornio",
|
||||
["Kirkenes"] = "Kirkenes",
|
||||
["Kiruna"] = "Kiruna",
|
||||
["Kuusamo"] = "Kuusamo",
|
||||
["Monchegorsk"] = "Monchegorsk",
|
||||
["Murmansk_International"] = "Murmansk International",
|
||||
["Olenya"] = "Olenya",
|
||||
["Rovaniemi"] = "Rovaniemi",
|
||||
["Severomorsk_1"] = "Severomorsk-1",
|
||||
["Severomorsk_3"] = "Severomorsk-3",
|
||||
["Vidsel"] = "Vidsel",
|
||||
["Vuojarvi"] = "Vuojarvi",
|
||||
["Andoya"] = "Andoya",
|
||||
["Alakourtti"] = "Alakourtti",
|
||||
["Kittila"] = "Kittila",
|
||||
["Bardufoss"] = "Bardufoss",
|
||||
}
|
||||
|
||||
--- Airbases of the Afghanistan map
|
||||
--
|
||||
-- * AIRBASE.Afghanistan.Bost
|
||||
-- * AIRBASE.Afghanistan.Bagram
|
||||
-- * AIRBASE.Afghanistan.Bamyan
|
||||
-- * AIRBASE.Afghanistan.Camp_Bastion
|
||||
-- * AIRBASE.Afghanistan.Camp_Bastion_Heliport
|
||||
-- * AIRBASE.Afghanistan.Chaghcharan
|
||||
-- * AIRBASE.Afghanistan.Dwyer
|
||||
-- * AIRBASE.Afghanistan.Farah
|
||||
-- * AIRBASE.Afghanistan.Herat
|
||||
-- * AIRBASE.Afghanistan.Gardez
|
||||
-- * AIRBASE.Afghanistan.Ghazni_Heliport
|
||||
-- * AIRBASE.Afghanistan.Jalalabad
|
||||
-- * AIRBASE.Afghanistan.Kabul
|
||||
-- * AIRBASE.Afghanistan.Kandahar
|
||||
-- * AIRBASE.Afghanistan.Kandahar_Heliport
|
||||
-- * AIRBASE.Afghanistan.Khost
|
||||
-- * AIRBASE.Afghanistan.Khost_Heliport
|
||||
-- * AIRBASE.Afghanistan.Maymana_Zahiraddin_Faryabi
|
||||
-- * AIRBASE.Afghanistan.Nimroz
|
||||
-- * AIRBASE.Afghanistan.Qala_i_Naw
|
||||
-- * AIRBASE.Afghanistan.Shindand
|
||||
-- * AIRBASE.Afghanistan.Shindand_Heliport
|
||||
-- * AIRBASE.Afghanistan.Tarinkot
|
||||
-- * AIRBASE.Afghanistan.Urgoon_Heliport
|
||||
--
|
||||
-- @field Afghanistan
|
||||
AIRBASE.Afghanistan = {
|
||||
["Bagram"] = "Bagram",
|
||||
["Bamyan"] = "Bamyan",
|
||||
["Bost"] = "Bost",
|
||||
["Camp_Bastion"] = "Camp Bastion",
|
||||
["Camp_Bastion_Heliport"] = "Camp Bastion Heliport",
|
||||
["Chaghcharan"] = "Chaghcharan",
|
||||
["Dwyer"] = "Dwyer",
|
||||
["Farah"] = "Farah",
|
||||
["Gardez"] = "Gardez",
|
||||
["Ghazni_Heliport"] = "Ghazni Heliport",
|
||||
["Herat"] = "Herat",
|
||||
["Jalalabad"] = "Jalalabad",
|
||||
["Kabul"] = "Kabul",
|
||||
["Kandahar"] = "Kandahar",
|
||||
["Kandahar_Heliport"] = "Kandahar Heliport",
|
||||
["Khost"] = "Khost",
|
||||
["Khost_Heliport"] = "Khost Heliport",
|
||||
["Maymana_Zahiraddin_Faryabi"] = "Maymana Zahiraddin Faryabi",
|
||||
["Nimroz"] = "Nimroz",
|
||||
["Qala_i_Naw"] = "Qala i Naw",
|
||||
["Sharana"] = "Sharana",
|
||||
["Shindand"] = "Shindand",
|
||||
["Shindand_Heliport"] = "Shindand Heliport",
|
||||
["Tarinkot"] = "Tarinkot",
|
||||
["Urgoon_Heliport"] = "Urgoon Heliport",
|
||||
}
|
||||
|
||||
--- Airbases of the Iraq map
|
||||
--
|
||||
-- * AIRBASE.Iraq.Baghdad_International_Airport
|
||||
-- * AIRBASE.Iraq.Sulaimaniyah_International_Airport
|
||||
-- * AIRBASE.Iraq.Al_Sahra_Airport
|
||||
-- * AIRBASE.Iraq.Erbil_International_Airpor
|
||||
-- * AIRBASE.Iraq.Al_Taji_Airport
|
||||
-- * AIRBASE.Iraq.Al_Asad_Airbase
|
||||
-- * AIRBASE.Iraq.Al_Salam_Airbase
|
||||
-- * AIRBASE.Iraq.Balad_Airbase
|
||||
-- * AIRBASE.Iraq.Kirkuk_International_Airport
|
||||
-- * AIRBASE.Iraq.Bashur_Airport
|
||||
-- * AIRBASE.Iraq.Al_Taquddum_Airport
|
||||
-- * AIRBASE.Iraq.Qayyarah_Airfield_West
|
||||
-- * AIRBASE.Iraq.K1_Base
|
||||
--
|
||||
-- @field Iraq
|
||||
AIRBASE.Iraq = {
|
||||
["Baghdad_International_Airport"] = "Baghdad International Airport",
|
||||
["Sulaimaniyah_International_Airport"] = "Sulaimaniyah International Airport",
|
||||
["Al_Sahra_Airport"] = "Al-Sahra Airport",
|
||||
["Erbil_International_Airport"] = "Erbil International Airport",
|
||||
["Al_Taji_Airport"] = "Al-Taji Airport",
|
||||
["Al_Asad_Airbase"] = "Al-Asad Airbase",
|
||||
["Al_Salam_Airbase"] = "Al-Salam Airbase",
|
||||
["Balad_Airbase"] = "Balad Airbase",
|
||||
["Kirkuk_International_Airport"] = "Kirkuk International Airport",
|
||||
["Bashur_Airport"] = "Bashur Airport",
|
||||
["Al_Taquddum_Airport"] = "Al-Taquddum Airport",
|
||||
["Qayyarah_Airfield_West"] = "Qayyarah Airfield West",
|
||||
["K1_Base"] = "K1 Base",
|
||||
}
|
||||
|
||||
--- AIRBASE.ParkingSpot ".Coordinate, ".TerminalID", ".TerminalType", ".TOAC", ".Free", ".TerminalID0", ".DistToRwy".
|
||||
@@ -791,11 +947,12 @@ AIRBASE.Kola = {
|
||||
-- @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 SmallSizeFigher 100: Tight spots for smaller type fixed wing aircraft, like the F-16. Example of these spots: 04, 05, 06 on Muwaffaq_Salti. A Viper sized plane can spawn here, but an A-10 or Strike Eagle can't
|
||||
-- @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.
|
||||
-- @field #number SmallSizeFigher 100: Tight spots for smaller type fixed wing aircraft, like the F-16. Example of these spots: 04, 05, 06 on Muwaffaq_Salti. A Viper sized plane can spawn here, but an A-10 or Strike Eagle can't
|
||||
-- @field #number FighterAircraft 244: Combines Shelter, OpenMed and OpenBig spots. So effectively all spots usable by fixed wing aircraft.
|
||||
-- @field #number FighterAircraftSmall 344: Combines Shelter, SmallsizeFighter, OpenMed and OpenBig spots. So effectively all spots usable by small fixed wing aircraft.
|
||||
AIRBASE.TerminalType = {
|
||||
Runway=16,
|
||||
HelicopterOnly=40,
|
||||
@@ -806,6 +963,7 @@ AIRBASE.TerminalType = {
|
||||
OpenMedOrBig=176,
|
||||
HelicopterUsable=216,
|
||||
FighterAircraft=244,
|
||||
FighterAircraftSmall=344,
|
||||
}
|
||||
|
||||
--- Status of a parking spot.
|
||||
@@ -894,40 +1052,55 @@ function AIRBASE:Register(AirbaseName)
|
||||
--end
|
||||
|
||||
-- Set category.
|
||||
if self.category==Airbase.Category.AIRDROME then
|
||||
self.isAirdrome=true
|
||||
elseif self.category==Airbase.Category.HELIPAD then
|
||||
if self.category==Airbase.Category.AIRDROME then
|
||||
self.isAirdrome=true
|
||||
elseif self.category==Airbase.Category.HELIPAD or self.descriptors.typeName=="FARP_SINGLE_01" then
|
||||
self.isHelipad=true
|
||||
self.category=Airbase.Category.HELIPAD
|
||||
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
|
||||
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!")
|
||||
self.isShip=false
|
||||
self.category=Airbase.Category.HELIPAD
|
||||
_DATABASE:AddStatic(AirbaseName)
|
||||
end
|
||||
else
|
||||
self:E("ERROR: Unknown airbase category!")
|
||||
end
|
||||
|
||||
-- Init Runways.
|
||||
self:_InitRunways()
|
||||
|
||||
|
||||
-- Number of runways
|
||||
local Nrunways=#self.runways
|
||||
|
||||
-- Set the active runways based on wind direction.
|
||||
if self.isAirdrome then
|
||||
if Nrunways>0 then
|
||||
self:SetActiveRunway()
|
||||
end
|
||||
|
||||
-- Init parking spots.
|
||||
self:_InitParkingSpots()
|
||||
|
||||
-- Some heliports identify as airdromes in the airbase category. This is buggy in the descriptors category but also in the getCategory() and getCategoryEx() functions.
|
||||
-- Well, thinking about it, this is actually not that "buggy" since these are really helicopter airdromes, which do not have an automatic parking spot routine.
|
||||
-- I am still changing the category but marking it as airdrome and heliport at the same time via isAirdrome=true and isHelipad=true (important in SPAWN.SpawnAtAirbase).
|
||||
-- The main reason for changing the category is to be able to filter airdromes from helipads, e.g. in SET_AIRBASE.
|
||||
if self.category==Airbase.Category.AIRDROME and (Nrunways==0 or self.NparkingTotal==self.NparkingTerminal[AIRBASE.TerminalType.HelicopterOnly]) then
|
||||
--self:E(string.format("WARNING: %s identifies as airdrome (category=0) but has no runways or just helo parking ==> will change to helipad (category=1)", self.AirbaseName))
|
||||
self.category=Airbase.Category.HELIPAD
|
||||
self.isAirdrome=true
|
||||
self.isHelipad=true
|
||||
end
|
||||
|
||||
-- Get 2D position vector.
|
||||
local vec2=self:GetVec2()
|
||||
|
||||
-- Init coordinate.
|
||||
self:GetCoordinate()
|
||||
|
||||
|
||||
-- Storage.
|
||||
self.storage=_DATABASE:AddStorage(AirbaseName)
|
||||
|
||||
@@ -950,6 +1123,46 @@ function AIRBASE:Register(AirbaseName)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Get the category of this airbase. This is only a debug function because DCS 2.9 incorrectly returns heliports as airdromes.
|
||||
-- @param #AIRBASE self
|
||||
function AIRBASE:_GetCategory()
|
||||
|
||||
local name=self.AirbaseName
|
||||
|
||||
local static=StaticObject.getByName(name)
|
||||
local airbase=Airbase.getByName(name)
|
||||
local unit=Unit.getByName(name)
|
||||
|
||||
local text=string.format("\n=====================================================")
|
||||
text=text..string.format("\nAirbase %s:", name)
|
||||
if static then
|
||||
local oc, uc=static:getCategory()
|
||||
local ex=static:getCategoryEx()
|
||||
text=text..string.format("\nSTATIC: oc=%d, uc=%d, ex=%d", oc, uc, ex)
|
||||
--text=text..UTILS.PrintTableToLog(static:getDesc(), nil, true)
|
||||
text=text..string.format("\n--------------------------------------------------")
|
||||
end
|
||||
if unit then
|
||||
local oc, uc=unit:getCategory()
|
||||
local ex=unit:getCategoryEx()
|
||||
text=text..string.format("\nUNIT: oc=%d, uc=%d, ex=%d", oc, uc, ex)
|
||||
--text=text..UTILS.PrintTableToLog(unit:getDesc(), nil, true)
|
||||
text=text..string.format("\n--------------------------------------------------")
|
||||
end
|
||||
if airbase then
|
||||
local oc, uc=airbase:getCategory()
|
||||
local ex=airbase:getCategoryEx()
|
||||
text=text..string.format("\nAIRBASE: oc=%d, uc=%d, ex=%d", oc, uc, ex)
|
||||
text=text..string.format("\n--------------------------------------------------")
|
||||
text=text..UTILS.PrintTableToLog(airbase:getDesc(), nil, true)
|
||||
end
|
||||
|
||||
text=text..string.format("\n=====================================================")
|
||||
|
||||
|
||||
env.info(text)
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Reference methods
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -1629,7 +1842,7 @@ function AIRBASE:_InitParkingSpots()
|
||||
self.NparkingTotal=self.NparkingTotal+1
|
||||
|
||||
for _,terminalType in pairs(AIRBASE.TerminalType) do
|
||||
if self._CheckTerminalType(terminalType, park.TerminalType) then
|
||||
if self._CheckTerminalType(park.TerminalType, terminalType) then
|
||||
self.NparkingTerminal[terminalType]=self.NparkingTerminal[terminalType]+1
|
||||
end
|
||||
end
|
||||
@@ -1637,6 +1850,9 @@ function AIRBASE:_InitParkingSpots()
|
||||
self.parkingByID[park.TerminalID]=park
|
||||
table.insert(self.parking, park)
|
||||
end
|
||||
|
||||
-- Runways are not included in total number of parking spots
|
||||
self.NparkingTotal=self.NparkingTotal-self.NparkingTerminal[AIRBASE.TerminalType.Runway]
|
||||
|
||||
return self
|
||||
end
|
||||
@@ -2060,9 +2276,13 @@ function AIRBASE._CheckTerminalType(Term_Type, termtype)
|
||||
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 or Term_Type==AIRBASE.TerminalType.SmallSizeFighter then
|
||||
if Term_Type==AIRBASE.TerminalType.OpenMed or Term_Type==AIRBASE.TerminalType.OpenBig or Term_Type==AIRBASE.TerminalType.Shelter then
|
||||
match=true
|
||||
end
|
||||
elseif termtype==AIRBASE.TerminalType.FighterAircraftSmall then
|
||||
if Term_Type==AIRBASE.TerminalType.OpenMed or Term_Type==AIRBASE.TerminalType.OpenBig or Term_Type==AIRBASE.TerminalType.Shelter or Term_Type==AIRBASE.TerminalType.SmallSizeFighter then
|
||||
match=true
|
||||
end
|
||||
end
|
||||
|
||||
return match
|
||||
@@ -2120,11 +2340,6 @@ function AIRBASE:_InitRunways(IncludeInverse)
|
||||
-- Runway table.
|
||||
local Runways={}
|
||||
|
||||
if self:GetAirbaseCategory()~=Airbase.Category.AIRDROME then
|
||||
self.runways={}
|
||||
return {}
|
||||
end
|
||||
|
||||
--- Function to create a runway data table.
|
||||
local function _createRunway(name, course, width, length, center)
|
||||
|
||||
@@ -2210,7 +2425,7 @@ function AIRBASE:_InitRunways(IncludeInverse)
|
||||
-- Debug info.
|
||||
self:T2(runways)
|
||||
|
||||
if runways then
|
||||
if runways and #runways>0 then
|
||||
|
||||
-- Loop over runways.
|
||||
for _,rwy in pairs(runways) do
|
||||
@@ -2243,6 +2458,12 @@ function AIRBASE:_InitRunways(IncludeInverse)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
-- No runways
|
||||
self.runways={}
|
||||
return {}
|
||||
|
||||
end
|
||||
|
||||
|
||||
@@ -201,6 +201,13 @@ function CLIENT:AddPlayer(PlayerName)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Get number of associated players.
|
||||
-- @param #CLIENT self
|
||||
-- @return #number Count
|
||||
function CLIENT:CountPlayers()
|
||||
return #self.Players or 0
|
||||
end
|
||||
|
||||
--- Get player name(s).
|
||||
-- @param #CLIENT self
|
||||
-- @return #table List of player names or an empty table `{}`.
|
||||
@@ -306,7 +313,7 @@ function CLIENT:IsMultiSeated()
|
||||
return false
|
||||
end
|
||||
|
||||
--- Checks for a client alive event and calls a function on a continuous basis.
|
||||
--- Checks for a client alive event and calls a function on a continuous basis. Does **NOT** work for dynamic spawn client slots!
|
||||
-- @param #CLIENT self
|
||||
-- @param #function CallBackFunction Create a function that will be called when a player joins the slot.
|
||||
-- @param ... (Optional) Arguments for callback function as comma separated list.
|
||||
@@ -325,7 +332,7 @@ end
|
||||
|
||||
-- @param #CLIENT self
|
||||
function CLIENT:_AliveCheckScheduler( SchedulerName )
|
||||
self:F3( { SchedulerName, self.ClientName, self.ClientAlive2, self.ClientBriefingShown, self.ClientCallBack } )
|
||||
self:T2( { SchedulerName, self.ClientName, self.ClientAlive2, self.ClientBriefingShown, self.ClientCallBack } )
|
||||
|
||||
if self:IsAlive() then
|
||||
|
||||
@@ -608,4 +615,3 @@ function CLIENT:GetPlayerInfo(Attribute)
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
-- * @{#CONTROLLABLE.TaskFollow}: (AIR) Following another airborne controllable.
|
||||
-- * @{#CONTROLLABLE.TaskHold}: (GROUND) Hold ground controllable from moving.
|
||||
-- * @{#CONTROLLABLE.TaskHoldPosition}: (AIR) Hold position at the current position of the first unit of the controllable.
|
||||
-- * @{#CONTROLLABLE.TaskLand}: (AIR HELICOPTER) Landing at the ground. For helicopters only.
|
||||
-- * @{#CONTROLLABLE.TaskLandAtVec2}: (AIR HELICOPTER) Landing at the ground. For helicopters only.
|
||||
-- * @{#CONTROLLABLE.TaskLandAtZone}: (AIR) Land the controllable at a @{Core.Zone#ZONE_RADIUS).
|
||||
-- * @{#CONTROLLABLE.TaskOrbitCircle}: (AIR) Orbit at the current position of the first unit of the controllable at a specified altitude.
|
||||
-- * @{#CONTROLLABLE.TaskOrbitCircleAtVec2}: (AIR) Orbit at a specified position at a specified altitude during a specified duration with a specified speed.
|
||||
@@ -174,7 +174,10 @@
|
||||
-- * @{#CONTROLLABLE.OptionKeepWeaponsOnThreat}
|
||||
--
|
||||
-- ## 5.5) Air-2-Air missile attack range:
|
||||
-- * @{#CONTROLLABLE.OptionAAAttackRange}(): Defines the usage of A2A missiles against possible targets .
|
||||
-- * @{#CONTROLLABLE.OptionAAAttackRange}(): Defines the usage of A2A missiles against possible targets.
|
||||
--
|
||||
-- # 6) [GROUND] IR Maker Beacons for GROUPs and UNITs
|
||||
-- * @{#CONTROLLABLE:NewIRMarker}(): Create a blinking IR Marker on a GROUP or UNIT.
|
||||
--
|
||||
-- @field #CONTROLLABLE
|
||||
CONTROLLABLE = {
|
||||
@@ -899,7 +902,11 @@ function CONTROLLABLE:CommandEPLRS( SwitchOnOff, Delay )
|
||||
groupId = self:GetID(),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
--if self:IsGround() then
|
||||
--CommandEPLRS.params.groupId = self:GetID()
|
||||
--end
|
||||
|
||||
if Delay and Delay > 0 then
|
||||
SCHEDULER:New( nil, self.CommandEPLRS, { self, SwitchOnOff }, Delay )
|
||||
else
|
||||
@@ -934,7 +941,7 @@ function CONTROLLABLE:CommandSetUnlimitedFuel(OnOff, Delay)
|
||||
end
|
||||
|
||||
|
||||
--- Set radio frequency. See [DCS command EPLRS](https://wiki.hoggitworld.com/view/DCS_command_setFrequency)
|
||||
--- Set radio frequency. See [DCS command SetFrequency](https://wiki.hoggitworld.com/view/DCS_command_setFrequency)
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param #number Frequency Radio frequency in MHz.
|
||||
-- @param #number Modulation Radio modulation. Default `radio.modulation.AM`.
|
||||
@@ -953,7 +960,7 @@ function CONTROLLABLE:CommandSetFrequency( Frequency, Modulation, Power, Delay )
|
||||
}
|
||||
|
||||
if Delay and Delay > 0 then
|
||||
SCHEDULER:New( nil, self.CommandSetFrequency, { self, Frequency, Modulation, Power } )
|
||||
SCHEDULER:New( nil, self.CommandSetFrequency, { self, Frequency, Modulation, Power },Delay )
|
||||
else
|
||||
self:SetCommand( CommandSetFrequency )
|
||||
end
|
||||
@@ -961,12 +968,12 @@ function CONTROLLABLE:CommandSetFrequency( Frequency, Modulation, Power, Delay )
|
||||
return self
|
||||
end
|
||||
|
||||
--- [AIR] Set radio frequency. See [DCS command EPLRS](https://wiki.hoggitworld.com/view/DCS_command_setFrequencyForUnit)
|
||||
--- [AIR] Set radio frequency. See [DCS command SetFrequencyForUnit](https://wiki.hoggitworld.com/view/DCS_command_setFrequencyForUnit)
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param #number Frequency Radio frequency in MHz.
|
||||
-- @param #number Modulation Radio modulation. Default `radio.modulation.AM`.
|
||||
-- @param #number Power (Optional) Power of the Radio in Watts. Defaults to 10.
|
||||
-- @param #UnitID UnitID (Optional, if your object is a UNIT) The UNIT ID this is for.
|
||||
-- @param #number UnitID (Optional, if your object is a UNIT) The UNIT ID this is for.
|
||||
-- @param #number Delay (Optional) Delay in seconds before the frequency is set. Default is immediately.
|
||||
-- @return #CONTROLLABLE self
|
||||
function CONTROLLABLE:CommandSetFrequencyForUnit(Frequency,Modulation,Power,UnitID,Delay)
|
||||
@@ -980,13 +987,72 @@ function CONTROLLABLE:CommandSetFrequencyForUnit(Frequency,Modulation,Power,Unit
|
||||
},
|
||||
}
|
||||
if Delay and Delay>0 then
|
||||
SCHEDULER:New(nil,self.CommandSetFrequencyForUnit,{self,Frequency,Modulation,Power,UnitID})
|
||||
SCHEDULER:New(nil,self.CommandSetFrequencyForUnit,{self,Frequency,Modulation,Power,UnitID},Delay)
|
||||
else
|
||||
self:SetCommand(CommandSetFrequencyForUnit)
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- [AIR] Set smoke on or off. See [DCS command smoke on off](https://wiki.hoggitworld.com/view/DCS_command_smoke_on_off)
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param #boolean OnOff Set to true for on and false for off. Defaults to true.
|
||||
-- @param #number Delay (Optional) Delay the command by this many seconds.
|
||||
-- @return #CONTROLLABLE self
|
||||
function CONTROLLABLE:CommandSmokeOnOff(OnOff, Delay)
|
||||
local switch = (OnOff == nil) and true or OnOff
|
||||
local command = {
|
||||
id = 'SMOKE_ON_OFF',
|
||||
params = {
|
||||
value = switch
|
||||
}
|
||||
}
|
||||
if Delay and Delay>0 then
|
||||
SCHEDULER:New(nil,self.CommandSmokeOnOff,{self,switch},Delay)
|
||||
else
|
||||
self:SetCommand(command)
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- [AIR] Set smoke on. See [DCS command smoke on off](https://wiki.hoggitworld.com/view/DCS_command_smoke_on_off)
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param #number Delay (Optional) Delay the command by this many seconds.
|
||||
-- @return #CONTROLLABLE self
|
||||
function CONTROLLABLE:CommandSmokeON(Delay)
|
||||
local command = {
|
||||
id = 'SMOKE_ON_OFF',
|
||||
params = {
|
||||
value = true
|
||||
}
|
||||
}
|
||||
if Delay and Delay>0 then
|
||||
SCHEDULER:New(nil,self.CommandSmokeON,{self},Delay)
|
||||
else
|
||||
self:SetCommand(command)
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- [AIR] Set smoke off. See [DCS command smoke on off](https://wiki.hoggitworld.com/view/DCS_command_smoke_on_off)
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param #number Delay (Optional) Delay the command by this many seconds.
|
||||
-- @return #CONTROLLABLE self
|
||||
function CONTROLLABLE:CommandSmokeOFF(Delay)
|
||||
local command = {
|
||||
id = 'SMOKE_ON_OFF',
|
||||
params = {
|
||||
value = false
|
||||
}
|
||||
}
|
||||
if Delay and Delay>0 then
|
||||
SCHEDULER:New(nil,self.CommandSmokeOFF,{self},Delay)
|
||||
else
|
||||
self:SetCommand(command)
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set EPLRS data link on/off.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param #boolean SwitchOnOff If true (or nil) switch EPLRS on. If false switch off.
|
||||
@@ -1006,13 +1072,17 @@ function CONTROLLABLE:TaskEPLRS( SwitchOnOff, idx )
|
||||
groupId = self:GetID(),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
--if self:IsGround() then
|
||||
--CommandEPLRS.params.groupId = self:GetID()
|
||||
--end
|
||||
|
||||
return self:TaskWrappedAction( CommandEPLRS, idx or 1 )
|
||||
end
|
||||
|
||||
-- TASKS FOR AIR CONTROLLABLES
|
||||
|
||||
--- (AIR) Attack a Controllable.
|
||||
--- (AIR + GROUND) Attack a Controllable.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param Wrapper.Group#GROUP AttackGroup The Group to be attacked.
|
||||
-- @param #number WeaponType (optional) Bitmask of weapon types those allowed to use. If parameter is not defined that means no limits on weapon usage.
|
||||
@@ -1060,7 +1130,7 @@ function CONTROLLABLE:TaskAttackGroup( AttackGroup, WeaponType, WeaponExpend, At
|
||||
return DCSTask
|
||||
end
|
||||
|
||||
--- (AIR) Attack the Unit.
|
||||
--- (AIR + GROUND) Attack the Unit.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param Wrapper.Unit#UNIT AttackUnit The UNIT to be attacked
|
||||
-- @param #boolean GroupAttack (Optional) If true, all units in the group will attack the Unit when found. Default false.
|
||||
@@ -1148,10 +1218,10 @@ function CONTROLLABLE:TaskStrafing( Vec2, AttackQty, Length, WeaponType, WeaponE
|
||||
id = 'Strafing',
|
||||
params = {
|
||||
point = Vec2, -- req
|
||||
weaponType = WeaponType or 1073741822,
|
||||
weaponType = WeaponType or 805337088, -- Default 805337088 corresponds to guns/cannons (805306368) + any rocket (30720). You can set other types but then the AI uses even bombs for a strafing run!
|
||||
expend = WeaponExpend or "Auto",
|
||||
attackQty = AttackQty or 1, -- req
|
||||
attackQtyLimit = AttackQty >1 and true or false,
|
||||
attackQtyLimit = AttackQty~=nil and true or false,
|
||||
direction = Direction and math.rad(Direction) or 0,
|
||||
directionEnabled = Direction and true or false,
|
||||
groupAttack = GroupAttack or false,
|
||||
@@ -1516,8 +1586,10 @@ end
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param DCS#Vec2 Vec2 The point where to land.
|
||||
-- @param #number Duration The duration in seconds to stay on the ground.
|
||||
-- @param #boolean CombatLanding (optional) If true, set the Combat Landing option.
|
||||
-- @param #number DirectionAfterLand (optional) Heading after landing in degrees.
|
||||
-- @return #CONTROLLABLE self
|
||||
function CONTROLLABLE:TaskLandAtVec2( Vec2, Duration )
|
||||
function CONTROLLABLE:TaskLandAtVec2( Vec2, Duration , CombatLanding, DirectionAfterLand)
|
||||
|
||||
local DCSTask = {
|
||||
id = 'Land',
|
||||
@@ -1525,9 +1597,15 @@ function CONTROLLABLE:TaskLandAtVec2( Vec2, Duration )
|
||||
point = Vec2,
|
||||
durationFlag = Duration and true or false,
|
||||
duration = Duration,
|
||||
combatLandingFlag = CombatLanding == true and true or false,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
if DirectionAfterLand ~= nil and type(DirectionAfterLand) == "number" then
|
||||
DCSTask.params.directionEnabled = true
|
||||
DCSTask.params.direction = math.rad(DirectionAfterLand)
|
||||
end
|
||||
|
||||
return DCSTask
|
||||
end
|
||||
|
||||
@@ -1535,13 +1613,16 @@ end
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param Core.Zone#ZONE Zone The zone where to land.
|
||||
-- @param #number Duration The duration in seconds to stay on the ground.
|
||||
-- @param #boolean RandomPoint (optional) If true,land at a random point inside of the zone.
|
||||
-- @param #boolean CombatLanding (optional) If true, set the Combat Landing option.
|
||||
-- @param #number DirectionAfterLand (optional) Heading after landing in degrees.
|
||||
-- @return DCS#Task The DCS task structure.
|
||||
function CONTROLLABLE:TaskLandAtZone( Zone, Duration, RandomPoint )
|
||||
function CONTROLLABLE:TaskLandAtZone( Zone, Duration, RandomPoint, CombatLanding, DirectionAfterLand )
|
||||
|
||||
-- Get landing point
|
||||
local Point = RandomPoint and Zone:GetRandomVec2() or Zone:GetVec2()
|
||||
|
||||
local DCSTask = CONTROLLABLE.TaskLandAtVec2( self, Point, Duration )
|
||||
local DCSTask = CONTROLLABLE.TaskLandAtVec2( self, Point, Duration, CombatLanding, DirectionAfterLand)
|
||||
|
||||
return DCSTask
|
||||
end
|
||||
@@ -1755,8 +1836,6 @@ function CONTROLLABLE:TaskFAC_AttackGroup( AttackGroup, WeaponType, Designation,
|
||||
return DCSTask
|
||||
end
|
||||
|
||||
-- EN-ACT_ROUTE TASKS FOR AIRBORNE CONTROLLABLES
|
||||
|
||||
--- (AIR) Engaging targets of defined types.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param DCS#Distance Distance Maximal distance from the target to a route leg. If the target is on a greater distance it will be ignored.
|
||||
@@ -2983,7 +3062,7 @@ function CONTROLLABLE:GetDetectedTargets( DetectVisual, DetectOptical, DetectRad
|
||||
if DCSControllable then
|
||||
|
||||
local DetectionVisual = (DetectVisual and DetectVisual == true) and Controller.Detection.VISUAL or nil
|
||||
local DetectionOptical = (DetectOptical and DetectOptical == true) and Controller.Detection.OPTICAL or nil
|
||||
local DetectionOptical = (DetectOptical and DetectOptical == true) and Controller.Detection.OPTIC or nil
|
||||
local DetectionRadar = (DetectRadar and DetectRadar == true) and Controller.Detection.RADAR or nil
|
||||
local DetectionIRST = (DetectIRST and DetectIRST == true) and Controller.Detection.IRST or nil
|
||||
local DetectionRWR = (DetectRWR and DetectRWR == true) and Controller.Detection.RWR or nil
|
||||
@@ -3017,26 +3096,27 @@ function CONTROLLABLE:GetDetectedTargets( DetectVisual, DetectOptical, DetectRad
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Check if a target is detected.
|
||||
--- Check if a DCS object (unit or static) is detected by the controllable.
|
||||
-- Note that after a target is detected it remains "detected" for a certain amount of time, even if the controllable cannot "see" the target any more with it's sensors.
|
||||
-- The optional parametes specify the detection methods that can be applied.
|
||||
--
|
||||
-- If **no** detection method is given, the detection will use **all** the available methods by default.
|
||||
-- If **at least one** detection method is specified, only the methods set to *true* will be used.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param DCS#Object DCSObject The DCS object that is checked.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param #boolean DetectVisual (Optional) If *false*, do not include visually detected targets.
|
||||
-- @param #boolean DetectOptical (Optional) If *false*, do not include optically detected targets.
|
||||
-- @param #boolean DetectRadar (Optional) If *false*, do not include targets detected by radar.
|
||||
-- @param #boolean DetectIRST (Optional) If *false*, do not include targets detected by IRST.
|
||||
-- @param #boolean DetectRWR (Optional) If *false*, do not include targets detected by RWR.
|
||||
-- @param #boolean DetectDLINK (Optional) If *false*, do not include targets detected by data link.
|
||||
-- @return #boolean True if target is detected.
|
||||
-- @return #boolean True if target is visible by line of sight.
|
||||
-- @return #number Mission time when target was detected.
|
||||
-- @return #boolean True if target type is known.
|
||||
-- @return #boolean True if distance to target is known.
|
||||
-- @return DCS#Vec3 Last known position vector of the target.
|
||||
-- @return DCS#Vec3 Last known velocity vector of the target.
|
||||
-- @return #boolean `true` if target is detected.
|
||||
-- @return #boolean `true` if target is *currently* visible by line of sight. Target must be detected (first parameter returns `true`).
|
||||
-- @return #boolean `true` if target type is known. Target must be detected (first parameter returns `true`).
|
||||
-- @return #boolean `true` if distance to target is known. Target must be detected (first parameter returns `true`).
|
||||
-- @return #number Mission time in seconds when target was last detected. Only present if the target is currently not visible (second parameter returns `false`) otherwise `nil` is returned.
|
||||
-- @return DCS#Vec3 Last known position vector of the target. Only present if the target is currently not visible (second parameter returns `false`) otherwise `nil` is returned.
|
||||
-- @return DCS#Vec3 Last known velocity vector of the target. Only present if the target is currently not visible (second parameter returns `false`) otherwise `nil` is returned.
|
||||
function CONTROLLABLE:IsTargetDetected( DCSObject, DetectVisual, DetectOptical, DetectRadar, DetectIRST, DetectRWR, DetectDLINK )
|
||||
self:F2( self.ControllableName )
|
||||
|
||||
@@ -3045,7 +3125,7 @@ function CONTROLLABLE:IsTargetDetected( DCSObject, DetectVisual, DetectOptical,
|
||||
if DCSControllable then
|
||||
|
||||
local DetectionVisual = (DetectVisual and DetectVisual == true) and Controller.Detection.VISUAL or nil
|
||||
local DetectionOptical = (DetectOptical and DetectOptical == true) and Controller.Detection.OPTICAL or nil
|
||||
local DetectionOptical = (DetectOptical and DetectOptical == true) and Controller.Detection.OPTIC or nil
|
||||
local DetectionRadar = (DetectRadar and DetectRadar == true) and Controller.Detection.RADAR or nil
|
||||
local DetectionIRST = (DetectIRST and DetectIRST == true) and Controller.Detection.IRST or nil
|
||||
local DetectionRWR = (DetectRWR and DetectRWR == true) and Controller.Detection.RWR or nil
|
||||
@@ -3053,10 +3133,10 @@ function CONTROLLABLE:IsTargetDetected( DCSObject, DetectVisual, DetectOptical,
|
||||
|
||||
local Controller = self:_GetController()
|
||||
|
||||
local TargetIsDetected, TargetIsVisible, TargetLastTime, TargetKnowType, TargetKnowDistance, TargetLastPos, TargetLastVelocity
|
||||
local TargetIsDetected, TargetIsVisible, TargetKnowType, TargetKnowDistance, TargetLastTime, TargetLastPos, TargetLastVelocity
|
||||
= Controller:isTargetDetected( DCSObject, DetectionVisual, DetectionOptical, DetectionRadar, DetectionIRST, DetectionRWR, DetectionDLINK )
|
||||
|
||||
return TargetIsDetected, TargetIsVisible, TargetLastTime, TargetKnowType, TargetKnowDistance, TargetLastPos, TargetLastVelocity
|
||||
return TargetIsDetected, TargetIsVisible, TargetKnowType, TargetKnowDistance, TargetLastTime, TargetLastPos, TargetLastVelocity
|
||||
end
|
||||
|
||||
return nil
|
||||
@@ -3064,6 +3144,7 @@ end
|
||||
|
||||
--- Check if a certain UNIT is detected by the controllable.
|
||||
-- The optional parametes specify the detection methods that can be applied.
|
||||
--
|
||||
-- If **no** detection method is given, the detection will use **all** the available methods by default.
|
||||
-- If **at least one** detection method is specified, only the methods set to *true* will be used.
|
||||
-- @param #CONTROLLABLE self
|
||||
@@ -3074,13 +3155,13 @@ end
|
||||
-- @param #boolean DetectIRST (Optional) If *false*, do not include targets detected by IRST.
|
||||
-- @param #boolean DetectRWR (Optional) If *false*, do not include targets detected by RWR.
|
||||
-- @param #boolean DetectDLINK (Optional) If *false*, do not include targets detected by data link.
|
||||
-- @return #boolean True if target is detected.
|
||||
-- @return #boolean True if target is visible by line of sight.
|
||||
-- @return #number Mission time when target was detected.
|
||||
-- @return #boolean True if target type is known.
|
||||
-- @return #boolean True if distance to target is known.
|
||||
-- @return DCS#Vec3 Last known position vector of the target.
|
||||
-- @return DCS#Vec3 Last known velocity vector of the target.
|
||||
-- @return #boolean `true` if target is detected.
|
||||
-- @return #boolean `true` if target is *currently* visible by line of sight. Target must be detected (first parameter returns `true`).
|
||||
-- @return #boolean `true` if target type is known. Target must be detected (first parameter returns `true`).
|
||||
-- @return #boolean `true` if distance to target is known. Target must be detected (first parameter returns `true`).
|
||||
-- @return #number Mission time in seconds when target was last detected. Only present if the target is currently not visible (second parameter returns `false`) otherwise `nil` is returned.
|
||||
-- @return DCS#Vec3 Last known position vector of the target. Only present if the target is currently not visible (second parameter returns `false`) otherwise `nil` is returned.
|
||||
-- @return DCS#Vec3 Last known velocity vector of the target. Only present if the target is currently not visible (second parameter returns `false`) otherwise `nil` is returned.
|
||||
function CONTROLLABLE:IsUnitDetected( Unit, DetectVisual, DetectOptical, DetectRadar, DetectIRST, DetectRWR, DetectDLINK )
|
||||
self:F2( self.ControllableName )
|
||||
|
||||
@@ -3800,6 +3881,48 @@ function CONTROLLABLE:OptionProhibitAfterburner( Prohibit )
|
||||
return self
|
||||
end
|
||||
|
||||
--- [Ground] Allows AI radar units to take defensive actions to avoid anti radiation missiles. Units are allowed to shut radar off and displace.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param #number Seconds Can be - nil, 0 or false = switch off this option, any positive number = number of seconds the escape sequency runs.
|
||||
-- @return #CONTROLLABLE self
|
||||
function CONTROLLABLE:OptionEvasionOfARM(Seconds)
|
||||
self:F2( { self.ControllableName } )
|
||||
|
||||
local DCSControllable = self:GetDCSObject()
|
||||
if DCSControllable then
|
||||
local Controller = self:_GetController()
|
||||
|
||||
if self:IsGround() then
|
||||
if Seconds == nil then Seconds = false end
|
||||
Controller:setOption( AI.Option.Ground.id.EVASION_OF_ARM, Seconds)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- [Ground] Option that defines the vehicle spacing when in an on road and off road formation.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param #number meters Can be zero to 100 meters. Defaults to 50 meters.
|
||||
-- @return #CONTROLLABLE self
|
||||
function CONTROLLABLE:OptionFormationInterval(meters)
|
||||
self:F2( { self.ControllableName } )
|
||||
|
||||
local DCSControllable = self:GetDCSObject()
|
||||
if DCSControllable then
|
||||
local Controller = self:_GetController()
|
||||
|
||||
if self:IsGround() then
|
||||
if meters == nil or meters > 100 or meters < 0 then meters = 50 end
|
||||
Controller:setOption( 30, meters)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- [Air] Defines the usage of Electronic Counter Measures by airborne forces.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param #number ECMvalue Can be - 0=Never on, 1=if locked by radar, 2=if detected by radar, 3=always on, defaults to 1
|
||||
@@ -4197,6 +4320,9 @@ function CONTROLLABLE:RelocateGroundRandomInRadius( speed, radius, onroad, short
|
||||
self:F2( { self.ControllableName } )
|
||||
|
||||
local _coord = self:GetCoordinate()
|
||||
if not _coord then
|
||||
return self
|
||||
end
|
||||
local _radius = radius or 500
|
||||
local _speed = speed or 20
|
||||
local _tocoord = _coord:GetRandomCoordinateInRadius( _radius, 100 )
|
||||
@@ -4246,7 +4372,7 @@ function CONTROLLABLE:OptionDisperseOnAttack( Seconds )
|
||||
end
|
||||
|
||||
--- Returns if the unit is a submarine.
|
||||
-- @param #POSITIONABLE self
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @return #boolean Submarines attributes result.
|
||||
function CONTROLLABLE:IsSubmarine()
|
||||
self:F2()
|
||||
@@ -5566,3 +5692,166 @@ function CONTROLLABLE:PatrolRaceTrack(Point1, Point2, Altitude, Speed, Formation
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- IR Marker courtesy Florian Brinker (fbrinker)
|
||||
|
||||
--- [GROUND] Create and enable a new IR Marker for the given controllable UNIT or GROUP.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param #boolean EnableImmediately (Optionally) If true start up the IR Marker immediately. Else you need to call `myobject:EnableIRMarker()` later on.
|
||||
-- @param #number Runtime (Optionally) Run this IR Marker for the given number of seconds, then stop. Use in conjunction with EnableImmediately. Defaults to 60 seconds.
|
||||
-- @return #CONTROLLABLE self
|
||||
function CONTROLLABLE:NewIRMarker(EnableImmediately, Runtime)
|
||||
self:T2("NewIRMarker")
|
||||
if self:IsInstanceOf("GROUP") then
|
||||
if self.IRMarkerGroup == true then return end
|
||||
self.IRMarkerGroup = true
|
||||
self.IRMarkerUnit = false
|
||||
elseif self:IsInstanceOf("UNIT") then
|
||||
if self.IRMarkerUnit == true then return end
|
||||
self.IRMarkerGroup = false
|
||||
self.IRMarkerUnit = true
|
||||
end
|
||||
|
||||
self.Runtime = Runtime or 60
|
||||
if EnableImmediately and EnableImmediately == true then
|
||||
self:EnableIRMarker(Runtime)
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- [GROUND] Enable the IR marker.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param #number Runtime (Optionally) Run this IR Marker for the given number of seconds, then stop. Else run until you call `myobject:DisableIRMarker()`.
|
||||
-- @return #CONTROLLABLE self
|
||||
function CONTROLLABLE:EnableIRMarker(Runtime)
|
||||
self:T2("EnableIRMarker")
|
||||
if self.IRMarkerGroup == nil then
|
||||
self:NewIRMarker(true,Runtime)
|
||||
return
|
||||
end
|
||||
|
||||
if self:IsInstanceOf("GROUP") then
|
||||
self:EnableIRMarkerForGroup(Runtime)
|
||||
return
|
||||
end
|
||||
|
||||
if self.timer and self.timer:IsRunning() then return self end
|
||||
|
||||
local Runtime = Runtime or self.Runtime
|
||||
self.timer = TIMER:New(CONTROLLABLE._MarkerBlink, self)
|
||||
self.timer:Start(nil, 1 - math.random(1, 5) / 10 / 2, Runtime) -- start randomized
|
||||
self.IRMarkerUnit = true
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- [GROUND] Disable the IR marker.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @return #CONTROLLABLE self
|
||||
function CONTROLLABLE:DisableIRMarker()
|
||||
self:T2("DisableIRMarker")
|
||||
if self:IsInstanceOf("GROUP") then
|
||||
self:DisableIRMarkerForGroup()
|
||||
return
|
||||
end
|
||||
|
||||
if self.spot then
|
||||
self.spot = nil
|
||||
end
|
||||
if self.timer and self.timer:IsRunning() then
|
||||
self.timer:Stop()
|
||||
self.timer = nil
|
||||
end
|
||||
|
||||
if self:IsInstanceOf("GROUP") then
|
||||
self.IRMarkerGroup = nil
|
||||
elseif self:IsInstanceOf("UNIT") then
|
||||
self.IRMarkerUnit = nil
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- [GROUND] Enable the IR markers for a whole group.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param #number Runtime Runtime of the marker in seconds
|
||||
-- @return #CONTROLLABLE self
|
||||
function CONTROLLABLE:EnableIRMarkerForGroup(Runtime)
|
||||
self:T2("EnableIRMarkerForGroup")
|
||||
if self:IsInstanceOf("GROUP")
|
||||
then
|
||||
local units = self:GetUnits() or {}
|
||||
for _,_unit in pairs(units) do
|
||||
_unit:EnableIRMarker(Runtime)
|
||||
end
|
||||
self.IRMarkerGroup = true
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- [GROUND] Disable the IR markers for a whole group.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @return #CONTROLLABLE self
|
||||
function CONTROLLABLE:DisableIRMarkerForGroup()
|
||||
self:T2("DisableIRMarkerForGroup")
|
||||
if self:IsInstanceOf("GROUP") then
|
||||
local units = self:GetUnits() or {}
|
||||
for _,_unit in pairs(units) do
|
||||
_unit:DisableIRMarker()
|
||||
end
|
||||
self.IRMarkerGroup = nil
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- [GROUND] Check if an IR Spot exists.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @return #boolean outcome
|
||||
function CONTROLLABLE:HasIRMarker()
|
||||
self:T2("HasIRMarker")
|
||||
if self:IsInstanceOf("GROUP") then
|
||||
local units = self:GetUnits() or {}
|
||||
for _,_unit in pairs(units) do
|
||||
if _unit.timer and _unit.timer:IsRunning() then return true end
|
||||
end
|
||||
elseif self.timer and self.timer:IsRunning() then return true end
|
||||
return false
|
||||
end
|
||||
|
||||
--- [Internal] This method is called by the scheduler to blink the IR marker.
|
||||
function CONTROLLABLE._StopSpot(spot)
|
||||
if spot then
|
||||
spot:destroy()
|
||||
end
|
||||
end
|
||||
|
||||
--- [Internal] This method is called by the scheduler after enabling the IR marker.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @return #CONTROLLABLE self
|
||||
function CONTROLLABLE:_MarkerBlink()
|
||||
self:T2("_MarkerBlink")
|
||||
if self:IsAlive() ~= true then
|
||||
self:DisableIRMarker()
|
||||
return
|
||||
end
|
||||
|
||||
self.timer.dT = 1 - (math.random(1, 2) / 10 / 2) -- randomize the blinking by a small amount
|
||||
|
||||
local _, _, unitBBHeight, _ = self:GetObjectSize()
|
||||
local unitPos = self:GetPositionVec3()
|
||||
|
||||
if self.timer:IsRunning() then
|
||||
self:T2("Create Spot")
|
||||
local spot = Spot.createInfraRed(
|
||||
self.DCSUnit,
|
||||
{ x = 0, y = (unitBBHeight + 1), z = 0 },
|
||||
{ x = unitPos.x, y = (unitPos.y + unitBBHeight), z = unitPos.z }
|
||||
)
|
||||
self.spot = spot
|
||||
local offTimer = nil
|
||||
local offTimer = TIMER:New(CONTROLLABLE._StopSpot, spot)
|
||||
offTimer:Start(0.5)
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
535
Moose Development/Moose/Wrapper/DynamicCargo.lua
Normal file
535
Moose Development/Moose/Wrapper/DynamicCargo.lua
Normal file
@@ -0,0 +1,535 @@
|
||||
--- **Wrapper** - Dynamic Cargo create from the F8 menu.
|
||||
--
|
||||
-- ## Main Features:
|
||||
--
|
||||
-- * Convenient access to Ground Crew created cargo items.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ## Example Missions:
|
||||
--
|
||||
-- Demo missions can be found on [github](https://github.com/FlightControl-Master/MOOSE_Demos/tree/master/).
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **Applevangelist**; additional checks **Chesster**
|
||||
--
|
||||
-- ===
|
||||
-- @module Wrapper.DynamicCargo
|
||||
-- @image Wrapper_Storage.png
|
||||
|
||||
|
||||
--- DYNAMICCARGO class.
|
||||
-- @type DYNAMICCARGO
|
||||
-- @field #string ClassName Name of the class.
|
||||
-- @field #number verbose Verbosity level.
|
||||
-- @field #string lid Class id string for output to DCS log file.
|
||||
-- @field Wrapper.Storage#STORAGE warehouse The STORAGE object.
|
||||
-- @field #string version.
|
||||
-- @field #string CargoState.
|
||||
-- @field #table DCS#Vec3 LastPosition.
|
||||
-- @field #number Interval Check Interval. 20 secs default.
|
||||
-- @field #boolean testing
|
||||
-- @field Core.Timer#TIMER timer Timmer to run intervals
|
||||
-- @field #string Owner The playername who has created, loaded or unloaded this cargo. Depends on state.
|
||||
-- @extends Wrapper.Positionable#POSITIONABLE
|
||||
|
||||
--- *The capitalist cannot store labour-power in warehouses after he has bought it, as he may do with the raw material.* -- Karl Marx
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- # The DYNAMICCARGO Concept
|
||||
--
|
||||
-- The DYNAMICCARGO class offers an easy-to-use wrapper interface to all DCS API functions of DCS dynamically spawned cargo crates.
|
||||
-- We named the class DYNAMICCARGO, because the name WAREHOUSE is already taken by another MOOSE class..
|
||||
--
|
||||
-- # Constructor
|
||||
--
|
||||
-- @field #DYNAMICCARGO
|
||||
DYNAMICCARGO = {
|
||||
ClassName = "DYNAMICCARGO",
|
||||
verbose = 0,
|
||||
testing = false,
|
||||
Interval = 10,
|
||||
|
||||
}
|
||||
|
||||
--- Liquid types.
|
||||
-- @type DYNAMICCARGO.Liquid
|
||||
-- @field #number JETFUEL Jet fuel (0).
|
||||
-- @field #number GASOLINE Aviation gasoline (1).
|
||||
-- @field #number MW50 MW50 (2).
|
||||
-- @field #number DIESEL Diesel (3).
|
||||
DYNAMICCARGO.Liquid = {
|
||||
JETFUEL = 0,
|
||||
GASOLINE = 1,
|
||||
MW50 = 2,
|
||||
DIESEL = 3,
|
||||
}
|
||||
|
||||
--- Liquid Names for the static cargo resource table.
|
||||
-- @type DYNAMICCARGO.LiquidName
|
||||
-- @field #number JETFUEL "jet_fuel".
|
||||
-- @field #number GASOLINE "gasoline".
|
||||
-- @field #number MW50 "methanol_mixture".
|
||||
-- @field #number DIESEL "diesel".
|
||||
DYNAMICCARGO.LiquidName = {
|
||||
GASOLINE = "gasoline",
|
||||
DIESEL = "diesel",
|
||||
MW50 = "methanol_mixture",
|
||||
JETFUEL = "jet_fuel",
|
||||
}
|
||||
|
||||
--- Storage types.
|
||||
-- @type DYNAMICCARGO.Type
|
||||
-- @field #number WEAPONS weapons.
|
||||
-- @field #number LIQUIDS liquids. Also see #list<#DYNAMICCARGO.Liquid> for types of liquids.
|
||||
-- @field #number AIRCRAFT aircraft.
|
||||
DYNAMICCARGO.Type = {
|
||||
WEAPONS = "weapons",
|
||||
LIQUIDS = "liquids",
|
||||
AIRCRAFT = "aircrafts",
|
||||
}
|
||||
|
||||
--- State types
|
||||
-- @type DYNAMICCARGO.State
|
||||
-- @field #string NEW
|
||||
-- @field #string LOADED
|
||||
-- @field #string UNLOADED
|
||||
-- @field #string REMOVED
|
||||
DYNAMICCARGO.State = {
|
||||
NEW = "NEW",
|
||||
LOADED = "LOADED",
|
||||
UNLOADED = "UNLOADED",
|
||||
REMOVED = "REMOVED",
|
||||
}
|
||||
|
||||
--- Helo types possible.
|
||||
-- @type DYNAMICCARGO.AircraftTypes
|
||||
DYNAMICCARGO.AircraftTypes = {
|
||||
["CH-47Fbl1"] = "CH-47Fbl1",
|
||||
}
|
||||
|
||||
--- Helo types possible.
|
||||
-- @type DYNAMICCARGO.AircraftDimensions
|
||||
DYNAMICCARGO.AircraftDimensions = {
|
||||
-- CH-47 model start coordinate is quite exactly in the middle of the model, so half values here
|
||||
["CH-47Fbl1"] = {
|
||||
["width"] = 4,
|
||||
["height"] = 6,
|
||||
["length"] = 11,
|
||||
["ropelength"] = 30,
|
||||
},
|
||||
}
|
||||
|
||||
--- DYNAMICCARGO class version.
|
||||
-- @field #string version
|
||||
DYNAMICCARGO.version="0.0.7"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- TODO: A lot...
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Constructor
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- Create a new DYNAMICCARGO object from the DCS static cargo object.
|
||||
-- @param #DYNAMICCARGO self
|
||||
-- @param #string CargoName Name of the Cargo.
|
||||
-- @return #DYNAMICCARGO self
|
||||
function DYNAMICCARGO:Register(CargoName)
|
||||
|
||||
-- Inherit everything from a BASE class.
|
||||
local self=BASE:Inherit(self, POSITIONABLE:New(CargoName)) -- #DYNAMICCARGO
|
||||
|
||||
self.StaticName = CargoName
|
||||
|
||||
self.LastPosition = self:GetCoordinate()
|
||||
|
||||
self.CargoState = DYNAMICCARGO.State.NEW
|
||||
|
||||
self.Interval = DYNAMICCARGO.Interval or 10
|
||||
|
||||
local DCSObject = self:GetDCSObject()
|
||||
|
||||
if DCSObject then
|
||||
local warehouse = STORAGE:NewFromDynamicCargo(CargoName)
|
||||
self.warehouse = warehouse
|
||||
end
|
||||
|
||||
self.lid = string.format("DYNAMICCARGO %s", CargoName)
|
||||
|
||||
self.Owner = string.match(CargoName,"^(.+)|%d%d:%d%d|PKG%d+") or "None"
|
||||
|
||||
self.timer = TIMER:New(DYNAMICCARGO._UpdatePosition,self)
|
||||
self.timer:Start(self.Interval,self.Interval)
|
||||
|
||||
if not _DYNAMICCARGO_HELOS then
|
||||
_DYNAMICCARGO_HELOS = SET_CLIENT:New():FilterAlive():FilterFunction(DYNAMICCARGO._FilterHeloTypes):FilterStart()
|
||||
end
|
||||
|
||||
if self.testing then
|
||||
BASE:TraceOn()
|
||||
BASE:TraceClass("DYNAMICCARGO")
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Get DCS object.
|
||||
-- @param #DYNAMICCARGO self
|
||||
-- @return DCS static object
|
||||
function DYNAMICCARGO:GetDCSObject()
|
||||
local DCSStatic = StaticObject.getByName( self.StaticName ) or Unit.getByName( self.StaticName )
|
||||
if DCSStatic then
|
||||
return DCSStatic
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- User API Functions
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- Get last known owner name of this DYNAMICCARGO
|
||||
-- @param #DYNAMICCARGO self
|
||||
-- @return #string Owner
|
||||
function DYNAMICCARGO:GetLastOwner()
|
||||
return self.Owner
|
||||
end
|
||||
|
||||
--- Returns true if the cargo is new and has never been loaded into a Helo.
|
||||
-- @param #DYNAMICCARGO self
|
||||
-- @return #boolean Outcome
|
||||
function DYNAMICCARGO:IsNew()
|
||||
if self.CargoState and self.CargoState == DYNAMICCARGO.State.NEW then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
--- Returns true if the cargo been loaded into a Helo.
|
||||
-- @param #DYNAMICCARGO self
|
||||
-- @return #boolean Outcome
|
||||
function DYNAMICCARGO:IsLoaded()
|
||||
if self.CargoState and self.CargoState == DYNAMICCARGO.State.LOADED then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
--- Returns true if the cargo has been unloaded from a Helo.
|
||||
-- @param #DYNAMICCARGO self
|
||||
-- @return #boolean Outcome
|
||||
function DYNAMICCARGO:IsUnloaded()
|
||||
if self.CargoState and self.CargoState == DYNAMICCARGO.State.UNLOADED then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
--- Returns true if the cargo has been removed.
|
||||
-- @param #DYNAMICCARGO self
|
||||
-- @return #boolean Outcome
|
||||
function DYNAMICCARGO:IsRemoved()
|
||||
if self.CargoState and self.CargoState == DYNAMICCARGO.State.REMOVED then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
--- [CTLD] Get number of crates this DYNAMICCARGO consists of. Always one.
|
||||
-- @param #DYNAMICCARGO self
|
||||
-- @return #number crate number, always one
|
||||
function DYNAMICCARGO:GetCratesNeeded()
|
||||
return 1
|
||||
end
|
||||
|
||||
--- [CTLD] Get this DYNAMICCARGO drop state. True if DYNAMICCARGO.State.UNLOADED
|
||||
-- @param #DYNAMICCARGO self
|
||||
-- @return #boolean Dropped
|
||||
function DYNAMICCARGO:WasDropped()
|
||||
return self.CargoState == DYNAMICCARGO.State.UNLOADED and true or false
|
||||
end
|
||||
|
||||
--- [CTLD] Get CTLD_CARGO.Enum type of this DYNAMICCARGO
|
||||
-- @param #DYNAMICCARGO self
|
||||
-- @return #string Type, only one at the moment is CTLD_CARGO.Enum.GCLOADABLE
|
||||
function DYNAMICCARGO:GetType()
|
||||
return CTLD_CARGO.Enum.GCLOADABLE
|
||||
end
|
||||
|
||||
|
||||
--- Find last known position of this DYNAMICCARGO
|
||||
-- @param #DYNAMICCARGO self
|
||||
-- @return DCS#Vec3 Position in 3D space
|
||||
function DYNAMICCARGO:GetLastPosition()
|
||||
return self.LastPosition
|
||||
end
|
||||
|
||||
--- Find current state of this DYNAMICCARGO
|
||||
-- @param #DYNAMICCARGO self
|
||||
-- @return string The current state
|
||||
function DYNAMICCARGO:GetState()
|
||||
return self.CargoState
|
||||
end
|
||||
|
||||
--- Find a DYNAMICCARGO in the **_DATABASE** using the name associated with it.
|
||||
-- @param #DYNAMICCARGO self
|
||||
-- @param #string Name The dynamic cargo name
|
||||
-- @return #DYNAMICCARGO self
|
||||
function DYNAMICCARGO:FindByName( Name )
|
||||
local storage = _DATABASE:FindDynamicCargo( Name )
|
||||
return storage
|
||||
end
|
||||
|
||||
--- Find the first(!) DYNAMICCARGO matching using patterns. Note that this is **a lot** slower than `:FindByName()`!
|
||||
-- @param #DYNAMICCARGO self
|
||||
-- @param #string Pattern The pattern to look for. Refer to [LUA patterns](http://www.easyuo.com/openeuo/wiki/index.php/Lua_Patterns_and_Captures_\(Regular_Expressions\)) for regular expressions in LUA.
|
||||
-- @return #DYNAMICCARGO The DYNAMICCARGO.
|
||||
-- @usage
|
||||
-- -- Find a dynamic cargo with a partial dynamic cargo name
|
||||
-- local grp = DYNAMICCARGO:FindByMatching( "Apple" )
|
||||
-- -- will return e.g. a dynamic cargo named "Apple|08:00|PKG08"
|
||||
--
|
||||
-- -- using a pattern
|
||||
-- local grp = DYNAMICCARGO:FindByMatching( ".%d.%d$" )
|
||||
-- -- will return the first dynamic cargo found ending in "-1-1" to "-9-9", but not e.g. "-10-1"
|
||||
function DYNAMICCARGO:FindByMatching( Pattern )
|
||||
local GroupFound = nil
|
||||
|
||||
for name,static in pairs(_DATABASE.DYNAMICCARGO) do
|
||||
if string.match(name, Pattern ) then
|
||||
GroupFound = static
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
return GroupFound
|
||||
end
|
||||
|
||||
--- Find all DYNAMICCARGO objects matching using patterns. Note that this is **a lot** slower than `:FindByName()`!
|
||||
-- @param #DYNAMICCARGO self
|
||||
-- @param #string Pattern The pattern to look for. Refer to [LUA patterns](http://www.easyuo.com/openeuo/wiki/index.php/Lua_Patterns_and_Captures_\(Regular_Expressions\)) for regular expressions in LUA.
|
||||
-- @return #table Groups Table of matching #DYNAMICCARGO objects found
|
||||
-- @usage
|
||||
-- -- Find all dynamic cargo with a partial dynamic cargo name
|
||||
-- local grptable = DYNAMICCARGO:FindAllByMatching( "Apple" )
|
||||
-- -- will return all dynamic cargos with "Apple" in the name
|
||||
--
|
||||
-- -- using a pattern
|
||||
-- local grp = DYNAMICCARGO:FindAllByMatching( ".%d.%d$" )
|
||||
-- -- will return the all dynamic cargos found ending in "-1-1" to "-9-9", but not e.g. "-10-1" or "-1-10"
|
||||
function DYNAMICCARGO:FindAllByMatching( Pattern )
|
||||
local GroupsFound = {}
|
||||
|
||||
for name,static in pairs(_DATABASE.DYNAMICCARGO) do
|
||||
if string.match(name, Pattern ) then
|
||||
GroupsFound[#GroupsFound+1] = static
|
||||
end
|
||||
end
|
||||
|
||||
return GroupsFound
|
||||
end
|
||||
|
||||
--- Get the #STORAGE object from this dynamic cargo.
|
||||
-- @param #DYNAMICCARGO self
|
||||
-- @return Wrapper.Storage#STORAGE Storage The #STORAGE object
|
||||
function DYNAMICCARGO:GetStorageObject()
|
||||
return self.warehouse
|
||||
end
|
||||
|
||||
--- Get the weight in kgs from this dynamic cargo.
|
||||
-- @param #DYNAMICCARGO self
|
||||
-- @return #number Weight in kgs.
|
||||
function DYNAMICCARGO:GetCargoWeight()
|
||||
local DCSObject = self:GetDCSObject()
|
||||
if DCSObject then
|
||||
local weight = DCSObject:getCargoWeight()
|
||||
return weight
|
||||
else
|
||||
return 0
|
||||
end
|
||||
end
|
||||
|
||||
--- Get the cargo display name from this dynamic cargo.
|
||||
-- @param #DYNAMICCARGO self
|
||||
-- @return #string The display name
|
||||
function DYNAMICCARGO:GetCargoDisplayName()
|
||||
local DCSObject = self:GetDCSObject()
|
||||
if DCSObject then
|
||||
local weight = DCSObject:getCargoDisplayName()
|
||||
return weight
|
||||
else
|
||||
return self.StaticName
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Private Functions
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- [Internal] _Get helo hovering intel
|
||||
-- @param #DYNAMICCARGO self
|
||||
-- @param Wrapper.Unit#UNIT Unit The Unit to test
|
||||
-- @param #number ropelength Ropelength to test
|
||||
-- @return #boolean Outcome
|
||||
function DYNAMICCARGO:_HeloHovering(Unit,ropelength)
|
||||
local DCSUnit = Unit:GetDCSObject() --DCS#Unit
|
||||
local hovering = false
|
||||
local Height = 0
|
||||
if DCSUnit then
|
||||
local UnitInAir = DCSUnit:inAir()
|
||||
local UnitCategory = DCSUnit:getDesc().category
|
||||
if UnitInAir == true and UnitCategory == 1 then
|
||||
local VelocityVec3 = DCSUnit:getVelocity()
|
||||
local Velocity = UTILS.VecNorm(VelocityVec3)
|
||||
local Coordinate = DCSUnit:getPoint()
|
||||
local LandHeight = land.getHeight({ x = Coordinate.x, y = Coordinate.z })
|
||||
Height = Coordinate.y - LandHeight
|
||||
if Velocity < 1 and Height <= ropelength and Height > 6 then -- hover lower than ropelength but higher than the normal FARP height.
|
||||
hovering = true
|
||||
end
|
||||
end
|
||||
return hovering, Height
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
--- [Internal] _Get Possible Player Helo Nearby
|
||||
-- @param #DYNAMICCARGO self
|
||||
-- @param Core.Point#COORDINATE pos
|
||||
-- @param #boolean loading If true measure distance for loading else for unloading
|
||||
-- @return #boolean Success
|
||||
-- @return Wrapper.Client#CLIENT Helo
|
||||
-- @return #string PlayerName
|
||||
function DYNAMICCARGO:_GetPossibleHeloNearby(pos,loading)
|
||||
local set = _DYNAMICCARGO_HELOS:GetAliveSet()
|
||||
local success = false
|
||||
local Helo = nil
|
||||
local Playername = nil
|
||||
for _,_helo in pairs (set or {}) do
|
||||
local helo = _helo -- Wrapper.Client#CLIENT
|
||||
local name = helo:GetPlayerName() or _DATABASE:_FindPlayerNameByUnitName(helo:GetName()) or "None"
|
||||
self:T(self.lid.." Checking: "..name)
|
||||
local hpos = helo:GetCoordinate()
|
||||
-- TODO Check unloading via sling load?
|
||||
local typename = helo:GetTypeName()
|
||||
local dimensions = DYNAMICCARGO.AircraftDimensions[typename]
|
||||
local hovering, height = self:_HeloHovering(helo,dimensions.ropelength)
|
||||
local helolanded = not helo:InAir()
|
||||
self:T(self.lid.." InAir: AGL/Hovering: "..hpos.y-hpos:GetLandHeight().."/"..tostring(hovering))
|
||||
if hpos and typename and dimensions then
|
||||
local delta2D = hpos:Get2DDistance(pos)
|
||||
local delta3D = hpos:Get3DDistance(pos)
|
||||
if self.testing then
|
||||
self:T(string.format("Cargo relative position: 2D %dm | 3D %dm",delta2D,delta3D))
|
||||
self:T(string.format("Helo dimension: length %dm | width %dm | rope %dm",dimensions.length,dimensions.width,dimensions.ropelength))
|
||||
self:T(string.format("Helo hovering: %s at %dm",tostring(hovering),height))
|
||||
end
|
||||
-- unloading from ground
|
||||
if loading~=true and (delta2D > dimensions.length or delta2D > dimensions.width) and helolanded then -- Theoretically the cargo could still be attached to the sling if landed next to the cargo. But once moved again it would go back into loaded state once lifted again.
|
||||
success = true
|
||||
Helo = helo
|
||||
Playername = name
|
||||
end
|
||||
-- unloading from hover/rope
|
||||
if loading~=true and delta3D > dimensions.ropelength then
|
||||
success = true
|
||||
Helo = helo
|
||||
Playername = name
|
||||
end
|
||||
-- loading
|
||||
if loading == true and ((delta2D < dimensions.length and delta2D < dimensions.width and helolanded) or (delta3D == dimensions.ropelength and helo:InAir())) then -- Loaded via ground or sling
|
||||
success = true
|
||||
Helo = helo
|
||||
Playername = name
|
||||
end
|
||||
end
|
||||
end
|
||||
return success,Helo,Playername
|
||||
end
|
||||
|
||||
--- [Internal] Update internal states.
|
||||
-- @param #DYNAMICCARGO self
|
||||
-- @return #DYNAMICCARGO self
|
||||
function DYNAMICCARGO:_UpdatePosition()
|
||||
self:T(self.lid.." _UpdatePositionAndState")
|
||||
if self:IsAlive() then
|
||||
local pos = self:GetCoordinate()
|
||||
if self.testing then
|
||||
self:T(string.format("Cargo position: x=%d, y=%d, z=%d",pos.x,pos.y,pos.z))
|
||||
self:T(string.format("Last position: x=%d, y=%d, z=%d",self.LastPosition.x,self.LastPosition.y,self.LastPosition.z))
|
||||
end
|
||||
if UTILS.Round(UTILS.VecDist3D(pos,self.LastPosition),2) > 0.5 then -- This checks if the cargo has moved more than 0.5m since last check. If so then the cargo is loaded
|
||||
---------------
|
||||
-- LOAD Cargo
|
||||
---------------
|
||||
if self.CargoState == DYNAMICCARGO.State.NEW or self.CargoState == DYNAMICCARGO.State.UNLOADED then
|
||||
local isloaded, client, playername = self:_GetPossibleHeloNearby(pos,true)
|
||||
self:T(self.lid.." moved! NEW -> LOADED by "..tostring(playername))
|
||||
self.CargoState = DYNAMICCARGO.State.LOADED
|
||||
self.Owner = playername
|
||||
_DATABASE:CreateEventDynamicCargoLoaded(self)
|
||||
end
|
||||
---------------
|
||||
-- UNLOAD Cargo
|
||||
---------------
|
||||
-- If the cargo is stationary then we need to end this condition here to check whether it is unloaded or still onboard or still hooked if anyone can hover that precisly
|
||||
elseif self.CargoState == DYNAMICCARGO.State.LOADED then
|
||||
-- TODO add checker if we are in flight somehow
|
||||
-- ensure not just the helo is moving
|
||||
local count = _DYNAMICCARGO_HELOS:CountAlive()
|
||||
-- Testing
|
||||
local landheight = pos:GetLandHeight()
|
||||
local agl = pos.y-landheight
|
||||
agl = UTILS.Round(agl,2)
|
||||
self:T(self.lid.." AGL: "..agl or -1)
|
||||
local isunloaded = true
|
||||
local client
|
||||
local playername = self.Owner
|
||||
if count > 0 then
|
||||
self:T(self.lid.." Possible alive helos: "..count or -1)
|
||||
isunloaded, client, playername = self:_GetPossibleHeloNearby(pos,false)
|
||||
if isunloaded then
|
||||
self:T(self.lid.." moved! LOADED -> UNLOADED by "..tostring(playername))
|
||||
self.CargoState = DYNAMICCARGO.State.UNLOADED
|
||||
self.Owner = playername
|
||||
_DATABASE:CreateEventDynamicCargoUnloaded(self)
|
||||
end
|
||||
end
|
||||
end
|
||||
self.LastPosition = pos
|
||||
--end
|
||||
else
|
||||
---------------
|
||||
-- REMOVED Cargo
|
||||
---------------
|
||||
if self.timer and self.timer:IsRunning() then self.timer:Stop() end
|
||||
self:T(self.lid.." dead! " ..self.CargoState.."-> REMOVED")
|
||||
self.CargoState = DYNAMICCARGO.State.REMOVED
|
||||
_DATABASE:CreateEventDynamicCargoRemoved(self)
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- [Internal] Track helos for loaded/unloaded decision making.
|
||||
-- @param Wrapper.Client#CLIENT client
|
||||
-- @return #boolean IsIn
|
||||
function DYNAMICCARGO._FilterHeloTypes(client)
|
||||
if not client then return false end
|
||||
local typename = client:GetTypeName()
|
||||
local isinclude = DYNAMICCARGO.AircraftTypes[typename] ~= nil and true or false
|
||||
return isinclude
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
File diff suppressed because it is too large
Load Diff
@@ -11,7 +11,8 @@
|
||||
-- @module Wrapper.Identifiable
|
||||
-- @image MOOSE.JPG
|
||||
|
||||
--- @type IDENTIFIABLE
|
||||
---
|
||||
-- @type IDENTIFIABLE
|
||||
-- @extends Wrapper.Object#OBJECT
|
||||
-- @field #string IdentifiableName The name of the identifiable.
|
||||
|
||||
@@ -111,19 +112,28 @@ end
|
||||
-- * Object.Category.SCENERY = 5
|
||||
-- * Object.Category.Cargo = 6
|
||||
--
|
||||
-- For UNITs this returns a second value, one of
|
||||
--
|
||||
-- Unit.Category.AIRPLANE = 0
|
||||
-- Unit.Category.HELICOPTER = 1
|
||||
-- Unit.Category.GROUND_UNIT = 2
|
||||
-- Unit.Category.SHIP = 3
|
||||
-- Unit.Category.STRUCTURE = 4
|
||||
--
|
||||
-- @param #IDENTIFIABLE self
|
||||
-- @return DCS#Object.Category The category ID, i.e. a number.
|
||||
-- @return DCS#Unit.Category The unit category ID, i.e. a number. For units only.
|
||||
function IDENTIFIABLE:GetCategory()
|
||||
self:F2( self.ObjectName )
|
||||
|
||||
local DCSObject = self:GetDCSObject()
|
||||
if DCSObject then
|
||||
local ObjectCategory = DCSObject:getCategory()
|
||||
local ObjectCategory, UnitCategory = DCSObject:getCategory()
|
||||
self:T3( ObjectCategory )
|
||||
return ObjectCategory
|
||||
return ObjectCategory, UnitCategory
|
||||
end
|
||||
|
||||
return nil
|
||||
return nil,nil
|
||||
end
|
||||
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ do
|
||||
-- @field #NET
|
||||
NET = {
|
||||
ClassName = "NET",
|
||||
Version = "0.1.3",
|
||||
Version = "0.1.4",
|
||||
BlockTime = 600,
|
||||
BlockedPilots = {},
|
||||
BlockedUCIDs = {},
|
||||
@@ -67,6 +67,9 @@ function NET:New()
|
||||
self.KnownPilots = {}
|
||||
self:SetBlockMessage()
|
||||
self:SetUnblockMessage()
|
||||
self.BlockedSides = {}
|
||||
self.BlockedSides[1] = false
|
||||
self.BlockedSides[2] = false
|
||||
|
||||
-- Start State.
|
||||
self:SetStartState("Stopped")
|
||||
@@ -160,11 +163,12 @@ end
|
||||
-- @param #string PlayerSlot
|
||||
-- @return #boolean IsBlocked
|
||||
function NET:IsAnyBlocked(UCID,Name,PlayerID,PlayerSide,PlayerSlot)
|
||||
self:T({UCID,Name,PlayerID,PlayerSide,PlayerSlot})
|
||||
local blocked = false
|
||||
local TNow = timer.getTime()
|
||||
-- UCID
|
||||
if UCID and self.BlockedUCIDs[UCID] and TNow < self.BlockedUCIDs[UCID] then
|
||||
return true
|
||||
blocked = true
|
||||
end
|
||||
-- ID/Name
|
||||
if PlayerID and not Name then
|
||||
@@ -172,16 +176,18 @@ function NET:IsAnyBlocked(UCID,Name,PlayerID,PlayerSide,PlayerSlot)
|
||||
end
|
||||
-- Name
|
||||
if Name and self.BlockedPilots[Name] and TNow < self.BlockedPilots[Name] then
|
||||
return true
|
||||
blocked = true
|
||||
end
|
||||
-- Side
|
||||
if PlayerSide and self.BlockedSides[PlayerSide] and TNow < self.BlockedSides[PlayerSide] then
|
||||
return true
|
||||
self:T({time = self.BlockedSides[PlayerSide]})
|
||||
if PlayerSide and type(self.BlockedSides[PlayerSide]) == "number" and TNow < self.BlockedSides[PlayerSide] then
|
||||
blocked = true
|
||||
end
|
||||
-- Slot
|
||||
if PlayerSlot and self.BlockedSlots[PlayerSlot] and TNow < self.BlockedSlots[PlayerSlot] then
|
||||
return true
|
||||
blocked = true
|
||||
end
|
||||
self:T("IsAnyBlocked: "..tostring(blocked))
|
||||
return blocked
|
||||
end
|
||||
|
||||
@@ -200,19 +206,27 @@ function NET:_EventHandler(EventData)
|
||||
local ucid = self:GetPlayerUCID(nil,name) or "none"
|
||||
local PlayerID = self:GetPlayerIDByName(name) or "none"
|
||||
local PlayerSide, PlayerSlot = self:GetSlot(data.IniUnit)
|
||||
if not PlayerSide then PlayerSide = EventData.IniCoalition end
|
||||
if not PlayerSlot then PlayerSlot = EventData.IniUnit:GetID() or -1 end
|
||||
local TNow = timer.getTime()
|
||||
|
||||
self:T(self.lid.."Event for: "..name.." | UCID: "..ucid)
|
||||
--self:T(self.lid.."Event for: "..name.." | UCID: "..ucid .. " | ID/SIDE/SLOT "..PlayerID.."/"..PlayerSide.."/"..PlayerSlot)
|
||||
|
||||
-- Joining
|
||||
if data.id == EVENTS.PlayerEnterUnit or data.id == EVENTS.PlayerEnterAircraft then
|
||||
self:T(self.lid.."Pilot Joining: "..name.." | UCID: "..ucid.." | Event ID: "..data.id)
|
||||
-- Check for blockages
|
||||
local blocked = self:IsAnyBlocked(ucid,name,PlayerID,PlayerSide,PlayerSlot)
|
||||
|
||||
if blocked and PlayerID and tonumber(PlayerID) ~= 1 then
|
||||
if blocked and PlayerID then -- and tonumber(PlayerID) ~= 1 then
|
||||
self:T("Player blocked")
|
||||
-- block pilot
|
||||
local outcome = net.force_player_slot(tonumber(PlayerID), 0, '' )
|
||||
local outcome = net.force_player_slot(tonumber(PlayerID), PlayerSide, data.IniUnit:GetID() )
|
||||
self:T({Blocked_worked=outcome})
|
||||
if outcome == false then
|
||||
local unit = data.IniUnit
|
||||
local sched = TIMER:New(unit.Destroy,unit,3):Start(3)
|
||||
self:__PlayerBlocked(5,unit,name,1)
|
||||
end
|
||||
else
|
||||
local client = CLIENT:FindByPlayerName(name) or data.IniUnit
|
||||
if not self.KnownPilots[name] or (self.KnownPilots[name] and TNow-self.KnownPilots[name].timestamp > 3) then
|
||||
@@ -225,6 +239,7 @@ function NET:_EventHandler(EventData)
|
||||
slot = PlayerSlot,
|
||||
timestamp = TNow,
|
||||
}
|
||||
--UTILS.PrintTableToLog(self.KnownPilots[name])
|
||||
end
|
||||
return self
|
||||
end
|
||||
@@ -350,11 +365,10 @@ end
|
||||
|
||||
--- Block a specific coalition side, does NOT automatically kick all players of that side or kick out joined players
|
||||
-- @param #NET self
|
||||
-- @param #number side The side to block - 1 : Red, 2 : Blue
|
||||
-- @param #number Side The side to block - 1 : Red, 2 : Blue
|
||||
-- @param #number Seconds Seconds (optional) Number of seconds the player has to wait before rejoining.
|
||||
-- @return #NET self
|
||||
function NET:BlockSide(Side,Seconds)
|
||||
self:T({Side,Seconds})
|
||||
local addon = Seconds or self.BlockTime
|
||||
if Side == 1 or Side == 2 then
|
||||
self.BlockedSides[Side] = timer.getTime()+addon
|
||||
@@ -367,10 +381,9 @@ end
|
||||
-- @param #number Seconds Seconds (optional) Number of seconds the player has to wait before rejoining.
|
||||
-- @return #NET self
|
||||
function NET:UnblockSide(Side,Seconds)
|
||||
self:T({Side,Seconds})
|
||||
local addon = Seconds or self.BlockTime
|
||||
if Side == 1 or Side == 2 then
|
||||
self.BlockedSides[Side] = nil
|
||||
self.BlockedSides[Side] = false
|
||||
end
|
||||
return self
|
||||
end
|
||||
@@ -485,8 +498,11 @@ end
|
||||
-- @param Wrapper.Client#CLIENT Client The client
|
||||
-- @return #number PlayerID or nil
|
||||
function NET:GetPlayerIDFromClient(Client)
|
||||
self:T("GetPlayerIDFromClient")
|
||||
self:T({Client=Client})
|
||||
if Client then
|
||||
local name = Client:GetPlayerName()
|
||||
self:T({name=name})
|
||||
local id = self:GetPlayerIDByName(name)
|
||||
return id
|
||||
else
|
||||
@@ -528,6 +544,7 @@ function NET:SendChatToPlayer(Message, ToPlayer, FromPlayer)
|
||||
return self
|
||||
end
|
||||
|
||||
--[[ not in 2.97 MSE any longer
|
||||
--- Load a specific mission.
|
||||
-- @param #NET self
|
||||
-- @param #string Path and Mission
|
||||
@@ -550,6 +567,7 @@ function NET:LoadNextMission()
|
||||
outcome = net.load_next_mission()
|
||||
return outcome
|
||||
end
|
||||
--]]
|
||||
|
||||
--- Return a table of players currently connected to the server.
|
||||
-- @param #NET self
|
||||
@@ -680,16 +698,19 @@ end
|
||||
-- @return #number SideID i.e. 0 : spectators, 1 : Red, 2 : Blue
|
||||
-- @return #number SlotID
|
||||
function NET:GetSlot(Client)
|
||||
self:T("NET.GetSlot")
|
||||
local PlayerID = self:GetPlayerIDFromClient(Client)
|
||||
self:T("NET.GetSlot PlayerID = "..tostring(PlayerID))
|
||||
if PlayerID then
|
||||
local side,slot = net.get_slot(tonumber(PlayerID))
|
||||
self:T("NET.GetSlot side, slot = "..tostring(side)..","..tostring(slot))
|
||||
return side,slot
|
||||
else
|
||||
return nil,nil
|
||||
end
|
||||
end
|
||||
|
||||
--- Force the slot for a specific client.
|
||||
--- Force the slot for a specific client. If this returns false, it didn't work via `net` (which is ALWAYS the case as of Nov 2024)!
|
||||
-- @param #NET self
|
||||
-- @param Wrapper.Client#CLIENT Client The client
|
||||
-- @param #number SideID i.e. 0 : spectators, 1 : Red, 2 : Blue
|
||||
@@ -697,19 +718,22 @@ end
|
||||
-- @return #boolean Success
|
||||
function NET:ForceSlot(Client,SideID,SlotID)
|
||||
local PlayerID = self:GetPlayerIDFromClient(Client)
|
||||
if PlayerID and tonumber(PlayerID) ~= 1 then
|
||||
return net.force_player_slot(tonumber(PlayerID), SideID, SlotID or '' )
|
||||
local SlotID = SlotID or Client:GetID()
|
||||
if PlayerID then -- and tonumber(PlayerID) ~= 1 then
|
||||
return net.force_player_slot(tonumber(PlayerID), SideID, SlotID )
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
--- Force a client back to spectators.
|
||||
--- Force a client back to spectators. If this returns false, it didn't work via `net` (which is ALWAYS the case as of Nov 2024)!
|
||||
-- @param #NET self
|
||||
-- @param Wrapper.Client#CLIENT Client The client
|
||||
-- @return #boolean Succes
|
||||
function NET:ReturnToSpectators(Client)
|
||||
local outcome = self:ForceSlot(Client,0)
|
||||
-- workaround
|
||||
local sched = TIMER:New(Client.Destroy,Client,1):Start(1)
|
||||
return outcome
|
||||
end
|
||||
|
||||
@@ -779,7 +803,7 @@ function NET:onafterStatus(From,Event,To)
|
||||
local function HouseHold(tavolo)
|
||||
local TNow = timer.getTime()
|
||||
for _,entry in pairs (tavolo) do
|
||||
if entry >= TNow then entry = nil end
|
||||
if type(entry) == "number" and entry >= TNow then entry = false end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
--- @type POSITIONABLE
|
||||
-- @field Core.Point#COORDINATE coordinate Coordinate object.
|
||||
-- @field Core.Point#POINT_VEC3 pointvec3 Point Vec3 object.
|
||||
-- @field Core.Point#COORDINATE pointvec3 Point Vec3 object.
|
||||
-- @extends Wrapper.Identifiable#IDENTIFIABLE
|
||||
|
||||
|
||||
@@ -110,14 +110,17 @@ function POSITIONABLE:Destroy( GenerateEvent )
|
||||
|
||||
if GenerateEvent and GenerateEvent == true then
|
||||
if self:IsAir() then
|
||||
--self:ScheduleOnce(1,self.CreateEventCrash,self,timer.getTime(),DCSObject)
|
||||
self:CreateEventCrash( timer.getTime(), DCSObject )
|
||||
else
|
||||
--self:ScheduleOnce(1,self.CreateEventDead,self,timer.getTime(),DCSObject)
|
||||
self:CreateEventDead( timer.getTime(), DCSObject )
|
||||
end
|
||||
elseif GenerateEvent == false then
|
||||
-- Do nothing!
|
||||
else
|
||||
self:CreateEventRemoveUnit( timer.getTime(), DCSObject )
|
||||
--self:ScheduleOnce(1,self.CreateEventRemoveUnit,self,timer.getTime(),DCSObject)
|
||||
end
|
||||
|
||||
USERFLAG:New( UnitGroupName ):Set( 100 )
|
||||
@@ -142,7 +145,11 @@ function POSITIONABLE:GetPosition()
|
||||
self:F2( self.PositionableName )
|
||||
|
||||
local DCSPositionable = self:GetDCSObject()
|
||||
|
||||
|
||||
if self:IsInstanceOf("GROUP") then
|
||||
DCSPositionable = self:GetFirstUnitAlive():GetDCSObject()
|
||||
end
|
||||
|
||||
if DCSPositionable then
|
||||
local PositionablePosition = DCSPositionable:getPosition()
|
||||
self:T3( PositionablePosition )
|
||||
@@ -277,9 +284,9 @@ function POSITIONABLE:GetVec2()
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Returns a POINT_VEC2 object indicating the point in 2D of the POSITIONABLE within the mission.
|
||||
--- Returns a COORDINATE object indicating the point in 2D of the POSITIONABLE within the mission.
|
||||
-- @param #POSITIONABLE self
|
||||
-- @return Core.Point#POINT_VEC2 The 2D point vector of the POSITIONABLE.
|
||||
-- @return Core.Point#COORDINATE The 3D point vector of the POSITIONABLE.
|
||||
-- @return #nil The POSITIONABLE is not existing or alive.
|
||||
function POSITIONABLE:GetPointVec2()
|
||||
self:F2( self.PositionableName )
|
||||
@@ -289,20 +296,20 @@ function POSITIONABLE:GetPointVec2()
|
||||
if DCSPositionable then
|
||||
local PositionableVec3 = DCSPositionable:getPosition().p
|
||||
|
||||
local PositionablePointVec2 = POINT_VEC2:NewFromVec3( PositionableVec3 )
|
||||
local PositionablePointVec2 = COORDINATE:NewFromVec3( PositionableVec3 )
|
||||
|
||||
-- self:F( PositionablePointVec2 )
|
||||
return PositionablePointVec2
|
||||
end
|
||||
|
||||
self:E( { "Cannot GetPointVec2", Positionable = self, Alive = self:IsAlive() } )
|
||||
self:E( { "Cannot Coordinate", Positionable = self, Alive = self:IsAlive() } )
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Returns a POINT_VEC3 object indicating the point in 3D of the POSITIONABLE within the mission.
|
||||
--- Returns a COORDINATE object indicating the point in 3D of the POSITIONABLE within the mission.
|
||||
-- @param #POSITIONABLE self
|
||||
-- @return Core.Point#POINT_VEC3 The 3D point vector of the POSITIONABLE.
|
||||
-- @return Core.Point#COORDINATE The 3D point vector of the POSITIONABLE.
|
||||
-- @return #nil The POSITIONABLE is not existing or alive.
|
||||
function POSITIONABLE:GetPointVec3()
|
||||
|
||||
@@ -322,8 +329,8 @@ function POSITIONABLE:GetPointVec3()
|
||||
|
||||
else
|
||||
|
||||
-- Create a new POINT_VEC3 object.
|
||||
self.pointvec3 = POINT_VEC3:NewFromVec3( PositionableVec3 )
|
||||
-- Create a new COORDINATE object.
|
||||
self.pointvec3 = COORDINATE:NewFromVec3( PositionableVec3 )
|
||||
|
||||
end
|
||||
|
||||
@@ -671,7 +678,7 @@ function POSITIONABLE:GetBoundingRadius( MinDist )
|
||||
return math.max( math.max( CX, CZ ), boxmin )
|
||||
end
|
||||
|
||||
BASE:E( { "Cannot GetBoundingRadius", Positionable = self, Alive = self:IsAlive() } )
|
||||
BASE:T( { "Cannot GetBoundingRadius", Positionable = self, Alive = self:IsAlive() } )
|
||||
|
||||
return nil
|
||||
end
|
||||
@@ -1853,6 +1860,7 @@ do -- Cargo
|
||||
["HL_KORD"] = 6*POSITIONABLE.DefaultInfantryWeight,
|
||||
["HL_DSHK"] = 6*POSITIONABLE.DefaultInfantryWeight,
|
||||
["CCKW_353"] = 16*POSITIONABLE.DefaultInfantryWeight, --GMC CCKW 2½-ton 6×6 truck, estimating 16 soldiers,
|
||||
["MaxxPro_MRAP"] = 7*POSITIONABLE.DefaultInfantryWeight,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
--- **Wrapper** - SCENERY models scenery within the DCS simulator.
|
||||
--
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
--
|
||||
-- ### Author: **FlightControl**
|
||||
--
|
||||
--
|
||||
-- ### Contributions: **Applevangelist**, **funkyfranky**
|
||||
--
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
--
|
||||
-- @module Wrapper.Scenery
|
||||
-- @image Wrapper_Scenery.JPG
|
||||
|
||||
@@ -23,13 +23,13 @@
|
||||
|
||||
|
||||
--- Wrapper class to handle Scenery objects that are defined on the map.
|
||||
--
|
||||
--
|
||||
-- The @{Wrapper.Scenery#SCENERY} class is a wrapper class to handle the DCS Scenery objects:
|
||||
--
|
||||
--
|
||||
-- * Wraps the DCS Scenery objects.
|
||||
-- * Support all DCS Scenery APIs.
|
||||
-- * Enhance with Scenery specific APIs not in the DCS API set.
|
||||
--
|
||||
--
|
||||
-- @field #SCENERY
|
||||
SCENERY = {
|
||||
ClassName = "SCENERY",
|
||||
@@ -43,23 +43,23 @@ SCENERY = {
|
||||
function SCENERY:Register( SceneryName, SceneryObject )
|
||||
|
||||
local self = BASE:Inherit( self, POSITIONABLE:New( SceneryName ) )
|
||||
|
||||
|
||||
self.SceneryName = tostring(SceneryName)
|
||||
|
||||
|
||||
self.SceneryObject = SceneryObject
|
||||
|
||||
if self.SceneryObject then
|
||||
self.Life0 = self.SceneryObject:getLife()
|
||||
|
||||
if self.SceneryObject and self.SceneryObject.getLife then -- fix some objects do not have all functions
|
||||
self.Life0 = self.SceneryObject:getLife() or 0
|
||||
else
|
||||
self.Life0 = 0
|
||||
end
|
||||
|
||||
|
||||
self.Properties = {}
|
||||
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Returns the Value of the zone with the given PropertyName, or nil if no matching property exists.
|
||||
--- Returns the value of the scenery with the given PropertyName, or nil if no matching property exists.
|
||||
-- @param #SCENERY self
|
||||
-- @param #string PropertyName The name of a the QuadZone Property from the scenery assignment to be retrieved.
|
||||
-- @return #string The Value of the QuadZone Property from the scenery assignment with the given PropertyName, or nil if absent.
|
||||
@@ -67,6 +67,14 @@ function SCENERY:GetProperty(PropertyName)
|
||||
return self.Properties[PropertyName]
|
||||
end
|
||||
|
||||
--- Checks if the value of the scenery with the given PropertyName exists.
|
||||
-- @param #SCENERY self
|
||||
-- @param #string PropertyName The name of a the QuadZone Property from the scenery assignment to be retrieved.
|
||||
-- @return #boolean Outcome True if it exists, else false.
|
||||
function SCENERY:HasProperty(PropertyName)
|
||||
return self.Properties[PropertyName] ~= nil and true or false
|
||||
end
|
||||
|
||||
--- Returns the scenery Properties table.
|
||||
-- @param #SCENERY self
|
||||
-- @return #table The Key:Value table of QuadZone properties of the zone from the scenery assignment .
|
||||
@@ -83,6 +91,7 @@ function SCENERY:SetProperty(PropertyName, PropertyValue)
|
||||
self.Properties[PropertyName] = PropertyValue
|
||||
return self
|
||||
end
|
||||
|
||||
--- Obtain object name.
|
||||
--@param #SCENERY self
|
||||
--@return #string Name
|
||||
@@ -97,15 +106,15 @@ function SCENERY:GetDCSObject()
|
||||
return self.SceneryObject
|
||||
end
|
||||
|
||||
--- Get current life points from the SCENERY Object.
|
||||
-- **CAVEAT**: Some objects change their life value or "hitpoints" **after** the first hit. Hence we will adjust the life0 value to 120%
|
||||
-- of the last life value if life exceeds life0 (initial life) at any point. Thus will will get a smooth percentage decrease, if you use this e.g. as success
|
||||
--- Get current life points from the SCENERY Object. Note - Some scenery objects always have 0 life points.
|
||||
-- **CAVEAT**: Some objects change their life value or "hitpoints" **after** the first hit. Hence we will adjust the life0 value to 120%
|
||||
-- of the last life value if life exceeds life0 (initial life) at any point. Thus will will get a smooth percentage decrease, if you use this e.g. as success
|
||||
-- criteria for a bombing task.
|
||||
--@param #SCENERY self
|
||||
--@return #number life
|
||||
function SCENERY:GetLife()
|
||||
local life = 0
|
||||
if self.SceneryObject then
|
||||
if self.SceneryObject and self.SceneryObject.getLife then
|
||||
life = self.SceneryObject:getLife()
|
||||
if life > self.Life0 then
|
||||
self.Life0 = math.floor(life * 1.2)
|
||||
@@ -121,7 +130,7 @@ function SCENERY:GetLife0()
|
||||
return self.Life0 or 0
|
||||
end
|
||||
|
||||
--- Check if SCENERY Object is alive.
|
||||
--- Check if SCENERY Object is alive. Note - Some scenery objects always have 0 life points.
|
||||
--@param #SCENERY self
|
||||
--@param #number Threshold (Optional) If given, SCENERY counts as alive above this relative life in percent (1..100).
|
||||
--@return #number life
|
||||
@@ -133,7 +142,7 @@ function SCENERY:IsAlive(Threshold)
|
||||
end
|
||||
end
|
||||
|
||||
--- Check if SCENERY Object is dead.
|
||||
--- Check if SCENERY Object is dead. Note - Some scenery objects always have 0 life points.
|
||||
--@param #SCENERY self
|
||||
--@param #number Threshold (Optional) If given, SCENERY counts as dead below this relative life in percent (1..100).
|
||||
--@return #number life
|
||||
@@ -145,12 +154,13 @@ function SCENERY:IsDead(Threshold)
|
||||
end
|
||||
end
|
||||
|
||||
--- Get SCENERY relative life in percent, e.g. 75.
|
||||
--- Get SCENERY relative life in percent, e.g. 75. Note - Some scenery objects always have 0 life points.
|
||||
--@param #SCENERY self
|
||||
--@return #number rlife
|
||||
function SCENERY:GetRelativeLife()
|
||||
local life = self:GetLife()
|
||||
local life0 = self:GetLife0()
|
||||
if life == 0 or life0 == 0 then return 0 end
|
||||
local rlife = math.floor((life/life0)*100)
|
||||
return rlife
|
||||
end
|
||||
@@ -175,7 +185,7 @@ function SCENERY:FindByName(Name, Coordinate, Radius, Role)
|
||||
local radius = Radius or 100
|
||||
local name = Name or "unknown"
|
||||
local scenery = nil
|
||||
|
||||
|
||||
---
|
||||
-- @param Core.Point#COORDINATE coordinate
|
||||
-- @param #number radius
|
||||
@@ -199,13 +209,13 @@ function SCENERY:FindByName(Name, Coordinate, Radius, Role)
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
if Coordinate then
|
||||
--BASE:I("Coordinate Scenery Scan")
|
||||
scenery = SceneryScan(Coordinate, radius, name)
|
||||
end
|
||||
|
||||
return scenery
|
||||
return scenery
|
||||
end
|
||||
|
||||
--- Find a SCENERY object from its name or id. Since SCENERY isn't registered in the Moose database (just too many objects per map), we need to do a scan first
|
||||
@@ -215,7 +225,7 @@ end
|
||||
--@param Core.Zone#ZONE_BASE Zone Where to find the scenery object. Can be handed as zone name.
|
||||
--@param #number Radius (optional) Search radius around coordinate, defaults to 100
|
||||
--@return #SCENERY Scenery Object or `nil` if it cannot be found
|
||||
function SCENERY:FindByNameInZone(Name, Zone, Radius)
|
||||
function SCENERY:FindByNameInZone(Name, Zone, Radius)
|
||||
local radius = Radius or 100
|
||||
local name = Name or "unknown"
|
||||
if type(Zone) == "string" then
|
||||
@@ -270,7 +280,7 @@ end
|
||||
function SCENERY:FindAllByZoneName( ZoneName )
|
||||
local zone = ZoneName -- Core.Zone#ZONE_RADIUS
|
||||
if type(ZoneName) == "string" then
|
||||
zone = ZONE:FindByName(ZoneName)
|
||||
zone = ZONE:FindByName(ZoneName)
|
||||
end
|
||||
local _id = zone:GetProperty('OBJECT ID')
|
||||
--local properties = zone:GetAllProperties() or {}
|
||||
@@ -290,7 +300,7 @@ function SCENERY:FindAllByZoneName( ZoneName )
|
||||
return {obj}
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -61,6 +61,8 @@ function STATIC:Register( StaticName )
|
||||
if DCSStatic then
|
||||
local Life0 = DCSStatic:getLife() or 1
|
||||
self.Life0 = Life0
|
||||
else
|
||||
self:E(string.format("Static object %s does not exist!", tostring(self.StaticName)))
|
||||
end
|
||||
|
||||
return self
|
||||
@@ -178,7 +180,7 @@ end
|
||||
-- @param #STATIC self
|
||||
-- @return DCS static object
|
||||
function STATIC:GetDCSObject()
|
||||
local DCSStatic = StaticObject.getByName( self.StaticName )
|
||||
local DCSStatic = StaticObject.getByName( self.StaticName )
|
||||
|
||||
if DCSStatic then
|
||||
return DCSStatic
|
||||
@@ -330,3 +332,26 @@ function STATIC:FindAllByMatching( Pattern )
|
||||
|
||||
return GroupsFound
|
||||
end
|
||||
|
||||
--- Get the Wrapper.Storage#STORAGE object of an static if it is used as cargo and has been set up as storage object.
|
||||
-- @param #STATIC self
|
||||
-- @return Wrapper.Storage#STORAGE Storage or `nil` if not fund or set up.
|
||||
function STATIC:GetStaticStorage()
|
||||
local name = self:GetName()
|
||||
local storage = STORAGE:NewFromStaticCargo(name)
|
||||
return storage
|
||||
end
|
||||
|
||||
--- Get the Cargo Weight of a static object in kgs. Returns -1 if not found.
|
||||
-- @param #STATIC self
|
||||
-- @return #number Mass Weight in kgs.
|
||||
function STATIC:GetCargoWeight()
|
||||
local DCSObject = StaticObject.getByName(self.StaticName )
|
||||
local mass = -1
|
||||
if DCSObject then
|
||||
mass = DCSObject:getCargoWeight() or 0
|
||||
local masstxt = DCSObject:getCargoDisplayName() or "none"
|
||||
--BASE:I("GetCargoWeight "..tostring(mass).." MassText "..masstxt)
|
||||
end
|
||||
return mass
|
||||
end
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
-- @field #string lid Class id string for output to DCS log file.
|
||||
-- @field DCS#Warehouse warehouse The DCS warehouse object.
|
||||
-- @field DCS#Airbase airbase The DCS airbase object.
|
||||
-- @field Core.Timer#TIMER SaverTimer The TIMER for autosave.
|
||||
-- @extends Core.Base#BASE
|
||||
|
||||
--- *The capitalist cannot store labour-power in warehouses after he has bought it, as he may do with the raw material.* -- Karl Marx
|
||||
@@ -124,6 +125,39 @@
|
||||
-- UTILS.PrintTableToLog(liquids)
|
||||
-- UTILS.PrintTableToLog(weapons)
|
||||
--
|
||||
-- # Weapons Helper Enumerater
|
||||
--
|
||||
-- The currently available weapon items are available in the `ENUMS.Storage.weapons`, e.g. `ENUMS.Storage.weapons.bombs.Mk_82Y`.
|
||||
--
|
||||
-- # Persistence
|
||||
--
|
||||
-- The contents of the storage can be saved to and read from disk. For this to function, `io` and `lfs` need to be desanitized in `MissionScripting.lua`.
|
||||
--
|
||||
-- ## Save once
|
||||
--
|
||||
-- ### To save once, e.g. this is sufficient:
|
||||
--
|
||||
-- -- Filenames created are the Filename given amended by "_Liquids", "_Aircraft" and "_Weapons" followed by a ".csv". Only Storage NOT set to unlimited will be saved.
|
||||
-- local Path = "C:\\Users\\UserName\\Saved Games\\DCS\\Missions\\"
|
||||
-- local Filename = "Batumi"
|
||||
-- storage:SaveToFile(Path,Filename)
|
||||
--
|
||||
-- ### Autosave
|
||||
--
|
||||
-- storage:StartAutoSave(Path,Filename,300,true) -- save every 300 secs/5 mins starting in 5 mins, load the existing storage - if any - first if the last parameter is **not** `false`.
|
||||
--
|
||||
-- ### Stop Autosave
|
||||
--
|
||||
-- storage:StopAutoSave() -- stop the scheduler.
|
||||
--
|
||||
-- ### Load back with e.g.
|
||||
--
|
||||
-- -- Filenames searched for the Filename given amended by "_Liquids", "_Aircraft" and "_Weapons" followed by a ".csv". Only Storage NOT set to unlimited will be loaded.
|
||||
-- local Path = "C:\\Users\\UserName\\Saved Games\\DCS\\Missions\\"
|
||||
-- local Filename = "Batumi"
|
||||
-- storage:LoadFromFile(Path,Filename)
|
||||
--
|
||||
--
|
||||
-- @field #STORAGE
|
||||
STORAGE = {
|
||||
ClassName = "STORAGE",
|
||||
@@ -143,22 +177,46 @@ STORAGE.Liquid = {
|
||||
DIESEL = 3,
|
||||
}
|
||||
|
||||
--- Liquid Names for the static cargo resource table.
|
||||
-- @type STORAGE.LiquidName
|
||||
-- @field #number JETFUEL "jet_fuel".
|
||||
-- @field #number GASOLINE "gasoline".
|
||||
-- @field #number MW50 "methanol_mixture".
|
||||
-- @field #number DIESEL "diesel".
|
||||
STORAGE.LiquidName = {
|
||||
GASOLINE = "gasoline",
|
||||
DIESEL = "diesel",
|
||||
MW50 = "methanol_mixture",
|
||||
JETFUEL = "jet_fuel",
|
||||
}
|
||||
|
||||
--- Storage types.
|
||||
-- @type STORAGE.Type
|
||||
-- @field #number WEAPONS weapons.
|
||||
-- @field #number LIQUIDS liquids. Also see #list<#STORAGE.Liquid> for types of liquids.
|
||||
-- @field #number AIRCRAFT aircraft.
|
||||
STORAGE.Type = {
|
||||
WEAPONS = "weapons",
|
||||
LIQUIDS = "liquids",
|
||||
AIRCRAFT = "aircrafts",
|
||||
}
|
||||
|
||||
--- STORAGE class version.
|
||||
-- @field #string version
|
||||
STORAGE.version="0.0.1"
|
||||
STORAGE.version="0.1.5"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- TODO: A lot...
|
||||
-- TODO: Persistence
|
||||
-- DONE: Persistence
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Constructor
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- Create a new STORAGE object from the DCS weapon object.
|
||||
--- Create a new STORAGE object from the DCS airbase object.
|
||||
-- @param #STORAGE self
|
||||
-- @param #string AirbaseName Name of the airbase.
|
||||
-- @return #STORAGE self
|
||||
@@ -169,17 +227,57 @@ function STORAGE:New(AirbaseName)
|
||||
|
||||
self.airbase=Airbase.getByName(AirbaseName)
|
||||
|
||||
if Airbase.getWarehouse then
|
||||
if Airbase.getWarehouse and self.airbase then
|
||||
self.warehouse=self.airbase:getWarehouse()
|
||||
end
|
||||
|
||||
self.lid = string.format("STORAGE %s", AirbaseName)
|
||||
self.lid = string.format("STORAGE %s | ", AirbaseName)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Create a new STORAGE object from an DCS static cargo object.
|
||||
-- @param #STORAGE self
|
||||
-- @param #string StaticCargoName Unit name of the static.
|
||||
-- @return #STORAGE self
|
||||
function STORAGE:NewFromStaticCargo(StaticCargoName)
|
||||
|
||||
-- Inherit everything from BASE class.
|
||||
local self=BASE:Inherit(self, BASE:New()) -- #STORAGE
|
||||
|
||||
self.airbase=StaticObject.getByName(StaticCargoName)
|
||||
|
||||
if Airbase.getWarehouse then
|
||||
self.warehouse=Warehouse.getCargoAsWarehouse(self.airbase)
|
||||
end
|
||||
|
||||
self.lid = string.format("STORAGE %s | ", StaticCargoName)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Create a new STORAGE object from a Wrapper.DynamicCargo#DYNAMICCARGO object.
|
||||
-- @param #STORAGE self
|
||||
-- @param #string DynamicCargoName Unit name of the dynamic cargo.
|
||||
-- @return #STORAGE self
|
||||
function STORAGE:NewFromDynamicCargo(DynamicCargoName)
|
||||
|
||||
-- Inherit everything from BASE class.
|
||||
local self=BASE:Inherit(self, BASE:New()) -- #STORAGE
|
||||
|
||||
self.airbase=Unit.getByName(DynamicCargoName) or StaticObject.getByName(DynamicCargoName)
|
||||
|
||||
if Airbase.getWarehouse then
|
||||
self.warehouse=Warehouse.getCargoAsWarehouse(self.airbase)
|
||||
end
|
||||
|
||||
self.lid = string.format("STORAGE %s | ", DynamicCargoName)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Find a STORAGE in the **_DATABASE** using the name associated airbase.
|
||||
--- Airbases only - Find a STORAGE in the **_DATABASE** using the name associated airbase.
|
||||
-- @param #STORAGE self
|
||||
-- @param #string AirbaseName The Airbase Name.
|
||||
-- @return #STORAGE self
|
||||
@@ -198,6 +296,10 @@ end
|
||||
-- @return #STORAGE self
|
||||
function STORAGE:SetVerbosity(VerbosityLevel)
|
||||
self.verbose=VerbosityLevel or 0
|
||||
if self.verbose > 1 then
|
||||
BASE:TraceOn()
|
||||
BASE:TraceClass("STORAGE")
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -406,7 +508,7 @@ end
|
||||
--- Returns whether a given type of aircraft, liquid, weapon is set to be unlimited.
|
||||
-- @param #STORAGE self
|
||||
-- @param #string Type Name of aircraft, weapon or equipment or type of liquid (as `#number`).
|
||||
-- @return #boolen If `true` the given type is unlimited or `false` otherwise.
|
||||
-- @return #boolean If `true` the given type is unlimited or `false` otherwise.
|
||||
function STORAGE:IsUnlimited(Type)
|
||||
|
||||
-- Get current amount of type.
|
||||
@@ -423,7 +525,7 @@ function STORAGE:IsUnlimited(Type)
|
||||
local n=self:GetAmount(Type)
|
||||
|
||||
-- If amount did not change, it is unlimited.
|
||||
unlimited=n==N
|
||||
unlimited=unlimited or n > 2^29 or n==N
|
||||
|
||||
-- Add item back.
|
||||
if not unlimited then
|
||||
@@ -431,7 +533,7 @@ function STORAGE:IsUnlimited(Type)
|
||||
end
|
||||
|
||||
-- Debug info.
|
||||
self:I(self.lid..string.format("Type=%s: unlimited=%s (N=%d n=%d)", tostring(Type), tostring(unlimited), N, n))
|
||||
self:T(self.lid..string.format("Type=%s: unlimited=%s (N=%d n=%d)", tostring(Type), tostring(unlimited), N, n))
|
||||
end
|
||||
|
||||
return unlimited
|
||||
@@ -440,7 +542,7 @@ end
|
||||
--- Returns whether a given type of aircraft, liquid, weapon is set to be limited.
|
||||
-- @param #STORAGE self
|
||||
-- @param #number Type Type of liquid or name of aircraft, weapon or equipment.
|
||||
-- @return #boolen If `true` the given type is limited or `false` otherwise.
|
||||
-- @return #boolean If `true` the given type is limited or `false` otherwise.
|
||||
function STORAGE:IsLimited(Type)
|
||||
|
||||
local limited=not self:IsUnlimited(Type)
|
||||
@@ -450,7 +552,7 @@ end
|
||||
|
||||
--- Returns whether aircraft are unlimited.
|
||||
-- @param #STORAGE self
|
||||
-- @return #boolen If `true` aircraft are unlimited or `false` otherwise.
|
||||
-- @return #boolean If `true` aircraft are unlimited or `false` otherwise.
|
||||
function STORAGE:IsUnlimitedAircraft()
|
||||
|
||||
-- We test with a specific type but if it is unlimited, than all aircraft are.
|
||||
@@ -461,7 +563,7 @@ end
|
||||
|
||||
--- Returns whether liquids are unlimited.
|
||||
-- @param #STORAGE self
|
||||
-- @return #boolen If `true` liquids are unlimited or `false` otherwise.
|
||||
-- @return #boolean If `true` liquids are unlimited or `false` otherwise.
|
||||
function STORAGE:IsUnlimitedLiquids()
|
||||
|
||||
-- We test with a specific type but if it is unlimited, than all are.
|
||||
@@ -472,7 +574,7 @@ end
|
||||
|
||||
--- Returns whether weapons and equipment are unlimited.
|
||||
-- @param #STORAGE self
|
||||
-- @return #boolen If `true` weapons and equipment are unlimited or `false` otherwise.
|
||||
-- @return #boolean If `true` weapons and equipment are unlimited or `false` otherwise.
|
||||
function STORAGE:IsUnlimitedWeapons()
|
||||
|
||||
-- We test with a specific type but if it is unlimited, than all are.
|
||||
@@ -483,7 +585,7 @@ end
|
||||
|
||||
--- Returns whether aircraft are limited.
|
||||
-- @param #STORAGE self
|
||||
-- @return #boolen If `true` aircraft are limited or `false` otherwise.
|
||||
-- @return #boolean If `true` aircraft are limited or `false` otherwise.
|
||||
function STORAGE:IsLimitedAircraft()
|
||||
|
||||
-- We test with a specific type but if it is limited, than all are.
|
||||
@@ -494,7 +596,7 @@ end
|
||||
|
||||
--- Returns whether liquids are limited.
|
||||
-- @param #STORAGE self
|
||||
-- @return #boolen If `true` liquids are limited or `false` otherwise.
|
||||
-- @return #boolean If `true` liquids are limited or `false` otherwise.
|
||||
function STORAGE:IsLimitedLiquids()
|
||||
|
||||
-- We test with a specific type but if it is limited, than all are.
|
||||
@@ -505,7 +607,7 @@ end
|
||||
|
||||
--- Returns whether weapons and equipment are limited.
|
||||
-- @param #STORAGE self
|
||||
-- @return #boolen If `true` liquids are limited or `false` otherwise.
|
||||
-- @return #boolean If `true` liquids are limited or `false` otherwise.
|
||||
function STORAGE:IsLimitedWeapons()
|
||||
|
||||
-- We test with a specific type but if it is limited, than all are.
|
||||
@@ -527,6 +629,247 @@ function STORAGE:GetInventory(Item)
|
||||
return inventory.aircraft, inventory.liquids, inventory.weapon
|
||||
end
|
||||
|
||||
--- Save the contents of a STORAGE to files in CSV format. Filenames created are the Filename given amended by "_Liquids", "_Aircraft" and "_Weapons" followed by a ".csv". Requires io and lfs to be desanitized to be working.
|
||||
-- @param #STORAGE self
|
||||
-- @param #string Path The path to use. Use double backslashes \\\\ on Windows filesystems.
|
||||
-- @param #string Filename The base name of the files. Existing files will be overwritten.
|
||||
-- @return #STORAGE self
|
||||
function STORAGE:SaveToFile(Path,Filename)
|
||||
|
||||
if not io then
|
||||
BASE:E("ERROR: io not desanitized. Can't save the files.")
|
||||
return false
|
||||
end
|
||||
|
||||
-- Check default path.
|
||||
if Path==nil and not lfs then
|
||||
BASE:E("WARNING: lfs not desanitized. File will be saved in DCS installation root directory rather than your given path.")
|
||||
end
|
||||
|
||||
local ac, lq, wp = self:GetInventory()
|
||||
local DataAircraft = ""
|
||||
local DataLiquids = ""
|
||||
local DataWeapons = ""
|
||||
|
||||
if #lq > 0 then
|
||||
DataLiquids = DataLiquids .."Liquids in Storage:\n"
|
||||
for key,amount in pairs(lq) do
|
||||
DataLiquids = DataLiquids..tostring(key).."="..tostring(amount).."\n"
|
||||
end
|
||||
UTILS.SaveToFile(Path,Filename.."_Liquids.csv",DataLiquids)
|
||||
if self.verbose and self.verbose > 0 then
|
||||
self:I(self.lid.."Saving Liquids to "..tostring(Path).."\\"..tostring(Filename).."_Liquids.csv")
|
||||
end
|
||||
end
|
||||
|
||||
if UTILS.TableLength(ac) > 0 then
|
||||
DataAircraft = DataAircraft .."Aircraft in Storage:\n"
|
||||
for key,amount in pairs(ac) do
|
||||
DataAircraft = DataAircraft..tostring(key).."="..tostring(amount).."\n"
|
||||
end
|
||||
UTILS.SaveToFile(Path,Filename.."_Aircraft.csv",DataAircraft)
|
||||
if self.verbose and self.verbose > 0 then
|
||||
self:I(self.lid.."Saving Aircraft to "..tostring(Path).."\\"..tostring(Filename).."_Aircraft.csv")
|
||||
end
|
||||
end
|
||||
|
||||
if UTILS.TableLength(wp) > 0 then
|
||||
DataWeapons = DataWeapons .."Weapons and Materiel in Storage:\n"
|
||||
|
||||
for _,_category in pairs(ENUMS.Storage.weapons) do
|
||||
for _,_key in pairs(_category) do
|
||||
local amount = self:GetAmount(_key)
|
||||
if type(_key) == "table" then
|
||||
_key = "{"..table.concat(_key,",").."}"
|
||||
end
|
||||
DataWeapons = DataWeapons..tostring(_key).."="..tostring(amount).."\n"
|
||||
end
|
||||
end
|
||||
|
||||
-- Gazelle table keys
|
||||
for key,amount in pairs(ENUMS.Storage.weapons.Gazelle) do
|
||||
amount = self:GetItemAmount(ENUMS.Storage.weapons.Gazelle[key])
|
||||
DataWeapons = DataWeapons.."ENUMS.Storage.weapons.Gazelle."..tostring(key).."="..tostring(amount).."\n"
|
||||
end
|
||||
-- CH47
|
||||
for key,amount in pairs(ENUMS.Storage.weapons.CH47) do
|
||||
amount = self:GetItemAmount(ENUMS.Storage.weapons.CH47[key])
|
||||
DataWeapons = DataWeapons.."ENUMS.Storage.weapons.CH47."..tostring(key).."="..tostring(amount).."\n"
|
||||
end
|
||||
-- UH1H
|
||||
for key,amount in pairs(ENUMS.Storage.weapons.UH1H) do
|
||||
amount = self:GetItemAmount(ENUMS.Storage.weapons.UH1H[key])
|
||||
DataWeapons = DataWeapons.."ENUMS.Storage.weapons.UH1H."..tostring(key).."="..tostring(amount).."\n"
|
||||
end
|
||||
-- OH58D
|
||||
for key,amount in pairs(ENUMS.Storage.weapons.OH58) do
|
||||
amount = self:GetItemAmount(ENUMS.Storage.weapons.OH58[key])
|
||||
DataWeapons = DataWeapons.."ENUMS.Storage.weapons.OH58."..tostring(key).."="..tostring(amount).."\n"
|
||||
end
|
||||
-- AH64D
|
||||
for key,amount in pairs(ENUMS.Storage.weapons.AH64D) do
|
||||
amount = self:GetItemAmount(ENUMS.Storage.weapons.AH64D[key])
|
||||
DataWeapons = DataWeapons.."ENUMS.Storage.weapons.AH64D."..tostring(key).."="..tostring(amount).."\n"
|
||||
end
|
||||
UTILS.SaveToFile(Path,Filename.."_Weapons.csv",DataWeapons)
|
||||
if self.verbose and self.verbose > 0 then
|
||||
self:I(self.lid.."Saving Weapons to "..tostring(Path).."\\"..tostring(Filename).."_Weapons.csv")
|
||||
end
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Load the contents of a STORAGE from files. Filenames searched for are the Filename given amended by "_Liquids", "_Aircraft" and "_Weapons" followed by a ".csv". Requires io and lfs to be desanitized to be working.
|
||||
-- @param #STORAGE self
|
||||
-- @param #string Path The path to use. Use double backslashes \\\\ on Windows filesystems.
|
||||
-- @param #string Filename The name of the file.
|
||||
-- @return #STORAGE self
|
||||
function STORAGE:LoadFromFile(Path,Filename)
|
||||
|
||||
if not io then
|
||||
BASE:E("ERROR: io not desanitized. Can't read the files.")
|
||||
return false
|
||||
end
|
||||
|
||||
-- Check default path.
|
||||
if Path==nil and not lfs then
|
||||
BASE:E("WARNING: lfs not desanitized. File will be read from DCS installation root directory rather than your give path.")
|
||||
end
|
||||
|
||||
--Liquids
|
||||
if self:IsLimitedLiquids() then
|
||||
local Ok,Liquids = UTILS.LoadFromFile(Path,Filename.."_Liquids.csv")
|
||||
if Ok then
|
||||
if self.verbose and self.verbose > 0 then
|
||||
self:I(self.lid.."Loading Liquids from "..tostring(Path).."\\"..tostring(Filename).."_Liquids.csv")
|
||||
end
|
||||
for _id,_line in pairs(Liquids) do
|
||||
if string.find(_line,"Storage") == nil then
|
||||
local tbl=UTILS.Split(_line,"=")
|
||||
local lqno = tonumber(tbl[1])
|
||||
local lqam = tonumber(tbl[2])
|
||||
self:SetLiquid(lqno,lqam)
|
||||
end
|
||||
end
|
||||
else
|
||||
self:E("File for Liquids could not be found: "..tostring(Path).."\\"..tostring(Filename"_Liquids.csv"))
|
||||
end
|
||||
end
|
||||
|
||||
--Aircraft
|
||||
if self:IsLimitedAircraft() then
|
||||
local Ok,Aircraft = UTILS.LoadFromFile(Path,Filename.."_Aircraft.csv")
|
||||
if Ok then
|
||||
if self.verbose and self.verbose > 0 then
|
||||
self:I(self.lid.."Loading Aircraft from "..tostring(Path).."\\"..tostring(Filename).."_Aircraft.csv")
|
||||
end
|
||||
for _id,_line in pairs(Aircraft) do
|
||||
if string.find(_line,"Storage") == nil then
|
||||
local tbl=UTILS.Split(_line,"=")
|
||||
local acname = tbl[1]
|
||||
local acnumber = tonumber(tbl[2])
|
||||
self:SetAmount(acname,acnumber)
|
||||
end
|
||||
end
|
||||
else
|
||||
self:E("File for Aircraft could not be found: "..tostring(Path).."\\"..tostring(Filename"_Aircraft.csv"))
|
||||
end
|
||||
end
|
||||
|
||||
--Weapons
|
||||
if self:IsLimitedWeapons() then
|
||||
local Ok,Weapons = UTILS.LoadFromFile(Path,Filename.."_Weapons.csv")
|
||||
if Ok then
|
||||
if self.verbose and self.verbose > 0 then
|
||||
self:I(self.lid.."Loading Weapons from "..tostring(Path).."\\"..tostring(Filename).."_Weapons.csv")
|
||||
end
|
||||
for _id,_line in pairs(Weapons) do
|
||||
if string.find(_line,"Storage") == nil then
|
||||
local tbl=UTILS.Split(_line,"=")
|
||||
local wpname = tbl[1]
|
||||
local wpnumber = tonumber(tbl[2])
|
||||
if string.find(wpname,"{") == 1 then
|
||||
--self:I("Found a table: "..wpname)
|
||||
wpname = string.gsub(wpname,"{","")
|
||||
wpname = string.gsub(wpname,"}","")
|
||||
local tbl = UTILS.Split(wpname,",")
|
||||
local wptbl = {}
|
||||
for _id,_key in ipairs(tbl) do
|
||||
table.insert(wptbl,_id,_key)
|
||||
end
|
||||
self:SetAmount(wptbl,wpnumber)
|
||||
else
|
||||
self:SetAmount(wpname,wpnumber)
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
self:E("File for Weapons could not be found: "..tostring(Path).."\\"..tostring(Filename"_Weapons.csv"))
|
||||
end
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Start a STORAGE autosave process.
|
||||
-- @param #STORAGE self
|
||||
-- @param #string Path The path to use. Use double backslashes \\\\ on Windows filesystems.
|
||||
-- @param #string Filename The name of the file.
|
||||
-- @param #number Interval The interval, start after this many seconds and repeat every interval seconds. Defaults to 300.
|
||||
-- @param #boolean LoadOnce If LoadOnce is true or nil, we try to load saved storage first.
|
||||
-- @return #STORAGE self
|
||||
function STORAGE:StartAutoSave(Path,Filename,Interval,LoadOnce)
|
||||
if LoadOnce ~= false then
|
||||
self:LoadFromFile(Path,Filename)
|
||||
end
|
||||
local interval = Interval or 300
|
||||
self.SaverTimer = TIMER:New(STORAGE.SaveToFile,self,Path,Filename)
|
||||
self.SaverTimer:Start(interval,interval)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Stop a running STORAGE autosave process.
|
||||
-- @param #STORAGE self
|
||||
-- @return #STORAGE self
|
||||
function STORAGE:StopAutoSave()
|
||||
if self.SaverTimer and self.SaverTimer:IsRunning() then
|
||||
self.SaverTimer:Stop()
|
||||
self.SaverTimer = nil
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- Try to find the #STORAGE object of one of the many "H"-Helipads in Syria. You need to put a (small, round) zone on top of it, because the name is not unique(!).
|
||||
-- @param #STORAGE self
|
||||
-- @param #string ZoneName The name of the zone where to find the helipad.
|
||||
-- @return #STORAGE self or nil if not found.
|
||||
function STORAGE:FindSyriaHHelipadWarehouse(ZoneName)
|
||||
local findzone = ZONE:New(ZoneName)
|
||||
local base = world.getAirbases()
|
||||
for i = 1, #base do
|
||||
local info = {}
|
||||
--info.desc = Airbase.getDesc(base[i])
|
||||
info.callsign = Airbase.getCallsign(base[i])
|
||||
info.id = Airbase.getID(base[i])
|
||||
--info.cat = Airbase.getCategory(base[i])
|
||||
info.point = Airbase.getPoint(base[i])
|
||||
info.coordinate = COORDINATE:NewFromVec3(info.point)
|
||||
info.DCSObject = base[i]
|
||||
--if Airbase.getUnit(base[i]) then
|
||||
--info.unitId = Airbase.getUnit(base[i]):getID()
|
||||
--end
|
||||
if info.callsign == "H" and findzone:IsCoordinateInZone(info.coordinate) then
|
||||
info.warehouse = info.DCSObject:getWarehouse()
|
||||
info.Storage = STORAGE:New(info.callsign..info.id)
|
||||
info.Storage.airbase = info.DCSObject
|
||||
info.Storage.warehouse = info.warehouse
|
||||
return info.Storage
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Private Functions
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -385,24 +385,26 @@ function WEAPON:GetTarget()
|
||||
|
||||
--Target name
|
||||
local name=object:getName()
|
||||
|
||||
-- Debug info.
|
||||
self:T(self.lid..string.format("Got Target Object %s, category=%d", object:getName(), category))
|
||||
|
||||
if category==Object.Category.UNIT then
|
||||
|
||||
target=UNIT:FindByName(name)
|
||||
|
||||
elseif category==Object.Category.STATIC then
|
||||
|
||||
target=STATIC:FindByName(name, false)
|
||||
|
||||
elseif category==Object.Category.SCENERY then
|
||||
self:E(self.lid..string.format("ERROR: Scenery target not implemented yet!"))
|
||||
else
|
||||
self:E(self.lid..string.format("ERROR: Object category=%d is not implemented yet!", category))
|
||||
|
||||
if name then
|
||||
|
||||
-- Debug info.
|
||||
self:T(self.lid..string.format("Got Target Object %s, category=%d", name, category))
|
||||
|
||||
if category==Object.Category.UNIT then
|
||||
|
||||
target=UNIT:FindByName(name)
|
||||
|
||||
elseif category==Object.Category.STATIC then
|
||||
|
||||
target=STATIC:FindByName(name, false)
|
||||
|
||||
elseif category==Object.Category.SCENERY then
|
||||
self:E(self.lid..string.format("ERROR: Scenery target not implemented yet!"))
|
||||
else
|
||||
self:E(self.lid..string.format("ERROR: Object category=%d is not implemented yet!", category))
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user