From 0392417189bdbafd13d92a8505771433466d329b Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Fri, 18 Apr 2025 14:43:03 +0200 Subject: [PATCH 001/234] Germany CW Bases --- Moose Development/Moose/Wrapper/Airbase.lua | 82 +++++++++++---------- 1 file changed, 43 insertions(+), 39 deletions(-) diff --git a/Moose Development/Moose/Wrapper/Airbase.lua b/Moose Development/Moose/Wrapper/Airbase.lua index 206b4a5b6..7785fafcb 100644 --- a/Moose Development/Moose/Wrapper/Airbase.lua +++ b/Moose Development/Moose/Wrapper/Airbase.lua @@ -911,12 +911,12 @@ AIRBASE.Iraq = { --- Airbases of the Germany Cold War map -- * AIRBASE.GermanyCW.Airracing_Frankfurt +-- * AIRBASE.GermanyCW.Airracing_Frankfurt -- * AIRBASE.GermanyCW.Airracing_Koblenz --- * AIRBASE.GermanyCW.Airracing_Luebeck +-- * AIRBASE.GermanyCW.Airracing_Lubeck -- * AIRBASE.GermanyCW.Allstedt --- * AIRBASE.GermanyCW.Alt_Daber -- * AIRBASE.GermanyCW.Altes_Lager --- * AIRBASE.GermanyCW.Bad_Duerkheim +-- * AIRBASE.GermanyCW.Bad_Durkheim -- * AIRBASE.GermanyCW.Barth -- * AIRBASE.GermanyCW.Bienenfarm -- * AIRBASE.GermanyCW.Bindersleben @@ -924,8 +924,8 @@ AIRBASE.Iraq = { -- * AIRBASE.GermanyCW.Braunschweig -- * AIRBASE.GermanyCW.Bremen -- * AIRBASE.GermanyCW.Briest --- * AIRBASE.GermanyCW.Buechel --- * AIRBASE.GermanyCW.Bueckeburg +-- * AIRBASE.GermanyCW.Buchel +-- * AIRBASE.GermanyCW.Buckeburg -- * AIRBASE.GermanyCW.Celle -- * AIRBASE.GermanyCW.Cochstedt -- * AIRBASE.GermanyCW.Damgarten @@ -937,15 +937,14 @@ AIRBASE.Iraq = { -- * AIRBASE.GermanyCW.Fritzlar -- * AIRBASE.GermanyCW.Fulda -- * AIRBASE.GermanyCW.Gardelegen +-- * AIRBASE.GermanyCW.Garz -- * AIRBASE.GermanyCW.Gatow -- * AIRBASE.GermanyCW.Gelnhausen -- * AIRBASE.GermanyCW.Giebelstadt --- * AIRBASE.GermanyCW.Glindbruchkippe --- * AIRBASE.GermanyCW.Gross_Doelln +-- * AIRBASE.GermanyCW.Glindbruchkippe_ -- * AIRBASE.GermanyCW.Gross_Mohrdorf -- * AIRBASE.GermanyCW.Grosse_Wiese --- * AIRBASE.GermanyCW.Gaerz --- * AIRBASE.GermanyCW.Guetersloh +-- * AIRBASE.GermanyCW.Gutersloh -- * AIRBASE.GermanyCW.H_FRG_01 -- * AIRBASE.GermanyCW.H_FRG_02 -- * AIRBASE.GermanyCW.H_FRG_03 @@ -994,7 +993,7 @@ AIRBASE.Iraq = { -- * AIRBASE.GermanyCW.H_GDR_04 -- * AIRBASE.GermanyCW.H_GDR_05 -- * AIRBASE.GermanyCW.H_GDR_06 --- * AIRBASE.GermanyCW.H_GDR_07 +-- * AIRBASE.GermanyCW.H_GDR_07 -- * AIRBASE.GermanyCW.H_GDR_08 -- * AIRBASE.GermanyCW.H_GDR_09 -- * AIRBASE.GermanyCW.H_GDR_10 @@ -1016,10 +1015,11 @@ AIRBASE.Iraq = { -- * AIRBASE.GermanyCW.H_GDR_31 -- * AIRBASE.GermanyCW.H_GDR_32 -- * AIRBASE.GermanyCW.H_GDR_33 +-- * AIRBASE.GermanyCW.H_GDR_34 +-- * AIRBASE.GermanyCW.H_Med_FRG_01 -- * AIRBASE.GermanyCW.H_Med_FRG_02 -- * AIRBASE.GermanyCW.H_Med_FRG_04 -- * AIRBASE.GermanyCW.H_Med_FRG_06 --- * AIRBASE.GermanyCW.H_Med_FRG_09 -- * AIRBASE.GermanyCW.H_Med_FRG_11 -- * AIRBASE.GermanyCW.H_Med_FRG_12 -- * AIRBASE.GermanyCW.H_Med_FRG_13 @@ -1064,37 +1064,38 @@ AIRBASE.Iraq = { -- * AIRBASE.GermanyCW.Hockenheim -- * AIRBASE.GermanyCW.Holzdorf -- * AIRBASE.GermanyCW.Kammermark --- * AIRBASE.GermanyCW.Koethen +-- * AIRBASE.GermanyCW.Kothen -- * AIRBASE.GermanyCW.Laage -- * AIRBASE.GermanyCW.Langenselbold +-- * AIRBASE.GermanyCW.Larz -- * AIRBASE.GermanyCW.Leipzig_Halle -- * AIRBASE.GermanyCW.Leipzig_Mockau --- * AIRBASE.GermanyCW.Laerz --- * AIRBASE.GermanyCW.Luebeck --- * AIRBASE.GermanyCW.Lueneburg +-- * AIRBASE.GermanyCW.Lubeck +-- * AIRBASE.GermanyCW.Luneburg -- * AIRBASE.GermanyCW.Mahlwinkel -- * AIRBASE.GermanyCW.Mendig -- * AIRBASE.GermanyCW.Merseburg -- * AIRBASE.GermanyCW.Neubrandenburg -- * AIRBASE.GermanyCW.Neuruppin -- * AIRBASE.GermanyCW.Northeim --- * AIRBASE.GermanyCW.Ober_Moerlen +-- * AIRBASE.GermanyCW.Ober_Morlen -- * AIRBASE.GermanyCW.Obermehler_Schlotheim -- * AIRBASE.GermanyCW.Parchim --- * AIRBASE.GermanyCW.Peenemuende +-- * AIRBASE.GermanyCW.Peenemunde -- * AIRBASE.GermanyCW.Pferdsfeld -- * AIRBASE.GermanyCW.Pinnow --- * AIRBASE.GermanyCW.Pottschutthoehe +-- * AIRBASE.GermanyCW.Pottschutthohe -- * AIRBASE.GermanyCW.Ramstein -- * AIRBASE.GermanyCW.Rinteln +-- * AIRBASE.GermanyCW.Schonefeld -- * AIRBASE.GermanyCW.Schweinfurt --- * AIRBASE.GermanyCW.Schoenefeld -- * AIRBASE.GermanyCW.Sembach -- * AIRBASE.GermanyCW.Spangdahlem -- * AIRBASE.GermanyCW.Sperenberg -- * AIRBASE.GermanyCW.Stendal -- * AIRBASE.GermanyCW.Tegel -- * AIRBASE.GermanyCW.Tempelhof +-- * AIRBASE.GermanyCW.Templin -- * AIRBASE.GermanyCW.Tutow -- * AIRBASE.GermanyCW.Uelzen -- * AIRBASE.GermanyCW.Uetersen @@ -1103,23 +1104,23 @@ AIRBASE.Iraq = { -- * AIRBASE.GermanyCW.Walldorf -- * AIRBASE.GermanyCW.Waren_Vielist -- * AIRBASE.GermanyCW.Werneuchen --- * AIRBASE.GermanyCW.Weser_Wuemme +-- * AIRBASE.GermanyCW.Weser_Wumme -- * AIRBASE.GermanyCW.Wiesbaden -- * AIRBASE.GermanyCW.Wismar +-- * AIRBASE.GermanyCW.Wittstock -- * AIRBASE.GermanyCW.Worms -- * AIRBASE.GermanyCW.Wunstorf -- * AIRBASE.GermanyCW.Zerbst --- * AIRBASE.GermanyCW.Zweibruecken +-- * AIRBASE.GermanyCW.Zweibrucken -- -- @field GermanyCW AIRBASE.GermanyCW = { ["Airracing_Frankfurt"] = "Airracing Frankfurt", ["Airracing_Koblenz"] = "Airracing Koblenz", - ["Airracing_Luebeck"] = "Airracing Lubeck", + ["Airracing_Lubeck"] = "Airracing Lubeck", ["Allstedt"] = "Allstedt", - ["Alt_Daber"] = "Alt Daber", ["Altes_Lager"] = "Altes Lager", - ["Bad_Duerkheim"] = "Bad Durkheim", + ["Bad_Durkheim"] = "Bad Durkheim", ["Barth"] = "Barth", ["Bienenfarm"] = "Bienenfarm", ["Bindersleben"] = "Bindersleben", @@ -1127,8 +1128,8 @@ AIRBASE.GermanyCW = { ["Braunschweig"] = "Braunschweig", ["Bremen"] = "Bremen", ["Briest"] = "Briest", - ["Buechel"] = "Buchel", - ["Bueckeburg"] = "Buckeburg", + ["Buchel"] = "Buchel", + ["Buckeburg"] = "Buckeburg", ["Celle"] = "Celle", ["Cochstedt"] = "Cochstedt", ["Damgarten"] = "Damgarten", @@ -1140,15 +1141,14 @@ AIRBASE.GermanyCW = { ["Fritzlar"] = "Fritzlar", ["Fulda"] = "Fulda", ["Gardelegen"] = "Gardelegen", + ["Garz"] = "Garz", ["Gatow"] = "Gatow", ["Gelnhausen"] = "Gelnhausen", ["Giebelstadt"] = "Giebelstadt", ["Glindbruchkippe_"] = "Glindbruchkippe ", - ["Gross_Doelln"] = "Gross Dolln", ["Gross_Mohrdorf"] = "Gross Mohrdorf", ["Grosse_Wiese"] = "Grosse Wiese", - ["Gaerz"] = "Garz", - ["Guetersloh"] = "Gutersloh", + ["Gutersloh"] = "Gutersloh", ["H_FRG_01"] = "H FRG 01", ["H_FRG_02"] = "H FRG 02", ["H_FRG_03"] = "H FRG 03", @@ -1219,10 +1219,11 @@ AIRBASE.GermanyCW = { ["H_GDR_31"] = "H GDR 31", ["H_GDR_32"] = "H GDR 32", ["H_GDR_33"] = "H GDR 33", + ["H_GDR_34"] = "H GDR 34", + ["H_Med_FRG_01"] = "H Med FRG 01", ["H_Med_FRG_02"] = "H Med FRG 02", ["H_Med_FRG_04"] = "H Med FRG 04", ["H_Med_FRG_06"] = "H Med FRG 06", - ["H_Med_FRG_09"] = "H Med FRG 09", ["H_Med_FRG_11"] = "H Med FRG 11", ["H_Med_FRG_12"] = "H Med FRG 12", ["H_Med_FRG_13"] = "H Med FRG 13", @@ -1267,29 +1268,30 @@ AIRBASE.GermanyCW = { ["Hockenheim"] = "Hockenheim", ["Holzdorf"] = "Holzdorf", ["Kammermark"] = "Kammermark", - ["Koethen"] = "Kothen", + ["Kothen"] = "Kothen", ["Laage"] = "Laage", ["Langenselbold"] = "Langenselbold", + ["Larz"] = "Larz", ["Leipzig_Halle"] = "Leipzig Halle", ["Leipzig_Mockau"] = "Leipzig Mockau", - ["Laerz"] = "Larz", - ["Luebeck"] = "Lubeck", - ["Lueneburg"] = "Luneburg", + ["Lubeck"] = "Lubeck", + ["Luneburg"] = "Luneburg", ["Mahlwinkel"] = "Mahlwinkel", ["Mendig"] = "Mendig", ["Merseburg"] = "Merseburg", ["Neubrandenburg"] = "Neubrandenburg", ["Neuruppin"] = "Neuruppin", ["Northeim"] = "Northeim", - ["Ober_Moerlen"] = "Ober-Morlen", + ["Ober_Morlen"] = "Ober-Morlen", ["Obermehler_Schlotheim"] = "Obermehler Schlotheim", ["Parchim"] = "Parchim", - ["Peenemuende"] = "Peenemunde", + ["Peenemunde"] = "Peenemunde", ["Pferdsfeld"] = "Pferdsfeld", ["Pinnow"] = "Pinnow", - ["Pottschutthoehe"] = "Pottschutthohe", + ["Pottschutthohe"] = "Pottschutthohe", ["Ramstein"] = "Ramstein", ["Rinteln"] = "Rinteln", + ["Schonefeld"] = "Schonefeld", ["Schweinfurt"] = "Schweinfurt", ["Schoenefeld"] = "Schonefeld", ["Sembach"] = "Sembach", @@ -1298,6 +1300,7 @@ AIRBASE.GermanyCW = { ["Stendal"] = "Stendal", ["Tegel"] = "Tegel", ["Tempelhof"] = "Tempelhof", + ["Templin"] = "Templin", ["Tutow"] = "Tutow", ["Uelzen"] = "Uelzen", ["Uetersen"] = "Uetersen", @@ -1306,13 +1309,14 @@ AIRBASE.GermanyCW = { ["Walldorf"] = "Walldorf", ["Waren_Vielist"] = "Waren Vielist", ["Werneuchen"] = "Werneuchen", - ["Weser_Wuemme"] = "Weser Wumme", + ["Weser_Wumme"] = "Weser Wumme", ["Wiesbaden"] = "Wiesbaden", ["Wismar"] = "Wismar", + ["Wittstock"] = "Wittstock", ["Worms"] = "Worms", ["Wunstorf"] = "Wunstorf", ["Zerbst"] = "Zerbst", - ["Zweibruecken"] = "Zweibrucken", + ["Zweibrucken"] = "Zweibrucken", } From d1ae2c0f5e35aff86f398f67f1dffc29533fc6ea Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Fri, 18 Apr 2025 16:01:55 +0200 Subject: [PATCH 002/234] xx --- Moose Development/Moose/Wrapper/Airbase.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/Wrapper/Airbase.lua b/Moose Development/Moose/Wrapper/Airbase.lua index 7785fafcb..d36cff246 100644 --- a/Moose Development/Moose/Wrapper/Airbase.lua +++ b/Moose Development/Moose/Wrapper/Airbase.lua @@ -2585,7 +2585,7 @@ function AIRBASE:_InitRunways(IncludeInverse) runway.name=string.format("%02d", tonumber(namefromheading)) else runway.name=string.format("%02d", tonumber(name)) - self:I("RunwayName: "..runway.name) + --self:I("RunwayName: "..runway.name) end --runway.name=string.format("%02d", tonumber(name)) From 207698a2dd50f6590be39f1beec25d8185d3d980 Mon Sep 17 00:00:00 2001 From: Frank Date: Fri, 18 Apr 2025 17:40:55 +0200 Subject: [PATCH 003/234] Update Airbase.lua - Germany map readded Umlaute in keys --- Moose Development/Moose/Wrapper/Airbase.lua | 55 ++++++++++----------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/Moose Development/Moose/Wrapper/Airbase.lua b/Moose Development/Moose/Wrapper/Airbase.lua index d36cff246..8afbc8d45 100644 --- a/Moose Development/Moose/Wrapper/Airbase.lua +++ b/Moose Development/Moose/Wrapper/Airbase.lua @@ -913,10 +913,10 @@ AIRBASE.Iraq = { -- * AIRBASE.GermanyCW.Airracing_Frankfurt -- * AIRBASE.GermanyCW.Airracing_Frankfurt -- * AIRBASE.GermanyCW.Airracing_Koblenz --- * AIRBASE.GermanyCW.Airracing_Lubeck +-- * AIRBASE.GermanyCW.Airracing_Luebeck -- * AIRBASE.GermanyCW.Allstedt -- * AIRBASE.GermanyCW.Altes_Lager --- * AIRBASE.GermanyCW.Bad_Durkheim +-- * AIRBASE.GermanyCW.Bad_Duerkheim -- * AIRBASE.GermanyCW.Barth -- * AIRBASE.GermanyCW.Bienenfarm -- * AIRBASE.GermanyCW.Bindersleben @@ -924,8 +924,8 @@ AIRBASE.Iraq = { -- * AIRBASE.GermanyCW.Braunschweig -- * AIRBASE.GermanyCW.Bremen -- * AIRBASE.GermanyCW.Briest --- * AIRBASE.GermanyCW.Buchel --- * AIRBASE.GermanyCW.Buckeburg +-- * AIRBASE.GermanyCW.Buechel +-- * AIRBASE.GermanyCW.Bueckeburg -- * AIRBASE.GermanyCW.Celle -- * AIRBASE.GermanyCW.Cochstedt -- * AIRBASE.GermanyCW.Damgarten @@ -941,10 +941,10 @@ AIRBASE.Iraq = { -- * AIRBASE.GermanyCW.Gatow -- * AIRBASE.GermanyCW.Gelnhausen -- * AIRBASE.GermanyCW.Giebelstadt --- * AIRBASE.GermanyCW.Glindbruchkippe_ +-- * AIRBASE.GermanyCW.Glindbruchkippe_ -- * AIRBASE.GermanyCW.Gross_Mohrdorf -- * AIRBASE.GermanyCW.Grosse_Wiese --- * AIRBASE.GermanyCW.Gutersloh +-- * AIRBASE.GermanyCW.Guetersloh -- * AIRBASE.GermanyCW.H_FRG_01 -- * AIRBASE.GermanyCW.H_FRG_02 -- * AIRBASE.GermanyCW.H_FRG_03 @@ -1064,14 +1064,14 @@ AIRBASE.Iraq = { -- * AIRBASE.GermanyCW.Hockenheim -- * AIRBASE.GermanyCW.Holzdorf -- * AIRBASE.GermanyCW.Kammermark --- * AIRBASE.GermanyCW.Kothen +-- * AIRBASE.GermanyCW.Koethen -- * AIRBASE.GermanyCW.Laage -- * AIRBASE.GermanyCW.Langenselbold --- * AIRBASE.GermanyCW.Larz +-- * AIRBASE.GermanyCW.Laerz -- * AIRBASE.GermanyCW.Leipzig_Halle -- * AIRBASE.GermanyCW.Leipzig_Mockau --- * AIRBASE.GermanyCW.Lubeck --- * AIRBASE.GermanyCW.Luneburg +-- * AIRBASE.GermanyCW.Luebeck +-- * AIRBASE.GermanyCW.Lueneburg -- * AIRBASE.GermanyCW.Mahlwinkel -- * AIRBASE.GermanyCW.Mendig -- * AIRBASE.GermanyCW.Merseburg @@ -1081,13 +1081,13 @@ AIRBASE.Iraq = { -- * AIRBASE.GermanyCW.Ober_Morlen -- * AIRBASE.GermanyCW.Obermehler_Schlotheim -- * AIRBASE.GermanyCW.Parchim --- * AIRBASE.GermanyCW.Peenemunde +-- * AIRBASE.GermanyCW.Peenemuende -- * AIRBASE.GermanyCW.Pferdsfeld -- * AIRBASE.GermanyCW.Pinnow -- * AIRBASE.GermanyCW.Pottschutthohe -- * AIRBASE.GermanyCW.Ramstein -- * AIRBASE.GermanyCW.Rinteln --- * AIRBASE.GermanyCW.Schonefeld +-- * AIRBASE.GermanyCW.Schoenefeld -- * AIRBASE.GermanyCW.Schweinfurt -- * AIRBASE.GermanyCW.Sembach -- * AIRBASE.GermanyCW.Spangdahlem @@ -1111,16 +1111,16 @@ AIRBASE.Iraq = { -- * AIRBASE.GermanyCW.Worms -- * AIRBASE.GermanyCW.Wunstorf -- * AIRBASE.GermanyCW.Zerbst --- * AIRBASE.GermanyCW.Zweibrucken +-- * AIRBASE.GermanyCW.Zweibruecken -- -- @field GermanyCW AIRBASE.GermanyCW = { ["Airracing_Frankfurt"] = "Airracing Frankfurt", ["Airracing_Koblenz"] = "Airracing Koblenz", - ["Airracing_Lubeck"] = "Airracing Lubeck", + ["Airracing_Luebeck"] = "Airracing Lubeck", ["Allstedt"] = "Allstedt", ["Altes_Lager"] = "Altes Lager", - ["Bad_Durkheim"] = "Bad Durkheim", + ["Bad_Duerkheim"] = "Bad Durkheim", ["Barth"] = "Barth", ["Bienenfarm"] = "Bienenfarm", ["Bindersleben"] = "Bindersleben", @@ -1128,8 +1128,8 @@ AIRBASE.GermanyCW = { ["Braunschweig"] = "Braunschweig", ["Bremen"] = "Bremen", ["Briest"] = "Briest", - ["Buchel"] = "Buchel", - ["Buckeburg"] = "Buckeburg", + ["Buechel"] = "Buchel", + ["Bueckeburg"] = "Buckeburg", ["Celle"] = "Celle", ["Cochstedt"] = "Cochstedt", ["Damgarten"] = "Damgarten", @@ -1145,10 +1145,10 @@ AIRBASE.GermanyCW = { ["Gatow"] = "Gatow", ["Gelnhausen"] = "Gelnhausen", ["Giebelstadt"] = "Giebelstadt", - ["Glindbruchkippe_"] = "Glindbruchkippe ", + ["Glindbruchkippe"] = "Glindbruchkippe ", ["Gross_Mohrdorf"] = "Gross Mohrdorf", ["Grosse_Wiese"] = "Grosse Wiese", - ["Gutersloh"] = "Gutersloh", + ["Guetersloh"] = "Gutersloh", ["H_FRG_01"] = "H FRG 01", ["H_FRG_02"] = "H FRG 02", ["H_FRG_03"] = "H FRG 03", @@ -1268,14 +1268,14 @@ AIRBASE.GermanyCW = { ["Hockenheim"] = "Hockenheim", ["Holzdorf"] = "Holzdorf", ["Kammermark"] = "Kammermark", - ["Kothen"] = "Kothen", + ["Koethen"] = "Kothen", ["Laage"] = "Laage", ["Langenselbold"] = "Langenselbold", - ["Larz"] = "Larz", + ["Laerz"] = "Larz", ["Leipzig_Halle"] = "Leipzig Halle", ["Leipzig_Mockau"] = "Leipzig Mockau", - ["Lubeck"] = "Lubeck", - ["Luneburg"] = "Luneburg", + ["Luebeck"] = "Lubeck", + ["Lueneburg"] = "Luneburg", ["Mahlwinkel"] = "Mahlwinkel", ["Mendig"] = "Mendig", ["Merseburg"] = "Merseburg", @@ -1285,15 +1285,14 @@ AIRBASE.GermanyCW = { ["Ober_Morlen"] = "Ober-Morlen", ["Obermehler_Schlotheim"] = "Obermehler Schlotheim", ["Parchim"] = "Parchim", - ["Peenemunde"] = "Peenemunde", + ["Peenemuende"] = "Peenemunde", ["Pferdsfeld"] = "Pferdsfeld", ["Pinnow"] = "Pinnow", - ["Pottschutthohe"] = "Pottschutthohe", + ["Pottschutthoehe"] = "Pottschutthohe", ["Ramstein"] = "Ramstein", ["Rinteln"] = "Rinteln", - ["Schonefeld"] = "Schonefeld", - ["Schweinfurt"] = "Schweinfurt", ["Schoenefeld"] = "Schonefeld", + ["Schweinfurt"] = "Schweinfurt", ["Sembach"] = "Sembach", ["Spangdahlem"] = "Spangdahlem", ["Sperenberg"] = "Sperenberg", @@ -1316,7 +1315,7 @@ AIRBASE.GermanyCW = { ["Worms"] = "Worms", ["Wunstorf"] = "Wunstorf", ["Zerbst"] = "Zerbst", - ["Zweibrucken"] = "Zweibrucken", + ["Zweibruecken"] = "Zweibrucken", } From 544db963eaa0a40c7ea0be1108905c7c77bfd5e0 Mon Sep 17 00:00:00 2001 From: Frank Date: Fri, 18 Apr 2025 17:45:43 +0200 Subject: [PATCH 004/234] Update Airbase.lua --- Moose Development/Moose/Wrapper/Airbase.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Wrapper/Airbase.lua b/Moose Development/Moose/Wrapper/Airbase.lua index 8afbc8d45..bbeff6a43 100644 --- a/Moose Development/Moose/Wrapper/Airbase.lua +++ b/Moose Development/Moose/Wrapper/Airbase.lua @@ -941,7 +941,7 @@ AIRBASE.Iraq = { -- * AIRBASE.GermanyCW.Gatow -- * AIRBASE.GermanyCW.Gelnhausen -- * AIRBASE.GermanyCW.Giebelstadt --- * AIRBASE.GermanyCW.Glindbruchkippe_ +-- * AIRBASE.GermanyCW.Glindbruchkippe -- * AIRBASE.GermanyCW.Gross_Mohrdorf -- * AIRBASE.GermanyCW.Grosse_Wiese -- * AIRBASE.GermanyCW.Guetersloh @@ -1084,7 +1084,7 @@ AIRBASE.Iraq = { -- * AIRBASE.GermanyCW.Peenemuende -- * AIRBASE.GermanyCW.Pferdsfeld -- * AIRBASE.GermanyCW.Pinnow --- * AIRBASE.GermanyCW.Pottschutthohe +-- * AIRBASE.GermanyCW.Pottschutthoehe -- * AIRBASE.GermanyCW.Ramstein -- * AIRBASE.GermanyCW.Rinteln -- * AIRBASE.GermanyCW.Schoenefeld From 2c10943cb18c2c48d231f476adb25bb0201274a0 Mon Sep 17 00:00:00 2001 From: Frank Date: Fri, 18 Apr 2025 17:50:01 +0200 Subject: [PATCH 005/234] Update Airbase.lua Germany map Umlaute --- Moose Development/Moose/Wrapper/Airbase.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Moose Development/Moose/Wrapper/Airbase.lua b/Moose Development/Moose/Wrapper/Airbase.lua index bbeff6a43..21d69a296 100644 --- a/Moose Development/Moose/Wrapper/Airbase.lua +++ b/Moose Development/Moose/Wrapper/Airbase.lua @@ -1078,7 +1078,7 @@ AIRBASE.Iraq = { -- * AIRBASE.GermanyCW.Neubrandenburg -- * AIRBASE.GermanyCW.Neuruppin -- * AIRBASE.GermanyCW.Northeim --- * AIRBASE.GermanyCW.Ober_Morlen +-- * AIRBASE.GermanyCW.Ober_Moerlen -- * AIRBASE.GermanyCW.Obermehler_Schlotheim -- * AIRBASE.GermanyCW.Parchim -- * AIRBASE.GermanyCW.Peenemuende @@ -1104,7 +1104,7 @@ AIRBASE.Iraq = { -- * AIRBASE.GermanyCW.Walldorf -- * AIRBASE.GermanyCW.Waren_Vielist -- * AIRBASE.GermanyCW.Werneuchen --- * AIRBASE.GermanyCW.Weser_Wumme +-- * AIRBASE.GermanyCW.Weser_Wuemme -- * AIRBASE.GermanyCW.Wiesbaden -- * AIRBASE.GermanyCW.Wismar -- * AIRBASE.GermanyCW.Wittstock @@ -1282,7 +1282,7 @@ AIRBASE.GermanyCW = { ["Neubrandenburg"] = "Neubrandenburg", ["Neuruppin"] = "Neuruppin", ["Northeim"] = "Northeim", - ["Ober_Morlen"] = "Ober-Morlen", + ["Ober_Moerlen"] = "Ober-Morlen", ["Obermehler_Schlotheim"] = "Obermehler Schlotheim", ["Parchim"] = "Parchim", ["Peenemuende"] = "Peenemunde", @@ -1308,7 +1308,7 @@ AIRBASE.GermanyCW = { ["Walldorf"] = "Walldorf", ["Waren_Vielist"] = "Waren Vielist", ["Werneuchen"] = "Werneuchen", - ["Weser_Wumme"] = "Weser Wumme", + ["Weser_Wuemme"] = "Weser Wumme", ["Wiesbaden"] = "Wiesbaden", ["Wismar"] = "Wismar", ["Wittstock"] = "Wittstock", From 9364579a18e51086084f285a3c8e5a989ba966f6 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sat, 19 Apr 2025 17:53:00 +0200 Subject: [PATCH 006/234] #EASYGCICAP - fixed some wrongly used self.values #OPSZONE - make check time schedule configureable --- Moose Development/Moose/Ops/EasyGCICAP.lua | 7 +++++-- Moose Development/Moose/Ops/OpsZone.lua | 9 ++++++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/Moose Development/Moose/Ops/EasyGCICAP.lua b/Moose Development/Moose/Ops/EasyGCICAP.lua index 4fcd7c2cb..31b732a74 100644 --- a/Moose Development/Moose/Ops/EasyGCICAP.lua +++ b/Moose Development/Moose/Ops/EasyGCICAP.lua @@ -259,7 +259,7 @@ EASYGCICAP = { --- EASYGCICAP class version. -- @field #string version -EASYGCICAP.version="0.1.18" +EASYGCICAP.version="0.1.20" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO list @@ -606,6 +606,9 @@ function EASYGCICAP:_AddAirwing(Airbasename, Alias) local Intel = self.Intel local TankerInvisible = self.TankerInvisible + local engagerange = self.engagerange + local GoZoneSet = self.GoZoneSet + local NoGoZoneSet = self.NoGoZoneSet function CAP_Wing:onbeforeFlightOnMission(From, Event, To, Flightgroup, Mission) local flightgroup = Flightgroup -- Ops.FlightGroup#FLIGHTGROUP @@ -619,7 +622,7 @@ function EASYGCICAP:_AddAirwing(Airbasename, Alias) flightgroup:GetGroup():SetOptionRadarUsingForContinousSearch() if Mission.type ~= AUFTRAG.Type.TANKER and Mission.type ~= AUFTRAG.Type.AWACS and Mission.type ~= AUFTRAG.Type.RECON then flightgroup:SetDetection(true) - flightgroup:SetEngageDetectedOn(self.engagerange,{"Air"},self.GoZoneSet,self.NoGoZoneSet) + flightgroup:SetEngageDetectedOn(engagerange,{"Air"},GoZoneSet,NoGoZoneSet) flightgroup:SetOutOfAAMRTB() if CapFormation then flightgroup:GetGroup():SetOption(AI.Option.Air.id.FORMATION,CapFormation) diff --git a/Moose Development/Moose/Ops/OpsZone.lua b/Moose Development/Moose/Ops/OpsZone.lua index bbcf4f97b..9a47b16ae 100644 --- a/Moose Development/Moose/Ops/OpsZone.lua +++ b/Moose Development/Moose/Ops/OpsZone.lua @@ -53,7 +53,8 @@ -- @field #number threatlevelCapture Threat level necessary to capture a zone. -- @field Core.Set#SET_UNIT ScanUnitSet Set of scanned units. -- @field Core.Set#SET_GROUP ScanGroupSet Set of scanned groups. --- @extends Core.Fsm#FSM +-- @field #number UpdateSeconds Run status every this many seconds. +-- @extends Core.Fsm#FSM --- *Gentlemen, when the enemy is committed to a mistake we must not interrupt him too soon.* --- Horation Nelson -- @@ -77,6 +78,7 @@ OPSZONE = { Tnut = 0, chiefs = {}, Missions = {}, + UpdateSeconds = 120, } --- OPSZONE.MISSION @@ -97,7 +99,7 @@ OPSZONE.ZoneType={ --- OPSZONE class version. -- @field #string version -OPSZONE.version="0.6.1" +OPSZONE.version="0.6.2" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- ToDo list @@ -733,7 +735,8 @@ function OPSZONE:onafterStart(From, Event, To) self.timerStatus=self.timerStatus or TIMER:New(OPSZONE.Status, self) -- Status update. - self.timerStatus:Start(1, 120) + local EveryUpdateIn = self.UpdateSeconds or 120 + self.timerStatus:Start(1, EveryUpdateIn) -- Handle base captured event. if self.airbase then From 9705b49dbeeeaed9273aa4e6110fa14f46d85812 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sun, 20 Apr 2025 15:52:30 +0200 Subject: [PATCH 007/234] #PLAYERTASKMANAGER - Surfaced some functions for conflict zones --- Moose Development/Moose/Ops/PlayerTask.lua | 72 ++++++++++++++++++---- 1 file changed, 59 insertions(+), 13 deletions(-) diff --git a/Moose Development/Moose/Ops/PlayerTask.lua b/Moose Development/Moose/Ops/PlayerTask.lua index 673c5095c..74d53667d 100644 --- a/Moose Development/Moose/Ops/PlayerTask.lua +++ b/Moose Development/Moose/Ops/PlayerTask.lua @@ -21,7 +21,7 @@ -- === -- @module Ops.PlayerTask -- @image OPS_PlayerTask.jpg --- @date Last Update Jan 2025 +-- @date Last Update April 2025 do @@ -1902,7 +1902,7 @@ PLAYERTASKCONTROLLER.Messages = { --- PLAYERTASK class version. -- @field #string version -PLAYERTASKCONTROLLER.version="0.1.69" +PLAYERTASKCONTROLLER.version="0.1.70" --- Create and run a new TASKCONTROLLER instance. -- @param #PLAYERTASKCONTROLLER self @@ -2415,7 +2415,7 @@ function PLAYERTASKCONTROLLER:EnablePrecisionBombing(FlightGroup,LaserCode,Holdi end ) else - self:E(self.lid.."No FLIGHTGROUP object passed or FLIGHTGROUP is not alive!") + self:E(self.lid.."No OPSGROUP/SET_OPSGROUP object passed or object is not alive!") end else self.autolase = nil @@ -3703,6 +3703,7 @@ function PLAYERTASKCONTROLLER:_ActiveTaskInfo(Task, Group, Client) else CoordText = Coordinate:ToStringA2A(Client,nil,self.ShowMagnetic) end + --self:I("CoordText = "..CoordText) -- Threat Level local ThreatLevel = task.Target:GetThreatLevelMax() --local ThreatLevelText = "high" @@ -3837,7 +3838,8 @@ function PLAYERTASKCONTROLLER:_ActiveTaskInfo(Task, Group, Client) Text = string.gsub(Text,"9","niner") CoordText = "MGRS;"..Text if self.PathToGoogleKey then - CoordText = string.format("%s",CoordText) + --CoordText = string.format("%s",CoordText) + --doesn't seem to work any longer end --self:I(self.lid.." | ".. CoordText) end @@ -3855,10 +3857,12 @@ function PLAYERTASKCONTROLLER:_ActiveTaskInfo(Task, Group, Client) CoordText = string.gsub(ttstext," BR, "," Bee, Arr, ") end elseif task:HasFreetext() then + -- add tts freetext local brieftxt = self.gettext:GetEntry("BRIEFING",self.locale) ttstext = ttstext .. string.format("; %s: ",brieftxt)..task:GetFreetextTTS() end + --self:I("**** TTS Text ****\n"..ttstext.."\n*****") self.SRSQueue:NewTransmission(ttstext,nil,self.SRS,nil,2) end else @@ -4357,7 +4361,7 @@ function PLAYERTASKCONTROLLER:SwitchDetectStatics(OnOff) return self end ---- [User] Add accept zone to INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this. +--- [User] Add an accept zone to INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this. -- @param #PLAYERTASKCONTROLLER self -- @param Core.Zone#ZONE AcceptZone Add a zone to the accept zone set. -- @return #PLAYERTASKCONTROLLER self @@ -4371,7 +4375,7 @@ function PLAYERTASKCONTROLLER:AddAcceptZone(AcceptZone) return self end ---- [User] Add accept SET_ZONE to INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this. +--- [User] Add an accept SET_ZONE to INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this. -- @param #PLAYERTASKCONTROLLER self -- @param Core.Set#SET_ZONE AcceptZoneSet Add a SET_ZONE to the accept zone set. -- @return #PLAYERTASKCONTROLLER self @@ -4385,7 +4389,7 @@ function PLAYERTASKCONTROLLER:AddAcceptZoneSet(AcceptZoneSet) return self end ---- [User] Add reject zone to INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this. +--- [User] Add a reject zone to INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this. -- @param #PLAYERTASKCONTROLLER self -- @param Core.Zone#ZONE RejectZone Add a zone to the reject zone set. -- @return #PLAYERTASKCONTROLLER self @@ -4399,7 +4403,7 @@ function PLAYERTASKCONTROLLER:AddRejectZone(RejectZone) return self end ---- [User] Add reject SET_ZONE to INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this. +--- [User] Add a reject SET_ZONE to INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this. -- @param #PLAYERTASKCONTROLLER self -- @param Core.Set#SET_ZONE RejectZoneSet Add a zone to the reject zone set. -- @return #PLAYERTASKCONTROLLER self @@ -4413,9 +4417,37 @@ function PLAYERTASKCONTROLLER:AddRejectZoneSet(RejectZoneSet) return self end ---- [User] Remove accept zone from INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this. +--- [User] Add a conflict zone to INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this. -- @param #PLAYERTASKCONTROLLER self --- @param Core.Zone#ZONE AcceptZone Add a zone to the accept zone set. +-- @param Core.Zone#ZONE ConflictZone Add a zone to the conflict zone set. +-- @return #PLAYERTASKCONTROLLER self +function PLAYERTASKCONTROLLER:AddConflictZone(ConflictZone) + self:T(self.lid.."AddConflictZone") + if self.Intel then + self.Intel:AddConflictZone(ConflictZone) + else + self:E(self.lid.."*****NO detection has been set up (yet)!") + end + return self +end + +--- [User] Add a conflict SET_ZONE to INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this. +-- @param #PLAYERTASKCONTROLLER self +-- @param Core.Set#SET_ZONE ConflictZoneSet Add a zone to the conflict zone set. +-- @return #PLAYERTASKCONTROLLER self +function PLAYERTASKCONTROLLER:AddConflictZoneSet(ConflictZoneSet) + self:T(self.lid.."AddConflictZoneSet") + if self.Intel then + self.Intel.conflictzoneset:AddSet(ConflictZoneSet) + else + self:E(self.lid.."*****NO detection has been set up (yet)!") + end + return self +end + +--- [User] Remove an accept zone from INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this. +-- @param #PLAYERTASKCONTROLLER self +-- @param Core.Zone#ZONE AcceptZone Remove this zone from the accept zone set. -- @return #PLAYERTASKCONTROLLER self function PLAYERTASKCONTROLLER:RemoveAcceptZone(AcceptZone) self:T(self.lid.."RemoveAcceptZone") @@ -4427,11 +4459,11 @@ function PLAYERTASKCONTROLLER:RemoveAcceptZone(AcceptZone) return self end ---- [User] Remove reject zone from INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this. +--- [User] Remove a reject zone from INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this. -- @param #PLAYERTASKCONTROLLER self --- @param Core.Zone#ZONE RejectZone Add a zone to the reject zone set. +-- @param Core.Zone#ZONE RejectZone Remove this zone from the reject zone set. -- @return #PLAYERTASKCONTROLLER self -function PLAYERTASKCONTROLLER:RemoveRejectZoneSet(RejectZone) +function PLAYERTASKCONTROLLER:RemoveRejectZone(RejectZone) self:T(self.lid.."RemoveRejectZone") if self.Intel then self.Intel:RemoveRejectZone(RejectZone) @@ -4441,6 +4473,20 @@ function PLAYERTASKCONTROLLER:RemoveRejectZoneSet(RejectZone) return self end +--- [User] Remove a conflict zone from INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this. +-- @param #PLAYERTASKCONTROLLER self +-- @param Core.Zone#ZONE ConflictZone Remove this zone from the conflict zone set. +-- @return #PLAYERTASKCONTROLLER self +function PLAYERTASKCONTROLLER:RemoveConflictZone(ConflictZone) + self:T(self.lid.."RemoveConflictZone") + if self.Intel then + self.Intel:RemoveConflictZone(ConflictZone) + else + self:E(self.lid.."*****NO detection has been set up (yet)!") + end + return self +end + --- [User] Set the top menu name to a custom string. -- @param #PLAYERTASKCONTROLLER self -- @param #string Name The name to use as the top menu designation. From 0f6439cf9fe6d8cc38a2919adce2dedf031100c4 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sun, 20 Apr 2025 17:49:25 +0200 Subject: [PATCH 008/234] #MANTIS - added C-RAM Point Defense --- Moose Development/Moose/Functional/Mantis.lua | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Moose Development/Moose/Functional/Mantis.lua b/Moose Development/Moose/Functional/Mantis.lua index 0ebe76f4a..bd529dcd3 100644 --- a/Moose Development/Moose/Functional/Mantis.lua +++ b/Moose Development/Moose/Functional/Mantis.lua @@ -22,7 +22,7 @@ -- @module Functional.Mantis -- @image Functional.Mantis.jpg -- --- Last Update: Mar 2025 +-- Last Update: Apr 2025 ------------------------------------------------------------------------- --- **MANTIS** class, extends Core.Base#BASE @@ -393,6 +393,7 @@ MANTIS.SamData = { ["Chaparral"] = { Range=8, Blindspot=0, Height=3, Type="Short", Radar="Chaparral" }, ["Linebacker"] = { Range=4, Blindspot=0, Height=3, Type="Point", Radar="Linebacker", Point="true" }, ["Silkworm"] = { Range=90, Blindspot=1, Height=0.2, Type="Long", Radar="Silkworm" }, + ["HEMTT_C-RAM_Phalanx"] = { Range=2, Blindspot=0, Height=2, Type="Point", Radar="HEMTT_C-RAM_Phalanx", Point="true" }, -- units from HDS Mod, multi launcher options is tricky ["SA-10B"] = { Range=75, Blindspot=0, Height=18, Type="Medium" , Radar="SA-10B"}, ["SA-17"] = { Range=50, Blindspot=3, Height=30, Type="Medium", Radar="SA-17" }, @@ -689,7 +690,7 @@ do -- TODO Version -- @field #string version - self.version="0.9.27" + self.version="0.9.28" self:I(string.format("***** Starting MANTIS Version %s *****", self.version)) --- FSM Functions --- @@ -1493,7 +1494,7 @@ do elseif chm then SAMData = self.SamDataCH end - --self:T("Looking to auto-match for "..grpname) + --self:I("Looking to auto-match for "..grpname) for _,_unit in pairs(units) do local unit = _unit -- Wrapper.Unit#UNIT local type = string.lower(unit:GetTypeName()) From 6f72697e267e81ec859108f619045989bdb4dbdc Mon Sep 17 00:00:00 2001 From: shaji Date: Mon, 21 Apr 2025 19:11:22 +0200 Subject: [PATCH 009/234] [ADDED] New Kola airbases -- * AIRBASE.Kola.Alta -- * AIRBASE.Kola.Sodankyla -- * AIRBASE.Kola.Enontekio -- * AIRBASE.Kola.Evenes -- * AIRBASE.Kola.Hosio --- Moose Development/Moose/Wrapper/Airbase.lua | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Moose Development/Moose/Wrapper/Airbase.lua b/Moose Development/Moose/Wrapper/Airbase.lua index 21d69a296..0e3e8d9e3 100644 --- a/Moose Development/Moose/Wrapper/Airbase.lua +++ b/Moose Development/Moose/Wrapper/Airbase.lua @@ -793,6 +793,11 @@ AIRBASE.Sinai = { -- * AIRBASE.Kola.Alakourtti -- * AIRBASE.Kola.Kittila -- * AIRBASE.Kola.Bardufoss +-- * AIRBASE.Kola.Alta +-- * AIRBASE.Kola.Sodankyla +-- * AIRBASE.Kola.Enontekio +-- * AIRBASE.Kola.Evenes +-- * AIRBASE.Kola.Hosio -- -- @field Kola AIRBASE.Kola = { @@ -818,6 +823,11 @@ AIRBASE.Kola = { ["Alakourtti"] = "Alakourtti", ["Kittila"] = "Kittila", ["Bardufoss"] = "Bardufoss", + ["Alta"] = "Alta", + ["Sodankyla"] = "Sodankyla", + ["Enontekio"] = "Enontekio", + ["Evenes"] = "Evenes", + ["Hosio"] = "Hosio", } --- Airbases of the Afghanistan map From 195aac45048426d4b01104507f1039426f1f8021 Mon Sep 17 00:00:00 2001 From: shaji Date: Tue, 22 Apr 2025 20:57:06 +0200 Subject: [PATCH 010/234] [ADDED] IsAlive condition for Unit and Group out message --- Moose Development/Moose/Core/Message.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Core/Message.lua b/Moose Development/Moose/Core/Message.lua index 4165bdc57..ff74527f2 100644 --- a/Moose Development/Moose/Core/Message.lua +++ b/Moose Development/Moose/Core/Message.lua @@ -206,7 +206,7 @@ end function MESSAGE:ToGroup( Group, Settings ) self:F( Group.GroupName ) - if Group then + if Group and Group:IsAlive() then if self.MessageType then local Settings = Settings or (Group and _DATABASE:GetPlayerSettings( Group:GetPlayerName() )) or _SETTINGS -- Core.Settings#SETTINGS @@ -231,7 +231,7 @@ end function MESSAGE:ToUnit( Unit, Settings ) self:F( Unit.IdentifiableName ) - if Unit then + if Unit and Unit:IsAlive() then if self.MessageType then local Settings = Settings or ( Unit and _DATABASE:GetPlayerSettings( Unit:GetPlayerName() ) ) or _SETTINGS -- Core.Settings#SETTINGS From 3c742727490b1eea304a0e8a7f6d23a3bc37a4fc Mon Sep 17 00:00:00 2001 From: Thomas <72444570+Applevangelist@users.noreply.github.com> Date: Wed, 23 Apr 2025 09:00:05 +0200 Subject: [PATCH 011/234] Update Range.lua #RANGE log an error if os/os.date() are not available --- Moose Development/Moose/Functional/Range.lua | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Moose Development/Moose/Functional/Range.lua b/Moose Development/Moose/Functional/Range.lua index 62b85e828..8badfd798 100644 --- a/Moose Development/Moose/Functional/Range.lua +++ b/Moose Development/Moose/Functional/Range.lua @@ -2102,7 +2102,12 @@ function RANGE._OnImpact(weapon, self, playerData, attackHdg, attackAlt, attackV result.attackHdg = attackHdg result.attackVel = attackVel result.attackAlt = attackAlt - result.date=os and os.date() or "n/a" + if os and os.date then + result.date=os.date() + else + self:E(self.lid.."os or os.date() not available") + result.date = "n/a" + end -- Add to table. table.insert( _results, result ) From dd7b87e9cd6f38aced7935d38ce74804c182199c Mon Sep 17 00:00:00 2001 From: shaji Date: Wed, 23 Apr 2025 13:39:55 +0200 Subject: [PATCH 012/234] [ADDED] AIRBOSS:SetMaxSectionDistance --- Moose Development/Moose/Ops/Airboss.lua | 161 +++++++++++++----------- 1 file changed, 90 insertions(+), 71 deletions(-) diff --git a/Moose Development/Moose/Ops/Airboss.lua b/Moose Development/Moose/Ops/Airboss.lua index 5ef25bdc7..5e6f70443 100644 --- a/Moose Development/Moose/Ops/Airboss.lua +++ b/Moose Development/Moose/Ops/Airboss.lua @@ -1731,10 +1731,10 @@ AIRBOSS.Difficulty = { -- @field #table trapsheet Groove data table recorded every 0.5 seconds. -- @field #boolean trapon If true, save trap sheets. -- @field #string debriefschedulerID Debrief scheduler ID. --- +-- -- @field Sound.SRS#MSRS SRS -- @field Sound.SRS#MSRSQUEUE SRSQ --- +-- -- @extends #AIRBOSS.FlightGroup --- Main group level radio menu: F10 Other/Airboss. @@ -1912,6 +1912,9 @@ function AIRBOSS:New( carriername, alias ) -- Set max section members. Default 2. self:SetMaxSectionSize() + -- Set max section distance. Default 100 meters. + self:SetMaxSectionDistance() + -- Set max flights per stack. Default is 2. self:SetMaxFlightsPerStack() @@ -2539,7 +2542,7 @@ function AIRBOSS:AddRecoveryWindow( starttime, stoptime, case, holdingoffset, tu return self end if Tstop <= Tnow then - string.format( "WARNING: Recovery stop time %s already over. Tnow=%s! Recovery window rejected.", UTILS.SecondsToClock( Tstop ), UTILS.SecondsToClock( Tnow ) ) + string.format( "WARNING: Recovery stop time %s already over. Tnow=%s! Recovery window rejected.", UTILS.SecondsToClock( Tstop ), UTILS.SecondsToClock( Tnow ) ) return self end @@ -3066,7 +3069,7 @@ end -- @param #number Port Port of the SRS server, defaults to 5002. -- @param #string Culture (Optional, Airboss Culture) Culture, defaults to "en-US". -- @param #string Gender (Optional, Airboss Gender) Gender, e.g. "male" or "female". Defaults to "male". --- @param #string Voice (Optional, Airboss Voice) Set to use a specific voice. Will **override gender and culture** settings. +-- @param #string Voice (Optional, Airboss Voice) Set to use a specific voice. Will **override gender and culture** settings. -- @param #string GoogleCreds (Optional) Path to Google credentials, e.g. "C:\\Program Files\\DCS-SimpleRadio-Standalone\\yourgooglekey.json". -- @param #number Volume (Optional) E.g. 0.75. Defaults to 1.0 (loudest). -- @param #table AltBackend (Optional) See MSRS for details. @@ -3097,10 +3100,10 @@ function AIRBOSS:EnableSRS(PathToSRS,Port,Culture,Gender,Voice,GoogleCreds,Volum -- SRSQUEUE self.SRSQ = MSRSQUEUE:New("AIRBOSS") self.SRSQ:SetTransmitOnlyWithPlayers(true) - if not self.PilotRadio then + if not self.PilotRadio then self:SetSRSPilotVoice() end - return self + return self end --- Set LSO radio frequency and modulation. Default frequency is 264 MHz AM. @@ -3343,6 +3346,22 @@ function AIRBOSS:SetMaxSectionSize( nmax ) return self end +--- Set maximum distance up to which section members are allowed (default: 100 meters). +-- @param #AIRBOSS self +-- @param #number dmax Max distance in meters (default 100 m). Minimum is 10 m, maximum is 5000 m. +-- @return #AIRBOSS self +function AIRBOSS:SetMaxSectionDistance( dmax ) + if dmax then + if dmax < 10 then + dmax = 10 + elseif dmax > 5000 then + dmax = 5000 + end + end + self.maxsectiondistance = dmax or 100 + return self +end + --- Set max number of flights per stack. All members of a section count as one "flight". -- @param #AIRBOSS self -- @param #number nmax Number of max allowed flights per stack. Default is two. Minimum is one, maximum is 4. @@ -11596,7 +11615,7 @@ function AIRBOSS:GetHeadingIntoWind_old( vdeck, magnetic, coord ) local function adjustDegreesForWindSpeed(windSpeed) local degreesAdjustment = 0 -- the windspeeds are in m/s - + -- +0 degrees at 15m/s = 37kts -- +0 degrees at 14m/s = 35kts -- +0 degrees at 13m/s = 33kts @@ -11611,7 +11630,7 @@ function AIRBOSS:GetHeadingIntoWind_old( vdeck, magnetic, coord ) -- +20 degrees at 4m/s = 26kts -- +20 degrees at 3m/s = 26kts -- +30 degrees at 2m/s = 26kts 1s - + if windSpeed > 0 and windSpeed < 3 then degreesAdjustment = 30 elseif windSpeed >= 3 and windSpeed < 5 then @@ -11623,7 +11642,7 @@ function AIRBOSS:GetHeadingIntoWind_old( vdeck, magnetic, coord ) elseif windSpeed >= 13 then degreesAdjustment = 0 end - + return degreesAdjustment end @@ -11682,60 +11701,60 @@ function AIRBOSS:GetHeadingIntoWind_new( vdeck, magnetic, coord ) local h=self:GetHeading(magnetic) return h, math.min(vdeck, Vmax) end - + -- Convert wind speed to knots. vwind=UTILS.MpsToKnots(vwind) - + -- Wind to in knots. local windto=(windfrom+180)%360 - + -- Offset angle in rad. We also define the rotation to be clock-wise, which requires a minus sign. local alpha=math.rad(-Offset) - + -- Constant. local C = math.sqrt(math.cos(alpha)^2 / math.sin(alpha)^2 + 1) - + -- Upper limit of desired speed due to max boat speed. local vdeckMax=vwind + math.cos(alpha) * Vmax - + -- Lower limit of desired speed due to min boat speed. local vdeckMin=vwind + math.cos(alpha) * Vmin - - + + -- Speed of ship so it matches the desired speed. local v=0 - - -- Angle wrt. to wind TO-direction + + -- Angle wrt. to wind TO-direction local theta=0 if vdeck>vdeckMax then -- Boat cannot go fast enough - + -- Set max speed. v=Vmax - + -- Calculate theta. theta = math.asin(v/(vwind*C)) - math.asin(-1/C) - + elseif vdeckvwind then -- Too little wind - + -- Set theta to 90° theta=math.pi/2 - + -- Set speed. v = math.sqrt(vdeck^2 - vwind^2) - + else -- Normal case theta = math.asin(vdeck * math.sin(alpha) / vwind) @@ -11744,9 +11763,9 @@ function AIRBOSS:GetHeadingIntoWind_new( vdeck, magnetic, coord ) -- Magnetic heading. local magvar= magnetic and self.magvar or 0 - + -- Ship heading so cross wind is min for the given wind. - local intowind = (540 + (windto - magvar + math.deg(theta) )) % 360 + local intowind = (540 + (windto - magvar + math.deg(theta) )) % 360 return intowind, v end @@ -12204,7 +12223,7 @@ function AIRBOSS:_LSOgrade( playerData ) -- Normal laning part at the beginning local Gb = GXX .. " " .. GIM - -- Number of deviations that occurred at the the beginning of the landing (XX or IM). These are graded like in non-VTOL landings, i.e. on deviations is + -- Number of deviations that occurred at the the beginning of the landing (XX or IM). These are graded like in non-VTOL landings, i.e. on deviations is local N=nXX+nIM local nL=count(Gb, '_')/2 local nS=count(Gb, '%(') @@ -12222,7 +12241,7 @@ function AIRBOSS:_LSOgrade( playerData ) if nL>0 or nLv>1 then -- Larger deviations at XX or IM or at least one larger deviation IC or AR==> "No grade" 2.0 points. - -- In other words, we allow one larger deviation at IC+AR + -- In other words, we allow one larger deviation at IC+AR grade="--" points=2.0 elseif nN>0 or nNv>1 or nLv==1 then @@ -13718,7 +13737,7 @@ function AIRBOSS:CarrierTurnIntoWind( time, vdeck, uturn ) local deltaH = self:_GetDeltaHeading( hdg, hiw ) -- Debug output - self:I( self.lid .. string.format( "Carrier steaming into the wind (%.1f kts). Heading=%03d-->%03d (Delta=%.1f), Speed=%.1f knots, Distance=%.1f NM, Time=%d sec", + self:I( self.lid .. string.format( "Carrier steaming into the wind (%.1f kts). Heading=%03d-->%03d (Delta=%.1f), Speed=%.1f knots, Distance=%.1f NM, Time=%d sec", UTILS.MpsToKnots( vwind ), hdg, hiw, deltaH, speedknots, distNM, speedknots, time ) ) -- Current coordinate. @@ -14930,12 +14949,12 @@ function AIRBOSS:RadioTransmission( radio, call, loud, delay, interval, click, p if radio == nil or call == nil then return end - + if not self.SRS then - + -- Create a new radio transmission item. local transmission = {} -- #AIRBOSS.Radioitem - + transmission.radio = radio transmission.call = call transmission.Tplay = timer.getAbsTime() + (delay or 0) @@ -14943,49 +14962,49 @@ function AIRBOSS:RadioTransmission( radio, call, loud, delay, interval, click, p transmission.isplaying = false transmission.Tstarted = nil transmission.loud = loud and call.loud - + -- Player onboard number if sender has one. if self:_IsOnboard( call.modexsender ) then self:_Number2Radio( radio, call.modexsender, delay, 0.3, pilotcall ) end - + -- Play onboard number if receiver has one. if self:_IsOnboard( call.modexreceiver ) then self:_Number2Radio( radio, call.modexreceiver, delay, 0.3, pilotcall ) end - + -- Add transmission to the right queue. local caller = "" if radio.alias == "LSO" then - + table.insert( self.RQLSO, transmission ) - + caller = "LSOCall" - + -- Schedule radio queue checks. if not self.RQLid then self:T( self.lid .. string.format( "Starting LSO radio queue." ) ) self.RQLid = self.radiotimer:Schedule( nil, AIRBOSS._CheckRadioQueue, { self, self.RQLSO, "LSO" }, 0.02, 0.05 ) end - + elseif radio.alias == "MARSHAL" then - + table.insert( self.RQMarshal, transmission ) - + caller = "MarshalCall" - + if not self.RQMid then self:T( self.lid .. string.format( "Starting Marhal radio queue." ) ) self.RQMid = self.radiotimer:Schedule( nil, AIRBOSS._CheckRadioQueue, { self, self.RQMarshal, "MARSHAL" }, 0.02, 0.05 ) end - + end - + -- Append radio click sound at the end of the transmission. if click then self:RadioTransmission( radio, self[caller].CLICK, false, delay ) end - + else -- SRS transmission @@ -14996,7 +15015,7 @@ function AIRBOSS:RadioTransmission( radio, call, loud, delay, interval, click, p local voice = nil local gender = nil local culture = nil - + if radio.alias == "AIRBOSS" then frequency = self.AirbossRadio.frequency modulation = self.AirbossRadio.modulation @@ -15004,13 +15023,13 @@ function AIRBOSS:RadioTransmission( radio, call, loud, delay, interval, click, p gender = self.AirbossRadio.gender culture = self.AirbossRadio.culture end - + if radio.alias == "MARSHAL" then voice = self.MarshalRadio.voice gender = self.MarshalRadio.gender culture = self.MarshalRadio.culture end - + if radio.alias == "LSO" then frequency = self.LSORadio.frequency modulation = self.LSORadio.modulation @@ -15018,7 +15037,7 @@ function AIRBOSS:RadioTransmission( radio, call, loud, delay, interval, click, p gender = self.LSORadio.gender culture = self.LSORadio.culture end - + if pilotcall then voice = self.PilotRadio.voice gender = self.PilotRadio.gender @@ -15032,16 +15051,16 @@ function AIRBOSS:RadioTransmission( radio, call, loud, delay, interval, click, p modulation = self.AirbossRadio.modulation radio.alias = "AIRBOSS" end - + local volume = nil - + if loud then volume = 1.0 end - + --local text = tostring(call.modexreceiver).."; "..radio.alias.."; "..call.subtitle local text = call.subtitle - self:T(self.lid..text) + self:T(self.lid..text) local srstext = self:_GetNiceSRSText(text) self.SRSQ:NewTransmission(srstext, call.duration, self.SRS, nil, 0.1, nil, call.subtitle, call.subduration, frequency, modulation, gender, culture, voice, volume, radio.alias) end @@ -15061,11 +15080,11 @@ function AIRBOSS:SetSRSPilotVoice( Voice, Gender, Culture ) self.PilotRadio.voice = Voice or MSRS.Voices.Microsoft.David self.PilotRadio.gender = Gender or "male" self.PilotRadio.culture = Culture or "en-US" - + if (not Voice) and self.SRS and self.SRS:GetProvider() == MSRS.Provider.GOOGLE then self.PilotRadio.voice = MSRS.Voices.Google.Standard.en_US_Standard_J end - + return self end @@ -15379,44 +15398,44 @@ function AIRBOSS:MessageToPlayer( playerData, message, sender, receiver, duratio -- SCHEDULER:New(nil, self.MessageToPlayer, {self, playerData, message, sender, receiver, duration, clear}, delay) self:ScheduleOnce( delay, self.MessageToPlayer, self, playerData, message, sender, receiver, duration, clear ) else - + if not self.SRS then -- Wait until previous sound finished. local wait = 0 - + -- Onboard number to get the attention. if receiver == playerData.onboard then - + -- Which voice over number to use. if sender and (sender == "LSO" or sender == "MARSHAL" or sender == "AIRBOSS") then - + -- User sound of board number. wait = wait + self:_Number2Sound( playerData, sender, receiver ) - + end end - + -- Negative. if string.find( text:lower(), "negative" ) then local filename = self:_RadioFilename( self.MarshalCall.NEGATIVE, false, "MARSHAL" ) USERSOUND:New( filename ):ToGroup( playerData.group, wait ) wait = wait + self.MarshalCall.NEGATIVE.duration end - + -- Affirm. if string.find( text:lower(), "affirm" ) then local filename = self:_RadioFilename( self.MarshalCall.AFFIRMATIVE, false, "MARSHAL" ) USERSOUND:New( filename ):ToGroup( playerData.group, wait ) wait = wait + self.MarshalCall.AFFIRMATIVE.duration end - + -- Roger. if string.find( text:lower(), "roger" ) then local filename = self:_RadioFilename( self.MarshalCall.ROGER, false, "MARSHAL" ) USERSOUND:New( filename ):ToGroup( playerData.group, wait ) wait = wait + self.MarshalCall.ROGER.duration end - + -- Play click sound to end message. if wait > 0 then local filename = self:_RadioFilename( self.MarshalCall.CLICK ) @@ -15429,7 +15448,7 @@ function AIRBOSS:MessageToPlayer( playerData, message, sender, receiver, duratio local voice = self.MarshalRadio.voice local gender = self.MarshalRadio.gender local culture = self.MarshalRadio.culture - + if not sender then sender = "AIRBOSS" end if string.find(sender,"AIRBOSS" ) then @@ -17047,7 +17066,7 @@ function AIRBOSS:_RemoveSectionMember( playerData, sectionmember ) return false end ---- Set all flights within 100 meters to be part of my section. +--- Set all flights within maxsectiondistance meters to be part of my section (default: 100 meters). -- @param #AIRBOSS self -- @param #string _unitName Name of the player unit. function AIRBOSS:_SetSection( _unitName ) @@ -17065,7 +17084,7 @@ function AIRBOSS:_SetSection( _unitName ) local mycoord = _unit:GetCoordinate() -- Max distance up to which section members are allowed. - local dmax = 100 + local dmax = self.maxsectiondistance -- Check if player is in Marshal or pattern queue already. local text From cdad3bd058b08ae9ae636a9c9b748aab575c8ee7 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 24 Apr 2025 14:48:12 +0200 Subject: [PATCH 013/234] #PLAYERTASK - make an existing marker move with the group if the group is moving around --- Moose Development/Moose/Ops/PlayerTask.lua | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Moose Development/Moose/Ops/PlayerTask.lua b/Moose Development/Moose/Ops/PlayerTask.lua index 74d53667d..8c6361a48 100644 --- a/Moose Development/Moose/Ops/PlayerTask.lua +++ b/Moose Development/Moose/Ops/PlayerTask.lua @@ -98,7 +98,7 @@ PLAYERTASK = { --- PLAYERTASK class version. -- @field #string version -PLAYERTASK.version="0.1.25" +PLAYERTASK.version="0.1.26" --- Generic task condition. -- @type PLAYERTASK.Condition @@ -979,6 +979,12 @@ function PLAYERTASK:onafterStatus(From, Event, To) if status == "Stopped" then return self end + -- update marker in case target is moving + if self.TargetMarker then + local coordinate = self.Target:GetCoordinate() + self.TargetMarker:UpdateCoordinate(coordinate,0.5) + end + -- Check Target status local targetdead = false From 1547d66327f0d7659df52c525ec001128977edd3 Mon Sep 17 00:00:00 2001 From: leka1986 <83298840+leka1986@users.noreply.github.com> Date: Sat, 26 Apr 2025 03:28:16 +0200 Subject: [PATCH 014/234] Update CTLD.lua Getting rid of this error, bad argument #1 to 'find' (string expected, got nil) --- Moose Development/Moose/Ops/CTLD.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/Ops/CTLD.lua b/Moose Development/Moose/Ops/CTLD.lua index cd0bc8403..a10860011 100644 --- a/Moose Development/Moose/Ops/CTLD.lua +++ b/Moose Development/Moose/Ops/CTLD.lua @@ -3564,7 +3564,7 @@ end function CTLD:IsFixedWing(Unit) local typename = Unit:GetTypeName() or "none" for _,_name in pairs(self.FixedWingTypes or {}) do - if typename == _name or string.find(typename,_name,1,true) then + if _name and (typename==_name or string.find(typename,_name,1,true))then return true end end From ac4b620f16b33fcda0072e4107d29ec525d12174 Mon Sep 17 00:00:00 2001 From: Frank Date: Sat, 26 Apr 2025 23:39:22 +0200 Subject: [PATCH 015/234] COORDINATE - Improved Smoke and Fire and Smoke functions by adding delay and duration parameters --- Moose Development/Moose/Core/Base.lua | 2 +- Moose Development/Moose/Core/Point.lua | 201 +++++++++++++------- Moose Development/Moose/Utilities/Utils.lua | 34 ++-- 3 files changed, 158 insertions(+), 79 deletions(-) diff --git a/Moose Development/Moose/Core/Base.lua b/Moose Development/Moose/Core/Base.lua index b1a12e740..81cf8892d 100644 --- a/Moose Development/Moose/Core/Base.lua +++ b/Moose Development/Moose/Core/Base.lua @@ -974,7 +974,7 @@ do -- Scheduling -- @param #BASE self -- @param #number Start Specifies the amount of seconds that will be waited before the scheduling is started, and the event function is called. -- @param #function SchedulerFunction The event function to be called when a timer event occurs. The event function needs to accept the parameters specified in SchedulerArguments. - -- @param #table ... Optional arguments that can be given as part of scheduler. The arguments need to be given as a table { param1, param 2, ... }. + -- @param ... Optional arguments that can be given as part of scheduler. The arguments need to be given as a table { param1, param 2, ... }. -- @return #string The Schedule ID of the planned schedule. function BASE:ScheduleOnce( Start, SchedulerFunction, ... ) diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index 4a5d26e22..f1aa66289 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -25,7 +25,7 @@ do -- COORDINATE - --- + --- Coordinate class -- @type COORDINATE -- @field #string ClassName Name of the class -- @field #number x Component of the 3D vector. @@ -2118,14 +2118,35 @@ do -- COORDINATE end - --- Smokes the point in a color. + --- Create colored smoke the point. The smoke we last up to 5 min (DCS limitation) but you can optionally specify a shorter duration or stop it manually. -- @param #COORDINATE self - -- @param Utilities.Utils#SMOKECOLOR SmokeColor - -- @param #string name (Optional) Name if you want to stop the smoke early (normal duration: 5mins) - function COORDINATE:Smoke( SmokeColor, name ) - self:F2( { SmokeColor } ) - self.firename = name or "Smoke-"..math.random(1,100000) - trigger.action.smoke( self:GetVec3(), SmokeColor, self.firename ) + -- @param #number SmokeColor Color of smoke, e.g. `SMOKECOLOR.Green` for green smoke. + -- @param #number Duration (Optional) Duration of the smoke in seconds. DCS stopps the smoke automatically after 5 min. + -- @param #number Delay (Optional) Delay before the smoke is started in seconds. + -- @param #string Name (Optional) Name if you want to stop the smoke early (normal duration: 5mins) + -- @return #COORDINATE self + function COORDINATE:Smoke( SmokeColor, Duration, Delay, Name) + self:F2( { SmokeColor, Name, Duration, Delay } ) + + SmokeColor=SmokeColor or SMOKECOLOR.Green + + if Delay and Delay>0 then + self:ScheduleOnce(Delay, COORDINATE.Smoke, self, SmokeColor, Duration, 0, Name) + else + + -- Create a name which is used to stop the smoke manually + self.firename = Name or "Smoke-"..math.random(1,100000) + + -- Create smoke + trigger.action.smoke( self:GetVec3(), SmokeColor, self.firename ) + + -- Stop smoke + if Duration and Duration>0 then + self:ScheduleOnce(Duration, COORDINATE.StopSmoke, self, self.firename ) + end + end + + return self end --- Stops smoking the point in a color. @@ -2137,49 +2158,83 @@ do -- COORDINATE --- Smoke the COORDINATE Green. -- @param #COORDINATE self - function COORDINATE:SmokeGreen() - self:F2() - self:Smoke( SMOKECOLOR.Green ) + -- @param #number Duration (Optional) Duration of the smoke in seconds. DCS stopps the smoke automatically after 5 min. + -- @param #number Delay (Optional) Delay before the smoke is started in seconds. + -- @return #COORDINATE self + function COORDINATE:SmokeGreen(Duration, Delay) + self:Smoke( SMOKECOLOR.Green, Duration, Delay ) + return self end --- Smoke the COORDINATE Red. -- @param #COORDINATE self - function COORDINATE:SmokeRed() - self:F2() - self:Smoke( SMOKECOLOR.Red ) + -- @param #number Duration (Optional) Duration of the smoke in seconds. DCS stopps the smoke automatically after 5 min. + -- @param #number Delay (Optional) Delay before the smoke is started in seconds. + -- @return #COORDINATE self + function COORDINATE:SmokeRed(Duration, Delay) + self:Smoke( SMOKECOLOR.Red, Duration, Delay ) + return self end --- Smoke the COORDINATE White. -- @param #COORDINATE self - function COORDINATE:SmokeWhite() - self:F2() - self:Smoke( SMOKECOLOR.White ) + -- @param #number Duration (Optional) Duration of the smoke in seconds. DCS stopps the smoke automatically after 5 min. + -- @param #number Delay (Optional) Delay before the smoke is started in seconds. + -- @return #COORDINATE self + function COORDINATE:SmokeWhite(Duration, Delay) + self:Smoke( SMOKECOLOR.White, Duration, Delay ) + return self end --- Smoke the COORDINATE Orange. -- @param #COORDINATE self - function COORDINATE:SmokeOrange() - self:F2() - self:Smoke( SMOKECOLOR.Orange ) + -- @param #number Duration (Optional) Duration of the smoke in seconds. DCS stopps the smoke automatically after 5 min. + -- @param #number Delay (Optional) Delay before the smoke is started in seconds. + -- @return #COORDINATE self + function COORDINATE:SmokeOrange(Duration, Delay) + self:Smoke( SMOKECOLOR.Orange, Duration, Delay ) + return self end --- Smoke the COORDINATE Blue. -- @param #COORDINATE self - function COORDINATE:SmokeBlue() - self:F2() - self:Smoke( SMOKECOLOR.Blue ) + -- @param #number Duration (Optional) Duration of the smoke in seconds. DCS stopps the smoke automatically after 5 min. + -- @param #number Delay (Optional) Delay before the smoke is started in seconds. + -- @return #COORDINATE self + function COORDINATE:SmokeBlue(Duration, Delay) + self:Smoke( SMOKECOLOR.Blue, Duration, Delay ) + return self end --- Big smoke and fire at the coordinate. -- @param #COORDINATE self - -- @param Utilities.Utils#BIGSMOKEPRESET preset Smoke preset (1=small smoke and fire, 2=medium smoke and fire, 3=large smoke and fire, 4=huge smoke and fire, 5=small smoke, 6=medium smoke, 7=large smoke, 8=huge smoke). - -- @param #number density (Optional) Smoke density. Number in [0,...,1]. Default 0.5. - -- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number. - function COORDINATE:BigSmokeAndFire( preset, density, name ) - self:F2( { preset=preset, density=density } ) - density=density or 0.5 - self.firename = name or "Fire-"..math.random(1,10000) - trigger.action.effectSmokeBig( self:GetVec3(), preset, density, self.firename ) + -- @param #number Preset Smoke preset (1=small smoke and fire, 2=medium smoke and fire, 3=large smoke and fire, 4=huge smoke and fire, 5=small smoke, 6=medium smoke, 7=large smoke, 8=huge smoke). + -- @param #number Density (Optional) Smoke density. Number in [0,...,1]. Default 0.5. + -- @param #number Duration (Optional) Duration of the smoke and fire in seconds. + -- @param #number Delay (Optional) Delay before the smoke and fire is started in seconds. + -- @param #string Name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number. + -- @return #COORDINATE self + function COORDINATE:BigSmokeAndFire( Preset, Density, Duration, Delay, Name ) + self:F2( { preset=Preset, density=Density } ) + + Preset=Preset or BIGSMOKEPRESET.SmallSmokeAndFire + Density=Density or 0.5 + + if Delay and Delay>0 then + self:ScheduleOnce(Delay, COORDINATE.BigSmokeAndFire, self, Preset, Density, Duration, 0, Name) + else + + self.firename = Name or "Fire-"..math.random(1,10000) + + trigger.action.effectSmokeBig( self:GetVec3(), Preset, Density, self.firename ) + + -- Stop smoke + if Duration and Duration>0 then + self:ScheduleOnce(Duration, COORDINATE.StopBigSmokeAndFire, self, self.firename ) + end + end + + return self end --- Stop big smoke and fire at the coordinate. @@ -2192,82 +2247,98 @@ do -- COORDINATE --- Small smoke and fire at the coordinate. -- @param #COORDINATE self - -- @param #number density (Optional) Smoke density. Number between 0 and 1. Default 0.5. - -- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number. - function COORDINATE:BigSmokeAndFireSmall( density, name ) - self:F2( { density=density } ) - density=density or 0.5 - self:BigSmokeAndFire(BIGSMOKEPRESET.SmallSmokeAndFire, density, name) + -- @param #number Density (Optional) Smoke density. Number between 0 and 1. Default 0.5. + -- @param #number Duration (Optional) Duration of the smoke and fire in seconds. + -- @param #number Delay (Optional) Delay before the smoke and fire is started in seconds. + -- @param #string Name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number. + -- @return #COORDINATE self + function COORDINATE:BigSmokeAndFireSmall( Density, Duration, Delay, Name ) + self:BigSmokeAndFire(BIGSMOKEPRESET.SmallSmokeAndFire, Density, Duration, Delay, Name) + return self end --- Medium smoke and fire at the coordinate. -- @param #COORDINATE self -- @param #number density (Optional) Smoke density. Number between 0 and 1. Default 0.5. + -- @param #number Duration (Optional) Duration of the smoke and fire in seconds. + -- @param #number Delay (Optional) Delay before the smoke and fire is started in seconds. -- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number. - function COORDINATE:BigSmokeAndFireMedium( density, name ) - self:F2( { density=density } ) - density=density or 0.5 - self:BigSmokeAndFire(BIGSMOKEPRESET.MediumSmokeAndFire, density, name) + -- @return #COORDINATE self + function COORDINATE:BigSmokeAndFireMedium( Density, Duration, Delay, Name ) + self:BigSmokeAndFire(BIGSMOKEPRESET.MediumSmokeAndFire, Density, Duration, Delay, Name) + return self end --- Large smoke and fire at the coordinate. -- @param #COORDINATE self -- @param #number density (Optional) Smoke density. Number between 0 and 1. Default 0.5. + -- @param #number Duration (Optional) Duration of the smoke and fire in seconds. + -- @param #number Delay (Optional) Delay before the smoke and fire is started in seconds. -- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number. - function COORDINATE:BigSmokeAndFireLarge( density, name ) - self:F2( { density=density } ) - density=density or 0.5 - self:BigSmokeAndFire(BIGSMOKEPRESET.LargeSmokeAndFire, density, name) + -- @return #COORDINATE self + function COORDINATE:BigSmokeAndFireLarge( Density, Duration, Delay, Name ) + self:BigSmokeAndFire(BIGSMOKEPRESET.LargeSmokeAndFire, Density, Duration, Delay, Name) + return self end --- Huge smoke and fire at the coordinate. -- @param #COORDINATE self -- @param #number density (Optional) Smoke density. Number between 0 and 1. Default 0.5. + -- @param #number Duration (Optional) Duration of the smoke and fire in seconds. + -- @param #number Delay (Optional) Delay before the smoke and fire is started in seconds. -- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number. - function COORDINATE:BigSmokeAndFireHuge( density, name ) - self:F2( { density=density } ) - density=density or 0.5 - self:BigSmokeAndFire(BIGSMOKEPRESET.HugeSmokeAndFire, density, name) + -- @return #COORDINATE self + function COORDINATE:BigSmokeAndFireHuge( Density, Duration, Delay, Name ) + self:BigSmokeAndFire(BIGSMOKEPRESET.HugeSmokeAndFire, Density, Duration, Delay, Name) + return self end --- Small smoke at the coordinate. -- @param #COORDINATE self -- @param #number density (Optional) Smoke density. Number between 0 and 1. Default 0.5. + -- @param #number Duration (Optional) Duration of the smoke and fire in seconds. + -- @param #number Delay (Optional) Delay before the smoke and fire is started in seconds. -- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number. - function COORDINATE:BigSmokeSmall( density, name ) - self:F2( { density=density } ) - density=density or 0.5 - self:BigSmokeAndFire(BIGSMOKEPRESET.SmallSmoke, density, name) + -- @return #COORDINATE self + function COORDINATE:BigSmokeSmall( Density, Duration, Delay, Name ) + self:BigSmokeAndFire(BIGSMOKEPRESET.SmallSmoke, Density, Duration, Delay, Name) + return self end --- Medium smoke at the coordinate. -- @param #COORDINATE self -- @param number density (Optional) Smoke density. Number between 0 and 1. Default 0.5. + -- @param #number Duration (Optional) Duration of the smoke and fire in seconds. + -- @param #number Delay (Optional) Delay before the smoke and fire is started in seconds. -- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number. - function COORDINATE:BigSmokeMedium( density, name ) - self:F2( { density=density } ) - density=density or 0.5 - self:BigSmokeAndFire(BIGSMOKEPRESET.MediumSmoke, density, name) + -- @return #COORDINATE self + function COORDINATE:BigSmokeMedium( Density, Duration, Delay, Name ) + self:BigSmokeAndFire(BIGSMOKEPRESET.MediumSmoke, Density, Duration, Delay, Name) + return self end --- Large smoke at the coordinate. -- @param #COORDINATE self -- @param #number density (Optional) Smoke density. Number between 0 and 1. Default 0.5. + -- @param #number Duration (Optional) Duration of the smoke and fire in seconds. + -- @param #number Delay (Optional) Delay before the smoke and fire is started in seconds. -- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number. - function COORDINATE:BigSmokeLarge( density, name ) - self:F2( { density=density } ) - density=density or 0.5 - self:BigSmokeAndFire(BIGSMOKEPRESET.LargeSmoke, density,name) + -- @return #COORDINATE self + function COORDINATE:BigSmokeLarge( Density, Duration, Delay, Name ) + self:BigSmokeAndFire(BIGSMOKEPRESET.LargeSmoke, Density, Duration, Delay, Name) + return self end --- Huge smoke at the coordinate. -- @param #COORDINATE self -- @param #number density (Optional) Smoke density. Number between 0 and 1. Default 0.5. + -- @param #number Duration (Optional) Duration of the smoke and fire in seconds. + -- @param #number Delay (Optional) Delay before the smoke and fire is started in seconds. -- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number. - function COORDINATE:BigSmokeHuge( density, name ) - self:F2( { density=density } ) - density=density or 0.5 - self:BigSmokeAndFire(BIGSMOKEPRESET.HugeSmoke, density,name) + -- @return #COORDINATE self + function COORDINATE:BigSmokeHuge( Density, Duration, Delay, Name ) + self:BigSmokeAndFire(BIGSMOKEPRESET.HugeSmoke, Density, Duration, Delay, Name) + return self end --- Flares the point in a color. diff --git a/Moose Development/Moose/Utilities/Utils.lua b/Moose Development/Moose/Utilities/Utils.lua index 361e786d5..73ce154c9 100644 --- a/Moose Development/Moose/Utilities/Utils.lua +++ b/Moose Development/Moose/Utilities/Utils.lua @@ -12,27 +12,35 @@ -- @module Utilities.Utils -- @image MOOSE.JPG ---- +--- Smoke color enum `trigger.smokeColor`. -- @type SMOKECOLOR --- @field Green --- @field Red --- @field White --- @field Orange --- @field Blue +-- @field #number Green Green smoke (0) +-- @field #number Red Red smoke (1) +-- @field #number White White smoke (2) +-- @field #number Orange Orange smoke (3) +-- @field #number Blue Blue smoke (4) SMOKECOLOR = trigger.smokeColor -- #SMOKECOLOR ---- +--- Flare colur enum `trigger.flareColor`. -- @type FLARECOLOR --- @field Green --- @field Red --- @field White --- @field Yellow +-- @field #number Green (0) +-- @field #number Red Red flare (1) +-- @field #number White White flare (2) +-- @field #number Yellow Yellow flare (3) FLARECOLOR = trigger.flareColor -- #FLARECOLOR --- Big smoke preset enum. -- @type BIGSMOKEPRESET +-- @field #number SmallSmokeAndFire Small moke and fire (1) +-- @field #number MediumSmokeAndFire Medium smoke and fire (2) +-- @field #number LargeSmokeAndFire Large smoke and fire (3) +-- @field #number HugeSmokeAndFire Huge smoke and fire (4) +-- @field #number SmallSmoke Small smoke (5) +-- @field #number MediumSmoke Medium smoke (6) +-- @field #number LargeSmoke Large smoke (7) +-- @field #number HugeSmoke Huge smoke (8) BIGSMOKEPRESET = { SmallSmokeAndFire=1, MediumSmokeAndFire=2, @@ -351,7 +359,7 @@ end -- @return #string Table as a string. UTILS.OneLineSerialize = function( tbl ) -- serialization of a table all on a single line, no comments, made to replace old get_table_string function - lookup_table = {} + local lookup_table = {} local function _Serialize( tbl ) @@ -490,7 +498,7 @@ end --- Counts the number of elements in a table. -- @param #table T Table to count --- @return #int Number of elements in the table +-- @return #number Number of elements in the table function UTILS.TableLength(T) local count = 0 for _ in pairs(T or {}) do count = count + 1 end From 5c3b7312c06631a6e0e990b7dc29b71a52db9985 Mon Sep 17 00:00:00 2001 From: Frank Date: Sat, 26 Apr 2025 23:55:13 +0200 Subject: [PATCH 016/234] Update Range.lua - Reduced smoke duration at impact coordinate to 30 seconds --- Moose Development/Moose/Functional/Range.lua | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/Moose Development/Moose/Functional/Range.lua b/Moose Development/Moose/Functional/Range.lua index 8badfd798..6c0143823 100644 --- a/Moose Development/Moose/Functional/Range.lua +++ b/Moose Development/Moose/Functional/Range.lua @@ -603,7 +603,7 @@ RANGE.MenuF10Root = nil --- Range script version. -- @field #string version -RANGE.version = "2.8.0" +RANGE.version = "2.8.1" -- TODO list: -- TODO: Verbosity level for messages. @@ -2032,10 +2032,10 @@ function RANGE._OnImpact(weapon, self, playerData, attackHdg, attackAlt, attackV -- Smoke impact point of bomb. if playerData and playerData.smokebombimpact and insidezone then - if playerData and playerData.delaysmoke then - timer.scheduleFunction( self._DelayedSmoke, { coord = impactcoord, color = playerData.smokecolor }, timer.getTime() + self.TdelaySmoke ) + if playerData.delaysmoke then + impactcoord:Smoke(playerData.smokecolor, 30, self.TdelaySmoke) else - impactcoord:Smoke( playerData.smokecolor ) + impactcoord:Smoke(playerData.smokecolor, 30) end end @@ -2640,13 +2640,6 @@ end -- Display Messages ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---- Start smoking a coordinate with a delay. --- @param #table _args Argements passed. -function RANGE._DelayedSmoke( _args ) - _args.coord:Smoke(_args.color) - --trigger.action.smoke( _args.coord:GetVec3(), _args.color ) -end - --- Display top 10 stafing results of a specific player. -- @param #RANGE self -- @param #string _unitName Name of the player unit. From 3ad60a95cecc59e5699261228ee4d1e6bf2cc1f2 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sun, 27 Apr 2025 11:25:46 +0200 Subject: [PATCH 017/234] #MANTIS - Adde Gepard data, made Roland Short --- Moose Development/Moose/Functional/Mantis.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Functional/Mantis.lua b/Moose Development/Moose/Functional/Mantis.lua index bd529dcd3..9a412d768 100644 --- a/Moose Development/Moose/Functional/Mantis.lua +++ b/Moose Development/Moose/Functional/Mantis.lua @@ -374,7 +374,7 @@ MANTIS.radiusscale[MANTIS.SamType.POINT] = 3 MANTIS.SamData = { ["Hawk"] = { Range=35, Blindspot=0, Height=12, Type="Medium", Radar="Hawk" }, -- measures in km ["NASAMS"] = { Range=14, Blindspot=0, Height=7, Type="Short", Radar="NSAMS" }, -- AIM 120B - ["Patriot"] = { Range=99, Blindspot=0, Height=25, Type="Long", Radar="Patriot" }, + ["Patriot"] = { Range=99, Blindspot=0, Height=25, Type="Long", Radar="Patriot str" }, ["Rapier"] = { Range=10, Blindspot=0, Height=3, Type="Short", Radar="rapier" }, ["SA-2"] = { Range=40, Blindspot=7, Height=25, Type="Medium", Radar="S_75M_Volhov" }, ["SA-3"] = { Range=18, Blindspot=6, Height=18, Type="Short", Radar="5p73 s-125 ln" }, @@ -382,7 +382,8 @@ MANTIS.SamData = { ["SA-6"] = { Range=25, Blindspot=0, Height=8, Type="Medium", Radar="1S91" }, ["SA-10"] = { Range=119, Blindspot=0, Height=18, Type="Long" , Radar="S-300PS 4"}, ["SA-11"] = { Range=35, Blindspot=0, Height=20, Type="Medium", Radar="SA-11" }, - ["Roland"] = { Range=5, Blindspot=0, Height=5, Type="Point", Radar="Roland" }, + ["Roland"] = { Range=6, Blindspot=0, Height=5, Type="Short", Radar="Roland" }, + ["Gepard"] = { Range=5, Blindspot=0, Height=4, Type="Point", Radar="Gepard" }, ["HQ-7"] = { Range=12, Blindspot=0, Height=3, Type="Short", Radar="HQ-7" }, ["SA-9"] = { Range=4, Blindspot=0, Height=3, Type="Point", Radar="Strela", Point="true" }, ["SA-8"] = { Range=10, Blindspot=0, Height=5, Type="Short", Radar="Osa 9A33" }, From db23a0bf2be682a0edbe79594f7203188c1b0080 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sun, 27 Apr 2025 11:26:22 +0200 Subject: [PATCH 018/234] #FlightGroup - added nil check for name --- Moose Development/Moose/Ops/FlightGroup.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/Ops/FlightGroup.lua b/Moose Development/Moose/Ops/FlightGroup.lua index 1d77397e0..81a19cd80 100644 --- a/Moose Development/Moose/Ops/FlightGroup.lua +++ b/Moose Development/Moose/Ops/FlightGroup.lua @@ -259,7 +259,7 @@ function FLIGHTGROUP:New(group) local self=BASE:Inherit(self, OPSGROUP:New(group)) -- #FLIGHTGROUP -- Set some string id for output to DCS.log file. - self.lid=string.format("FLIGHTGROUP %s | ", self.groupname) + self.lid=string.format("FLIGHTGROUP %s | ", self.groupname or "N/A") -- Defaults self:SetDefaultROE() From b145588ed5db17767f4cb4efbae60b912a789816 Mon Sep 17 00:00:00 2001 From: Thomas <72444570+Applevangelist@users.noreply.github.com> Date: Mon, 28 Apr 2025 09:20:04 +0200 Subject: [PATCH 019/234] Update CTLD.lua Fix an issue when a ship is used as loading zone and the ship is destroyed --- Moose Development/Moose/Ops/CTLD.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/Moose Development/Moose/Ops/CTLD.lua b/Moose Development/Moose/Ops/CTLD.lua index a10860011..c0c30ec72 100644 --- a/Moose Development/Moose/Ops/CTLD.lua +++ b/Moose Development/Moose/Ops/CTLD.lua @@ -5662,6 +5662,7 @@ function CTLD:IsUnitInZone(Unit,Zonetype) if Zonetype == CTLD.CargoZoneType.SHIP then self:T("Checking Type Ship: "..zonename) local ZoneUNIT = UNIT:FindByName(zonename) + if not ZoneUNIT then return false end zonecoord = ZoneUNIT:GetCoordinate() zoneradius = czone.shiplength zonewidth = czone.shipwidth From f97ef251049d8048e34ad2300237d296582b1f1a Mon Sep 17 00:00:00 2001 From: Frank Date: Thu, 1 May 2025 22:11:43 +0200 Subject: [PATCH 020/234] Update Unit.lua --- Moose Development/Moose/Wrapper/Unit.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/Moose Development/Moose/Wrapper/Unit.lua b/Moose Development/Moose/Wrapper/Unit.lua index 10d59ed81..b4a80c643 100644 --- a/Moose Development/Moose/Wrapper/Unit.lua +++ b/Moose Development/Moose/Wrapper/Unit.lua @@ -1107,7 +1107,6 @@ function UNIT:GetUnits() if DCSUnit then Units[1] = UNIT:Find(DCSUnit) - - self:T3(Units) return Units end From 0c90e90c180b0c7808081b4aae1905b5cb2bc6fc Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Fri, 2 May 2025 10:52:52 +0200 Subject: [PATCH 021/234] #CSAR - fixed design issue that prevented usage of ZONE objects as MASHes --- Moose Development/Moose/Ops/CSAR.lua | 40 +++++++++++++++++++--------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/Moose Development/Moose/Ops/CSAR.lua b/Moose Development/Moose/Ops/CSAR.lua index e7805f25a..76f6df917 100644 --- a/Moose Development/Moose/Ops/CSAR.lua +++ b/Moose Development/Moose/Ops/CSAR.lua @@ -31,7 +31,7 @@ -- @image OPS_CSAR.jpg --- --- Last Update Jan 2025 +-- Last Update May 2025 ------------------------------------------------------------------------- --- **CSAR** class, extends Core.Base#BASE, Core.Fsm#FSM @@ -313,7 +313,7 @@ CSAR.AircraftType["CH-47Fbl1"] = 31 --- CSAR class version. -- @field #string version -CSAR.version="1.0.30" +CSAR.version="1.0.31" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- ToDo list @@ -2120,7 +2120,11 @@ end function CSAR:_GetClosestMASH(_heli) self:T(self.lid .. " _GetClosestMASH") local _mashset = self.mash -- Core.Set#SET_GROUP - local _mashes = _mashset:GetSetObjects() -- #table + local MashSets = {} + --local _mashes = _mashset.Set-- #table + table.insert(MashSets,_mashset.Set) + table.insert(MashSets,self.zonemashes.Set) + table.insert(MashSets,self.staticmashes.Set) local _shortestDistance = -1 local _distance = 0 local _helicoord = _heli:GetCoordinate() @@ -2151,14 +2155,19 @@ function CSAR:_GetClosestMASH(_heli) _shortestDistance = distance end - for _, _mashUnit in pairs(_mashes) do - if _mashUnit and _mashUnit:IsAlive() then - local _mashcoord = _mashUnit:GetCoordinate() - _distance = self:_GetDistance(_helicoord, _mashcoord) - if _distance ~= nil and (_shortestDistance == -1 or _distance < _shortestDistance) then - _shortestDistance = _distance - end - end + for _,_mashes in pairs(MashSets) do + for _, _mashUnit in pairs(_mashes or {}) do + local _mashcoord + if _mashUnit and (not _mashUnit:IsInstanceOf("ZONE_BASE")) and _mashUnit:IsAlive() then + _mashcoord = _mashUnit:GetCoordinate() + elseif _mashUnit and _mashUnit:IsInstanceOf("ZONE_BASE") then + _mashcoord = _mashUnit:GetCoordinate() + end + _distance = self:_GetDistance(_helicoord, _mashcoord) + if _distance ~= nil and (_shortestDistance == -1 or _distance < _shortestDistance) then + _shortestDistance = _distance + end + end end if _shortestDistance ~= -1 then @@ -2166,6 +2175,7 @@ function CSAR:_GetClosestMASH(_heli) else return -1 end + end --- (Internal) Display onboarded rescued pilots. @@ -2454,9 +2464,10 @@ function CSAR:onafterStart(From, Event, To) self.mash = SET_GROUP:New():FilterCoalitions(self.coalitiontxt):FilterPrefixes(self.mashprefix):FilterStart() - local staticmashes = SET_STATIC:New():FilterCoalitions(self.coalitiontxt):FilterPrefixes(self.mashprefix):FilterOnce() - local zonemashes = SET_ZONE:New():FilterPrefixes(self.mashprefix):FilterOnce() + self.staticmashes = SET_STATIC:New():FilterCoalitions(self.coalitiontxt):FilterPrefixes(self.mashprefix):FilterOnce() + self.zonemashes = SET_ZONE:New():FilterPrefixes(self.mashprefix):FilterOnce() + --[[ if staticmashes:Count() > 0 then for _,_mash in pairs(staticmashes.Set) do self.mash:AddObject(_mash) @@ -2464,10 +2475,13 @@ function CSAR:onafterStart(From, Event, To) end if zonemashes:Count() > 0 then + self:T("Adding zones to self.mash SET") for _,_mash in pairs(zonemashes.Set) do self.mash:AddObject(_mash) end + self:T("Objects in SET: "..self.mash:Count()) end + --]] if not self.coordinate then local csarhq = self.mash:GetRandom() From f1af3a50b82b7975e1a3995ecc41b975f1326223 Mon Sep 17 00:00:00 2001 From: Frank Date: Fri, 2 May 2025 21:36:03 +0200 Subject: [PATCH 022/234] Update Unit.lua - GetAmmo HE shells can also be named "HESH" --- Moose Development/Moose/Wrapper/Unit.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/Wrapper/Unit.lua b/Moose Development/Moose/Wrapper/Unit.lua index b4a80c643..1a5e51011 100644 --- a/Moose Development/Moose/Wrapper/Unit.lua +++ b/Moose Development/Moose/Wrapper/Unit.lua @@ -897,7 +897,7 @@ function UNIT:GetAmmunition() nAPshells = nAPshells + Nammo end - if ammotable[w].desc.typeName and string.find(ammotable[w].desc.typeName, "_HE", 1, true) then + if ammotable[w].desc.typeName and (string.find(ammotable[w].desc.typeName, "_HE", 1, true) or string.find(ammotable[w].desc.typeName, "HESH", 1, true)) then nHEshells = nHEshells + Nammo end From a6b622ed312fc3e7f7a7bde89bf68724ca8ba421 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sat, 3 May 2025 17:01:02 +0200 Subject: [PATCH 023/234] #CTLD - Additional features by Lekaa to drop and build one/many in one go and pack/load or get/load in one go --- Moose Development/Moose/Ops/CTLD.lua | 1112 ++++++++++++++++---------- 1 file changed, 671 insertions(+), 441 deletions(-) diff --git a/Moose Development/Moose/Ops/CTLD.lua b/Moose Development/Moose/Ops/CTLD.lua index c0c30ec72..405ca9a07 100644 --- a/Moose Development/Moose/Ops/CTLD.lua +++ b/Moose Development/Moose/Ops/CTLD.lua @@ -20,11 +20,12 @@ -- -- ### Author: **Applevangelist** (Moose Version), ***Ciribob*** (original), Thanks to: Shadowze, Cammel (testing), bbirchnz (additional code!!) -- ### Repack addition for crates: **Raiden** +-- ### Additional cool features: **Lekaa** -- -- @module Ops.CTLD -- @image OPS_CTLD.jpg --- Last Update April 2025 +-- Last Update May 2025 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -865,6 +866,7 @@ do -- my_ctld.TroopUnloadDistGroundHook = 15 -- On the ground, unload troops this far behind the Chinook -- my_ctld.TroopUnloadDistHoverHook = 5 -- When hovering, unload troops this far behind the Chinook -- my_ctld.showstockinmenuitems = false -- When set to true, the menu lines will also show the remaining items in stock (that is, if you set any), downside is that the menu for all will be build every 30 seconds anew. +-- my_ctld.onestepmenu = false -- When set to true, the menu will create Drop and build, Get and load, Pack and remove, Pack and load, Pack only. it will be a 1 step solution. -- -- ## 2.1 CH-47 Chinook support -- @@ -1412,7 +1414,7 @@ CTLD.FixedWingTypes = { --- CTLD class version. -- @field #string version -CTLD.version="1.2.33" +CTLD.version="1.3.34" --- Instantiate a new CTLD. -- @param #CTLD self @@ -1591,6 +1593,7 @@ function CTLD:New(Coalition, Prefixes, Alias) self.subcats = {} self.subcatsTroop = {} self.showstockinmenuitems = false + self.onestepmenu = false -- disallow building in loadzones self.nobuildinloadzones = true @@ -2913,10 +2916,10 @@ function CTLD:_GetCrates(Group, Unit, Cargo, number, drop, pack) if drop then text = string.format("Crates for %s have been dropped!",cratename) self:__CratesDropped(1, Group, Unit, droppedcargo) + else + self:_SendMessage(text, 10, false, Group) end - self:_SendMessage(text, 10, false, Group) self:_RefreshLoadCratesMenu(Group, Unit) - return self end @@ -3576,11 +3579,14 @@ end -- @param Wrapper.Unit#UNIT Unit -- @return #boolean Outcome function CTLD:IsHook(Unit) - if Unit and string.find(Unit:GetTypeName(),"CH.47") then - return true - else - return false - end + if not Unit then return false end + local typeName = Unit:GetTypeName() + if not typeName then return false end + if string.find(typeName, "CH.47") then + return true + else + return false + end end --- (Internal) Function to set troops positions of a template to a nice circle @@ -3763,89 +3769,103 @@ end -- @param Wrapper.Group#GROUP Group -- @param Wrapper.Unit#UNIT Unit function CTLD:_UnloadCrates(Group, Unit) - self:T(self.lid .. " _UnloadCrates") - - if not self.dropcratesanywhere then -- #1570 - -- check if we are in DROP zone - local inzone, zonename, zone, distance = self:IsUnitInZone(Unit,CTLD.CargoZoneType.DROP) - if not inzone then - self:_SendMessage("You are not close enough to a drop zone!", 10, false, Group) - if not self.debug then - return self - end - end - end - -- Door check - if self.pilotmustopendoors and not UTILS.IsLoadingDoorOpen(Unit:GetName()) then - self:_SendMessage("You need to open the door(s) to drop cargo!", 10, false, Group) - if not self.debug then return self end - end - -- check for hover unload - local hoverunload = self:IsCorrectHover(Unit) --if true we\'re hovering in parameters - local IsHerc = self:IsFixedWing(Unit) - local IsHook = self:IsHook(Unit) - if IsHerc and (not IsHook) then - -- no hover but airdrop here - hoverunload = self:IsCorrectFlightParameters(Unit) - end - -- check if we\'re landed - local grounded = not self:IsUnitInAir(Unit) - -- Get what we have loaded - local unitname = Unit:GetName() - if self.Loaded_Cargo[unitname] and (grounded or hoverunload) then - local loadedcargo = self.Loaded_Cargo[unitname] or {} -- #CTLD.LoadedCargo - -- looking for crate - local cargotable = loadedcargo.Cargo - for _,_cargo in pairs (cargotable) do - local cargo = _cargo -- #CTLD_CARGO - local type = cargo:GetType() -- #CTLD_CARGO.Enum - if type ~= CTLD_CARGO.Enum.TROOPS and type ~= CTLD_CARGO.Enum.ENGINEERS and type ~= CTLD_CARGO.Enum.GCLOADABLE and (not cargo:WasDropped() or self.allowcratepickupagain) then - -- unload crates - self:_GetCrates(Group, Unit, cargo, 1, true) - cargo:SetWasDropped(true) - cargo:SetHasMoved(true) - end - end - -- cleanup load list - local loaded = {} -- #CTLD.LoadedCargo - loaded.Troopsloaded = 0 - loaded.Cratesloaded = 0 - loaded.Cargo = {} + self:T(self.lid .. " _UnloadCrates") - for _,_cargo in pairs (cargotable) do - local cargo = _cargo -- #CTLD_CARGO - local type = cargo:GetType() -- #CTLD_CARGO.Enum - local size = cargo:GetCratesNeeded() - if type == CTLD_CARGO.Enum.TROOPS or type == CTLD_CARGO.Enum.ENGINEERS then - table.insert(loaded.Cargo,_cargo) - loaded.Troopsloaded = loaded.Troopsloaded + size - end - if type == CTLD_CARGO.Enum.GCLOADABLE and not cargo:WasDropped() then - table.insert(loaded.Cargo,_cargo) - loaded.Cratesloaded = loaded.Cratesloaded + size + if not self.dropcratesanywhere then -- #1570 + local inzone, zonename, zone, distance = self:IsUnitInZone(Unit,CTLD.CargoZoneType.DROP) + if not inzone then + self:_SendMessage("You are not close enough to a drop zone!", 10, false, Group) + if not self.debug then + return self + end end end - self.Loaded_Cargo[unitname] = nil - self.Loaded_Cargo[unitname] = loaded - - self:_UpdateUnitCargoMass(Unit) - self:_RefreshDropCratesMenu(Group,Unit) - else - if IsHerc then - self:_SendMessage("Nothing loaded or not within airdrop parameters!", 10, false, Group) + if self.pilotmustopendoors and not UTILS.IsLoadingDoorOpen(Unit:GetName()) then + self:_SendMessage("You need to open the door(s) to drop cargo!", 10, false, Group) + if not self.debug then return self end + end + local hoverunload = self:IsCorrectHover(Unit) + local IsHerc = self:IsFixedWing(Unit) + local IsHook = self:IsHook(Unit) + if IsHerc and (not IsHook) then + hoverunload = self:IsCorrectFlightParameters(Unit) + end + local grounded = not self:IsUnitInAir(Unit) + local unitname = Unit:GetName() + if self.Loaded_Cargo[unitname] and (grounded or hoverunload) then + local loadedcargo = self.Loaded_Cargo[unitname] or {} + local cargotable = loadedcargo.Cargo + local droppedCount = {} + local neededMap = {} + for _,_cargo in pairs (cargotable) do + local cargo = _cargo + local type = cargo:GetType() + if type ~= CTLD_CARGO.Enum.TROOPS and type ~= CTLD_CARGO.Enum.ENGINEERS and type ~= CTLD_CARGO.Enum.GCLOADABLE and (not cargo:WasDropped() or self.allowcratepickupagain) then + self:_GetCrates(Group, Unit, cargo, 1, true) + cargo:SetWasDropped(true) + cargo:SetHasMoved(true) + local cname = cargo:GetName() or "Unknown" + droppedCount[cname] = (droppedCount[cname] or 0) + 1 + if not neededMap[cname] then + neededMap[cname] = cargo:GetCratesNeeded() or 1 + end + end + end + for cname,count in pairs(droppedCount) do + local needed = neededMap[cname] or 1 + if needed > 1 then + local full = math.floor(count/needed) + local left = count % needed + if full > 0 and left == 0 then + self:_SendMessage(string.format("Dropped %d %s.",full,cname),10,false,Group) + elseif full > 0 and left > 0 then + self:_SendMessage(string.format("Dropped %d %s(s), with %d leftover crate(s).",full,cname,left),10,false,Group) + else + self:_SendMessage(string.format("Dropped %d/%d crate(s) of %s.",count,needed,cname),15,false,Group) + end + else + self:_SendMessage(string.format("Dropped %d %s(s).",count,cname),10,false,Group) + end + end + local loaded = {} + loaded.Troopsloaded = 0 + loaded.Cratesloaded = 0 + loaded.Cargo = {} + for _,_cargo in pairs (cargotable) do + local cargo = _cargo + local type = cargo:GetType() + local size = cargo:GetCratesNeeded() + if type == CTLD_CARGO.Enum.TROOPS or type == CTLD_CARGO.Enum.ENGINEERS then + table.insert(loaded.Cargo,_cargo) + loaded.Troopsloaded = loaded.Troopsloaded + size + end + if type == CTLD_CARGO.Enum.GCLOADABLE and not cargo:WasDropped() then + table.insert(loaded.Cargo,_cargo) + loaded.Cratesloaded = loaded.Cratesloaded + size + end + end + self.Loaded_Cargo[unitname] = nil + self.Loaded_Cargo[unitname] = loaded + + self:_UpdateUnitCargoMass(Unit) + self:_RefreshDropCratesMenu(Group,Unit) else - self:_SendMessage("Nothing loaded or not hovering within parameters!", 10, false, Group) - end + if IsHerc then + self:_SendMessage("Nothing loaded or not within airdrop parameters!", 10, false, Group) + else + self:_SendMessage("Nothing loaded or not hovering within parameters!", 10, false, Group) + end + end + return self end - return self -end --- (Internal) Function to build nearby crates. -- @param #CTLD self -- @param Wrapper.Group#GROUP Group -- @param Wrapper.Unit#UNIT Unit -- @param #boolean Engineering If true build is by an engineering team. -function CTLD:_BuildCrates(Group, Unit,Engineering) +-- @param #boolean MultiDrop If true and not engineering or FOB, vary position a bit. +function CTLD:_BuildCrates(Group, Unit,Engineering,MultiDrop) self:T(self.lid .. " _BuildCrates") -- avoid users trying to build from flying Hercs if self:IsFixedWing(Unit) and self.enableFixedWing and not Engineering then @@ -3939,12 +3959,13 @@ function CTLD:_BuildCrates(Group, Unit,Engineering) if build.CanBuild then self:_CleanUpCrates(crates,build,number) if self.buildtime and self.buildtime > 0 then - local buildtimer = TIMER:New(self._BuildObjectFromCrates,self,Group,Unit,build,false,Group:GetCoordinate()) + local buildtimer = TIMER:New(self._BuildObjectFromCrates,self,Group,Unit,build,false,Group:GetCoordinate(),MultiDrop) buildtimer:Start(self.buildtime) self:_SendMessage(string.format("Build started, ready in %d seconds!",self.buildtime),15,false,Group) self:__CratesBuildStarted(1,Group,Unit) + self:_RefreshDropTroopsMenu(Group,Unit) else - self:_BuildObjectFromCrates(Group,Unit,build) + self:_BuildObjectFromCrates(Group,Unit,build,false,nil,MultiDrop) end end end @@ -3983,13 +4004,14 @@ function CTLD:_PackCratesNearby(Group, Unit) _Group:Destroy() -- if a match is found destroy the Wrapper.Group#GROUP near the player self:_GetCrates(Group, Unit, _entry, nil, false, true) -- spawn the appropriate crates near the player self:_RefreshLoadCratesMenu(Group,Unit) -- call the refresher to show the crates in the menu - return self + return true end end end end end - return self + self:_SendMessage("Nothing to pack at this distance pilot!",10,false,Group) + return false end --- (Internal) Function to repair nearby vehicles / FOBs @@ -4082,7 +4104,8 @@ end -- @param #CTLD.Buildable Build -- @param #boolean Repair If true this is a repair and not a new build -- @param Core.Point#COORDINATE RepairLocation Location for repair (e.g. where the destroyed unit was) -function CTLD:_BuildObjectFromCrates(Group,Unit,Build,Repair,RepairLocation) +-- @param #boolean MultiDrop if true and not a repair, vary location a bit if not a FOB +function CTLD:_BuildObjectFromCrates(Group,Unit,Build,Repair,RepairLocation,MultiDrop) self:T(self.lid .. " _BuildObjectFromCrates") -- Spawn-a-crate-content if Group and Group:IsAlive() or (RepairLocation and not Repair) then @@ -4099,7 +4122,7 @@ function CTLD:_BuildObjectFromCrates(Group,Unit,Build,Repair,RepairLocation) if type(temptable) == "string" then temptable = {temptable} end - local zone = nil + local zone = nil -- Core.Zone#ZONE_RADIUS if RepairLocation and not Repair then -- timed build zone = ZONE_RADIUS:New(string.format("Build zone-%d",math.random(1,10000)),RepairLocation:GetVec2(),100) @@ -4108,6 +4131,10 @@ function CTLD:_BuildObjectFromCrates(Group,Unit,Build,Repair,RepairLocation) end --local randomcoord = zone:GetRandomCoordinate(35):GetVec2() local randomcoord = Build.Coord or zone:GetRandomCoordinate(35):GetVec2() + if MultiDrop and (not Repair) and canmove then + -- coordinate may be the same, avoid + local randomcoord = zone:GetRandomCoordinate(35):GetVec2() + end if Repair then randomcoord = RepairLocation:GetVec2() end @@ -4199,310 +4226,458 @@ function CTLD:_CleanUpCrates(Crates,Build,Number) return self end +--- (Internal) Helper - Drop **all** loaded crates nearby and build them. +-- @param Wrapper.Group#GROUP Group The calling group +-- @param Wrapper.Unit#UNIT Unit The calling unit +function CTLD:_DropAndBuild(Group,Unit) + if self.nobuildinloadzones then + if self:IsUnitInZone(Unit,CTLD.CargoZoneType.LOAD) then + self:_SendMessage("You cannot build in a loading area, Pilot!",10,false,Group) + return self + end + end + self:_UnloadCrates(Group,Unit) + timer.scheduleFunction(function() self:_BuildCrates(Group,Unit,false,true) end,{},timer.getTime()+1) + end + + --- (Internal) Helper - Drop a **single** crate set and build it. +-- @param Wrapper.Group#GROUP Group The calling group +-- @param Wrapper.Unit#UNIT Unit The calling unit +-- @param number setIndex Index of the crate-set to drop + function CTLD:_DropSingleAndBuild(Group,Unit,setIndex) + if self.nobuildinloadzones then + if self:IsUnitInZone(Unit,CTLD.CargoZoneType.LOAD) then + self:_SendMessage("You cannot build in a loading area, Pilot!",10,false,Group) + return self + end + end + self:_UnloadSingleCrateSet(Group,Unit,setIndex) + timer.scheduleFunction(function() self:_BuildCrates(Group,Unit,false) end,{},timer.getTime()+1) + end + +--- (Internal) Helper - Pack crates near the unit and load them. +-- @param Wrapper.Group#GROUP Group The calling group +-- @param Wrapper.Unit#UNIT Unit The calling unit +function CTLD:_PackAndLoad(Group,Unit) + if self.pilotmustopendoors and not UTILS.IsLoadingDoorOpen(Unit:GetName()) then + self:_SendMessage("You need to open the door(s) to load cargo!",10,false,Group) + return self + end + if not self:_PackCratesNearby(Group,Unit) then + return self + end + timer.scheduleFunction(function() self:_LoadCratesNearby(Group,Unit) end,{},timer.getTime()+1) + return self + end + +--- (Internal) Helper - Pack crates near the unit and then remove them. +-- @param Wrapper.Group#GROUP Group The calling group +-- @param Wrapper.Unit#UNIT Unit The calling unit +function CTLD:_PackAndRemove(Group,Unit) + if not self:_PackCratesNearby(Group,Unit) then + return self + end + timer.scheduleFunction(function() self:_RemoveCratesNearby(Group,Unit) end,{},timer.getTime()+1) + return self +end + +--- (Internal) Helper - get and load in one step +-- @param Wrapper.Group#GROUP Group The calling group +-- @param Wrapper.Unit#UNIT Unit The calling unit +function CTLD:_GetAndLoad(Group,Unit,cargoObj) + if self.pilotmustopendoors and not UTILS.IsLoadingDoorOpen(Unit:GetName()) then + self:_SendMessage("You need to open the door(s) to load cargo!",10,false,Group) + return self + end + self:_GetCrates(Group,Unit,cargoObj) + + timer.scheduleFunction(function() self:_LoadSingleCrateSet(Group,Unit,cargoObj.Name) end,{},timer.getTime()+1) +end + +-- @param Wrapper.Group#GROUP Group The player’s group that triggered the action +-- @param Wrapper.Unit#UNIT Unit The unit performing the pack-and-load +function CTLD:_GetAllAndLoad(Group,Unit) + if self.pilotmustopendoors and not UTILS.IsLoadingDoorOpen(Unit:GetName()) then + self:_SendMessage("You need to open the door(s) to load cargo!",10,false,Group) + return self + end + + timer.scheduleFunction(function() self:_LoadCratesNearby(Group,Unit) end,{},timer.getTime()+1) +end + --- (Internal) Housekeeping - Function to refresh F10 menus. -- @param #CTLD self -- @return #CTLD self function CTLD:_RefreshF10Menus() - self:T(self.lid .. " _RefreshF10Menus") - - -- 1) Gather all the pilot groups from our Set - local PlayerSet = self.PilotGroups - local PlayerTable = PlayerSet:GetSetObjects() - - -- 2) Rebuild the self.CtldUnits table - local _UnitList = {} - for _, groupObj in pairs(PlayerTable) do - local firstUnit = groupObj:GetFirstUnitAlive() - if firstUnit then - if firstUnit:IsPlayer() then - if firstUnit:IsHelicopter() or (self.enableFixedWing and self:IsFixedWing(firstUnit)) then - local _unit = firstUnit:GetName() - _UnitList[_unit] = _unit + self:T(self.lid .. " _RefreshF10Menus") + self.onestepmenu = self.onestepmenu or false -- hybrid toggle (default = false) + + -- 1) Gather all the pilot groups from our Set + local PlayerSet = self.PilotGroups + local PlayerTable = PlayerSet:GetSetObjects() + + -- 2) Rebuild the self.CtldUnits table + local _UnitList = {} + for _, groupObj in pairs(PlayerTable) do + local firstUnit = groupObj:GetFirstUnitAlive() + if firstUnit then + if firstUnit:IsPlayer() then + if firstUnit:IsHelicopter() or (self.enableFixedWing and self:IsFixedWing(firstUnit)) then + local _unit = firstUnit:GetName() + _UnitList[_unit] = _unit + end end end end - end - - -- 3) CA Units - if self.allowCATransport and self.CATransportSet then - for _,_clientobj in pairs(self.CATransportSet.Set) do - local client = _clientobj -- Wrapper.Client#CLIENT - if client:IsGround() then - local cname = client:GetName() - self:T(self.lid.."Adding: "..cname) - _UnitList[cname] = cname + + -- 3) CA Units + if self.allowCATransport and self.CATransportSet then + for _,_clientobj in pairs(self.CATransportSet.Set) do + local client = _clientobj -- Wrapper.Client#CLIENT + if client:IsGround() then + local cname = client:GetName() + self:T(self.lid.."Adding: "..cname) + _UnitList[cname] = cname + end end end + + self.CtldUnits = _UnitList + + -- subcats? + if self.usesubcats then + for _id,_cargo in pairs(self.Cargo_Crates) do + local entry = _cargo -- #CTLD_CARGO + if not self.subcats[entry.Subcategory] then + self.subcats[entry.Subcategory] = entry.Subcategory + end + end + for _id,_cargo in pairs(self.Cargo_Statics) do + local entry = _cargo -- #CTLD_CARGO + if not self.subcats[entry.Subcategory] then + self.subcats[entry.Subcategory] = entry.Subcategory + end + end + for _id,_cargo in pairs(self.Cargo_Troops) do + local entry = _cargo -- #CTLD_CARGO + if not self.subcatsTroop[entry.Subcategory] then + self.subcatsTroop[entry.Subcategory] = entry.Subcategory + end + end + end + + local menucount = 0 + local menus = {} + for _, _unitName in pairs(self.CtldUnits) do + if (not self.MenusDone[_unitName]) or (self.showstockinmenuitems == true) then + self:T(self.lid.."Menu not done yet for ".._unitName) + local _unit = UNIT:FindByName(_unitName) + if not _unit and self.allowCATransport then + _unit = CLIENT:FindByName(_unitName) + end + if _unit and _unit:IsAlive() then + local _group = _unit:GetGroup() + if _group then + self:T(self.lid.."Unit and Group exist") + local capabilities = self:_GetUnitCapabilities(_unit) + local cantroops = capabilities.troops + local cancrates = capabilities.crates + local unittype = _unit:GetTypeName() + local isHook = self:IsHook(_unit) + local nohookswitch = true + --local nohookswitch = not (isHook and self.enableChinookGCLoading) + -- Clear old topmenu if it existed + if _group.CTLDTopmenu then + _group.CTLDTopmenu:Remove() + _group.CTLDTopmenu = nil + end + local toptroops = nil + local topcrates = nil + local topmenu = MENU_GROUP:New(_group, "CTLD", nil) + _group.CTLDTopmenu = topmenu + + if cantroops then + local toptroops = MENU_GROUP:New(_group, "Manage Troops", topmenu) + local troopsmenu = MENU_GROUP:New(_group, "Load troops", toptroops) + _group.MyTopTroopsMenu = toptroops + + if self.usesubcats then + local subcatmenus = {} + for catName, _ in pairs(self.subcatsTroop) do + subcatmenus[catName] = MENU_GROUP:New(_group, catName, troopsmenu) + end + for _, cargoObj in pairs(self.Cargo_Troops) do + if not cargoObj.DontShowInMenu then + local stock = cargoObj:GetStock() + local menutext = cargoObj.Name + if (stock >= 0) and (self.showstockinmenuitems == true) then menutext = menutext.." ["..stock.."]" end + MENU_GROUP_COMMAND:New(_group, menutext, subcatmenus[cargoObj.Subcategory], self._LoadTroops, self, _group, _unit, cargoObj) + end + end + else + for _, cargoObj in pairs(self.Cargo_Troops) do + if not cargoObj.DontShowInMenu then + local stock = cargoObj:GetStock() + local menutext = cargoObj.Name + if (stock >= 0) and (self.showstockinmenuitems == true) then menutext = menutext.." ["..stock.."]" end + MENU_GROUP_COMMAND:New(_group, menutext, troopsmenu, self._LoadTroops, self, _group, _unit, cargoObj) + end + end + end + local dropTroopsMenu=MENU_GROUP:New(_group,"Drop Troops",toptroops):Refresh() + MENU_GROUP_COMMAND:New(_group,"Drop ALL troops",dropTroopsMenu,self._UnloadTroops,self,_group,_unit):Refresh() + MENU_GROUP_COMMAND:New(_group,"Extract troops",toptroops,self._ExtractTroops,self,_group,_unit):Refresh() + local uName=_unit:GetName() + local loadedData=self.Loaded_Cargo[uName] + if loadedData and loadedData.Cargo then + for i,cargoObj in ipairs(loadedData.Cargo) do + if cargoObj and (cargoObj:GetType()==CTLD_CARGO.Enum.TROOPS or cargoObj:GetType()==CTLD_CARGO.Enum.ENGINEERS) and not cargoObj:WasDropped() then + local name=cargoObj:GetName() or "Unknown" + local needed=cargoObj:GetCratesNeeded() or 1 + local cID=cargoObj:GetID() + local line=string.format("Drop: %s",name,needed,cID) + MENU_GROUP_COMMAND:New(_group,line,dropTroopsMenu,self._UnloadSingleTroopByID,self,_group,_unit,cID):Refresh() + end + end + end + end + if cancrates then + local topcrates = MENU_GROUP:New(_group, "Manage Crates", topmenu) + _group.MyTopCratesMenu = topcrates + + -- Build the “Get Crates” sub-menu items + local cratesmenu = MENU_GROUP:New(_group,"Get Crates",topcrates) + + if self.onestepmenu then + if self.usesubcats then + local subcatmenus = {} + for catName,_ in pairs(self.subcats) do + subcatmenus[catName] = MENU_GROUP:New(_group,catName,cratesmenu) + end + for _,cargoObj in pairs(self.Cargo_Crates) do + if not cargoObj.DontShowInMenu then + local txt = string.format("Crate %s (%dkg)",cargoObj.Name,cargoObj.PerCrateMass or 0) + if cargoObj.Location then txt = txt.."[R]" end + local stock = cargoObj:GetStock() + if stock>=0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end + local mSet = MENU_GROUP:New(_group,txt,subcatmenus[cargoObj.Subcategory]) + MENU_GROUP_COMMAND:New(_group,"Get and Load",mSet,self._GetAndLoad,self,_group,_unit,cargoObj) + MENU_GROUP_COMMAND:New(_group,"Get only",mSet,self._GetCrates,self,_group,_unit,cargoObj) + end + end + for _,cargoObj in pairs(self.Cargo_Statics) do + if not cargoObj.DontShowInMenu then + local txt = string.format("Crate %s (%dkg)",cargoObj.Name,cargoObj.PerCrateMass or 0) + if cargoObj.Location then txt = txt.."[R]" end + local stock = cargoObj:GetStock() + if stock>=0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end + local mSet = MENU_GROUP:New(_group,txt,subcatmenus[cargoObj.Subcategory]) + MENU_GROUP_COMMAND:New(_group,"Get and Load",mSet,self._GetAndLoad,self,_group,_unit,cargoObj) + MENU_GROUP_COMMAND:New(_group,"Get only",mSet,self._GetCrates,self,_group,_unit,cargoObj) + end + end + else + for _,cargoObj in pairs(self.Cargo_Crates) do + if not cargoObj.DontShowInMenu then + local txt = string.format("Crate %s (%dkg)",cargoObj.Name,cargoObj.PerCrateMass or 0) + if cargoObj.Location then txt = txt.."[R]" end + local stock = cargoObj:GetStock() + if stock>=0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end + local mSet = MENU_GROUP:New(_group,txt,cratesmenu) + MENU_GROUP_COMMAND:New(_group,"Get and Load",mSet,self._GetAndLoad,self,_group,_unit,cargoObj) + MENU_GROUP_COMMAND:New(_group,"Get only",mSet,self._GetCrates,self,_group,_unit,cargoObj) + end + end + for _,cargoObj in pairs(self.Cargo_Statics) do + if not cargoObj.DontShowInMenu then + local txt = string.format("Crate %s (%dkg)",cargoObj.Name,cargoObj.PerCrateMass or 0) + if cargoObj.Location then txt = txt.."[R]" end + local stock = cargoObj:GetStock() + if stock>=0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end + local mSet = MENU_GROUP:New(_group,txt,cratesmenu) + MENU_GROUP_COMMAND:New(_group,"Get and Load",mSet,self._GetAndLoad,self,_group,_unit,cargoObj) + MENU_GROUP_COMMAND:New(_group,"Get only",mSet,self._GetCrates,self,_group,_unit,cargoObj) + end + end + end + else + if self.usesubcats then + local subcatmenus = {} + for catName, _ in pairs(self.subcats) do + subcatmenus[catName] = MENU_GROUP:New(_group, catName, cratesmenu) -- fixed variable case + end + for _, cargoObj in pairs(self.Cargo_Crates) do + if not cargoObj.DontShowInMenu then + local txt = string.format("Crate %s (%dkg)", cargoObj.Name, cargoObj.PerCrateMass or 0) + if cargoObj.Location then txt = txt.."[R]" end + local stock = cargoObj:GetStock() + if stock >= 0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end + MENU_GROUP_COMMAND:New(_group, txt, subcatmenus[cargoObj.Subcategory], self._GetCrates, self, _group, _unit, cargoObj) + end + end + for _, cargoObj in pairs(self.Cargo_Statics) do + if not cargoObj.DontShowInMenu then + local txt = string.format("Crate %s (%dkg)", cargoObj.Name, cargoObj.PerCrateMass or 0) + if cargoObj.Location then txt = txt.."[R]" end + local stock = cargoObj:GetStock() + if stock >= 0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end + MENU_GROUP_COMMAND:New(_group, txt, subcatmenus[cargoObj.Subcategory], self._GetCrates, self, _group, _unit, cargoObj) + end + end + else + for _, cargoObj in pairs(self.Cargo_Crates) do + if not cargoObj.DontShowInMenu then + local txt = string.format("Crate %s (%dkg)", cargoObj.Name, cargoObj.PerCrateMass or 0) + if cargoObj.Location then txt = txt.."[R]" end + local stock = cargoObj:GetStock() + if stock >= 0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end + MENU_GROUP_COMMAND:New(_group, txt, cratesmenu, self._GetCrates, self, _group, _unit, cargoObj) + end + end + for _, cargoObj in pairs(self.Cargo_Statics) do + if not cargoObj.DontShowInMenu then + local txt = string.format("Crate %s (%dkg)", cargoObj.Name, cargoObj.PerCrateMass or 0) + if cargoObj.Location then txt = txt.."[R]" end + local stock = cargoObj:GetStock() + if stock >= 0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end + MENU_GROUP_COMMAND:New(_group, txt, cratesmenu, self._GetCrates, self, _group, _unit, cargoObj) + end + end + end + end + + local loadCratesMenu=MENU_GROUP:New(_group,"Load Crates",topcrates) + _group.MyLoadCratesMenu=loadCratesMenu + MENU_GROUP_COMMAND:New(_group,"Load ALL",loadCratesMenu,self._LoadCratesNearby,self,_group,_unit) + MENU_GROUP_COMMAND:New(_group,"Show loadable crates",loadCratesMenu,self._RefreshLoadCratesMenu,self,_group,_unit) + + local dropCratesMenu = MENU_GROUP:New(_group,"Drop Crates",topcrates) + topcrates.DropCratesMenu = dropCratesMenu + + if not self.nobuildmenu then + MENU_GROUP_COMMAND:New(_group, "Build crates", topcrates, self._BuildCrates, self, _group, _unit) + MENU_GROUP_COMMAND:New(_group, "Repair", topcrates, self._RepairCrates, self, _group, _unit):Refresh() + end + + local removecratesmenu = MENU_GROUP:New(_group, "Remove crates", topcrates) + MENU_GROUP_COMMAND:New(_group, "Remove crates nearby", removecratesmenu, self._RemoveCratesNearby, self, _group, _unit) + + if self.onestepmenu then + local mPack=MENU_GROUP:New(_group,"Pack crates",topcrates) + MENU_GROUP_COMMAND:New(_group,"Pack and Load",mPack,self._PackAndLoad,self,_group,_unit) + MENU_GROUP_COMMAND:New(_group,"Pack and Remove",mPack,self._PackAndRemove,self,_group,_unit) + MENU_GROUP_COMMAND:New(_group,"Pack only",mPack,self._PackCratesNearby,self,_group,_unit) + MENU_GROUP_COMMAND:New(_group, "List crates nearby", topcrates, self._ListCratesNearby, self, _group, _unit) + else + MENU_GROUP_COMMAND:New(_group, "Pack crates", topcrates, self._PackCratesNearby, self, _group, _unit) + MENU_GROUP_COMMAND:New(_group, "List crates nearby", topcrates, self._ListCratesNearby, self, _group, _unit) + end + + local uName = _unit:GetName() + local loadedData = self.Loaded_Cargo[uName] + if loadedData and loadedData.Cargo then + local cargoByName = {} + for _, cgo in pairs(loadedData.Cargo) do + if cgo and (not cgo:WasDropped()) then + local cname = cgo:GetName() + local cneeded = cgo:GetCratesNeeded() + cargoByName[cname] = cargoByName[cname] or { count=0, needed=cneeded } + cargoByName[cname].count = cargoByName[cname].count + 1 + end + end + for name, info in pairs(cargoByName) do + local line = string.format("Drop %s (%d/%d)", name, info.count, info.needed) + MENU_GROUP_COMMAND:New(_group, line, dropCratesMenu, self._UnloadSingleCrateSet, self, _group, _unit, name) + end + end + end + + ----------------------------------------------------- + -- Misc sub‐menus + ----------------------------------------------------- + MENU_GROUP_COMMAND:New(_group, "List boarded cargo", topmenu, self._ListCargo, self, _group, _unit) + MENU_GROUP_COMMAND:New(_group, "Inventory", topmenu, self._ListInventory, self, _group, _unit) + MENU_GROUP_COMMAND:New(_group, "List active zone beacons", topmenu, self._ListRadioBeacons, self, _group, _unit) + + local smoketopmenu = MENU_GROUP:New(_group, "Smokes, Flares, Beacons", topmenu) + MENU_GROUP_COMMAND:New(_group, "Smoke zones nearby", smoketopmenu, self.SmokeZoneNearBy, self, _unit, false) + local smokeself = MENU_GROUP:New(_group, "Drop smoke now", smoketopmenu) + MENU_GROUP_COMMAND:New(_group, "Red smoke", smokeself, self.SmokePositionNow, self, _unit, false, SMOKECOLOR.Red) + MENU_GROUP_COMMAND:New(_group, "Blue smoke", smokeself, self.SmokePositionNow, self, _unit, false, SMOKECOLOR.Blue) + MENU_GROUP_COMMAND:New(_group, "Green smoke", smokeself, self.SmokePositionNow, self, _unit, false, SMOKECOLOR.Green) + MENU_GROUP_COMMAND:New(_group, "Orange smoke", smokeself, self.SmokePositionNow, self, _unit, false, SMOKECOLOR.Orange) + MENU_GROUP_COMMAND:New(_group, "White smoke", smokeself, self.SmokePositionNow, self, _unit, false, SMOKECOLOR.White) + + MENU_GROUP_COMMAND:New(_group, "Flare zones nearby", smoketopmenu, self.SmokeZoneNearBy, self, _unit, true) + MENU_GROUP_COMMAND:New(_group, "Fire flare now", smoketopmenu, self.SmokePositionNow, self, _unit, true) + MENU_GROUP_COMMAND:New(_group, "Drop beacon now", smoketopmenu, self.DropBeaconNow, self, _unit):Refresh() + + if self:IsFixedWing(_unit) then + MENU_GROUP_COMMAND:New(_group, "Show flight parameters", topmenu, self._ShowFlightParams, self, _group, _unit):Refresh() + else + MENU_GROUP_COMMAND:New(_group, "Show hover parameters", topmenu, self._ShowHoverParams, self, _group, _unit):Refresh() + end + + -- Mark we built the menu + self.MenusDone[_unitName] = true + self:_RefreshLoadCratesMenu(_group,_unit) + self:_RefreshDropCratesMenu(_group,_unit) + + end -- if _group + end -- if _unit + else + self:T(self.lid .. " Menus already done for this group!") + end + end -- for all pilot units + + return self end - self.CtldUnits = _UnitList - - -- subcats? - if self.usesubcats then - for _id,_cargo in pairs(self.Cargo_Crates) do - local entry = _cargo -- #CTLD_CARGO - if not self.subcats[entry.Subcategory] then - self.subcats[entry.Subcategory] = entry.Subcategory - end - end - for _id,_cargo in pairs(self.Cargo_Statics) do - local entry = _cargo -- #CTLD_CARGO - if not self.subcats[entry.Subcategory] then - self.subcats[entry.Subcategory] = entry.Subcategory - end - end - for _id,_cargo in pairs(self.Cargo_Troops) do - local entry = _cargo -- #CTLD_CARGO - if not self.subcatsTroop[entry.Subcategory] then - self.subcatsTroop[entry.Subcategory] = entry.Subcategory - end - end - end - - local menucount = 0 - local menus = {} - for _, _unitName in pairs(self.CtldUnits) do - if (not self.MenusDone[_unitName]) or (self.showstockinmenuitems == true) then - self:T(self.lid.."Menu not done yet for ".._unitName) - local _unit = UNIT:FindByName(_unitName) - if not _unit and self.allowCATransport then - _unit = CLIENT:FindByName(_unitName) - end - if _unit and _unit:IsAlive() then - local _group = _unit:GetGroup() - if _group then - self:T(self.lid.."Unit and Group exist") - local capabilities = self:_GetUnitCapabilities(_unit) - local cantroops = capabilities.troops - local cancrates = capabilities.crates - local unittype = _unit:GetTypeName() - local isHook = self:IsHook(_unit) - local nohookswitch = true - --local nohookswitch = not (isHook and self.enableChinookGCLoading) - -- Clear old topmenu if it existed - if _group.CTLDTopmenu then - _group.CTLDTopmenu:Remove() - _group.CTLDTopmenu = nil - end - local toptroops = nil - local topcrates = nil - local topmenu = MENU_GROUP:New(_group, "CTLD", nil) - _group.CTLDTopmenu = topmenu - - if cantroops then - local toptroops = MENU_GROUP:New(_group, "Manage Troops", topmenu) - local troopsmenu = MENU_GROUP:New(_group, "Load troops", toptroops) - _group.MyTopTroopsMenu = toptroops - - if self.usesubcats then - local subcatmenus = {} - for catName, _ in pairs(self.subcatsTroop) do - subcatmenus[catName] = MENU_GROUP:New(_group, catName, troopsmenu) - end - for _, cargoObj in pairs(self.Cargo_Troops) do - if not cargoObj.DontShowInMenu then - local stock = cargoObj:GetStock() - local menutext = cargoObj.Name - if (stock >= 0) and (self.showstockinmenuitems == true) then menutext = menutext.." ["..stock.."]" end - MENU_GROUP_COMMAND:New(_group, menutext, subcatmenus[cargoObj.Subcategory], self._LoadTroops, self, _group, _unit, cargoObj) - end - end - else - for _, cargoObj in pairs(self.Cargo_Troops) do - if not cargoObj.DontShowInMenu then - local stock = cargoObj:GetStock() - local menutext = cargoObj.Name - if (stock >= 0) and (self.showstockinmenuitems == true) then menutext = menutext.." ["..stock.."]" end - MENU_GROUP_COMMAND:New(_group, menutext, troopsmenu, self._LoadTroops, self, _group, _unit, cargoObj) - - end - end - end - local dropTroopsMenu=MENU_GROUP:New(_group,"Drop Troops",toptroops):Refresh() - MENU_GROUP_COMMAND:New(_group,"Drop ALL troops",dropTroopsMenu,self._UnloadTroops,self,_group,_unit):Refresh() - MENU_GROUP_COMMAND:New(_group,"Extract troops",toptroops,self._ExtractTroops,self,_group,_unit):Refresh() - local uName=_unit:GetName() - local loadedData=self.Loaded_Cargo[uName] - if loadedData and loadedData.Cargo then - for i,cargoObj in ipairs(loadedData.Cargo) do - if cargoObj and (cargoObj:GetType()==CTLD_CARGO.Enum.TROOPS or cargoObj:GetType()==CTLD_CARGO.Enum.ENGINEERS) and not cargoObj:WasDropped() then - local name=cargoObj:GetName() or "Unknown" - local needed=cargoObj:GetCratesNeeded() or 1 - local cID=cargoObj:GetID() - local line=string.format("Drop: %s",name,needed,cID) - MENU_GROUP_COMMAND:New(_group,line,dropTroopsMenu,self._UnloadSingleTroopByID,self,_group,_unit,cID):Refresh() - end - end - end - end - if cancrates then - local topcrates = MENU_GROUP:New(_group, "Manage Crates", topmenu) - _group.MyTopCratesMenu = topcrates - - -- Build the “Get Crates” sub-menu items - local cratesmenu = MENU_GROUP:New(_group, "Get Crates", topcrates) - if self.usesubcats then - local subcatmenus = {} - for catName, _ in pairs(self.subcats) do - subcatmenus[catName] = MENU_GROUP:New(_group, catName, cratesmenu) - end - for _, cargoObj in pairs(self.Cargo_Crates) do - if not cargoObj.DontShowInMenu then - local txt = string.format("Crate %s (%dkg)", cargoObj.Name, cargoObj.PerCrateMass or 0) - if cargoObj.Location then txt = txt.."[R]" end - local stock = cargoObj:GetStock() - if stock >= 0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end - MENU_GROUP_COMMAND:New(_group, txt, subcatmenus[cargoObj.Subcategory], self._GetCrates, self, _group, _unit, cargoObj) - end - end - for _, cargoObj in pairs(self.Cargo_Statics) do - if not cargoObj.DontShowInMenu then - local txt = string.format("Crate %s (%dkg)", cargoObj.Name, cargoObj.PerCrateMass or 0) - if cargoObj.Location then txt = txt.."[R]" end - local stock = cargoObj:GetStock() - if stock >= 0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end - MENU_GROUP_COMMAND:New(_group, txt, subcatmenus[cargoObj.Subcategory], self._GetCrates, self, _group, _unit, cargoObj) - end - end - else - for _, cargoObj in pairs(self.Cargo_Crates) do - if not cargoObj.DontShowInMenu then - local txt = string.format("Crate %s (%dkg)", cargoObj.Name, cargoObj.PerCrateMass or 0) - if cargoObj.Location then txt = txt.."[R]" end - local stock = cargoObj:GetStock() - if stock >= 0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end - MENU_GROUP_COMMAND:New(_group, txt, cratesmenu, self._GetCrates, self, _group, _unit, cargoObj) - end - end - for _, cargoObj in pairs(self.Cargo_Statics) do - if not cargoObj.DontShowInMenu then - local txt = string.format("Crate %s (%dkg)", cargoObj.Name, cargoObj.PerCrateMass or 0) - if cargoObj.Location then txt = txt.."[R]" end - local stock = cargoObj:GetStock() - if stock >= 0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end - MENU_GROUP_COMMAND:New(_group, txt, cratesmenu, self._GetCrates, self, _group, _unit, cargoObj) - end - end - end - - local loadCratesMenu=MENU_GROUP:New(_group,"Load Crates",topcrates) - _group.MyLoadCratesMenu=loadCratesMenu - MENU_GROUP_COMMAND:New(_group,"Load ALL",loadCratesMenu,self._LoadCratesNearby,self,_group,_unit) - MENU_GROUP_COMMAND:New(_group,"Show loadable crates",loadCratesMenu,self._RefreshLoadCratesMenu,self,_group,_unit) - - local dropCratesMenu=MENU_GROUP:New(_group,"Drop Crates",topcrates) - topcrates.DropCratesMenu=dropCratesMenu - - if not self.nobuildmenu then - MENU_GROUP_COMMAND:New(_group, "Build crates", topcrates, self._BuildCrates, self, _group, _unit) - MENU_GROUP_COMMAND:New(_group, "Repair", topcrates, self._RepairCrates, self, _group, _unit):Refresh() - end - - local removecratesmenu = MENU_GROUP:New(_group, "Remove crates", topcrates) - MENU_GROUP_COMMAND:New(_group, "Remove crates nearby", removecratesmenu, self._RemoveCratesNearby, self, _group, _unit) - - MENU_GROUP_COMMAND:New(_group, "Pack crates", topcrates, self._PackCratesNearby, self, _group, _unit) - MENU_GROUP_COMMAND:New(_group, "List crates nearby", topcrates, self._ListCratesNearby, self, _group, _unit) - - local uName = _unit:GetName() - local loadedData = self.Loaded_Cargo[uName] - if loadedData and loadedData.Cargo then - local cargoByName = {} - for _, cgo in pairs(loadedData.Cargo) do - if cgo and (not cgo:WasDropped()) then - local cname = cgo:GetName() - local cneeded = cgo:GetCratesNeeded() - cargoByName[cname] = cargoByName[cname] or { count=0, needed=cneeded } - cargoByName[cname].count = cargoByName[cname].count + 1 - end - end - for name, info in pairs(cargoByName) do - local line = string.format("Drop %s (%d/%d)", name, info.count, info.needed) - MENU_GROUP_COMMAND:New(_group, line, dropCratesMenu, self._UnloadSingleCrateSet, self, _group, _unit, name) - end - end - end - - - - ----------------------------------------------------- - -- Misc sub‐menus - ----------------------------------------------------- - MENU_GROUP_COMMAND:New(_group, "List boarded cargo", topmenu, self._ListCargo, self, _group, _unit) - MENU_GROUP_COMMAND:New(_group, "Inventory", topmenu, self._ListInventory, self, _group, _unit) - MENU_GROUP_COMMAND:New(_group, "List active zone beacons", topmenu, self._ListRadioBeacons, self, _group, _unit) - - local smoketopmenu = MENU_GROUP:New(_group, "Smokes, Flares, Beacons", topmenu) - MENU_GROUP_COMMAND:New(_group, "Smoke zones nearby", smoketopmenu, self.SmokeZoneNearBy, self, _unit, false) - local smokeself = MENU_GROUP:New(_group, "Drop smoke now", smoketopmenu) - MENU_GROUP_COMMAND:New(_group, "Red smoke", smokeself, self.SmokePositionNow, self, _unit, false, SMOKECOLOR.Red) - MENU_GROUP_COMMAND:New(_group, "Blue smoke", smokeself, self.SmokePositionNow, self, _unit, false, SMOKECOLOR.Blue) - MENU_GROUP_COMMAND:New(_group, "Green smoke", smokeself, self.SmokePositionNow, self, _unit, false, SMOKECOLOR.Green) - MENU_GROUP_COMMAND:New(_group, "Orange smoke", smokeself, self.SmokePositionNow, self, _unit, false, SMOKECOLOR.Orange) - MENU_GROUP_COMMAND:New(_group, "White smoke", smokeself, self.SmokePositionNow, self, _unit, false, SMOKECOLOR.White) - - MENU_GROUP_COMMAND:New(_group, "Flare zones nearby", smoketopmenu, self.SmokeZoneNearBy, self, _unit, true) - MENU_GROUP_COMMAND:New(_group, "Fire flare now", smoketopmenu, self.SmokePositionNow, self, _unit, true) - MENU_GROUP_COMMAND:New(_group, "Drop beacon now", smoketopmenu, self.DropBeaconNow, self, _unit):Refresh() - - if self:IsFixedWing(_unit) then - MENU_GROUP_COMMAND:New(_group, "Show flight parameters", topmenu, self._ShowFlightParams, self, _group, _unit):Refresh() - else - MENU_GROUP_COMMAND:New(_group, "Show hover parameters", topmenu, self._ShowHoverParams, self, _group, _unit):Refresh() - end - - -- Mark we built the menu - self.MenusDone[_unitName] = true - self:_RefreshLoadCratesMenu(_group, _unit) - self:_RefreshDropCratesMenu(_group,_unit) - - end -- if _group - end -- if _unit - else - self:T(self.lid .. " Menus already done for this group!") - end - end -- for all pilot units - - return self -end - --- (Internal) Function to refresh the menu for load crates. Triggered from land/getcrate/pack and more -- @param #CTLD self -- @param Wrapper.Group#GROUP Group The calling group. -- @param Wrapper.Unit#UNIT Unit The calling unit. -- @return #CTLD self -function CTLD:_RefreshLoadCratesMenu(Group, Unit) - if not Group.MyLoadCratesMenu then return end - Group.MyLoadCratesMenu:RemoveSubMenus() - - local d = self.CrateDistance or 35 - local nearby, n = self:_FindCratesNearby(Group, Unit, d, true, true) - if n == 0 then - MENU_GROUP_COMMAND:New(Group, "No crates found! Rescan?", Group.MyLoadCratesMenu, function() self:_RefreshLoadCratesMenu(Group, Unit) end) - return - end - MENU_GROUP_COMMAND:New(Group, "Load ALL", Group.MyLoadCratesMenu, self._LoadCratesNearby, self, Group, Unit) - local cargoByName = {} - for _, crate in pairs(nearby) do - local cName = crate:GetName() - cargoByName[cName] = cargoByName[cName] or {} - table.insert(cargoByName[cName], crate) - end - - for cName, cList in pairs(cargoByName) do - local needed = cList[1]:GetCratesNeeded() or 1 - local found = #cList - - local line - if found >= needed then - line = string.format("Load %s", cName) - else - MENU_GROUP_COMMAND:New(Group, "Rescan?", Group.MyLoadCratesMenu, function() self:_RefreshLoadCratesMenu(Group, Unit) end) - line = string.format("Load %s (%d/%d)", cName, found, needed) +function CTLD:_RefreshLoadCratesMenu(Group,Unit) + if not Group.MyLoadCratesMenu then return end + Group.MyLoadCratesMenu:RemoveSubMenus() + + local d=self.CrateDistance or 35 + local nearby,n=self:_FindCratesNearby(Group,Unit,d,true,true) + if n==0 then + MENU_GROUP_COMMAND:New(Group,"No crates found! Rescan?",Group.MyLoadCratesMenu,function() self:_RefreshLoadCratesMenu(Group,Unit) end) + return + end + MENU_GROUP_COMMAND:New(Group,"Load ALL",Group.MyLoadCratesMenu,self._LoadCratesNearby,self,Group,Unit) + + local cargoByName={} + for _,crate in pairs(nearby) do + local name=crate:GetName() + cargoByName[name]=cargoByName[name] or{} + table.insert(cargoByName[name],crate) + end + + local lineIndex=1 + for cName,list in pairs(cargoByName) do + local needed=list[1]:GetCratesNeeded() or 1 + table.sort(list,function(a,b)return a:GetID()=needed then + label=string.format("%d. Load %s",lineIndex,cName) + i=i+needed + else + label=string.format("%d. Load %s (%d/%d)",lineIndex,cName,left,needed) + i=#list+1 + end + MENU_GROUP_COMMAND:New(Group,label,Group.MyLoadCratesMenu,self._LoadSingleCrateSet,self,Group,Unit,cName) + lineIndex=lineIndex+1 + end end - MENU_GROUP_COMMAND:New(Group, line, Group.MyLoadCratesMenu, self._LoadSingleCrateSet, self, Group, Unit, cName) end -end + --- -- Loads exactly `CratesNeeded` crates for one cargoName in range. @@ -4745,78 +4920,133 @@ end -- @param Wrapper.Unit#UNIT Unit The calling unit. -- @return #CTLD self function CTLD:_RefreshDropCratesMenu(Group, Unit) - if not Group.CTLDTopmenu then return end - local topCrates = Group.MyTopCratesMenu - if not topCrates then return end - if topCrates.DropCratesMenu then - topCrates.DropCratesMenu:RemoveSubMenus() - else - topCrates.DropCratesMenu = MENU_GROUP:New(Group, "Drop Crates", topCrates) - end - local dropCratesMenu = topCrates.DropCratesMenu - local loadedData = self.Loaded_Cargo[Unit:GetName()] - if not loadedData or not loadedData.Cargo then - MENU_GROUP_COMMAND:New(Group,"No crates to drop!",dropCratesMenu,function() end) - return - end - - local cargoByName={} - local dropableCrates=0 - for _,cObj in ipairs(loadedData.Cargo) do - if cObj and not cObj:WasDropped() then - local cType=cObj:GetType() - if cType~=CTLD_CARGO.Enum.TROOPS and cType~=CTLD_CARGO.Enum.ENGINEERS and cType~=CTLD_CARGO.Enum.GCLOADABLE then - local name=cObj:GetName()or"Unknown" - cargoByName[name]=cargoByName[name]or{} - table.insert(cargoByName[name],cObj) - dropableCrates=dropableCrates+1 + if not Group.CTLDTopmenu then return end + local topCrates = Group.MyTopCratesMenu + if not topCrates then return end + if topCrates.DropCratesMenu then + topCrates.DropCratesMenu:RemoveSubMenus() + else + topCrates.DropCratesMenu = MENU_GROUP:New(Group, "Drop Crates", topCrates) + end + + local dropCratesMenu = topCrates.DropCratesMenu + local loadedData = self.Loaded_Cargo[Unit:GetName()] + if not loadedData or not loadedData.Cargo then + MENU_GROUP_COMMAND:New(Group,"No crates to drop!",dropCratesMenu,function() end) + return + end + + local cargoByName={} + local dropableCrates=0 + for _,cObj in ipairs(loadedData.Cargo) do + if cObj and not cObj:WasDropped() then + local cType=cObj:GetType() + if cType~=CTLD_CARGO.Enum.TROOPS and cType~=CTLD_CARGO.Enum.ENGINEERS and cType~=CTLD_CARGO.Enum.GCLOADABLE then + local name=cObj:GetName()or"Unknown" + cargoByName[name]=cargoByName[name]or{} + table.insert(cargoByName[name],cObj) + dropableCrates=dropableCrates+1 + end + end + end + + if dropableCrates==0 then + MENU_GROUP_COMMAND:New(Group,"No crates to drop!",dropCratesMenu,function() end) + return + end + + ---------------------------------------------------------------------- + -- DEFAULT (“classic”) versus ONE-STEP behaviour + ---------------------------------------------------------------------- + if not self.onestepmenu then + -------------------------------------------------------------------- + -- classic menu + -------------------------------------------------------------------- + MENU_GROUP_COMMAND:New(Group,"Drop ALL crates",dropCratesMenu,self._UnloadCrates,self,Group,Unit) + + self.CrateGroupList=self.CrateGroupList or{} + self.CrateGroupList[Unit:GetName()]={} + + local lineIndex=1 + for cName,list in pairs(cargoByName) do + local needed=list[1]:GetCratesNeeded() or 1 + table.sort(list,function(a,b)return a:GetID()=needed then + local chunk={} + for n=i,i+needed-1 do + table.insert(chunk,list[n]) + end + local label=string.format("%d. %s",lineIndex,cName) + table.insert(self.CrateGroupList[Unit:GetName()],chunk) + local setIndex=#self.CrateGroupList[Unit:GetName()] + MENU_GROUP_COMMAND:New(Group,label,dropCratesMenu,self._UnloadSingleCrateSet,self,Group,Unit,setIndex) + i=i+needed + else + local chunk={} + for n=i,#list do + table.insert(chunk,list[n]) + end + local label=string.format("%d. %s %d/%d",lineIndex,cName,left,needed) + table.insert(self.CrateGroupList[Unit:GetName()],chunk) + local setIndex=#self.CrateGroupList[Unit:GetName()] + MENU_GROUP_COMMAND:New(Group,label,dropCratesMenu,self._UnloadSingleCrateSet,self,Group,Unit,setIndex) + i=#list+1 + end + lineIndex=lineIndex+1 + end + end + + else + -------------------------------------------------------------------- + -- one-step (enhanced) menu + -------------------------------------------------------------------- + local mAll=MENU_GROUP:New(Group,"Drop ALL crates",dropCratesMenu) + MENU_GROUP_COMMAND:New(Group,"Drop and build",mAll,self._DropAndBuild,self,Group,Unit) + MENU_GROUP_COMMAND:New(Group,"Drop only",mAll,self._UnloadCrates,self,Group,Unit) + + self.CrateGroupList=self.CrateGroupList or{} + self.CrateGroupList[Unit:GetName()]={} + + local lineIndex=1 + for cName,list in pairs(cargoByName) do + local needed=list[1]:GetCratesNeeded() or 1 + table.sort(list,function(a,b)return a:GetID()=needed then + local chunk={} + for n=i,i+needed-1 do + table.insert(chunk,list[n]) + end + local label=string.format("%d. %s",lineIndex,cName) + table.insert(self.CrateGroupList[Unit:GetName()],chunk) + local setIndex=#self.CrateGroupList[Unit:GetName()] + local mSet=MENU_GROUP:New(Group,label,dropCratesMenu) + MENU_GROUP_COMMAND:New(Group,"Drop and build",mSet,self._DropSingleAndBuild,self,Group,Unit,setIndex) + MENU_GROUP_COMMAND:New(Group,"Drop only",mSet,self._UnloadSingleCrateSet,self,Group,Unit,setIndex) + i=i+needed + else + local chunk={} + for n=i,#list do + table.insert(chunk,list[n]) + end + local label=string.format("%d. %s %d/%d",lineIndex,cName,left,needed) + table.insert(self.CrateGroupList[Unit:GetName()],chunk) + local setIndex=#self.CrateGroupList[Unit:GetName()] + MENU_GROUP_COMMAND:New(Group,label,dropCratesMenu,self._UnloadSingleCrateSet,self,Group,Unit,setIndex) + i=#list+1 + end + lineIndex=lineIndex+1 + end end end end - if dropableCrates==0 then - MENU_GROUP_COMMAND:New(Group,"No crates to drop!",dropCratesMenu,function() end) - return - end - - MENU_GROUP_COMMAND:New(Group,"Drop ALL crates",dropCratesMenu,self._UnloadCrates,self,Group,Unit) - self.CrateGroupList=self.CrateGroupList or{} - self.CrateGroupList[Unit:GetName()]={} - - local lineIndex=1 - for cName,list in pairs(cargoByName) do - local needed=list[1]:GetCratesNeeded() or 1 - table.sort(list,function(a,b)return a:GetID()=needed then - local chunk={} - for n=i,i+needed-1 do - table.insert(chunk,list[n]) - end - local label=string.format("%d. %s",lineIndex,cName) - table.insert(self.CrateGroupList[Unit:GetName()],chunk) - local setIndex=#self.CrateGroupList[Unit:GetName()] - MENU_GROUP_COMMAND:New(Group,label,dropCratesMenu,self._UnloadSingleCrateSet,self,Group,Unit,setIndex) - i=i+needed - else - local chunk={} - for n=i,#list do - table.insert(chunk,list[n]) - end - local label=string.format("%d. %s %d/%d",lineIndex,cName,left,needed) - table.insert(self.CrateGroupList[Unit:GetName()],chunk) - local setIndex=#self.CrateGroupList[Unit:GetName()] - MENU_GROUP_COMMAND:New(Group,label,dropCratesMenu,self._UnloadSingleCrateSet,self,Group,Unit,setIndex) - i=#list+1 - end - lineIndex=lineIndex+1 - end - end -end - --- (Internal) Function to unload a single Troop group by ID. -- @param #CTLD self -- @param Wrapper.Group#GROUP Group The calling group. @@ -8167,4 +8397,4 @@ end ------------------------------------------------------------------- -- End Ops.CTLD.lua -------------------------------------------------------------------- +------------------------------------------------------------------- \ No newline at end of file From 89c3f7310b051746e175aa24e404d95f90e0979b Mon Sep 17 00:00:00 2001 From: leka1986 <83298840+leka1986@users.noreply.github.com> Date: Sat, 3 May 2025 19:22:59 +0200 Subject: [PATCH 024/234] Update CTLD.lua Changed the naming from Get only to Get and the order is Get, Get and load Instead of Get and load, and Get only. Changed the order on Pack and load, Pack and remove, pack only to Pack, Pack and load, Pack and remove. Same goes for Drop and build, Drop only to Drop, Drop and build. It purely subjective what one would like, so I leave it up to you. If you like it this way or the first version, you decide, then disregard this change. --- Moose Development/Moose/Ops/CTLD.lua | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/Moose Development/Moose/Ops/CTLD.lua b/Moose Development/Moose/Ops/CTLD.lua index 405ca9a07..487230947 100644 --- a/Moose Development/Moose/Ops/CTLD.lua +++ b/Moose Development/Moose/Ops/CTLD.lua @@ -866,7 +866,7 @@ do -- my_ctld.TroopUnloadDistGroundHook = 15 -- On the ground, unload troops this far behind the Chinook -- my_ctld.TroopUnloadDistHoverHook = 5 -- When hovering, unload troops this far behind the Chinook -- my_ctld.showstockinmenuitems = false -- When set to true, the menu lines will also show the remaining items in stock (that is, if you set any), downside is that the menu for all will be build every 30 seconds anew. --- my_ctld.onestepmenu = false -- When set to true, the menu will create Drop and build, Get and load, Pack and remove, Pack and load, Pack only. it will be a 1 step solution. +-- my_ctld.onestepmenu = false -- When set to true, the menu will create Drop and build, Get and load, Pack and remove, Pack and load, Pack. it will be a 1 step solution. -- -- ## 2.1 CH-47 Chinook support -- @@ -4461,8 +4461,8 @@ function CTLD:_RefreshF10Menus() local stock = cargoObj:GetStock() if stock>=0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end local mSet = MENU_GROUP:New(_group,txt,subcatmenus[cargoObj.Subcategory]) + MENU_GROUP_COMMAND:New(_group,"Get",mSet,self._GetCrates,self,_group,_unit,cargoObj) MENU_GROUP_COMMAND:New(_group,"Get and Load",mSet,self._GetAndLoad,self,_group,_unit,cargoObj) - MENU_GROUP_COMMAND:New(_group,"Get only",mSet,self._GetCrates,self,_group,_unit,cargoObj) end end for _,cargoObj in pairs(self.Cargo_Statics) do @@ -4472,8 +4472,8 @@ function CTLD:_RefreshF10Menus() local stock = cargoObj:GetStock() if stock>=0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end local mSet = MENU_GROUP:New(_group,txt,subcatmenus[cargoObj.Subcategory]) + MENU_GROUP_COMMAND:New(_group,"Get",mSet,self._GetCrates,self,_group,_unit,cargoObj) MENU_GROUP_COMMAND:New(_group,"Get and Load",mSet,self._GetAndLoad,self,_group,_unit,cargoObj) - MENU_GROUP_COMMAND:New(_group,"Get only",mSet,self._GetCrates,self,_group,_unit,cargoObj) end end else @@ -4484,8 +4484,8 @@ function CTLD:_RefreshF10Menus() local stock = cargoObj:GetStock() if stock>=0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end local mSet = MENU_GROUP:New(_group,txt,cratesmenu) + MENU_GROUP_COMMAND:New(_group,"Get",mSet,self._GetCrates,self,_group,_unit,cargoObj) MENU_GROUP_COMMAND:New(_group,"Get and Load",mSet,self._GetAndLoad,self,_group,_unit,cargoObj) - MENU_GROUP_COMMAND:New(_group,"Get only",mSet,self._GetCrates,self,_group,_unit,cargoObj) end end for _,cargoObj in pairs(self.Cargo_Statics) do @@ -4495,8 +4495,9 @@ function CTLD:_RefreshF10Menus() local stock = cargoObj:GetStock() if stock>=0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end local mSet = MENU_GROUP:New(_group,txt,cratesmenu) + MENU_GROUP_COMMAND:New(_group,"Get",mSet,self._GetCrates,self,_group,_unit,cargoObj) MENU_GROUP_COMMAND:New(_group,"Get and Load",mSet,self._GetAndLoad,self,_group,_unit,cargoObj) - MENU_GROUP_COMMAND:New(_group,"Get only",mSet,self._GetCrates,self,_group,_unit,cargoObj) + end end end @@ -4564,9 +4565,9 @@ function CTLD:_RefreshF10Menus() if self.onestepmenu then local mPack=MENU_GROUP:New(_group,"Pack crates",topcrates) + MENU_GROUP_COMMAND:New(_group,"Pack",mPack,self._PackCratesNearby,self,_group,_unit) MENU_GROUP_COMMAND:New(_group,"Pack and Load",mPack,self._PackAndLoad,self,_group,_unit) MENU_GROUP_COMMAND:New(_group,"Pack and Remove",mPack,self._PackAndRemove,self,_group,_unit) - MENU_GROUP_COMMAND:New(_group,"Pack only",mPack,self._PackCratesNearby,self,_group,_unit) MENU_GROUP_COMMAND:New(_group, "List crates nearby", topcrates, self._ListCratesNearby, self, _group, _unit) else MENU_GROUP_COMMAND:New(_group, "Pack crates", topcrates, self._PackCratesNearby, self, _group, _unit) @@ -5005,8 +5006,8 @@ function CTLD:_RefreshDropCratesMenu(Group, Unit) -- one-step (enhanced) menu -------------------------------------------------------------------- local mAll=MENU_GROUP:New(Group,"Drop ALL crates",dropCratesMenu) + MENU_GROUP_COMMAND:New(Group,"Drop",mAll,self._UnloadCrates,self,Group,Unit) MENU_GROUP_COMMAND:New(Group,"Drop and build",mAll,self._DropAndBuild,self,Group,Unit) - MENU_GROUP_COMMAND:New(Group,"Drop only",mAll,self._UnloadCrates,self,Group,Unit) self.CrateGroupList=self.CrateGroupList or{} self.CrateGroupList[Unit:GetName()]={} @@ -5027,8 +5028,8 @@ function CTLD:_RefreshDropCratesMenu(Group, Unit) table.insert(self.CrateGroupList[Unit:GetName()],chunk) local setIndex=#self.CrateGroupList[Unit:GetName()] local mSet=MENU_GROUP:New(Group,label,dropCratesMenu) + MENU_GROUP_COMMAND:New(Group,"Drop",mSet,self._UnloadSingleCrateSet,self,Group,Unit,setIndex) MENU_GROUP_COMMAND:New(Group,"Drop and build",mSet,self._DropSingleAndBuild,self,Group,Unit,setIndex) - MENU_GROUP_COMMAND:New(Group,"Drop only",mSet,self._UnloadSingleCrateSet,self,Group,Unit,setIndex) i=i+needed else local chunk={} @@ -5094,7 +5095,7 @@ function CTLD:_UnloadSingleTroopByID(Group, Unit, chunkID) return self end - -- Drop ONLY the FIRST cargo in that chunk + -- Drop the FIRST cargo in that chunk local foundCargo = chunk[1] if not foundCargo then self:_SendMessage(string.format("No troop cargo at chunk %d!", chunkID), 10, false, Group) @@ -8397,4 +8398,4 @@ end ------------------------------------------------------------------- -- End Ops.CTLD.lua -------------------------------------------------------------------- \ No newline at end of file +------------------------------------------------------------------- From b6074a4795fe0776b111a49a2c5b61885308c683 Mon Sep 17 00:00:00 2001 From: leka1986 Date: Sun, 4 May 2025 10:38:44 +0200 Subject: [PATCH 025/234] VS Code pointed out some errors, like duplicated values in tables. This is first time I do changes through VS Code, Hope for the best --- Moose Development/Debugger/debugger.lua | 2 +- Moose Development/Moose/AI/AI_Formation.lua | 2 -- Moose Development/Moose/Actions/Act_Account.lua | 2 +- Moose Development/Moose/DCS.lua | 2 +- Moose Development/Moose/Functional/Fox.lua | 1 - Moose Development/Moose/Tasking/Task_CARGO.lua | 2 +- 6 files changed, 4 insertions(+), 7 deletions(-) diff --git a/Moose Development/Debugger/debugger.lua b/Moose Development/Debugger/debugger.lua index a5f606f74..c8150ad13 100644 --- a/Moose Development/Debugger/debugger.lua +++ b/Moose Development/Debugger/debugger.lua @@ -1953,7 +1953,7 @@ local function refct_from_id(id) -- refct = refct_from_id(CTypeID) unsigned = refct.unsigned, size = bit.band(bit.rshift(ctype.info, 16), 127), } - refct.bool, refct.const, refct.volatile, refct.unsigned = nil + refct.bool, refct.const, refct.volatile, refct.unsigned = nil, nil, nil, nil end if CT[4] then -- Merge sibling attributes onto this type. diff --git a/Moose Development/Moose/AI/AI_Formation.lua b/Moose Development/Moose/AI/AI_Formation.lua index e42bd3a8f..4d5257eb1 100644 --- a/Moose Development/Moose/AI/AI_Formation.lua +++ b/Moose Development/Moose/AI/AI_Formation.lua @@ -158,7 +158,6 @@ AI_FORMATION.__Enum.Mode = { -- @field #number GroundRadar -- @field #number Ground AI_FORMATION.__Enum.ReportType = { - Airborne = "*", Airborne = "A", GroundRadar = "R", Ground = "G", @@ -1222,7 +1221,6 @@ function AI_FORMATION:FollowMe(FollowGroup, ClientUnit, CT1, CV1, CT2, CV2) local CVI = { x = CV2.x + CS * 10 * math.sin(Ca), y = GH2.y + Inclination, -- + FollowFormation.y, - y = GH2.y, z = CV2.z + CS * 10 * math.cos(Ca), } diff --git a/Moose Development/Moose/Actions/Act_Account.lua b/Moose Development/Moose/Actions/Act_Account.lua index 5b809af44..04b59fa9f 100644 --- a/Moose Development/Moose/Actions/Act_Account.lua +++ b/Moose Development/Moose/Actions/Act_Account.lua @@ -133,7 +133,7 @@ do -- ACT_ACCOUNT -- @param #string Event -- @param #string From -- @param #string To - function ACT_ACCOUNT:onafterEvent( ProcessUnit, From, Event, To, Event ) + function ACT_ACCOUNT:onafterEvent( ProcessUnit, From, Event, To ) self:__NoMore( 1 ) end diff --git a/Moose Development/Moose/DCS.lua b/Moose Development/Moose/DCS.lua index 8e01b8a73..ca7ec0a95 100644 --- a/Moose Development/Moose/DCS.lua +++ b/Moose Development/Moose/DCS.lua @@ -198,7 +198,7 @@ end -- env do -- radio - ---@type radio + --@type radio -- @field #radio.modulation modulation --- diff --git a/Moose Development/Moose/Functional/Fox.lua b/Moose Development/Moose/Functional/Fox.lua index 38d8eb585..9496f272d 100644 --- a/Moose Development/Moose/Functional/Fox.lua +++ b/Moose Development/Moose/Functional/Fox.lua @@ -141,7 +141,6 @@ FOX = { explosiondist = 200, explosiondist2 = 500, bigmissilemass = 50, - destroy = nil, dt50 = 5, dt10 = 1, dt05 = 0.5, diff --git a/Moose Development/Moose/Tasking/Task_CARGO.lua b/Moose Development/Moose/Tasking/Task_CARGO.lua index e2839d64e..76a3b9e9a 100644 --- a/Moose Development/Moose/Tasking/Task_CARGO.lua +++ b/Moose Development/Moose/Tasking/Task_CARGO.lua @@ -1176,7 +1176,7 @@ do -- TASK_CARGO end - ---@param Color Might be SMOKECOLOR.Blue, SMOKECOLOR.Red SMOKECOLOR.Orange, SMOKECOLOR.White or SMOKECOLOR.Green + --@param Color Might be SMOKECOLOR.Blue, SMOKECOLOR.Red SMOKECOLOR.Orange, SMOKECOLOR.White or SMOKECOLOR.Green function TASK_CARGO:SetSmokeColor(SmokeColor) -- Makes sure Coloe is set if SmokeColor == nil then From 0468bacc0bc7820b08e14b5e421e384f24e9c7e6 Mon Sep 17 00:00:00 2001 From: leka1986 Date: Sun, 11 May 2025 21:15:31 +0200 Subject: [PATCH 026/234] Fix Line 77390: attempt to index local 'zonecoord' (a nil value) --- Moose Development/Moose/Ops/CTLD.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Moose Development/Moose/Ops/CTLD.lua b/Moose Development/Moose/Ops/CTLD.lua index 487230947..4da45c663 100644 --- a/Moose Development/Moose/Ops/CTLD.lua +++ b/Moose Development/Moose/Ops/CTLD.lua @@ -5981,6 +5981,7 @@ function CTLD:SmokeZoneNearBy(Unit, Flare) end end local zonecoord = zone:GetCoordinate() + if zonecoord then local active = CZone.active local color = CZone.color local distance = self:_GetDistance(zonecoord,unitcoord) @@ -5997,6 +5998,7 @@ function CTLD:SmokeZoneNearBy(Unit, Flare) self:_SendMessage(string.format("Roger, %s zone %s!",txt, zonename), 10, false, Group) smoked = true end + end end end if not smoked then From 804004198bd4413b5106d5bd44dc5a3a374c2fc8 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Mon, 12 May 2025 17:49:25 +0200 Subject: [PATCH 027/234] #MANTIS - Update docu --- Moose Development/Moose/Functional/Mantis.lua | 41 ++++++------------- 1 file changed, 13 insertions(+), 28 deletions(-) diff --git a/Moose Development/Moose/Functional/Mantis.lua b/Moose Development/Moose/Functional/Mantis.lua index 9a412d768..b815ab352 100644 --- a/Moose Development/Moose/Functional/Mantis.lua +++ b/Moose Development/Moose/Functional/Mantis.lua @@ -74,10 +74,9 @@ -- -- * Moose derived Modular, Automatic and Network capable Targeting and Interception System. -- * Controls a network of SAM sites. Uses detection to switch on the SAM site closest to the enemy. --- * **Automatic mode** (default since 0.8) will set-up your SAM site network automatically for you --- * **Classic mode** behaves like before --- * Leverage evasiveness from SEAD, leverage attack range setting --- * Automatic setup of SHORAD based on groups of the class "short-range" +-- * **Automatic mode** (default) will set-up your SAM site network automatically for you. +-- * Leverage evasiveness from SEAD, leverage attack range setting. +-- * Automatic setup of SHORAD based on groups of the class "short-range". -- -- # 0. Base considerations and naming conventions -- @@ -136,7 +135,8 @@ -- Set up your SAM sites in the mission editor. Name the groups using a systematic approach like above. -- Set up your EWR system in the mission editor. Name the groups using a systematic approach like above. Can be e.g. AWACS or a combination of AWACS and Search Radars like e.g. EWR 1L13 etc. -- Search Radars usually have "SR" or "STR" in their names. Use the encyclopedia in the mission editor to inform yourself. --- Set up your SHORAD systems. They need to be **close** to (i.e. around) the SAM sites to be effective. Use **one** group per SAM location. SA-15 TOR systems offer a good missile defense. +-- Set up your SHORAD systems. They need to be **close** to (i.e. around) the SAM sites to be effective. Use **one unit ** per group (multiple groups) for the SAM location. +-- Else, evasive manoevers might club up all defenders in one place. Red SA-15 TOR systems offer a good missile defense. -- -- [optional] Set up your HQ. Can be any group, e.g. a command vehicle. -- @@ -188,7 +188,7 @@ -- -- ## 2.1 Auto mode features -- --- ### 2.1.1 You can now add Accept-, Reject- and Conflict-Zones to your setup, e.g. to consider borders or de-militarized zones: +-- ### 2.1.1 You can add Accept-, Reject- and Conflict-Zones to your setup, e.g. to consider borders or de-militarized zones: -- -- -- Parameters are tables of Core.Zone#ZONE objects! -- -- This is effectively a 3-stage filter allowing for zone overlap. A coordinate is accepted first when @@ -205,9 +205,6 @@ -- ### 2.1.3 SHORAD/Point defense will automatically be added from SAM sites of type "point" or if the range is less than 5km or if the type is AAA. -- -- ### 2.1.4 Advanced features --- --- -- Option to switch off auto mode **before** you start MANTIS (not recommended) --- mybluemantis.automode = false -- -- -- Option to set the scale of the activation range, i.e. don't activate at the fringes of max range, defaults below. -- -- also see engagerange below. @@ -220,6 +217,12 @@ -- -- -- For some scenarios, like Cold War, it might be useful not to activate SAMs if friendly aircraft are around to avoid death by friendly fire. -- mybluemantis.checkforfriendlies = true +-- +-- ### 2.1.6 Shoot & Scoot +-- +-- -- Option to make the (driveable) SHORAD units drive around and shuffle positions +-- -- We use a SET_ZONE for that, number of zones to consider defaults to three, Random is true for random coordinates and Formation is e.g. "Vee". +-- mybluemantis:AddScootZones(ZoneSet, Number, Random, Formation) -- -- # 3. Default settings [both modes unless stated otherwise] -- @@ -242,26 +245,8 @@ -- E.g. mymantis:SetAdvancedMode( true, 90 ) -- -- Use this option if you want to make use of or allow advanced SEAD tactics. --- --- # 5. Integrate SHORAD [classic mode, not necessary in automode, not recommended for manual setup] --- --- You can also choose to integrate Mantis with @{Functional.Shorad#SHORAD} for protection against HARMs and AGMs manually. When SHORAD detects a missile fired at one of MANTIS' SAM sites, it will activate SHORAD systems in --- the given defense checkradius around that SAM site. Create a SHORAD object first, then integrate with MANTIS like so: --- --- local SamSet = SET_GROUP:New():FilterPrefixes("Blue SAM"):FilterCoalitions("blue"):FilterStart() --- myshorad = SHORAD:New("BlueShorad", "Blue SHORAD", SamSet, 22000, 600, "blue") --- -- now set up MANTIS --- mymantis = MANTIS:New("BlueMantis","Blue SAM","Blue EWR",nil,"blue",false,"Blue Awacs") --- mymantis:AddShorad(myshorad,720) --- mymantis:Start() -- --- If you systematically name your SHORAD groups starting with "Blue SHORAD" you'll need exactly **one** SHORAD instance to manage all SHORAD groups. --- --- (Optionally) you can remove the link later on with --- --- mymantis:RemoveShorad() --- --- # 6. Integrated SEAD +-- # 5. Integrated SEAD -- -- MANTIS is using @{Functional.Sead#SEAD} internally to both detect and evade HARM attacks. No extra efforts needed to set this up! -- Once a HARM attack is detected, MANTIS (via SEAD) will shut down the radars of the attacked SAM site and take evasive action by moving the SAM From 3b50fee5a0b5dffa0f1d39b0e3f805696a8ba010 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Mon, 12 May 2025 17:50:37 +0200 Subject: [PATCH 028/234] #CTLD - extract troops, check for groupname in task properties of PLAYERTASKs, so the right people rescue the correct group --- Moose Development/Moose/Ops/CTLD.lua | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/Moose Development/Moose/Ops/CTLD.lua b/Moose Development/Moose/Ops/CTLD.lua index 4da45c663..5b2ecc4ef 100644 --- a/Moose Development/Moose/Ops/CTLD.lua +++ b/Moose Development/Moose/Ops/CTLD.lua @@ -7217,13 +7217,17 @@ end -- right subtype? if Event == subtype and not task:IsDone() then local targetzone = task.Target:GetObject() -- Core.Zone#ZONE should be a zone in this case .... - --self:T2({Name=Groupname,Property=task:GetProperty("ExtractName")}) - local okaygroup = string.find(Groupname,task:GetProperty("ExtractName"),1,true) - if targetzone and targetzone.ClassName and string.match(targetzone.ClassName,"ZONE") and okaygroup then - if task.Clients:HasUniqueID(playername) then - -- success - task:__Success(-1) + self:T2({Name=Groupname,Property=task:GetProperty("ExtractName")}) + if task:GetProperty("ExtractName") then + local okaygroup = string.find(Groupname,task:GetProperty("ExtractName"),1,true) + if targetzone and targetzone.ClassName and string.match(targetzone.ClassName,"ZONE") and okaygroup then + if task.Clients:HasUniqueID(playername) then + -- success + task:__Success(-1) + end end + else + self:T({Text="'ExtractName' Property not set",Name=Groupname,Property=task.Type}) end end end From 20406e40ca67d7f153340f4267c3bb22b8559402 Mon Sep 17 00:00:00 2001 From: shaji Date: Thu, 15 May 2025 01:17:55 +0200 Subject: [PATCH 029/234] [FIXED] Kola Airbase name "Alakourtti" to "Alakurtti" --- Moose Development/Moose/Wrapper/Airbase.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Wrapper/Airbase.lua b/Moose Development/Moose/Wrapper/Airbase.lua index 0e3e8d9e3..c7d576e38 100644 --- a/Moose Development/Moose/Wrapper/Airbase.lua +++ b/Moose Development/Moose/Wrapper/Airbase.lua @@ -790,7 +790,7 @@ AIRBASE.Sinai = { -- * AIRBASE.Kola.Vidsel -- * AIRBASE.Kola.Vuojarvi -- * AIRBASE.Kola.Andoya --- * AIRBASE.Kola.Alakourtti +-- * AIRBASE.Kola.Alakurtti -- * AIRBASE.Kola.Kittila -- * AIRBASE.Kola.Bardufoss -- * AIRBASE.Kola.Alta @@ -820,7 +820,7 @@ AIRBASE.Kola = { ["Vidsel"] = "Vidsel", ["Vuojarvi"] = "Vuojarvi", ["Andoya"] = "Andoya", - ["Alakourtti"] = "Alakourtti", + ["Alakurtti"] = "Alakurtti", ["Kittila"] = "Kittila", ["Bardufoss"] = "Bardufoss", ["Alta"] = "Alta", From db869bcb6d08134392c235166f007c1df71c697d Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 15 May 2025 08:51:26 +0200 Subject: [PATCH 030/234] #MANTIS - Make DLINK caching (DEV version) configureable --- Moose Development/Moose/Functional/Mantis.lua | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/Moose Development/Moose/Functional/Mantis.lua b/Moose Development/Moose/Functional/Mantis.lua index b815ab352..81f2c3d63 100644 --- a/Moose Development/Moose/Functional/Mantis.lua +++ b/Moose Development/Moose/Functional/Mantis.lua @@ -22,7 +22,7 @@ -- @module Functional.Mantis -- @image Functional.Mantis.jpg -- --- Last Update: Apr 2025 +-- Last Update: May 2025 ------------------------------------------------------------------------- --- **MANTIS** class, extends Core.Base#BASE @@ -62,7 +62,8 @@ -- @field #table FilterZones Table of Core.Zone#ZONE Zones Consider SAM groups in this zone(s) only for this MANTIS instance, must be handed as #table of Zone objects. -- @field #boolean SmokeDecoy If true, smoke short range SAM units as decoy if a plane is in firing range. -- @field #number SmokeDecoyColor Color to use, defaults to SMOKECOLOR.White --- @field #number checkcounter Counter for SAM Table refreshes +-- @field #number checkcounter Counter for SAM Table refreshes. +-- @field #number DLinkCacheTime Seconds after which cached contacts in DLink will decay. -- @extends Core.Base#BASE @@ -321,6 +322,7 @@ MANTIS = { SmokeDecoy = false, SmokeDecoyColor = SMOKECOLOR.White, checkcounter = 1, + DLinkCacheTime = 120, } --- Advanced state enumerator @@ -612,7 +614,8 @@ do self.advAwacs = false end - + self:SetDLinkCacheTime() + -- Set the string id for output to DCS.log file. self.lid=string.format("MANTIS %s | ", self.name) @@ -676,7 +679,7 @@ do -- TODO Version -- @field #string version - self.version="0.9.28" + self.version="0.9.29" self:I(string.format("***** Starting MANTIS Version %s *****", self.version)) --- FSM Functions --- @@ -1026,6 +1029,15 @@ do end return self end + + --- Function to set how long INTEL DLINK remembers contacts. + -- @param #MANTIS self + -- @param #number seconds Remember this many seconds + -- @return #MANTIS self + function MANTIS:SetDLinkCacheTime(seconds) + self.DLinkCacheTime = math.abs(seconds or 120) + return self + end --- Function to set the detection interval -- @param #MANTIS self @@ -1418,7 +1430,9 @@ do --IntelTwo:SetClusterRadius(5000) IntelTwo:Start() - local IntelDlink = INTEL_DLINK:New({IntelOne,IntelTwo},self.name.." DLINK",22,300) + local CacheTime = self.DLinkCacheTime or 120 + local IntelDlink = INTEL_DLINK:New({IntelOne,IntelTwo},self.name.." DLINK",22,CacheTime) + IntelDlink:__Start(1) self:SetUsingDLink(IntelDlink) From f8947aab9c4956d738d87511452f2b346aa564da Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 15 May 2025 08:51:44 +0200 Subject: [PATCH 031/234] #MANTIS - Make DLINK caching (DEV version) configureable --- Moose Development/Moose/Ops/Intelligence.lua | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/Moose Development/Moose/Ops/Intelligence.lua b/Moose Development/Moose/Ops/Intelligence.lua index f9996cf91..a893557b3 100644 --- a/Moose Development/Moose/Ops/Intelligence.lua +++ b/Moose Development/Moose/Ops/Intelligence.lua @@ -2324,7 +2324,7 @@ INTEL_DLINK = { verbose = 0, lid = nil, alias = nil, - cachetime = 300, + cachetime = 120, interval = 20, contacts = {}, clusters = {}, @@ -2333,7 +2333,7 @@ INTEL_DLINK = { --- Version string -- @field #string version -INTEL_DLINK.version = "0.0.1" +INTEL_DLINK.version = "0.0.2" --- Function to instantiate a new object -- @param #INTEL_DLINK self @@ -2385,7 +2385,7 @@ function INTEL_DLINK:New(Intels, Alias, Interval, Cachetime) end -- Cache time - self.cachetime = Cachetime or 300 + self:SetDLinkCacheTime(Cachetime or 120) -- Interval self.interval = Interval or 20 @@ -2477,6 +2477,16 @@ function INTEL_DLINK:onafterStart(From, Event, To) return self end + --- Function to set how long INTEL DLINK remembers contacts. + -- @param #INTEL_DLINK self + -- @param #number seconds Remember this many seconds. Defaults to 180. + -- @return #INTEL_DLINK self + function INTEL_DLINK:SetDLinkCacheTime(seconds) + self.cachetime = math.abs(seconds or 120) + self:I(self.lid.."Caching for "..self.cachetime.." seconds.") + return self + end + --- Function to collect data from the various #INTEL -- @param #INTEL_DLINK self -- @param #string From The From state From ebb94c07b34962cbe8cc00be3ff4929ef42ce9a6 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 15 May 2025 10:05:11 +0200 Subject: [PATCH 032/234] Small fix --- Moose Development/Moose/Ops/Intelligence.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Moose Development/Moose/Ops/Intelligence.lua b/Moose Development/Moose/Ops/Intelligence.lua index a893557b3..f582f0675 100644 --- a/Moose Development/Moose/Ops/Intelligence.lua +++ b/Moose Development/Moose/Ops/Intelligence.lua @@ -2384,15 +2384,15 @@ function INTEL_DLINK:New(Intels, Alias, Interval, Cachetime) self.alias="SPECTRE" end - -- Cache time - self:SetDLinkCacheTime(Cachetime or 120) - -- Interval self.interval = Interval or 20 -- Set some string id for output to DCS.log file. self.lid=string.format("INTEL_DLINK %s | ", self.alias) + -- Cache time + self:SetDLinkCacheTime(Cachetime or 120) + -- Start State. self:SetStartState("Stopped") From d7defe6f7fa5b9732ae3c37575c7f33b1d4f9a05 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 15 May 2025 11:42:05 +0200 Subject: [PATCH 033/234] xx --- Moose Development/Moose/Functional/Mantis.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Moose Development/Moose/Functional/Mantis.lua b/Moose Development/Moose/Functional/Mantis.lua index 81f2c3d63..989b400e0 100644 --- a/Moose Development/Moose/Functional/Mantis.lua +++ b/Moose Development/Moose/Functional/Mantis.lua @@ -133,8 +133,7 @@ -- -- # 0.1 Set-up in the mission editor -- --- Set up your SAM sites in the mission editor. Name the groups using a systematic approach like above. --- Set up your EWR system in the mission editor. Name the groups using a systematic approach like above. Can be e.g. AWACS or a combination of AWACS and Search Radars like e.g. EWR 1L13 etc. +-- Set up your SAM sites in the mission editor. Name the groups using a systematic approach like above.Can be e.g. AWACS or a combination of AWACS and Search Radars like e.g. EWR 1L13 etc. -- Search Radars usually have "SR" or "STR" in their names. Use the encyclopedia in the mission editor to inform yourself. -- Set up your SHORAD systems. They need to be **close** to (i.e. around) the SAM sites to be effective. Use **one unit ** per group (multiple groups) for the SAM location. -- Else, evasive manoevers might club up all defenders in one place. Red SA-15 TOR systems offer a good missile defense. @@ -1032,10 +1031,11 @@ do --- Function to set how long INTEL DLINK remembers contacts. -- @param #MANTIS self - -- @param #number seconds Remember this many seconds + -- @param #number seconds Remember this many seconds, at least 5 seconds. -- @return #MANTIS self function MANTIS:SetDLinkCacheTime(seconds) self.DLinkCacheTime = math.abs(seconds or 120) + if self.DLinkCacheTime < 5 then self.DLinkCacheTime = 5 end return self end From 1bfb4fc4e1272fbb84329097dece8fb73dd0260c Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 15 May 2025 11:42:27 +0200 Subject: [PATCH 034/234] Small fix --- Moose Development/Moose/Ops/PlayerTask.lua | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Moose Development/Moose/Ops/PlayerTask.lua b/Moose Development/Moose/Ops/PlayerTask.lua index 8c6361a48..ce95f00a4 100644 --- a/Moose Development/Moose/Ops/PlayerTask.lua +++ b/Moose Development/Moose/Ops/PlayerTask.lua @@ -556,6 +556,7 @@ end -- @param #PLAYERTASK self -- @param #SET_BASE CaptureSquadGroupNamePrefix The prefix of the group name that needs to capture the zone. -- @param #number Coalition The coalition that needs to capture the zone. +-- @param #boolean CheckClientInZone If true, a CLIENT assigned to this task also needs to be in the zone for the task to be successful. -- @return #PLAYERTASK self -- @usage -- -- We can use either STATIC, SET_STATIC, SCENERY or SET_SCENERY as target objects. @@ -570,20 +571,20 @@ end -- -- -- We set CaptureSquadGroupNamePrefix the group name prefix as set in the ME or the spawn of the group that need to be present at the OpsZone like a capture squad, -- -- and set the capturing Coalition in order to trigger a successful task. --- mytask:AddOpsZoneCaptureSuccessCondition("capture-squad", coalition.side.BLUE) +-- mytask:AddOpsZoneCaptureSuccessCondition("capture-squad", coalition.side.BLUE, false) -- -- playerTaskManager:AddPlayerTaskToQueue(mytask) -function PLAYERTASK:AddOpsZoneCaptureSuccessCondition(CaptureSquadGroupNamePrefix, Coalition) +function PLAYERTASK:AddOpsZoneCaptureSuccessCondition(CaptureSquadGroupNamePrefix, Coalition, CheckClientInZone) local task = self task:AddConditionSuccess( function(target) if target:IsInstanceOf("OPSZONE") then - return task:_CheckCaptureOpsZoneSuccess(target, CaptureSquadGroupNamePrefix, Coalition, true) + return task:_CheckCaptureOpsZoneSuccess(target, CaptureSquadGroupNamePrefix, Coalition, CheckClientInZone or true) elseif target:IsInstanceOf("SET_OPSZONE") then local successes = 0 local isClientInZone = false target:ForEachZone(function(opszone) - if task:_CheckCaptureOpsZoneSuccess(opszone, CaptureSquadGroupNamePrefix, Coalition) then + if task:_CheckCaptureOpsZoneSuccess(opszone, CaptureSquadGroupNamePrefix, Coalition, CheckClientInZone or true) then successes = successes + 1 end From 4bab2ee1deb41274a143a17253b56b88f2a59098 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 15 May 2025 13:19:42 +0200 Subject: [PATCH 035/234] Add deprecated banner --- Moose Development/Moose/AI/AI_A2A_Cap.lua | 4 +++- Moose Development/Moose/AI/AI_A2A_Dispatcher.lua | 4 +++- Moose Development/Moose/AI/AI_A2A_Gci.lua | 2 ++ Moose Development/Moose/AI/AI_A2A_Patrol.lua | 2 ++ Moose Development/Moose/AI/AI_A2G_BAI.lua | 4 +++- Moose Development/Moose/AI/AI_A2G_CAS.lua | 2 ++ Moose Development/Moose/AI/AI_A2G_Dispatcher.lua | 2 ++ Moose Development/Moose/AI/AI_A2G_SEAD.lua | 2 ++ Moose Development/Moose/AI/AI_Air.lua | 1 + Moose Development/Moose/AI/AI_Air_Dispatcher.lua | 2 ++ Moose Development/Moose/AI/AI_Air_Engage.lua | 4 +++- Moose Development/Moose/AI/AI_Air_Patrol.lua | 2 ++ Moose Development/Moose/AI/AI_Air_Squadron.lua | 4 +++- Moose Development/Moose/AI/AI_BAI.lua | 2 ++ Moose Development/Moose/AI/AI_Balancer.lua | 5 +++-- Moose Development/Moose/AI/AI_CAP.lua | 2 ++ Moose Development/Moose/AI/AI_CAS.lua | 3 +++ Moose Development/Moose/AI/AI_Cargo.lua | 4 +++- Moose Development/Moose/AI/AI_Cargo_APC.lua | 2 ++ Moose Development/Moose/AI/AI_Cargo_Airplane.lua | 2 ++ Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua | 2 ++ Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua | 2 ++ .../Moose/AI/AI_Cargo_Dispatcher_Airplane.lua | 2 ++ .../Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua | 2 ++ Moose Development/Moose/AI/AI_Cargo_Dispatcher_Ship.lua | 2 ++ Moose Development/Moose/AI/AI_Cargo_Helicopter.lua | 2 ++ Moose Development/Moose/AI/AI_Cargo_Ship.lua | 2 ++ Moose Development/Moose/AI/AI_Escort.lua | 2 ++ Moose Development/Moose/AI/AI_Escort_Dispatcher.lua | 2 ++ .../Moose/AI/AI_Escort_Dispatcher_Request.lua | 2 ++ Moose Development/Moose/AI/AI_Escort_Request.lua | 2 ++ Moose Development/Moose/AI/AI_Formation.lua | 2 ++ Moose Development/Moose/AI/AI_Patrol.lua | 2 ++ Moose Development/Moose/Actions/Act_Account.lua | 8 +++++--- Moose Development/Moose/Actions/Act_Assign.lua | 2 ++ Moose Development/Moose/Actions/Act_Assist.lua | 1 + Moose Development/Moose/Actions/Act_Route.lua | 2 ++ Moose Development/Moose/Cargo/Cargo.lua | 2 ++ Moose Development/Moose/Cargo/CargoCrate.lua | 3 +++ Moose Development/Moose/Cargo/CargoGroup.lua | 2 ++ Moose Development/Moose/Cargo/CargoSlingload.lua | 2 ++ Moose Development/Moose/Cargo/CargoUnit.lua | 2 ++ Moose Development/Moose/Functional/MissileTrainer.lua | 2 ++ Moose Development/Moose/Functional/ZoneGoalCargo.lua | 2 ++ Moose Development/Moose/Tasking/CommandCenter.lua | 2 ++ Moose Development/Moose/Tasking/DetectionManager.lua | 2 ++ Moose Development/Moose/Tasking/Mission.lua | 2 ++ Moose Development/Moose/Tasking/Task.lua | 2 ++ Moose Development/Moose/Tasking/TaskInfo.lua | 2 ++ Moose Development/Moose/Tasking/Task_A2A.lua | 3 +++ Moose Development/Moose/Tasking/Task_A2A_Dispatcher.lua | 2 ++ Moose Development/Moose/Tasking/Task_A2G.lua | 3 +++ Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua | 2 ++ Moose Development/Moose/Tasking/Task_CARGO.lua | 2 ++ .../Moose/Tasking/Task_Capture_Dispatcher.lua | 2 ++ Moose Development/Moose/Tasking/Task_Capture_Zone.lua | 2 ++ Moose Development/Moose/Tasking/Task_Cargo_CSAR.lua | 2 ++ Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua | 2 ++ Moose Development/Moose/Tasking/Task_Cargo_Transport.lua | 2 ++ Moose Development/Moose/Tasking/Task_Manager.lua | 2 ++ 60 files changed, 132 insertions(+), 11 deletions(-) diff --git a/Moose Development/Moose/AI/AI_A2A_Cap.lua b/Moose Development/Moose/AI/AI_A2A_Cap.lua index 0c8aff8fa..693895d6d 100644 --- a/Moose Development/Moose/AI/AI_A2A_Cap.lua +++ b/Moose Development/Moose/AI/AI_A2A_Cap.lua @@ -17,7 +17,9 @@ --- The AI_A2A_CAP class implements the core functions to patrol a @{Core.Zone} by an AI @{Wrapper.Group} or @{Wrapper.Group} -- and automatically engage any airborne enemies that are within a certain range or within a certain zone. --- +-- +-- ![Banner Image](..\Images\deprecated.png) +-- -- ![Process](..\Presentations\AI_CAP\Dia3.JPG) -- -- The AI_A2A_CAP is assigned a @{Wrapper.Group} and this must be done before the AI_A2A_CAP process can be started using the **Start** event. diff --git a/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua b/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua index bbfaa868b..8e8e3df05 100644 --- a/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua @@ -32,7 +32,9 @@ -- [DCS WORLD - MOOSE - A2A GCICAP - Build an automatic A2A Defense System](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl0S4KMNUUJpaUs6zZHjLKNx) -- -- === --- +-- +-- ![Banner Image](..\Images\deprecated.png) +-- -- # QUICK START GUIDE -- -- There are basically two classes available to model an A2A defense system. diff --git a/Moose Development/Moose/AI/AI_A2A_Gci.lua b/Moose Development/Moose/AI/AI_A2A_Gci.lua index 626e36d60..807fa9b78 100644 --- a/Moose Development/Moose/AI/AI_A2A_Gci.lua +++ b/Moose Development/Moose/AI/AI_A2A_Gci.lua @@ -19,6 +19,8 @@ --- Implements the core functions to intercept intruders. Use the Engage trigger to intercept intruders. -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- The AI_A2A_GCI is assigned a @{Wrapper.Group} and this must be done before the AI_A2A_GCI process can be started using the **Start** event. -- -- The AI will fly towards the random 3D point within the patrol zone, using a random speed within the given altitude and speed limits. diff --git a/Moose Development/Moose/AI/AI_A2A_Patrol.lua b/Moose Development/Moose/AI/AI_A2A_Patrol.lua index 1e66eb167..d858fb9e2 100644 --- a/Moose Development/Moose/AI/AI_A2A_Patrol.lua +++ b/Moose Development/Moose/AI/AI_A2A_Patrol.lua @@ -15,6 +15,8 @@ --- Implements the core functions to patrol a @{Core.Zone} by an AI @{Wrapper.Group} or @{Wrapper.Group}. -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- ![Process](..\Presentations\AI_PATROL\Dia3.JPG) -- -- The AI_A2A_PATROL is assigned a @{Wrapper.Group} and this must be done before the AI_A2A_PATROL process can be started using the **Start** event. diff --git a/Moose Development/Moose/AI/AI_A2G_BAI.lua b/Moose Development/Moose/AI/AI_A2G_BAI.lua index 28acea07f..729dbf5c2 100644 --- a/Moose Development/Moose/AI/AI_A2G_BAI.lua +++ b/Moose Development/Moose/AI/AI_A2G_BAI.lua @@ -16,7 +16,9 @@ -- @extends AI.AI_Air_Engage#AI_AIR_ENGAGE --- Implements the core functions to intercept intruders. Use the Engage trigger to intercept intruders. --- +-- +-- ![Banner Image](..\Images\deprecated.png) +-- -- # Developer Note -- -- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE diff --git a/Moose Development/Moose/AI/AI_A2G_CAS.lua b/Moose Development/Moose/AI/AI_A2G_CAS.lua index 7bae80ea3..830eb8b66 100644 --- a/Moose Development/Moose/AI/AI_A2G_CAS.lua +++ b/Moose Development/Moose/AI/AI_A2G_CAS.lua @@ -19,6 +19,8 @@ -- -- # Developer Note -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE -- Therefore, this class is considered to be deprecated -- diff --git a/Moose Development/Moose/AI/AI_A2G_Dispatcher.lua b/Moose Development/Moose/AI/AI_A2G_Dispatcher.lua index 0396e4e9f..5aff7ad4f 100644 --- a/Moose Development/Moose/AI/AI_A2G_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_A2G_Dispatcher.lua @@ -36,6 +36,8 @@ -- -- # QUICK START GUIDE -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- The following class is available to model an A2G defense system. -- -- AI_A2G_DISPATCHER is the main A2G defense class that models the A2G defense system. diff --git a/Moose Development/Moose/AI/AI_A2G_SEAD.lua b/Moose Development/Moose/AI/AI_A2G_SEAD.lua index 42662862c..bf876db35 100644 --- a/Moose Development/Moose/AI/AI_A2G_SEAD.lua +++ b/Moose Development/Moose/AI/AI_A2G_SEAD.lua @@ -20,6 +20,8 @@ --- Implements the core functions to SEAD intruders. Use the Engage trigger to intercept intruders. -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- The AI_A2G_SEAD is assigned a @{Wrapper.Group} and this must be done before the AI_A2G_SEAD process can be started using the **Start** event. -- -- The AI will fly towards the random 3D point within the patrol zone, using a random speed within the given altitude and speed limits. diff --git a/Moose Development/Moose/AI/AI_Air.lua b/Moose Development/Moose/AI/AI_Air.lua index d3d11cf16..1b0bf8cac 100644 --- a/Moose Development/Moose/AI/AI_Air.lua +++ b/Moose Development/Moose/AI/AI_Air.lua @@ -15,6 +15,7 @@ --- The AI_AIR class implements the core functions to operate an AI @{Wrapper.Group}. -- +-- ![Banner Image](..\Images\deprecated.png) -- -- # 1) AI_AIR constructor -- diff --git a/Moose Development/Moose/AI/AI_Air_Dispatcher.lua b/Moose Development/Moose/AI/AI_Air_Dispatcher.lua index 9e5939aa0..ad309f0c2 100644 --- a/Moose Development/Moose/AI/AI_Air_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_Air_Dispatcher.lua @@ -36,6 +36,8 @@ -- -- # QUICK START GUIDE -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- The following class is available to model an AIR defense system. -- -- AI_AIR_DISPATCHER is the main AIR defense class that models the AIR defense system. diff --git a/Moose Development/Moose/AI/AI_Air_Engage.lua b/Moose Development/Moose/AI/AI_Air_Engage.lua index ff3327421..772f10b2e 100644 --- a/Moose Development/Moose/AI/AI_Air_Engage.lua +++ b/Moose Development/Moose/AI/AI_Air_Engage.lua @@ -13,12 +13,14 @@ --- @type AI_AIR_ENGAGE +--- @type AI_AIR_ENGAGE -- @extends AI.AI_AIR#AI_AIR --- Implements the core functions to intercept intruders. Use the Engage trigger to intercept intruders. -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- The AI_AIR_ENGAGE is assigned a @{Wrapper.Group} and this must be done before the AI_AIR_ENGAGE process can be started using the **Start** event. -- -- The AI will fly towards the random 3D point within the patrol zone, using a random speed within the given altitude and speed limits. diff --git a/Moose Development/Moose/AI/AI_Air_Patrol.lua b/Moose Development/Moose/AI/AI_Air_Patrol.lua index 5b0abe72e..3e57476c5 100644 --- a/Moose Development/Moose/AI/AI_Air_Patrol.lua +++ b/Moose Development/Moose/AI/AI_Air_Patrol.lua @@ -15,6 +15,8 @@ --- The AI_AIR_PATROL class implements the core functions to patrol a @{Core.Zone} by an AI @{Wrapper.Group} -- and automatically engage any airborne enemies that are within a certain range or within a certain zone. -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- ![Process](..\Presentations\AI_CAP\Dia3.JPG) -- -- The AI_AIR_PATROL is assigned a @{Wrapper.Group} and this must be done before the AI_AIR_PATROL process can be started using the **Start** event. diff --git a/Moose Development/Moose/AI/AI_Air_Squadron.lua b/Moose Development/Moose/AI/AI_Air_Squadron.lua index 6651a92a5..7356c1baa 100644 --- a/Moose Development/Moose/AI/AI_Air_Squadron.lua +++ b/Moose Development/Moose/AI/AI_Air_Squadron.lua @@ -13,7 +13,7 @@ --- @type AI_AIR_SQUADRON +--- @type AI_AIR_SQUADRON -- @extends Core.Base#BASE @@ -21,6 +21,8 @@ -- -- # Developer Note -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE -- Therefore, this class is considered to be deprecated -- diff --git a/Moose Development/Moose/AI/AI_BAI.lua b/Moose Development/Moose/AI/AI_BAI.lua index 6b2a1dfe3..3037feb18 100644 --- a/Moose Development/Moose/AI/AI_BAI.lua +++ b/Moose Development/Moose/AI/AI_BAI.lua @@ -38,6 +38,8 @@ --- Implements the core functions to provide BattleGround Air Interdiction in an Engage @{Core.Zone} by an AIR @{Wrapper.Controllable} or @{Wrapper.Group}. -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- The AI_BAI_ZONE runs a process. It holds an AI in a Patrol Zone and when the AI is commanded to engage, it will fly to an Engage Zone. -- -- ![HoldAndEngage](..\Presentations\AI_BAI\Dia3.JPG) diff --git a/Moose Development/Moose/AI/AI_Balancer.lua b/Moose Development/Moose/AI/AI_Balancer.lua index 34afc35d0..b3c7fe1d1 100644 --- a/Moose Development/Moose/AI/AI_Balancer.lua +++ b/Moose Development/Moose/AI/AI_Balancer.lua @@ -33,8 +33,9 @@ -- @field Wrapper.Group#GROUP Test -- @extends Core.Fsm#FSM_SET - ---- Monitors and manages as many replacement AI groups as there are +--- ![Banner Image](..\Images\deprecated.png) +-- +-- Monitors and manages as many replacement AI groups as there are -- CLIENTS in a SET\_CLIENT collection, which are not occupied by human players. -- In other words, use AI_BALANCER to simulate human behaviour by spawning in replacement AI in multi player missions. -- diff --git a/Moose Development/Moose/AI/AI_CAP.lua b/Moose Development/Moose/AI/AI_CAP.lua index dc0a843a8..70f6fb438 100644 --- a/Moose Development/Moose/AI/AI_CAP.lua +++ b/Moose Development/Moose/AI/AI_CAP.lua @@ -39,6 +39,8 @@ --- Implements the core functions to patrol a @{Core.Zone} by an AI @{Wrapper.Controllable} or @{Wrapper.Group} -- and automatically engage any airborne enemies that are within a certain range or within a certain zone. -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- ![Process](..\Presentations\AI_CAP\Dia3.JPG) -- -- The AI_CAP_ZONE is assigned a @{Wrapper.Group} and this must be done before the AI_CAP_ZONE process can be started using the **Start** event. diff --git a/Moose Development/Moose/AI/AI_CAS.lua b/Moose Development/Moose/AI/AI_CAS.lua index 832cc6bd5..1c99401a8 100644 --- a/Moose Development/Moose/AI/AI_CAS.lua +++ b/Moose Development/Moose/AI/AI_CAS.lua @@ -38,6 +38,9 @@ -- @extends AI.AI_Patrol#AI_PATROL_ZONE --- Implements the core functions to provide Close Air Support in an Engage @{Core.Zone} by an AIR @{Wrapper.Controllable} or @{Wrapper.Group}. +-- +-- ![Banner Image](..\Images\deprecated.png) +-- -- The AI_CAS_ZONE runs a process. It holds an AI in a Patrol Zone and when the AI is commanded to engage, it will fly to an Engage Zone. -- -- ![HoldAndEngage](..\Presentations\AI_CAS\Dia3.JPG) diff --git a/Moose Development/Moose/AI/AI_Cargo.lua b/Moose Development/Moose/AI/AI_Cargo.lua index 0bd6ab9ea..eac91c668 100644 --- a/Moose Development/Moose/AI/AI_Cargo.lua +++ b/Moose Development/Moose/AI/AI_Cargo.lua @@ -9,12 +9,14 @@ -- @module AI.AI_Cargo -- @image Cargo.JPG --- @type AI_CARGO +--- @type AI_CARGO -- @extends Core.Fsm#FSM_CONTROLLABLE --- Base class for the dynamic cargo handling capability for AI groups. -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- Carriers can be mobilized to intelligently transport infantry and other cargo within the simulation. -- The AI_CARGO module uses the @{Cargo.Cargo} capabilities within the MOOSE framework. -- CARGO derived objects must be declared within the mission to make the AI_CARGO object recognize the cargo. diff --git a/Moose Development/Moose/AI/AI_Cargo_APC.lua b/Moose Development/Moose/AI/AI_Cargo_APC.lua index 6088ea865..ee026c599 100644 --- a/Moose Development/Moose/AI/AI_Cargo_APC.lua +++ b/Moose Development/Moose/AI/AI_Cargo_APC.lua @@ -15,6 +15,8 @@ --- Brings a dynamic cargo handling capability for an AI vehicle group. -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- Armoured Personnel Carriers (APC), Trucks, Jeeps and other ground based carrier equipment can be mobilized to intelligently transport infantry and other cargo within the simulation. -- -- The AI_CARGO_APC class uses the @{Cargo.Cargo} capabilities within the MOOSE framework. diff --git a/Moose Development/Moose/AI/AI_Cargo_Airplane.lua b/Moose Development/Moose/AI/AI_Cargo_Airplane.lua index 79d1b6307..4db63ee86 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Airplane.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Airplane.lua @@ -14,6 +14,8 @@ --- Brings a dynamic cargo handling capability for an AI airplane group. +-- +-- ![Banner Image](..\Images\deprecated.png) -- -- Airplane carrier equipment can be mobilized to intelligently transport infantry and other cargo within the simulation between airbases. -- diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua index 71b7f9f43..b63c76192 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua @@ -22,6 +22,8 @@ -- -- === -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- # The dispatcher concept. -- -- Carrier equipment can be mobilized to intelligently transport infantry and other cargo within the simulation. diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua index ab25a8e60..73d27da45 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua @@ -36,6 +36,8 @@ --- A dynamic cargo transportation capability for AI groups. -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- Armoured Personnel APCs (APC), Trucks, Jeeps and other carrier equipment can be mobilized to intelligently transport infantry and other cargo within the simulation. -- -- The AI_CARGO_DISPATCHER_APC module is derived from the AI_CARGO_DISPATCHER module. diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Airplane.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Airplane.lua index a971936f6..cc4835576 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Airplane.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Airplane.lua @@ -30,6 +30,8 @@ --- Brings a dynamic cargo handling capability for AI groups. -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- Airplanes can be mobilized to intelligently transport infantry and other cargo within the simulation. -- -- The AI_CARGO_DISPATCHER_AIRPLANE module is derived from the AI_CARGO_DISPATCHER module. diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua index c391324e4..182987d70 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua @@ -31,6 +31,8 @@ --- A dynamic cargo handling capability for AI helicopter groups. -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- Helicopters can be mobilized to intelligently transport infantry and other cargo within the simulation. -- -- diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Ship.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Ship.lua index 152ea7881..906d0801d 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Ship.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Ship.lua @@ -29,6 +29,8 @@ --- A dynamic cargo transportation capability for AI groups. -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- Naval vessels can be mobilized to semi-intelligently transport cargo within the simulation. -- -- The AI_CARGO_DISPATCHER_SHIP module is derived from the AI_CARGO_DISPATCHER module. diff --git a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua index b91c0db38..c0c0c1403 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua @@ -15,6 +15,8 @@ --- Brings a dynamic cargo handling capability for an AI helicopter group. -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- Helicopter carriers can be mobilized to intelligently transport infantry and other cargo within the simulation. -- -- The AI_CARGO_HELICOPTER class uses the @{Cargo.Cargo} capabilities within the MOOSE framework. diff --git a/Moose Development/Moose/AI/AI_Cargo_Ship.lua b/Moose Development/Moose/AI/AI_Cargo_Ship.lua index 669da09b5..2073c7a27 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Ship.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Ship.lua @@ -14,6 +14,8 @@ --- Brings a dynamic cargo handling capability for an AI naval group. -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- Naval ships can be utilized to transport cargo around the map following naval shipping lanes. -- The AI_CARGO_SHIP class uses the @{Cargo.Cargo} capabilities within the MOOSE framework. -- @{Cargo.Cargo} must be declared within the mission or warehouse to make the AI_CARGO_SHIP recognize the cargo. diff --git a/Moose Development/Moose/AI/AI_Escort.lua b/Moose Development/Moose/AI/AI_Escort.lua index ad325ed94..c32312f27 100644 --- a/Moose Development/Moose/AI/AI_Escort.lua +++ b/Moose Development/Moose/AI/AI_Escort.lua @@ -25,6 +25,8 @@ -- -- Allows you to interact with escorting AI on your flight and take the lead. -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- Each escorting group can be commanded with a complete set of radio commands (radio menu in your flight, and then F10). -- -- The radio commands will vary according the category of the group. The richest set of commands are with helicopters and airPlanes. diff --git a/Moose Development/Moose/AI/AI_Escort_Dispatcher.lua b/Moose Development/Moose/AI/AI_Escort_Dispatcher.lua index ff4c0ddfe..d2366568f 100644 --- a/Moose Development/Moose/AI/AI_Escort_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_Escort_Dispatcher.lua @@ -23,6 +23,8 @@ -- -- # Developer Note -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE -- Therefore, this class is considered to be deprecated -- diff --git a/Moose Development/Moose/AI/AI_Escort_Dispatcher_Request.lua b/Moose Development/Moose/AI/AI_Escort_Dispatcher_Request.lua index 0b3180910..14e8661a6 100644 --- a/Moose Development/Moose/AI/AI_Escort_Dispatcher_Request.lua +++ b/Moose Development/Moose/AI/AI_Escort_Dispatcher_Request.lua @@ -21,6 +21,8 @@ --- Models the assignment of AI escorts to player flights upon request using the radio menu. -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- # Developer Note -- -- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE diff --git a/Moose Development/Moose/AI/AI_Escort_Request.lua b/Moose Development/Moose/AI/AI_Escort_Request.lua index 08bee2f64..511e7ec2c 100644 --- a/Moose Development/Moose/AI/AI_Escort_Request.lua +++ b/Moose Development/Moose/AI/AI_Escort_Request.lua @@ -25,6 +25,8 @@ -- -- Allows you to interact with escorting AI on your flight and take the lead. -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- Each escorting group can be commanded with a complete set of radio commands (radio menu in your flight, and then F10). -- -- The radio commands will vary according the category of the group. The richest set of commands are with helicopters and airPlanes. diff --git a/Moose Development/Moose/AI/AI_Formation.lua b/Moose Development/Moose/AI/AI_Formation.lua index 4d5257eb1..4496ab65b 100644 --- a/Moose Development/Moose/AI/AI_Formation.lua +++ b/Moose Development/Moose/AI/AI_Formation.lua @@ -40,6 +40,8 @@ --- Build large formations, make AI follow a @{Wrapper.Client#CLIENT} (player) leader or a @{Wrapper.Unit#UNIT} (AI) leader. +-- +-- ![Banner Image](..\Images\deprecated.png) -- -- AI_FORMATION makes AI @{Wrapper.Group#GROUP}s fly in formation of various compositions. -- The AI_FORMATION class models formations in a different manner than the internal DCS formation logic!!! diff --git a/Moose Development/Moose/AI/AI_Patrol.lua b/Moose Development/Moose/AI/AI_Patrol.lua index 408e3b1a6..e8d21ed44 100644 --- a/Moose Development/Moose/AI/AI_Patrol.lua +++ b/Moose Development/Moose/AI/AI_Patrol.lua @@ -48,6 +48,8 @@ --- Implements the core functions to patrol a @{Core.Zone} by an AI @{Wrapper.Controllable} or @{Wrapper.Group}. -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- ![Process](..\Presentations\AI_PATROL\Dia3.JPG) -- -- The AI_PATROL_ZONE is assigned a @{Wrapper.Group} and this must be done before the AI_PATROL_ZONE process can be started using the **Start** event. diff --git a/Moose Development/Moose/Actions/Act_Account.lua b/Moose Development/Moose/Actions/Act_Account.lua index 04b59fa9f..9a26f437c 100644 --- a/Moose Development/Moose/Actions/Act_Account.lua +++ b/Moose Development/Moose/Actions/Act_Account.lua @@ -1,6 +1,6 @@ --- **Actions** - ACT_ACCOUNT_ classes **account for** (detect, count & report) various DCS events occurring on UNITs. -- --- ![Banner Image](..\Presentations\ACT_ACCOUNT\Dia1.JPG) +-- ![Banner Image](..\Images\deprecated.png) -- -- === -- @@ -8,9 +8,11 @@ -- @image MOOSE.JPG do -- ACT_ACCOUNT - + --- # @{#ACT_ACCOUNT} FSM class, extends @{Core.Fsm#FSM_PROCESS} - -- + -- + -- ![Banner Image](..\Images\deprecated.png) + -- -- ## ACT_ACCOUNT state machine: -- -- This class is a state machine: it manages a process that is triggered by events causing state transitions to occur. diff --git a/Moose Development/Moose/Actions/Act_Assign.lua b/Moose Development/Moose/Actions/Act_Assign.lua index 3b261cfb1..1f99b86e7 100644 --- a/Moose Development/Moose/Actions/Act_Assign.lua +++ b/Moose Development/Moose/Actions/Act_Assign.lua @@ -1,6 +1,8 @@ --- (SP) (MP) (FSM) Accept or reject process for player (task) assignments. -- -- === +-- +-- ![Banner Image](..\Images\deprecated.png) -- -- # @{#ACT_ASSIGN} FSM template class, extends @{Core.Fsm#FSM_PROCESS} -- diff --git a/Moose Development/Moose/Actions/Act_Assist.lua b/Moose Development/Moose/Actions/Act_Assist.lua index 9b4744561..badc69965 100644 --- a/Moose Development/Moose/Actions/Act_Assist.lua +++ b/Moose Development/Moose/Actions/Act_Assist.lua @@ -1,5 +1,6 @@ --- (SP) (MP) (FSM) Route AI or players through waypoints or to zones. -- +-- ![Banner Image](..\Images\deprecated.png) -- ## ACT_ASSIST state machine: -- -- This class is a state machine: it manages a process that is triggered by events causing state transitions to occur. diff --git a/Moose Development/Moose/Actions/Act_Route.lua b/Moose Development/Moose/Actions/Act_Route.lua index b387b6584..548c6a846 100644 --- a/Moose Development/Moose/Actions/Act_Route.lua +++ b/Moose Development/Moose/Actions/Act_Route.lua @@ -2,6 +2,8 @@ -- -- === -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- # @{#ACT_ROUTE} FSM class, extends @{Core.Fsm#FSM_PROCESS} -- -- ## ACT_ROUTE state machine: diff --git a/Moose Development/Moose/Cargo/Cargo.lua b/Moose Development/Moose/Cargo/Cargo.lua index 413beb514..76307dd78 100644 --- a/Moose Development/Moose/Cargo/Cargo.lua +++ b/Moose Development/Moose/Cargo/Cargo.lua @@ -2,6 +2,8 @@ -- -- === -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- # 1) MOOSE Cargo System. -- -- #### Those who have used the mission editor, know that the DCS mission editor provides cargo facilities. diff --git a/Moose Development/Moose/Cargo/CargoCrate.lua b/Moose Development/Moose/Cargo/CargoCrate.lua index 2dc94cd5a..7048e503f 100644 --- a/Moose Development/Moose/Cargo/CargoCrate.lua +++ b/Moose Development/Moose/Cargo/CargoCrate.lua @@ -22,6 +22,9 @@ do -- CARGO_CRATE -- @type CARGO_CRATE -- @extends Cargo.Cargo#CARGO_REPRESENTABLE + --- + -- ![Banner Image](..\Images\deprecated.png) + -- --- Defines a cargo that is represented by a UNIT object within the simulator, and can be transported by a carrier. -- Use the event functions as described above to Load, UnLoad, Board, UnBoard the CARGO\_CRATE objects to and from carriers. -- diff --git a/Moose Development/Moose/Cargo/CargoGroup.lua b/Moose Development/Moose/Cargo/CargoGroup.lua index c2d9b26a2..4532a21fa 100644 --- a/Moose Development/Moose/Cargo/CargoGroup.lua +++ b/Moose Development/Moose/Cargo/CargoGroup.lua @@ -26,6 +26,8 @@ do -- CARGO_GROUP -- @extends Cargo.Cargo#CARGO_REPORTABLE --- Defines a cargo that is represented by a @{Wrapper.Group} object within the simulator. + -- + -- ![Banner Image](..\Images\deprecated.png) -- The cargo can be Loaded, UnLoaded, Boarded, UnBoarded to and from Carriers. -- -- The above cargo classes are used by the following AI_CARGO_ classes to allow AI groups to transport cargo: diff --git a/Moose Development/Moose/Cargo/CargoSlingload.lua b/Moose Development/Moose/Cargo/CargoSlingload.lua index ad26e8868..a8cb5022a 100644 --- a/Moose Development/Moose/Cargo/CargoSlingload.lua +++ b/Moose Development/Moose/Cargo/CargoSlingload.lua @@ -32,6 +32,8 @@ do -- CARGO_SLINGLOAD -- -- # Developer Note -- + -- ![Banner Image](..\Images\deprecated.png) + -- -- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE -- Therefore, this class is considered to be deprecated -- diff --git a/Moose Development/Moose/Cargo/CargoUnit.lua b/Moose Development/Moose/Cargo/CargoUnit.lua index a76469870..bc504d003 100644 --- a/Moose Development/Moose/Cargo/CargoUnit.lua +++ b/Moose Development/Moose/Cargo/CargoUnit.lua @@ -30,6 +30,8 @@ do -- CARGO_UNIT -- -- # Developer Note -- + -- ![Banner Image](..\Images\deprecated.png) + -- -- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE -- Therefore, this class is considered to be deprecated -- diff --git a/Moose Development/Moose/Functional/MissileTrainer.lua b/Moose Development/Moose/Functional/MissileTrainer.lua index f52363ba2..42626071c 100644 --- a/Moose Development/Moose/Functional/MissileTrainer.lua +++ b/Moose Development/Moose/Functional/MissileTrainer.lua @@ -53,6 +53,8 @@ -- -- # Developer Note -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE. -- Therefore, this class is considered to be deprecated and superseded by the [Functional.Fox](https://flightcontrol-master.github.io/MOOSE_DOCS_DEVELOP/Documentation/Functional.Fox.html) class, which provides the same functionality. -- diff --git a/Moose Development/Moose/Functional/ZoneGoalCargo.lua b/Moose Development/Moose/Functional/ZoneGoalCargo.lua index 7a19ed02a..2e803b2a3 100644 --- a/Moose Development/Moose/Functional/ZoneGoalCargo.lua +++ b/Moose Development/Moose/Functional/ZoneGoalCargo.lua @@ -7,6 +7,8 @@ -- -- # Developer Note -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE -- Therefore, this class is considered to be deprecated -- diff --git a/Moose Development/Moose/Tasking/CommandCenter.lua b/Moose Development/Moose/Tasking/CommandCenter.lua index 873279e4a..30d285682 100644 --- a/Moose Development/Moose/Tasking/CommandCenter.lua +++ b/Moose Development/Moose/Tasking/CommandCenter.lua @@ -29,6 +29,8 @@ --- Governs multiple missions, the tasking and the reporting. +-- +-- ![Banner Image](..\Images\deprecated.png) -- -- Command centers govern missions, communicates the task assignments between human players of the coalition, and manages the menu flow. -- It can assign a random task to a player when requested. diff --git a/Moose Development/Moose/Tasking/DetectionManager.lua b/Moose Development/Moose/Tasking/DetectionManager.lua index da560e5d0..a1c4505d5 100644 --- a/Moose Development/Moose/Tasking/DetectionManager.lua +++ b/Moose Development/Moose/Tasking/DetectionManager.lua @@ -5,6 +5,8 @@ -- The @{#DETECTION_MANAGER} class defines the core functions to report detected objects to groups. -- Reportings can be done in several manners, and it is up to the derived classes if DETECTION_MANAGER to model the reporting behaviour. -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- 1.1) DETECTION_MANAGER constructor: -- ----------------------------------- -- * @{#DETECTION_MANAGER.New}(): Create a new DETECTION_MANAGER instance. diff --git a/Moose Development/Moose/Tasking/Mission.lua b/Moose Development/Moose/Tasking/Mission.lua index 1c65725d2..0c5b76ac3 100644 --- a/Moose Development/Moose/Tasking/Mission.lua +++ b/Moose Development/Moose/Tasking/Mission.lua @@ -27,6 +27,8 @@ --- Models goals to be achieved and can contain multiple tasks to be executed to achieve the goals. -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- A mission contains multiple tasks and can be of different task types. -- These tasks need to be assigned to human players to be executed. -- diff --git a/Moose Development/Moose/Tasking/Task.lua b/Moose Development/Moose/Tasking/Task.lua index 21be7dfd8..be3e86f2d 100644 --- a/Moose Development/Moose/Tasking/Task.lua +++ b/Moose Development/Moose/Tasking/Task.lua @@ -12,6 +12,8 @@ -- -- === -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- # 1) Tasking from a player perspective. -- -- Tasking can be controlled by using the "other" menu in the radio menu of the player group. diff --git a/Moose Development/Moose/Tasking/TaskInfo.lua b/Moose Development/Moose/Tasking/TaskInfo.lua index 4007230dc..effcdf698 100644 --- a/Moose Development/Moose/Tasking/TaskInfo.lua +++ b/Moose Development/Moose/Tasking/TaskInfo.lua @@ -17,6 +17,8 @@ --- -- # TASKINFO class, extends @{Core.Base#BASE} -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- ## The TASKINFO class implements the methods to contain information and display information of a task. -- -- # Developer Note diff --git a/Moose Development/Moose/Tasking/Task_A2A.lua b/Moose Development/Moose/Tasking/Task_A2A.lua index a43c79c9f..6ba36b054 100644 --- a/Moose Development/Moose/Tasking/Task_A2A.lua +++ b/Moose Development/Moose/Tasking/Task_A2A.lua @@ -20,6 +20,9 @@ do -- TASK_A2A --- Defines Air To Air tasks for a @{Core.Set} of Target Units, -- based on the tasking capabilities defined in @{Tasking.Task#TASK}. + -- + -- ![Banner Image](..\Images\deprecated.png) + -- -- The TASK_A2A is implemented using a @{Core.Fsm#FSM_TASK}, and has the following statuses: -- -- * **None**: Start of the process diff --git a/Moose Development/Moose/Tasking/Task_A2A_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_A2A_Dispatcher.lua index 9b0f8f5b5..69c29d731 100644 --- a/Moose Development/Moose/Tasking/Task_A2A_Dispatcher.lua +++ b/Moose Development/Moose/Tasking/Task_A2A_Dispatcher.lua @@ -30,6 +30,8 @@ do -- TASK_A2A_DISPATCHER -- @extends Tasking.DetectionManager#DETECTION_MANAGER --- Orchestrates the dynamic dispatching of tasks upon groups of detected units determined a @{Core.Set} of EWR installation groups. + -- + -- ![Banner Image](..\Images\deprecated.png) -- -- ![Banner Image](..\Presentations\TASK_A2A_DISPATCHER\Dia3.JPG) -- diff --git a/Moose Development/Moose/Tasking/Task_A2G.lua b/Moose Development/Moose/Tasking/Task_A2G.lua index 84bdcf360..f39c4968c 100644 --- a/Moose Development/Moose/Tasking/Task_A2G.lua +++ b/Moose Development/Moose/Tasking/Task_A2G.lua @@ -20,6 +20,9 @@ do -- TASK_A2G --- The TASK_A2G class defines Air To Ground tasks for a @{Core.Set} of Target Units, -- based on the tasking capabilities defined in @{Tasking.Task#TASK}. + -- + -- ![Banner Image](..\Images\deprecated.png) + -- -- The TASK_A2G is implemented using a @{Core.Fsm#FSM_TASK}, and has the following statuses: -- -- * **None**: Start of the process diff --git a/Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua index a98477d86..9fc410de1 100644 --- a/Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua +++ b/Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua @@ -33,6 +33,8 @@ do -- TASK_A2G_DISPATCHER -- @extends Tasking.DetectionManager#DETECTION_MANAGER --- Orchestrates dynamic **A2G Task Dispatching** based on the detection results of a linked @{Functional.Detection} object. + -- + -- ![Banner Image](..\Images\deprecated.png) -- -- It uses the Tasking System within the MOOSE framework, which is a multi-player Tasking Orchestration system. -- It provides a truly dynamic battle environment for pilots and ground commanders to engage upon, diff --git a/Moose Development/Moose/Tasking/Task_CARGO.lua b/Moose Development/Moose/Tasking/Task_CARGO.lua index 76a3b9e9a..526a508d4 100644 --- a/Moose Development/Moose/Tasking/Task_CARGO.lua +++ b/Moose Development/Moose/Tasking/Task_CARGO.lua @@ -10,6 +10,8 @@ -- -- === -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- ## Test Missions: -- -- Test missions can be located on the main GITHUB site. diff --git a/Moose Development/Moose/Tasking/Task_Capture_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_Capture_Dispatcher.lua index be2086a2f..5ede27694 100644 --- a/Moose Development/Moose/Tasking/Task_Capture_Dispatcher.lua +++ b/Moose Development/Moose/Tasking/Task_Capture_Dispatcher.lua @@ -76,6 +76,8 @@ do -- TASK_CAPTURE_DISPATCHER --- Implements the dynamic dispatching of capture zone tasks. -- + -- ![Banner Image](..\Images\deprecated.png) + -- -- The **TASK_CAPTURE_DISPATCHER** allows you to setup various tasks for let human -- players capture zones in a co-operation effort. -- diff --git a/Moose Development/Moose/Tasking/Task_Capture_Zone.lua b/Moose Development/Moose/Tasking/Task_Capture_Zone.lua index bd0637a9d..82265c8ae 100644 --- a/Moose Development/Moose/Tasking/Task_Capture_Zone.lua +++ b/Moose Development/Moose/Tasking/Task_Capture_Zone.lua @@ -20,6 +20,8 @@ do -- TASK_ZONE_GOAL --- # TASK_ZONE_GOAL class, extends @{Tasking.Task#TASK} -- + -- ![Banner Image](..\Images\deprecated.png) + -- -- The TASK_ZONE_GOAL class defines the task to protect or capture a protection zone. -- The TASK_ZONE_GOAL is implemented using a @{Core.Fsm#FSM_TASK}, and has the following statuses: -- diff --git a/Moose Development/Moose/Tasking/Task_Cargo_CSAR.lua b/Moose Development/Moose/Tasking/Task_Cargo_CSAR.lua index f0c14b227..e216c6ea2 100644 --- a/Moose Development/Moose/Tasking/Task_Cargo_CSAR.lua +++ b/Moose Development/Moose/Tasking/Task_Cargo_CSAR.lua @@ -44,6 +44,8 @@ -- -- === -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- Please read through the @{Tasking.Task_CARGO} process to understand the mechanisms of tasking and cargo tasking and handling. -- -- The cargo will be a downed pilot, which is located somwhere on the battlefield. Use the menus system and facilities to diff --git a/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua index d60318573..e50dbbfeb 100644 --- a/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua +++ b/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua @@ -2,6 +2,8 @@ -- -- The **TASK_CARGO_DISPATCHER** allows you to setup various tasks for let human -- players transport cargo as part of a task. +-- +-- ![Banner Image](..\Images\deprecated.png) -- -- The cargo dispatcher will implement for you mechanisms to create cargo transportation tasks: -- diff --git a/Moose Development/Moose/Tasking/Task_Cargo_Transport.lua b/Moose Development/Moose/Tasking/Task_Cargo_Transport.lua index 6f8137c6a..5f6fb6e51 100644 --- a/Moose Development/Moose/Tasking/Task_Cargo_Transport.lua +++ b/Moose Development/Moose/Tasking/Task_Cargo_Transport.lua @@ -1,5 +1,7 @@ --- **Tasking** - Models tasks for players to transport cargo. -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- **Specific features:** -- -- * Creates a task to transport #Cargo.Cargo to and between deployment zones. diff --git a/Moose Development/Moose/Tasking/Task_Manager.lua b/Moose Development/Moose/Tasking/Task_Manager.lua index 127b455ad..7cd71c485 100644 --- a/Moose Development/Moose/Tasking/Task_Manager.lua +++ b/Moose Development/Moose/Tasking/Task_Manager.lua @@ -2,6 +2,8 @@ -- -- === -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- 1) @{Tasking.Task_Manager#TASK_MANAGER} class, extends @{Core.Fsm#FSM} -- === -- The @{Tasking.Task_Manager#TASK_MANAGER} class defines the core functions to report tasks to groups. From 7a5b9a75f30f7f16fece6f62eab2e74fd6033d2d Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 15 May 2025 17:07:55 +0200 Subject: [PATCH 036/234] #AIRBASE - added Syria Marka AFB --- Moose Development/Moose/Wrapper/Airbase.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Moose Development/Moose/Wrapper/Airbase.lua b/Moose Development/Moose/Wrapper/Airbase.lua index c7d576e38..aaab918bd 100644 --- a/Moose Development/Moose/Wrapper/Airbase.lua +++ b/Moose Development/Moose/Wrapper/Airbase.lua @@ -513,6 +513,7 @@ AIRBASE.TheChannel = { -- * AIRBASE.Syria.Hatzor -- * AIRBASE.Syria.Palmashim -- * AIRBASE.Syria.Tel_Nof +-- * AIRBASE.Syria.Marka -- --@field Syria AIRBASE.Syria={ @@ -586,6 +587,7 @@ AIRBASE.Syria={ ["Hatzor"] = "Hatzor", ["Palmashim"] = "Palmashim", ["Tel_Nof"] = "Tel Nof", + ["Marka"] = "Marka", } --- Airbases of the Mariana Islands map: From 66032d68949906597c35b95807b6a8b8cca89d32 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 15 May 2025 18:24:26 +0200 Subject: [PATCH 037/234] #EASYGCICAP - added `SetDefaultTakeOffType()` --- Moose Development/Moose/Ops/EasyGCICAP.lua | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/Moose Development/Moose/Ops/EasyGCICAP.lua b/Moose Development/Moose/Ops/EasyGCICAP.lua index 31b732a74..943518b2e 100644 --- a/Moose Development/Moose/Ops/EasyGCICAP.lua +++ b/Moose Development/Moose/Ops/EasyGCICAP.lua @@ -70,6 +70,7 @@ -- @field #boolean DespawnAfterLanding -- @field #boolean DespawnAfterHolding -- @field #list ListOfAuftrag +-- @field #string defaulttakeofftype Take off type -- @extends Core.Fsm#FSM --- *“Airspeed, altitude, and brains. Two are always needed to successfully complete the flight.”* -- Unknown. @@ -223,7 +224,8 @@ EASYGCICAP = { ReadyFlightGroups = {}, DespawnAfterLanding = false, DespawnAfterHolding = true, - ListOfAuftrag = {} + ListOfAuftrag = {}, + defaulttakeofftype = "hot", } --- Internal Squadron data type @@ -259,7 +261,7 @@ EASYGCICAP = { --- EASYGCICAP class version. -- @field #string version -EASYGCICAP.version="0.1.20" +EASYGCICAP.version="0.1.21" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO list @@ -312,6 +314,7 @@ function EASYGCICAP:New(Alias, AirbaseName, Coalition, EWRName) self.DespawnAfterLanding = false self.DespawnAfterHolding = true self.ListOfAuftrag = {} + self.defaulttakeofftype = "hot" -- Set some string id for output to DCS.log file. self.lid=string.format("EASYGCICAP %s | ", self.alias) @@ -400,6 +403,16 @@ function EASYGCICAP:SetDefaultRepeatOnFailure(Retries) return self end +--- Add default take off type for the airwings. +-- @param #EASYGCICAP self +-- @param #string Takeoff Can be "hot", "cold", or "air" - default is "hot". +-- @return #EASYGCICAP self +function EASYGCICAP:SetDefaultTakeOffType(Takeoff) + self:T(self.lid.."SetDefaultTakeOffType") + self.defaulttakeofftype = Takeoff or "hot" + return self +end + --- Set default CAP Speed in knots -- @param #EASYGCICAP self -- @param #number Speed Speed defaults to 300 @@ -596,9 +609,8 @@ function EASYGCICAP:_AddAirwing(Airbasename, Alias) if #self.ManagedREC > 0 then CAP_Wing:SetNumberRecon(1) end - --local PatrolCoordinateKutaisi = ZONE:New(CapZoneName):GetCoordinate() - --CAP_Wing:AddPatrolPointCAP(PatrolCoordinateKutaisi,self.capalt,UTILS.KnotsToAltKIAS(self.capspeed,self.capalt),self.capdir,self.capleg) - CAP_Wing:SetTakeoffHot() + + CAP_Wing:SetTakeoffType(self.defaulttakeofftype) CAP_Wing:SetLowFuelThreshold(0.3) CAP_Wing.RandomAssetScore = math.random(50,100) CAP_Wing:Start() From 09b7922b84494f40a33557c9759e82dc6ca46c70 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Fri, 16 May 2025 11:58:40 +0200 Subject: [PATCH 038/234] Small fixes --- Moose Development/Moose/Core/Database.lua | 2 ++ Moose Development/Moose/Functional/Mantis.lua | 26 +++++++++++++++---- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/Moose Development/Moose/Core/Database.lua b/Moose Development/Moose/Core/Database.lua index 4aec2393a..85bde137c 100644 --- a/Moose Development/Moose/Core/Database.lua +++ b/Moose Development/Moose/Core/Database.lua @@ -872,6 +872,8 @@ end -- @return Wrapper.Group#GROUP The found GROUP. function DATABASE:FindGroup( GroupName ) + if type(GroupName) ~= "string" or GroupName == "" then return end + local GroupFound = self.GROUPS[GroupName] if GroupFound == nil and GroupName ~= nil and self.Templates.Groups[GroupName] == nil then diff --git a/Moose Development/Moose/Functional/Mantis.lua b/Moose Development/Moose/Functional/Mantis.lua index 989b400e0..965762d07 100644 --- a/Moose Development/Moose/Functional/Mantis.lua +++ b/Moose Development/Moose/Functional/Mantis.lua @@ -64,6 +64,7 @@ -- @field #number SmokeDecoyColor Color to use, defaults to SMOKECOLOR.White -- @field #number checkcounter Counter for SAM Table refreshes. -- @field #number DLinkCacheTime Seconds after which cached contacts in DLink will decay. +-- @field #boolean logsamstatus Log SAM status in dcs.log every cycle if true -- @extends Core.Base#BASE @@ -322,6 +323,7 @@ MANTIS = { SmokeDecoyColor = SMOKECOLOR.White, checkcounter = 1, DLinkCacheTime = 120, + logsamstatus = false, } --- Advanced state enumerator @@ -647,6 +649,8 @@ do table.insert(self.ewr_templates,awacs) end + self.logsamstatus = false + self:T({self.ewr_templates}) self.SAM_Group = SET_GROUP:New():FilterPrefixes(self.SAM_Templates_Prefix):FilterCoalitions(self.Coalition) @@ -678,7 +682,7 @@ do -- TODO Version -- @field #string version - self.version="0.9.29" + self.version="0.9.30" self:I(string.format("***** Starting MANTIS Version %s *****", self.version)) --- FSM Functions --- @@ -1695,7 +1699,9 @@ do local grpname = group:GetName() local grpcoord = group:GetCoordinate() local grprange, grpheight,type,blind = self:_GetSAMRange(grpname) - local radaralive = group:IsSAM() + -- TODO the below might stop working at some point after some hours, needs testing + --local radaralive = group:IsSAM() + local radaralive = true table.insert( SAM_Tbl, {grpname, grpcoord, grprange, grpheight, blind, type}) -- make the table lighter, as I don't really use the zone here table.insert( SEAD_Grps, grpname ) if type == MANTIS.SamType.LONG and radaralive then @@ -1878,8 +1884,9 @@ do -- @param #MANTIS self -- @param Functional.Detection#DETECTION_AREAS detection Detection object -- @param #boolean dlink + -- @param #boolean reporttolog -- @return #MANTIS self - function MANTIS:_Check(detection,dlink) + function MANTIS:_Check(detection,dlink,reporttolog) self:T(self.lid .. "Check") --get detected set local detset = detection:GetDetectedItemCoordinates() @@ -1906,7 +1913,8 @@ do local samset = self:_GetSAMTable() -- table of i.1=names, i.2=coordinates, i.3=firing range, i.4=firing height instatusred, instatusgreen, activeshorads = self:_CheckLoop(samset,detset,dlink,self.maxclassic) end - if self.debug or self.verbose then + + local function GetReport() local statusreport = REPORT:New("\nMANTIS Status "..self.name) statusreport:Add("+-----------------------------+") statusreport:Add(string.format("+ SAM in RED State: %2d",instatusred)) @@ -1915,7 +1923,15 @@ do statusreport:Add(string.format("+ SHORAD active: %2d",activeshorads)) end statusreport:Add("+-----------------------------+") + return statusreport + end + + if self.debug or self.verbose then + local statusreport = GetReport() MESSAGE:New(statusreport:Text(),10):ToAll():ToLog() + elseif reporttolog == true then + local statusreport = GetReport() + MESSAGE:New(statusreport:Text(),10):ToLog() end return self end @@ -2023,7 +2039,7 @@ do self:T({From, Event, To}) -- check detection if not self.state2flag then - self:_Check(self.Detection,self.DLink) + self:_Check(self.Detection,self.DLink,self.logsamstatus) end local EWRAlive = self:_CheckAnyEWRAlive() From b126cc00d05ec3e139864467443dbcd6177a1a21 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Fri, 16 May 2025 13:43:03 +0200 Subject: [PATCH 039/234] xx --- Moose Development/Moose/Functional/Mantis.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/Functional/Mantis.lua b/Moose Development/Moose/Functional/Mantis.lua index 965762d07..8ec4939d7 100644 --- a/Moose Development/Moose/Functional/Mantis.lua +++ b/Moose Development/Moose/Functional/Mantis.lua @@ -1863,7 +1863,7 @@ do end --end alive end --end check end --for loop - if self.debug or self.verbose then + if self.debug or self.verbose or self.logsamstatus then for _,_status in pairs(self.SamStateTracker) do if _status == "GREEN" then instatusgreen=instatusgreen+1 From 997baf21a0af023916a8b20221daa0e8dfda28f9 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Wed, 21 May 2025 10:04:58 +0200 Subject: [PATCH 040/234] #CSAR fix for ADF beacons --- Moose Development/Moose/Ops/CSAR.lua | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/Moose Development/Moose/Ops/CSAR.lua b/Moose Development/Moose/Ops/CSAR.lua index 76f6df917..f1a1578ae 100644 --- a/Moose Development/Moose/Ops/CSAR.lua +++ b/Moose Development/Moose/Ops/CSAR.lua @@ -313,7 +313,7 @@ CSAR.AircraftType["CH-47Fbl1"] = 31 --- CSAR class version. -- @field #string version -CSAR.version="1.0.31" +CSAR.version="1.0.32" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- ToDo list @@ -468,7 +468,7 @@ function CSAR:New(Coalition, Template, Alias) -- added 1.0.15 self.allowbronco = false -- set to true to use the Bronco mod as a CSAR plane - self.ADFRadioPwr = 1000 + self.ADFRadioPwr = 500 -- added 1.0.16 self.PilotWeight = 80 @@ -2333,9 +2333,9 @@ end -- @param #CSAR self -- @param Wrapper.Group#GROUP _group Group #GROUP object. -- @param #number _freq Frequency to use --- @param #string _name Beacon Name to use +-- @param #string BeaconName Beacon Name to use -- @return #CSAR self -function CSAR:_AddBeaconToGroup(_group, _freq, _name) +function CSAR:_AddBeaconToGroup(_group, _freq, BeaconName) self:T(self.lid .. " _AddBeaconToGroup") if self.CreateRadioBeacons == false then return end local _group = _group @@ -2356,10 +2356,11 @@ function CSAR:_AddBeaconToGroup(_group, _freq, _name) if _radioUnit then local name = _radioUnit:GetName() local Frequency = _freq -- Freq in Hertz - local name = _radioUnit:GetName() + --local name = _radioUnit:GetName() local Sound = "l10n/DEFAULT/"..self.radioSound local vec3 = _radioUnit:GetVec3() or _radioUnit:GetPositionVec3() or {x=0,y=0,z=0} - trigger.action.radioTransmission(Sound, vec3, 0, false, Frequency, self.ADFRadioPwr or 1000,_name) -- Beacon in MP only runs for exactly 30secs straight + self:I(self.lid..string.format("Added Radio Beacon %d Hertz | Name %s | Position {%d,%d,%d}",Frequency,BeaconName,vec3.x,vec3.y,vec3.z)) + trigger.action.radioTransmission(Sound, vec3, 0, true, Frequency, self.ADFRadioPwr or 500,BeaconName) -- Beacon in MP only runs for exactly 30secs straight end end @@ -2380,9 +2381,13 @@ function CSAR:_RefreshRadioBeacons() local group = pilot.group local frequency = pilot.frequency or 0 -- thanks to @Thrud local bname = pilot.BeaconName or pilot.name..math.random(1,100000) - trigger.action.stopRadioTransmission(bname) + --trigger.action.stopRadioTransmission(bname) if group and group:IsAlive() and frequency > 0 then - self:_AddBeaconToGroup(group,frequency,bname) + --self:_AddBeaconToGroup(group,frequency,bname) + else + if frequency > 0 then + trigger.action.stopRadioTransmission(bname) + end end end end From a4feafab8e9d4da5100238ebf21d80924b7cd90e Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Wed, 21 May 2025 10:21:48 +0200 Subject: [PATCH 041/234] #POINT - improved IsDay() for Kola --- Moose Development/Moose/Core/Point.lua | 11 +++++++++-- Moose Development/Moose/Utilities/Utils.lua | 4 ++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index f1aa66289..35ad76b4c 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -2992,8 +2992,10 @@ do -- COORDINATE local sunrise=UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, true, Tdiff) local sunset=UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, false, Tdiff) - if sunrise == "N/R" then return false end - if sunrise == "N/S" then return true end + if type(sunrise) == "string" or type(sunset) == "string" then + if sunrise == "N/R" then return false end + if sunset == "N/S" then return true end + end local time=UTILS.ClockToSeconds(clock) @@ -3011,6 +3013,11 @@ do -- COORDINATE -- Todays sun set in sec. local sunset=self:GetSunset(true) + + if type(sunrise) == "string" or type(sunset) == "string" then + if sunrise == "N/R" then return false end + if sunset == "N/S" then return true end + end -- Seconds passed since midnight. local time=UTILS.SecondsOfToday() diff --git a/Moose Development/Moose/Utilities/Utils.lua b/Moose Development/Moose/Utilities/Utils.lua index 73ce154c9..19e6889b3 100644 --- a/Moose Development/Moose/Utilities/Utils.lua +++ b/Moose Development/Moose/Utilities/Utils.lua @@ -2145,9 +2145,9 @@ function UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, Rising, Tlocal) local cosH = (cos(zenith) - (sinDec * sin(latitude))) / (cosDec * cos(latitude)) if rising and cosH > 1 then - return "N/S" -- The sun never rises on this location on the specified date + return "N/R" -- The sun never rises on this location on the specified date elseif cosH < -1 then - return "N/R" -- The sun never sets on this location on the specified date + return "N/S" -- The sun never sets on this location on the specified date end -- Finish calculating H and convert into hours From d3b62d026054395599155eb9bc12a685181ad065 Mon Sep 17 00:00:00 2001 From: shaji Date: Sat, 24 May 2025 11:18:41 +0200 Subject: [PATCH 042/234] [ADDED] `TARGET:GetObjects()` and `TARGET:GetCoordinates()` in case of SET --- Moose Development/Moose/Ops/Target.lua | 35 ++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/Moose Development/Moose/Ops/Target.lua b/Moose Development/Moose/Ops/Target.lua index fcc108087..4863f5202 100644 --- a/Moose Development/Moose/Ops/Target.lua +++ b/Moose Development/Moose/Ops/Target.lua @@ -1715,6 +1715,26 @@ function TARGET:GetAverageCoordinate() return nil end + +--- Get coordinates of all targets. (e.g. for a SET_STATIC) +-- @param #TARGET self +-- @return #table Table with coordinates of all targets. +function TARGET:GetCoordinates() + local coordinates={} + + for _,_target in pairs(self.targets) do + local target=_target --#TARGET.Object + + local coordinate=self:GetTargetCoordinate(target) + if coordinate then + table.insert(coordinates, coordinate) + end + + end + + return coordinates +end + --- Get heading of target. -- @param #TARGET self -- @return #number Heading of the target in degrees. @@ -1968,6 +1988,21 @@ function TARGET:GetObject(RefCoordinate, Coalitions) return nil end +--- Get all target objects. +-- @param #TARGET self +-- @return #table List of target objects. +function TARGET:GetObjects() + local objects={} + + for _,_target in pairs(self.targets) do + local target=_target --#TARGET.Object + + table.insert(objects, target.Object) + end + + return objects +end + --- Count alive objects. -- @param #TARGET self -- @param #TARGET.Object Target Target objective. From 20c50c751fc7162e3218454af6a25b21ff144ead Mon Sep 17 00:00:00 2001 From: shaji Date: Sat, 24 May 2025 11:29:01 +0200 Subject: [PATCH 043/234] [ADDED] Sets target support for Auftrag STRIKE and BOMBING --- Moose Development/Moose/Ops/Auftrag.lua | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/Moose Development/Moose/Ops/Auftrag.lua b/Moose Development/Moose/Ops/Auftrag.lua index 98d42aa37..fb4d0adbe 100644 --- a/Moose Development/Moose/Ops/Auftrag.lua +++ b/Moose Development/Moose/Ops/Auftrag.lua @@ -1717,7 +1717,7 @@ end --- **[AIR]** Create a STRIKE mission. Flight will attack the closest map object to the specified coordinate. -- @param #AUFTRAG self --- @param Core.Point#COORDINATE Target The target coordinate. Can also be given as a GROUP, UNIT, STATIC or TARGET object. +-- @param Core.Point#COORDINATE Target The target coordinate. Can also be given as a GROUP, UNIT, STATIC, SET_GROUP, SET_UNIT, SET_STATIC or TARGET object. -- @param #number Altitude Engage altitude in feet. Default 2000 ft. -- @param #number EngageWeaponType Which weapon to use. Defaults to auto, ie ENUMS.WeaponFlag.Auto. See ENUMS.WeaponFlag for options. -- @return #AUFTRAG self @@ -1749,7 +1749,7 @@ end --- **[AIR]** Create a BOMBING mission. Flight will drop bombs a specified coordinate. -- See [DCS task bombing](https://wiki.hoggitworld.com/view/DCS_task_bombing). -- @param #AUFTRAG self --- @param Core.Point#COORDINATE Target Target coordinate. Can also be specified as a GROUP, UNIT, STATIC or TARGET object. +-- @param Core.Point#COORDINATE Target Target coordinate. Can also be specified as a GROUP, UNIT, STATIC, SET_GROUP, SET_UNIT, SET_STATIC or TARGET object. -- @param #number Altitude Engage altitude in feet. Default 25000 ft. -- @param #number EngageWeaponType Which weapon to use. Defaults to auto, ie ENUMS.WeaponFlag.Auto. See ENUMS.WeaponFlag for options. -- @return #AUFTRAG self @@ -6108,10 +6108,13 @@ function AUFTRAG:GetDCSMissionTask() -- BOMBING Mission -- --------------------- - local DCStask=CONTROLLABLE.TaskBombing(nil, self:GetTargetVec2(), self.engageAsGroup, self.engageWeaponExpend, self.engageQuantity, self.engageDirection, self.engageAltitude, self.engageWeaponType, Divebomb) + local coords = self.engageTarget:GetCoordinates() + for _, coord in pairs(coords) do + local DCStask = CONTROLLABLE.TaskBombing(nil, coord:GetVec2(), self.engageAsGroup, self.engageWeaponExpend, self.engageQuantity, self.engageDirection, self.engageAltitude, self.engageWeaponType) + + table.insert(DCStasks, DCStask) + end - table.insert(DCStasks, DCStask) - elseif self.type==AUFTRAG.Type.STRAFING then ---------------------- @@ -6311,9 +6314,12 @@ function AUFTRAG:GetDCSMissionTask() -- STRIKE Mission -- -------------------- - local DCStask=CONTROLLABLE.TaskAttackMapObject(nil, self:GetTargetVec2(), self.engageAsGroup, self.engageWeaponExpend, self.engageQuantity, self.engageDirection, self.engageAltitude, self.engageWeaponType) + local coords = self.engageTarget:GetCoordinates() + for _, coord in pairs(coords) do + local DCStask=CONTROLLABLE.TaskAttackMapObject(nil, coord:GetVec2(), self.engageAsGroup, self.engageWeaponExpend, self.engageQuantity, self.engageDirection, self.engageAltitude, self.engageWeaponType) - table.insert(DCStasks, DCStask) + table.insert(DCStasks, DCStask) + end elseif self.type==AUFTRAG.Type.TANKER or self.type==AUFTRAG.Type.RECOVERYTANKER then From 2fc16ba694d8d28534c0af1b11d2d7483d7d9b13 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sat, 24 May 2025 15:53:43 +0200 Subject: [PATCH 044/234] Runway text duplication --- Moose Development/Moose/Ops/ATIS.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/Ops/ATIS.lua b/Moose Development/Moose/Ops/ATIS.lua index f53f953d0..107808898 100644 --- a/Moose Development/Moose/Ops/ATIS.lua +++ b/Moose Development/Moose/Ops/ATIS.lua @@ -2798,7 +2798,7 @@ function ATIS:onafterBroadcast( From, Event, To ) end _RUNACT = subtitle - alltext = alltext .. ";\n" .. subtitle + --alltext = alltext .. ";\n" .. subtitle -- Runway length. if self.rwylength then From 7ca219748dbb8927980f438cf4a0f2a791421367 Mon Sep 17 00:00:00 2001 From: shaji Date: Sat, 24 May 2025 19:46:20 +0200 Subject: [PATCH 045/234] [FIXED] Velocity is taking into account dead units for GROUP --- Moose Development/Moose/Wrapper/Group.lua | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index fa597e461..44f313f27 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -912,15 +912,18 @@ function GROUP:GetVelocityVec3() if DCSGroup and DCSGroup:isExist() then local GroupUnits = DCSGroup:getUnits() - local GroupCount = #GroupUnits + local GroupCount = 0 local VelocityVec3 = { x = 0, y = 0, z = 0 } for _, DCSUnit in pairs( GroupUnits ) do - local UnitVelocityVec3 = DCSUnit:getVelocity() - VelocityVec3.x = VelocityVec3.x + UnitVelocityVec3.x - VelocityVec3.y = VelocityVec3.y + UnitVelocityVec3.y - VelocityVec3.z = VelocityVec3.z + UnitVelocityVec3.z + if DCSUnit:isExist() and DCSUnit:isActive() then + local UnitVelocityVec3 = DCSUnit:getVelocity() + VelocityVec3.x = VelocityVec3.x + UnitVelocityVec3.x + VelocityVec3.y = VelocityVec3.y + UnitVelocityVec3.y + VelocityVec3.z = VelocityVec3.z + UnitVelocityVec3.z + GroupCount = GroupCount + 1 + end end VelocityVec3.x = VelocityVec3.x / GroupCount @@ -1754,11 +1757,13 @@ function GROUP:GetMaxVelocity() for Index, UnitData in pairs( DCSGroup:getUnits() ) do - local UnitVelocityVec3 = UnitData:getVelocity() - local UnitVelocity = math.abs( UnitVelocityVec3.x ) + math.abs( UnitVelocityVec3.y ) + math.abs( UnitVelocityVec3.z ) + if UnitData:isExist() and UnitData:isActive() then + local UnitVelocityVec3 = UnitData:getVelocity() + local UnitVelocity = math.abs( UnitVelocityVec3.x ) + math.abs( UnitVelocityVec3.y ) + math.abs( UnitVelocityVec3.z ) - if UnitVelocity > GroupVelocityMax then - GroupVelocityMax = UnitVelocity + if UnitVelocity > GroupVelocityMax then + GroupVelocityMax = UnitVelocity + end end end From dd5ca93f26a69932407927e161614f57c7475d4e Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Fri, 30 May 2025 11:13:50 +0200 Subject: [PATCH 046/234] CSAR Small addition --- Moose Development/Moose/Ops/CSAR.lua | 30 +++++++--------------------- 1 file changed, 7 insertions(+), 23 deletions(-) diff --git a/Moose Development/Moose/Ops/CSAR.lua b/Moose Development/Moose/Ops/CSAR.lua index f1a1578ae..98b8a2128 100644 --- a/Moose Development/Moose/Ops/CSAR.lua +++ b/Moose Development/Moose/Ops/CSAR.lua @@ -313,7 +313,7 @@ CSAR.AircraftType["CH-47Fbl1"] = 31 --- CSAR class version. -- @field #string version -CSAR.version="1.0.32" +CSAR.version="1.0.33" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- ToDo list @@ -2116,7 +2116,8 @@ end --- (Internal) Determine distance to closest MASH. -- @param #CSAR self -- @param Wrapper.Unit#UNIT _heli Helicopter #UNIT --- @return #CSAR self +-- @return #number Distance in meters +-- @return #string MASH Name as string function CSAR:_GetClosestMASH(_heli) self:T(self.lid .. " _GetClosestMASH") local _mashset = self.mash -- Core.Set#SET_GROUP @@ -2128,31 +2129,13 @@ function CSAR:_GetClosestMASH(_heli) local _shortestDistance = -1 local _distance = 0 local _helicoord = _heli:GetCoordinate() - - local function GetCloseAirbase(coordinate,Coalition,Category) - - local a=coordinate:GetVec3() - local distmin=math.huge - local airbase=nil - for DCSairbaseID, DCSairbase in pairs(world.getAirbases(Coalition)) do - local b=DCSairbase:getPoint() - - local c=UTILS.VecSubstract(a,b) - local dist=UTILS.VecNorm(c) - - if dist Date: Fri, 30 May 2025 16:03:01 +0200 Subject: [PATCH 047/234] - [ADDED] Removes previous downed pilot with the same player name in Ejection event - [ADDED] `useFIFOLimitReplacement` If true, it will remove the oldest downed pilot when a new one is added, if the limit is reached (FIFO queue), otherwise does not add downed pilots when the limit is reached. --- Moose Development/Moose/Ops/CSAR.lua | 71 +++++++++++++++++++++------- 1 file changed, 53 insertions(+), 18 deletions(-) diff --git a/Moose Development/Moose/Ops/CSAR.lua b/Moose Development/Moose/Ops/CSAR.lua index 98b8a2128..09af31eb5 100644 --- a/Moose Development/Moose/Ops/CSAR.lua +++ b/Moose Development/Moose/Ops/CSAR.lua @@ -263,6 +263,7 @@ CSAR = { rescuedpilots = 0, limitmaxdownedpilots = true, maxdownedpilots = 10, + useFIFOLimitReplacement = false, -- If true, it will remove the oldest downed pilot when a new one is added, if the limit is reached. allheligroupset = nil, topmenuname = "CSAR", ADFRadioPwr = 1000, @@ -1144,19 +1145,8 @@ function CSAR:_EventHandler(EventData) self:T("Double Ejection!") return self end - - -- limit no of pilots in the field. - if self.limitmaxdownedpilots and self:_ReachedPilotLimit() then - self:T("Maxed Downed Pilot!") - return self - end - - - -- TODO: Over water check --- EVENTS.LandingAfterEjection NOT triggered by DCS, so handle csarUsePara = true case - -- might create dual pilots in edge cases - - local wetfeet = false - + + local initdcscoord = nil local initcoord = nil if _event.id == EVENTS.Ejection then @@ -1168,6 +1158,36 @@ function CSAR:_EventHandler(EventData) initcoord = COORDINATE:NewFromVec3(initdcscoord) self:T({initdcscoord}) end + + -- Remove downed pilot if already exists to replace with new one. + if _event.IniPlayerName then + local PilotTable = self.downedPilots --#CSAR.DownedPilot + local _foundPilot = nil + for _,_pilot in pairs(PilotTable) do + if _pilot.player == _event.IniPlayerName and _pilot.alive == true then + _foundPilot = _pilot + break + end + end + if _foundPilot then + self:T("Downed pilot already exists!") + _foundPilot.group:Destroy(false) + self:_RemoveNameFromDownedPilots(_foundPilot.name) + self:_CheckDownedPilotTable() + end + end + + -- limit no of pilots in the field. + if self.limitmaxdownedpilots and self:_ReachedPilotLimit() then + self:T("Maxed Downed Pilot!") + return self + end + + + -- TODO: Over water check --- EVENTS.LandingAfterEjection NOT triggered by DCS, so handle csarUsePara = true case + -- might create dual pilots in edge cases + + local wetfeet = false --local surface = _unit:GetCoordinate():GetSurfaceType() local surface = initcoord:GetSurfaceType() @@ -2401,11 +2421,26 @@ function CSAR:_ReachedPilotLimit() local limit = self.maxdownedpilots local islimited = self.limitmaxdownedpilots local count = self:_CountActiveDownedPilots() - if islimited and (count >= limit) then - return true - else - return false - end + if islimited and (count >= limit) then + if self.useFIFOLimitReplacement then + local oldIndex = -1 + local oldDownedPilot = nil + for _index, _downedpilot in pairs(self.downedPilots) do + oldIndex = _index + oldDownedPilot = _downedpilot + break + end + if oldDownedPilot then + oldDownedPilot.group:Destroy(false) + oldDownedPilot.alive = false + self:_CheckDownedPilotTable() + return false + end + end + return true + else + return false + end end --- User - Function to add onw SET_GROUP Set-up for pilot filtering and assignment. From bb1caa6642bce39c2ec0a109cdae83b68cad3d39 Mon Sep 17 00:00:00 2001 From: Thomas <72444570+Applevangelist@users.noreply.github.com> Date: Fri, 30 May 2025 18:37:38 +0200 Subject: [PATCH 048/234] Update CSAR.lua --- Moose Development/Moose/Ops/CSAR.lua | 71 +++++++++++++++++++++------- 1 file changed, 53 insertions(+), 18 deletions(-) diff --git a/Moose Development/Moose/Ops/CSAR.lua b/Moose Development/Moose/Ops/CSAR.lua index 98b8a2128..09af31eb5 100644 --- a/Moose Development/Moose/Ops/CSAR.lua +++ b/Moose Development/Moose/Ops/CSAR.lua @@ -263,6 +263,7 @@ CSAR = { rescuedpilots = 0, limitmaxdownedpilots = true, maxdownedpilots = 10, + useFIFOLimitReplacement = false, -- If true, it will remove the oldest downed pilot when a new one is added, if the limit is reached. allheligroupset = nil, topmenuname = "CSAR", ADFRadioPwr = 1000, @@ -1144,19 +1145,8 @@ function CSAR:_EventHandler(EventData) self:T("Double Ejection!") return self end - - -- limit no of pilots in the field. - if self.limitmaxdownedpilots and self:_ReachedPilotLimit() then - self:T("Maxed Downed Pilot!") - return self - end - - - -- TODO: Over water check --- EVENTS.LandingAfterEjection NOT triggered by DCS, so handle csarUsePara = true case - -- might create dual pilots in edge cases - - local wetfeet = false - + + local initdcscoord = nil local initcoord = nil if _event.id == EVENTS.Ejection then @@ -1168,6 +1158,36 @@ function CSAR:_EventHandler(EventData) initcoord = COORDINATE:NewFromVec3(initdcscoord) self:T({initdcscoord}) end + + -- Remove downed pilot if already exists to replace with new one. + if _event.IniPlayerName then + local PilotTable = self.downedPilots --#CSAR.DownedPilot + local _foundPilot = nil + for _,_pilot in pairs(PilotTable) do + if _pilot.player == _event.IniPlayerName and _pilot.alive == true then + _foundPilot = _pilot + break + end + end + if _foundPilot then + self:T("Downed pilot already exists!") + _foundPilot.group:Destroy(false) + self:_RemoveNameFromDownedPilots(_foundPilot.name) + self:_CheckDownedPilotTable() + end + end + + -- limit no of pilots in the field. + if self.limitmaxdownedpilots and self:_ReachedPilotLimit() then + self:T("Maxed Downed Pilot!") + return self + end + + + -- TODO: Over water check --- EVENTS.LandingAfterEjection NOT triggered by DCS, so handle csarUsePara = true case + -- might create dual pilots in edge cases + + local wetfeet = false --local surface = _unit:GetCoordinate():GetSurfaceType() local surface = initcoord:GetSurfaceType() @@ -2401,11 +2421,26 @@ function CSAR:_ReachedPilotLimit() local limit = self.maxdownedpilots local islimited = self.limitmaxdownedpilots local count = self:_CountActiveDownedPilots() - if islimited and (count >= limit) then - return true - else - return false - end + if islimited and (count >= limit) then + if self.useFIFOLimitReplacement then + local oldIndex = -1 + local oldDownedPilot = nil + for _index, _downedpilot in pairs(self.downedPilots) do + oldIndex = _index + oldDownedPilot = _downedpilot + break + end + if oldDownedPilot then + oldDownedPilot.group:Destroy(false) + oldDownedPilot.alive = false + self:_CheckDownedPilotTable() + return false + end + end + return true + else + return false + end end --- User - Function to add onw SET_GROUP Set-up for pilot filtering and assignment. From fca6faa3a81188fbaa2fff28f3e859a2102f4c51 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Fri, 30 May 2025 20:51:04 +0200 Subject: [PATCH 049/234] xx --- Moose Development/Moose/Ops/PlayerTask.lua | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Moose Development/Moose/Ops/PlayerTask.lua b/Moose Development/Moose/Ops/PlayerTask.lua index ce95f00a4..7c912235f 100644 --- a/Moose Development/Moose/Ops/PlayerTask.lua +++ b/Moose Development/Moose/Ops/PlayerTask.lua @@ -21,7 +21,7 @@ -- === -- @module Ops.PlayerTask -- @image OPS_PlayerTask.jpg --- @date Last Update April 2025 +-- @date Last Update May 2025 do @@ -98,7 +98,7 @@ PLAYERTASK = { --- PLAYERTASK class version. -- @field #string version -PLAYERTASK.version="0.1.26" +PLAYERTASK.version="0.1.27" --- Generic task condition. -- @type PLAYERTASK.Condition @@ -1951,7 +1951,7 @@ function PLAYERTASKCONTROLLER:New(Name, Coalition, Type, ClientFilter) self.taskinfomenu = false self.activehasinfomenu = false self.MenuName = nil - self.menuitemlimit = 5 + self.menuitemlimit = 6 self.holdmenutime = 30 self.MarkerReadOnly = false @@ -2581,7 +2581,7 @@ function PLAYERTASKCONTROLLER:SetMenuOptions(InfoMenu,ItemLimit,HoldTime) if self.activehasinfomenu then self:EnableTaskInfoMenu() end - self.menuitemlimit = ItemLimit or 5 + self.menuitemlimit = ItemLimit+1 or 6 self.holdmenutime = HoldTime or 30 return self end @@ -3486,7 +3486,7 @@ end -- @param #PLAYERTASKCONTROLLER self -- @param Ops.PlayerTask#PLAYERTASK PlayerTask -- @param #boolean Silent If true, make no "has new task" announcement --- @param #boolen TaskFilter If true, apply the white/black-list task filters here, also +-- @param #boolean TaskFilter If true, apply the white/black-list task filters here, also -- @return #PLAYERTASKCONTROLLER self -- @usage -- Example to create a PLAYERTASK of type CTLD and give Players 10 minutes to complete: From f5881eda533a97bae379e3b5d5b81cd6895fa0d1 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sun, 1 Jun 2025 12:19:42 +0200 Subject: [PATCH 050/234] AIRBOSS - Remove useless E Messages for non-debug --- Moose Development/Moose/Ops/Airboss.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Moose Development/Moose/Ops/Airboss.lua b/Moose Development/Moose/Ops/Airboss.lua index 5e6f70443..d6d7b03a7 100644 --- a/Moose Development/Moose/Ops/Airboss.lua +++ b/Moose Development/Moose/Ops/Airboss.lua @@ -8741,13 +8741,13 @@ function AIRBOSS:OnEventRemoveUnit( EventData ) -- Nil checks. if EventData == nil then - self:E( self.lid .. "ERROR: EventData=nil in event REMOVEUNIT!" ) - self:E( EventData ) + self:T( self.lid .. "ERROR: EventData=nil in event REMOVEUNIT!" ) + self:T( EventData ) return end if EventData.IniUnit == nil then - self:E( self.lid .. "ERROR: EventData.IniUnit=nil in event REMOVEUNIT!" ) - self:E( EventData ) + self:T( self.lid .. "ERROR: EventData.IniUnit=nil in event REMOVEUNIT!" ) + self:T( EventData ) return end From 95767c5ef45ebfdb97423c5461a4da519de6eb2a Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sun, 1 Jun 2025 12:20:08 +0200 Subject: [PATCH 051/234] AIRBOSS - Remove useless E Messages for non-debug --- Moose Development/Moose/Ops/Airboss.lua | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/Moose Development/Moose/Ops/Airboss.lua b/Moose Development/Moose/Ops/Airboss.lua index f95a9ab7c..d6d7b03a7 100644 --- a/Moose Development/Moose/Ops/Airboss.lua +++ b/Moose Development/Moose/Ops/Airboss.lua @@ -3091,8 +3091,7 @@ function AIRBOSS:EnableSRS(PathToSRS,Port,Culture,Gender,Voice,GoogleCreds,Volum self.SRS:SetVolume(Volume or 1) --self.SRS:SetModulations(Modulations) if GoogleCreds then - self.SRS:SetProviderOptionsGoogle(GoogleCreds,GoogleCreds) - self.SRS:SetProvider(MSRS.Provider.GOOGLE) + self.SRS:SetGoogle(GoogleCreds) end if Voice then self.SRS:SetVoice(Voice) @@ -3642,7 +3641,6 @@ function AIRBOSS:onafterStart( From, Event, To ) self:HandleEvent( EVENTS.PlayerLeaveUnit, self._PlayerLeft ) self:HandleEvent( EVENTS.MissionEnd ) self:HandleEvent( EVENTS.RemoveUnit ) - self:HandleEvent( EVENTS.UnitLost, self.OnEventRemoveUnit ) -- self.StatusScheduler=SCHEDULER:New(self) -- self.StatusScheduler:Schedule(self, self._Status, {}, 1, 0.5) @@ -8743,13 +8741,13 @@ function AIRBOSS:OnEventRemoveUnit( EventData ) -- Nil checks. if EventData == nil then - self:E( self.lid .. "ERROR: EventData=nil in event REMOVEUNIT!" ) - self:E( EventData ) + self:T( self.lid .. "ERROR: EventData=nil in event REMOVEUNIT!" ) + self:T( EventData ) return end if EventData.IniUnit == nil then - self:E( self.lid .. "ERROR: EventData.IniUnit=nil in event REMOVEUNIT!" ) - self:E( EventData ) + self:T( self.lid .. "ERROR: EventData.IniUnit=nil in event REMOVEUNIT!" ) + self:T( EventData ) return end From eeeeda4e5e1550bf2c1b2aaaebe347b93b4eb48f Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sun, 8 Jun 2025 18:43:01 +0200 Subject: [PATCH 052/234] #POINT - Offset options for smoke --- Moose Development/Moose/Core/Point.lua | 89 ++++++++++++++++++++++++-- 1 file changed, 85 insertions(+), 4 deletions(-) diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index 35ad76b4c..a74356985 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -59,6 +59,10 @@ do -- COORDINATE -- * @{#COORDINATE.SmokeOrange}(): To smoke the point in orange. -- * @{#COORDINATE.SmokeWhite}(): To smoke the point in white. -- * @{#COORDINATE.SmokeGreen}(): To smoke the point in green. + -- * @{#COORDINATE.SetSmokeOffsetDirection}(): To set an offset point direction for smoke. + -- * @{#COORDINATE.SetSmokeOffsetDistance}(): To set an offset point distance for smoke. + -- * @{#COORDINATE.SwitchSmokeOffsetOn}(): To set an offset point for smoke to on. + -- * @{#COORDINATE.SwitchSmokeOffsetOff}(): To set an offset point for smoke to off. -- -- ## 2.2) Flare -- @@ -2124,21 +2128,32 @@ do -- COORDINATE -- @param #number Duration (Optional) Duration of the smoke in seconds. DCS stopps the smoke automatically after 5 min. -- @param #number Delay (Optional) Delay before the smoke is started in seconds. -- @param #string Name (Optional) Name if you want to stop the smoke early (normal duration: 5mins) + -- @param #boolean Offset (Optional) If true, offset the smokle a bit. + -- @param #number Direction (Optional) If Offset is true this is the direction of the offset, 1-359 (degrees). Default random. + -- @param #number Distance (Optional) If Offset is true this is the distance of the offset in meters. Default random 10-20. -- @return #COORDINATE self - function COORDINATE:Smoke( SmokeColor, Duration, Delay, Name) - self:F2( { SmokeColor, Name, Duration, Delay } ) + function COORDINATE:Smoke( SmokeColor, Duration, Delay, Name, Offset,Direction,Distance) + self:F2( { SmokeColor, Name, Duration, Delay, Offset } ) SmokeColor=SmokeColor or SMOKECOLOR.Green if Delay and Delay>0 then - self:ScheduleOnce(Delay, COORDINATE.Smoke, self, SmokeColor, Duration, 0, Name) + self:ScheduleOnce(Delay, COORDINATE.Smoke, self, SmokeColor, Duration, 0, Name, Direction,Distance) else -- Create a name which is used to stop the smoke manually self.firename = Name or "Smoke-"..math.random(1,100000) -- Create smoke - trigger.action.smoke( self:GetVec3(), SmokeColor, self.firename ) + if Offset or self.SmokeOffset then + local Angle = Direction or self:GetSmokeOffsetDirection() + local Distance = Distance or self:GetSmokeOffsetDistance() + local newpos = self:Translate(Distance,Angle,true,false) + local newvec3 = newpos:GetVec3() + trigger.action.smoke( newvec3, SmokeColor, self.firename ) + else + trigger.action.smoke( self:GetVec3(), SmokeColor, self.firename ) + end -- Stop smoke if Duration and Duration>0 then @@ -2148,6 +2163,72 @@ do -- COORDINATE return self end + + --- Get the offset direction when using `COORDINATE:Smoke()`. + -- @param #COORDINATE self + -- @return #number Direction in degrees. + function COORDINATE:GetSmokeOffsetDirection() + local direction = self.SmokeOffsetDirection or math.random(1,359) + return direction + end + + --- Set the offset direction when using `COORDINATE:Smoke()`. + -- @param #COORDINATE self + -- @param #number Direction (Optional) This is the direction of the offset, 1-359 (degrees). Default random. + -- @return #COORDINATE self + function COORDINATE:SetSmokeOffsetDirection(Direction) + if self then + self.SmokeOffsetDirection = Direction or math.random(1,359) + return self + else + COORDINATE.SmokeOffsetDirection = Direction or math.random(1,359) + end + end + + --- Get the offset distance when using `COORDINATE:Smoke()`. + -- @param #COORDINATE self + -- @return #number Distance Distance in meters. + function COORDINATE:GetSmokeOffsetDistance() + local distance = self.SmokeOffsetDistance or math.random(10,20) + return distance + end + + --- Set the offset distance when using `COORDINATE:Smoke()`. + -- @param #COORDINATE self + -- @param #number Distance (Optional) This is the distance of the offset in meters. Default random 10-20. + -- @return #COORDINATE self + function COORDINATE:SetSmokeOffsetDistance(Distance) + if self then + self.SmokeOffsetDistance = Distance or math.random(10,20) + return self + else + COORDINATE.SmokeOffsetDistance = Distance or math.random(10,20) + end + end + + --- Set the offset on when using `COORDINATE:Smoke()`. + -- @param #COORDINATE self + -- @return #COORDINATE self + function COORDINATE:SwitchSmokeOffsetOn() + if self then + self.SmokeOffset = true + return self + else + COORDINATE.SmokeOffset = true + end + end + + --- Set the offset off when using `COORDINATE:Smoke()`. + -- @param #COORDINATE self + -- @return #COORDINATE self + function COORDINATE:SwitchSmokeOffsetOff() + if self then + self.SmokeOffset = false + return self + else + COORDINATE.SmokeOffset = false + end + end --- Stops smoking the point in a color. -- @param #COORDINATE self From 26565d75499478c6d387f3aa7bfa8f173c8fa297 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Tue, 10 Jun 2025 09:25:00 +0200 Subject: [PATCH 053/234] #EASYGCICAP - Added noob/fatfinger checks for airbase static warehouses and CAP point airwing names --- Moose Development/Moose/Ops/EasyGCICAP.lua | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/Moose Development/Moose/Ops/EasyGCICAP.lua b/Moose Development/Moose/Ops/EasyGCICAP.lua index 943518b2e..89a3198d2 100644 --- a/Moose Development/Moose/Ops/EasyGCICAP.lua +++ b/Moose Development/Moose/Ops/EasyGCICAP.lua @@ -261,7 +261,7 @@ EASYGCICAP = { --- EASYGCICAP class version. -- @field #string version -EASYGCICAP.version="0.1.21" +EASYGCICAP.version="0.1.22" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO list @@ -582,6 +582,13 @@ function EASYGCICAP:_AddAirwing(Airbasename, Alias) local DespawnAfterLanding = self.DespawnAfterLanding local DespawnAfterHolding = self.DespawnAfterHolding + -- Check STATIC name + local check = STATIC:FindByName(Airbasename,false) + if check == nil then + MESSAGE:New(self.lid.."There's no warehouse static on the map (wrong naming?) for airbase "..tostring(Airbasename).."!",30,"CHECK"):ToAllIf(self.debug):ToLog() + return + end + -- Create Airwing local CAP_Wing = AIRWING:New(Airbasename,Alias) CAP_Wing:SetVerbosityLevel(0) @@ -816,6 +823,11 @@ function EASYGCICAP:_SetCAPPatrolPoints() self:T(self.lid.."_SetCAPPatrolPoints") for _,_data in pairs(self.ManagedCP) do local data = _data --#EASYGCICAP.CapPoint + self:T("Airbasename = "..data.AirbaseName) + if not self.wings[data.AirbaseName] then + MESSAGE:New(self.lid.."You are trying to create a CAP point for which there is no wing! "..tostring(data.AirbaseName),30,"CHECK"):ToAllIf(self.debug):ToLog() + return + end local Wing = self.wings[data.AirbaseName][1] -- Ops.Airwing#AIRWING local Coordinate = data.Coordinate local Altitude = data.Altitude From 0aeb1fc6afc2c3e2fcab252f43925d44b11dd0e7 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Tue, 10 Jun 2025 18:05:02 +0200 Subject: [PATCH 054/234] #UTILS - Small fix for GetReportingName to distinguish Shark from Mainstay --- Moose Development/Moose/Utilities/Utils.lua | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Moose Development/Moose/Utilities/Utils.lua b/Moose Development/Moose/Utilities/Utils.lua index 19e6889b3..f0c7b4aaf 100644 --- a/Moose Development/Moose/Utilities/Utils.lua +++ b/Moose Development/Moose/Utilities/Utils.lua @@ -1913,6 +1913,13 @@ end function UTILS.GetReportingName(Typename) local typename = string.lower(Typename) + + -- special cases - Shark and Manstay have "A-50" in the name + if string.find(typename,"ka-50",1,true) then + return "Shark" + elseif string.find(typename,"a-50",1,true) then + return "Mainstay" + end for name, value in pairs(ENUMS.ReportingName.NATO) do local svalue = string.lower(value) From 2a9a7db9b8f6c74786bbbd64dd517b9d84250d56 Mon Sep 17 00:00:00 2001 From: Frank Date: Tue, 10 Jun 2025 21:58:19 +0200 Subject: [PATCH 055/234] OPSGROUP - Improved behaviour when mission is unpaused and groups are teleported --- Moose Development/Moose/Ops/Auftrag.lua | 2 ++ Moose Development/Moose/Ops/FlightGroup.lua | 3 +++ Moose Development/Moose/Ops/OpsGroup.lua | 7 +++++-- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Ops/Auftrag.lua b/Moose Development/Moose/Ops/Auftrag.lua index fb4d0adbe..c6df7238c 100644 --- a/Moose Development/Moose/Ops/Auftrag.lua +++ b/Moose Development/Moose/Ops/Auftrag.lua @@ -1403,6 +1403,8 @@ function AUFTRAG:NewINTERCEPT(Target) end --- **[AIR]** Create a CAP mission. +-- Assinged groups are tasked to execute a CAP mission. This consists of a DCS orbit task combined with an enroute "search and engage in zone" task. +-- **Note** that currently DCS only supports *circular* zones for the task. -- @param #AUFTRAG self -- @param Core.Zone#ZONE_RADIUS ZoneCAP Circular CAP zone. Detected targets in this zone will be engaged. -- @param #number Altitude Altitude at which to orbit in feet. Default is 10,000 ft. diff --git a/Moose Development/Moose/Ops/FlightGroup.lua b/Moose Development/Moose/Ops/FlightGroup.lua index 81a19cd80..41b2fb35a 100644 --- a/Moose Development/Moose/Ops/FlightGroup.lua +++ b/Moose Development/Moose/Ops/FlightGroup.lua @@ -2002,6 +2002,9 @@ function FLIGHTGROUP:onafterElementAirborne(From, Event, To, Element) -- Debug info. self:T2(self.lid..string.format("Element airborne %s", Element.name)) + + -- Set parking spot to free. Also for FC. This is usually done after taxiing but doing it here in case the group is teleported. + self:_SetElementParkingFree(Element) -- Set element status. self:_UpdateStatus(Element, OPSGROUP.ElementStatus.AIRBORNE) diff --git a/Moose Development/Moose/Ops/OpsGroup.lua b/Moose Development/Moose/Ops/OpsGroup.lua index 268dfd008..0a62c204e 100644 --- a/Moose Development/Moose/Ops/OpsGroup.lua +++ b/Moose Development/Moose/Ops/OpsGroup.lua @@ -5589,10 +5589,13 @@ function OPSGROUP:onafterUnpauseMission(From, Event, To) -- Debug info. self:T(self.lid..string.format("Unpausing mission %s [%s]", mission:GetName(), mission:GetType())) + -- Set state of mission, e.g. for not teleporting again + mission.unpaused=true + -- Start mission. self:MissionStart(mission) - -- Remove mission from + -- Remove mission from pausedmissions queue for i,mid in pairs(self.pausedmissions) do --self:T(self.lid..string.format("Checking paused mission", mid)) if mid==mission.auftragsnummer then @@ -6232,7 +6235,7 @@ function OPSGROUP:RouteToMission(mission, delay) end -- Check if group is mobile. Note that some immobile units report a speed of 1 m/s = 3.6 km/h. - if self.speedMax<=3.6 or mission.teleport then + if (self.speedMax<=3.6 or mission.teleport) and not mission.unpaused then -- Teleport to waypoint coordinate. Mission will not be paused. self:Teleport(waypointcoord, nil, true) From 52cbb7202c3b1265cbeb63a22b81c03fc9777f9e Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 12 Jun 2025 09:09:38 +0200 Subject: [PATCH 056/234] #EASYGCICAP - more noob catches --- Moose Development/Moose/Ops/EasyGCICAP.lua | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/Moose Development/Moose/Ops/EasyGCICAP.lua b/Moose Development/Moose/Ops/EasyGCICAP.lua index 89a3198d2..f8def0685 100644 --- a/Moose Development/Moose/Ops/EasyGCICAP.lua +++ b/Moose Development/Moose/Ops/EasyGCICAP.lua @@ -261,7 +261,7 @@ EASYGCICAP = { --- EASYGCICAP class version. -- @field #string version -EASYGCICAP.version="0.1.22" +EASYGCICAP.version="0.1.23" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO list @@ -785,6 +785,11 @@ function EASYGCICAP:_SetTankerPatrolPoints() self:T(self.lid.."_SetTankerPatrolPoints") for _,_data in pairs(self.ManagedTK) do local data = _data --#EASYGCICAP.CapPoint + self:T("Airbasename = "..data.AirbaseName) + if not self.wings[data.AirbaseName] then + MESSAGE:New(self.lid.."You are trying to create a TANKER point for which there is no wing! "..tostring(data.AirbaseName),30,"CHECK"):ToAllIf(self.debug):ToLog() + return + end local Wing = self.wings[data.AirbaseName][1] -- Ops.Airwing#AIRWING local Coordinate = data.Coordinate local Altitude = data.Altitude @@ -804,6 +809,11 @@ function EASYGCICAP:_SetAwacsPatrolPoints() self:T(self.lid.."_SetAwacsPatrolPoints") for _,_data in pairs(self.ManagedEWR) do local data = _data --#EASYGCICAP.CapPoint + self:T("Airbasename = "..data.AirbaseName) + if not self.wings[data.AirbaseName] then + MESSAGE:New(self.lid.."You are trying to create an AWACS point for which there is no wing! "..tostring(data.AirbaseName),30,"CHECK"):ToAllIf(self.debug):ToLog() + return + end local Wing = self.wings[data.AirbaseName][1] -- Ops.Airwing#AIRWING local Coordinate = data.Coordinate local Altitude = data.Altitude @@ -847,6 +857,11 @@ function EASYGCICAP:_SetReconPatrolPoints() self:T(self.lid.."_SetReconPatrolPoints") for _,_data in pairs(self.ManagedREC) do local data = _data --#EASYGCICAP.CapPoint + self:T("Airbasename = "..data.AirbaseName) + if not self.wings[data.AirbaseName] then + MESSAGE:New(self.lid.."You are trying to create a RECON point for which there is no wing! "..tostring(data.AirbaseName),30,"CHECK"):ToAllIf(self.debug):ToLog() + return + end local Wing = self.wings[data.AirbaseName][1] -- Ops.Airwing#AIRWING local Coordinate = data.Coordinate local Altitude = data.Altitude From a9edb165543c686eae6208a7e355026b79602907 Mon Sep 17 00:00:00 2001 From: Thomas <72444570+Applevangelist@users.noreply.github.com> Date: Sun, 15 Jun 2025 10:17:32 +0200 Subject: [PATCH 057/234] Update CSAR.lua Make static and zone mash SETs dynamic --- Moose Development/Moose/Ops/CSAR.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Ops/CSAR.lua b/Moose Development/Moose/Ops/CSAR.lua index 09af31eb5..817cd19b9 100644 --- a/Moose Development/Moose/Ops/CSAR.lua +++ b/Moose Development/Moose/Ops/CSAR.lua @@ -2488,8 +2488,8 @@ function CSAR:onafterStart(From, Event, To) self.mash = SET_GROUP:New():FilterCoalitions(self.coalitiontxt):FilterPrefixes(self.mashprefix):FilterStart() - self.staticmashes = SET_STATIC:New():FilterCoalitions(self.coalitiontxt):FilterPrefixes(self.mashprefix):FilterOnce() - self.zonemashes = SET_ZONE:New():FilterPrefixes(self.mashprefix):FilterOnce() + self.staticmashes = SET_STATIC:New():FilterCoalitions(self.coalitiontxt):FilterPrefixes(self.mashprefix):FilterStart() + self.zonemashes = SET_ZONE:New():FilterPrefixes(self.mashprefix):FilterStart() --[[ if staticmashes:Count() > 0 then From a53763221c4cd17246ae550e6ca8c489289a4b6f Mon Sep 17 00:00:00 2001 From: Thomas <72444570+Applevangelist@users.noreply.github.com> Date: Sun, 15 Jun 2025 13:14:05 +0200 Subject: [PATCH 058/234] Update Airbase.lua Correct afb name gor Borg al arab on Sinai --- Moose Development/Moose/Wrapper/Airbase.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Wrapper/Airbase.lua b/Moose Development/Moose/Wrapper/Airbase.lua index aaab918bd..55bb2f4c3 100644 --- a/Moose Development/Moose/Wrapper/Airbase.lua +++ b/Moose Development/Moose/Wrapper/Airbase.lua @@ -691,7 +691,7 @@ AIRBASE.SouthAtlantic={ -- * AIRBASE.Sinai.Bilbeis_Air_Base -- * AIRBASE.Sinai.Bir_Hasanah -- * AIRBASE.Sinai.Birma_Air_Base --- * AIRBASE.Sinai.Borj_El_Arab_International_Airport +-- * AIRBASE.Sinai.Borg_El_Arab_International_Airport -- * AIRBASE.Sinai.Cairo_International_Airport -- * AIRBASE.Sinai.Cairo_West -- * AIRBASE.Sinai.Difarsuwar_Airfield @@ -739,7 +739,7 @@ AIRBASE.Sinai = { ["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", + ["Borg_El_Arab_International_Airport"] = "Borg El Arab International Airport", ["Cairo_International_Airport"] = "Cairo International Airport", ["Cairo_West"] = "Cairo West", ["Difarsuwar_Airfield"] = "Difarsuwar Airfield", From 382b049c5fe5f77c423cafdacaf75bca1b656f7e Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sun, 15 Jun 2025 15:38:07 +0200 Subject: [PATCH 059/234] #AIRBASE - Syria and Sinai few names corrected --- Moose Development/Moose/Wrapper/Airbase.lua | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Moose Development/Moose/Wrapper/Airbase.lua b/Moose Development/Moose/Wrapper/Airbase.lua index 55bb2f4c3..01ae1b1a2 100644 --- a/Moose Development/Moose/Wrapper/Airbase.lua +++ b/Moose Development/Moose/Wrapper/Airbase.lua @@ -449,7 +449,6 @@ AIRBASE.TheChannel = { -- * AIRBASE.Syria.Al_Dumayr -- * AIRBASE.Syria.Al_Qusayr -- * AIRBASE.Syria.Aleppo --- * AIRBASE.Syria.Amman -- * AIRBASE.Syria.An_Nasiriyah -- * AIRBASE.Syria.At_Tanf -- * AIRBASE.Syria.Bassel_Al_Assad @@ -511,7 +510,7 @@ AIRBASE.TheChannel = { -- * AIRBASE.Syria.Wujah_Al_Hajar -- * AIRBASE.Syria.Ben_Gurion -- * AIRBASE.Syria.Hatzor --- * AIRBASE.Syria.Palmashim +-- * AIRBASE.Syria.Palmachim -- * AIRBASE.Syria.Tel_Nof -- * AIRBASE.Syria.Marka -- @@ -523,7 +522,6 @@ AIRBASE.Syria={ ["Al_Dumayr"] = "Al-Dumayr", ["Al_Qusayr"] = "Al Qusayr", ["Aleppo"] = "Aleppo", - ["Amman"] = "Amman", ["An_Nasiriyah"] = "An Nasiriyah", ["At_Tanf"] = "At Tanf", ["Bassel_Al_Assad"] = "Bassel Al-Assad", @@ -555,6 +553,7 @@ AIRBASE.Syria={ ["Kuweires"] = "Kuweires", ["Lakatamia"] = "Lakatamia", ["Larnaca"] = "Larnaca", + ["Marka"] = "Marka", ["Marj_Ruhayyil"] = "Marj Ruhayyil", ["Marj_as_Sultan_North"] = "Marj as Sultan North", ["Marj_as_Sultan_South"] = "Marj as Sultan South", @@ -585,9 +584,8 @@ AIRBASE.Syria={ ["Wujah_Al_Hajar"] = "Wujah Al Hajar", ["Ben_Gurion"] = "Ben Gurion", ["Hatzor"] = "Hatzor", - ["Palmashim"] = "Palmashim", + ["Palmachim"] = "Palmachim", ["Tel_Nof"] = "Tel Nof", - ["Marka"] = "Marka", } --- Airbases of the Mariana Islands map: From d0f5712ca87d775aa7d1324ea47a6a0936668a07 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sun, 15 Jun 2025 15:42:33 +0200 Subject: [PATCH 060/234] #AUFTRAG - Allow CAP Auftrag w/o Zone --- Moose Development/Moose/Ops/Auftrag.lua | 53 +++++++++++++++++++++---- 1 file changed, 45 insertions(+), 8 deletions(-) diff --git a/Moose Development/Moose/Ops/Auftrag.lua b/Moose Development/Moose/Ops/Auftrag.lua index c6df7238c..ba5582a7e 100644 --- a/Moose Development/Moose/Ops/Auftrag.lua +++ b/Moose Development/Moose/Ops/Auftrag.lua @@ -1403,8 +1403,6 @@ function AUFTRAG:NewINTERCEPT(Target) end --- **[AIR]** Create a CAP mission. --- Assinged groups are tasked to execute a CAP mission. This consists of a DCS orbit task combined with an enroute "search and engage in zone" task. --- **Note** that currently DCS only supports *circular* zones for the task. -- @param #AUFTRAG self -- @param Core.Zone#ZONE_RADIUS ZoneCAP Circular CAP zone. Detected targets in this zone will be engaged. -- @param #number Altitude Altitude at which to orbit in feet. Default is 10,000 ft. @@ -1430,7 +1428,7 @@ function AUFTRAG:NewCAP(ZoneCAP, Altitude, Speed, Coordinate, Heading, Leg, Targ mission:_SetLogID() -- DCS task parameters: - mission.engageZone=ZoneCAP + mission.engageZone=ZoneCAP or Coordinate mission.engageTargetTypes=TargetTypes or {"Air"} -- Mission options: @@ -4824,6 +4822,11 @@ function AUFTRAG:CheckGroupsDone() self:T(self.lid..string.format("CheckGroupsDone: Mission is STARTED state %s [FSM=%s] but count of alive OPSGROUP is zero. Mission DONE!", self.status, self:GetState())) return true end + + if (self:IsStarted() or self:IsExecuting()) and self:CountOpsGroups()>0 then + self:T(self.lid..string.format("CheckGroupsDone: Mission is STARTED state %s [FSM=%s] and count of alive OPSGROUP > zero. Mission NOT DONE!", self.status, self:GetState())) + return true + end return true end @@ -6152,8 +6155,16 @@ function AUFTRAG:GetDCSMissionTask() ----------------- -- CAP Mission -- ----------------- - - local DCStask=CONTROLLABLE.EnRouteTaskEngageTargetsInZone(nil, self.engageZone:GetVec2(), self.engageZone:GetRadius(), self.engageTargetTypes, Priority) + + local Vec2 = self.engageZone:GetVec2() + local Radius + if self.engageZone:IsInstanceOf("COORDINATE") then + Radius = UTILS.NMToMeters(20) + else + Radius = self.engageZone:GetRadius() + end + + local DCStask=CONTROLLABLE.EnRouteTaskEngageTargetsInZone(nil, Vec2, Radius, self.engageTargetTypes, Priority) table.insert(self.enrouteTasks, DCStask) @@ -6307,9 +6318,35 @@ function AUFTRAG:GetDCSMissionTask() -- Add enroute task SEAD. Disabled that here because the group enganges everything on its route. --local DCStask=CONTROLLABLE.EnRouteTaskSEAD(nil, self.TargetType) --table.insert(self.enrouteTasks, DCStask) - - self:_GetDCSAttackTask(self.engageTarget, DCStasks) - + + if self.engageZone then + + --local DCStask=CONTROLLABLE.EnRouteTaskSEAD(nil, self.engageTargetTypes) + --table.insert(self.enrouteTasks, DCStask) + self.engageZone:Scan({Object.Category.UNIT},{Unit.Category.GROUND_UNIT}) + local ScanUnitSet = self.engageZone:GetScannedSetUnit() + local SeadUnitSet = SET_UNIT:New() + for _,_unit in pairs (ScanUnitSet.Set) do + local unit = _unit -- Wrapper.Unit#UNTI + if unit and unit:IsAlive() and unit:HasSEAD() then + self:T("Adding UNIT for SEAD: "..unit:GetName()) + local task = CONTROLLABLE.TaskAttackUnit(nil,unit,GroupAttack,AI.Task.WeaponExpend.ALL,1,Direction,self.engageAltitude,4161536) + table.insert(DCStasks, task) + SeadUnitSet:AddUnit(unit) + end + end + self.engageTarget = TARGET:New(SeadUnitSet) + --local OrbitTask = CONTROLLABLE.TaskOrbitCircle(nil,self.engageAltitude,self.missionSpeed,self.engageZone:GetCoordinate()) + --local Point = self.engageZone:GetVec2() + --local OrbitTask = CONTROLLABLE.TaskOrbitCircleAtVec2(nil,Point,self.engageAltitude,self.missionSpeed) + --table.insert(DCStasks, OrbitTask) + + else + + self:_GetDCSAttackTask(self.engageTarget, DCStasks) + + end + elseif self.type==AUFTRAG.Type.STRIKE then -------------------- From cbcc893ce5448885818c2bd43fd8d998ef7a7535 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sun, 15 Jun 2025 17:01:58 +0200 Subject: [PATCH 061/234] #CTLD - avoid smoking runways on airbase zones --- Moose Development/Moose/Ops/CTLD.lua | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Ops/CTLD.lua b/Moose Development/Moose/Ops/CTLD.lua index 5b2ecc4ef..78bf8a4fc 100644 --- a/Moose Development/Moose/Ops/CTLD.lua +++ b/Moose Development/Moose/Ops/CTLD.lua @@ -1414,7 +1414,7 @@ CTLD.FixedWingTypes = { --- CTLD class version. -- @field #string version -CTLD.version="1.3.34" +CTLD.version="1.3.35" --- Instantiate a new CTLD. -- @param #CTLD self @@ -5971,16 +5971,22 @@ function CTLD:SmokeZoneNearBy(Unit, Flare) for index,cargozone in pairs(zones[i]) do local CZone = cargozone --#CTLD.CargoZone local zonename = CZone.name - local zone = nil + local zone = nil -- Core.Zone#ZONE_RADIUS + local airbasezone = false if i == 4 then zone = UNIT:FindByName(zonename) else zone = ZONE:FindByName(zonename) if not zone then zone = AIRBASE:FindByName(zonename):GetZone() + airbasezone = true end end local zonecoord = zone:GetCoordinate() + -- Avoid smoke/flares on runways + if (i==1 or 1==3) and airbasezone==true and zone:IsInstanceOf("ZONE_BASE") then + zonecoord = zone:GetRandomCoordinate(inner,outer,{land.SurfaceType.LAND}) + end if zonecoord then local active = CZone.active local color = CZone.color From eb2c6ac6f2f4123265127eefba68e6fdae5b1205 Mon Sep 17 00:00:00 2001 From: Thomas <72444570+Applevangelist@users.noreply.github.com> Date: Wed, 18 Jun 2025 14:19:50 +0200 Subject: [PATCH 062/234] Update SRS.lua #MSRS Voice mapping correction --- Moose Development/Moose/Sound/SRS.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/Sound/SRS.lua b/Moose Development/Moose/Sound/SRS.lua index c2e9cf152..526094f5a 100644 --- a/Moose Development/Moose/Sound/SRS.lua +++ b/Moose Development/Moose/Sound/SRS.lua @@ -513,7 +513,7 @@ MSRS.Voices = { ["en_GB_Wavenet_F"] = 'en-GB-Wavenet-N', -- [13] FEMALE ["en_GB_Wavenet_O"] = 'en-GB-Wavenet-O', -- [12] MALE ["en_GB_Wavenet_N"] = 'en-GB-Wavenet-N', -- [13] FEMALE - ["en_US_Wavenet_A"] = 'en-US-Wavenet-N', -- [14] MALE + ["en_US_Wavenet_A"] = 'en-US-Wavenet-A', -- [14] MALE ["en_US_Wavenet_B"] = 'en-US-Wavenet-B', -- [15] MALE ["en_US_Wavenet_C"] = 'en-US-Wavenet-C', -- [16] FEMALE ["en_US_Wavenet_D"] = 'en-US-Wavenet-D', -- [17] MALE From 8ec86973c66a37871dde49f90ddc38d0989b52a2 Mon Sep 17 00:00:00 2001 From: Thomas <72444570+Applevangelist@users.noreply.github.com> Date: Wed, 18 Jun 2025 14:29:34 +0200 Subject: [PATCH 063/234] Update SpawnStatic.lua Fix SpawnFromZone() --- Moose Development/Moose/Core/SpawnStatic.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Core/SpawnStatic.lua b/Moose Development/Moose/Core/SpawnStatic.lua index f603450d7..38f3b0f87 100644 --- a/Moose Development/Moose/Core/SpawnStatic.lua +++ b/Moose Development/Moose/Core/SpawnStatic.lua @@ -459,8 +459,9 @@ end function SPAWNSTATIC:SpawnFromZone(Zone, Heading, NewName) -- Spawn the new static at the center of the zone. - local Static = self:SpawnFromPointVec2( Zone:GetPointVec2(), Heading, NewName ) - + --local Static = self:SpawnFromPointVec2( Zone:GetPointVec2(), Heading, NewName ) + local Static = self:SpawnFromCoordinate(Zone:GetCoordinate(), Heading, NewName) + return Static end From 763e3852acdafefa2a7ca06da5d678e24c5f0ac5 Mon Sep 17 00:00:00 2001 From: shaji Date: Thu, 19 Jun 2025 07:42:29 +0200 Subject: [PATCH 064/234] [FIXED] Error: attempt to index local 'Schedule' (a nil value) --- Moose Development/Moose/Core/ScheduleDispatcher.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/Core/ScheduleDispatcher.lua b/Moose Development/Moose/Core/ScheduleDispatcher.lua index 611cb6fba..023c20c95 100644 --- a/Moose Development/Moose/Core/ScheduleDispatcher.lua +++ b/Moose Development/Moose/Core/ScheduleDispatcher.lua @@ -326,7 +326,7 @@ function SCHEDULEDISPATCHER:Stop( Scheduler, CallID ) local Schedule = self.Schedule[Scheduler][CallID] -- #SCHEDULEDISPATCHER.ScheduleData -- Only stop when there is a ScheduleID defined for the CallID. So, when the scheduler was stopped before, do nothing. - if Schedule.ScheduleID then + if Schedule and Schedule.ScheduleID then self:T( string.format( "SCHEDULEDISPATCHER stopping scheduler CallID=%s, ScheduleID=%s", tostring( CallID ), tostring( Schedule.ScheduleID ) ) ) From a988e674908e74c94384daa395ab0ad345b641e1 Mon Sep 17 00:00:00 2001 From: shaji Date: Fri, 20 Jun 2025 12:20:58 +0200 Subject: [PATCH 065/234] [ADDED] New Kola Airbases --- Moose Development/Moose/Wrapper/Airbase.lua | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Moose Development/Moose/Wrapper/Airbase.lua b/Moose Development/Moose/Wrapper/Airbase.lua index 01ae1b1a2..175beb002 100644 --- a/Moose Development/Moose/Wrapper/Airbase.lua +++ b/Moose Development/Moose/Wrapper/Airbase.lua @@ -828,6 +828,12 @@ AIRBASE.Kola = { ["Enontekio"] = "Enontekio", ["Evenes"] = "Evenes", ["Hosio"] = "Hosio", + ["Kilpyavr"] = "Kilpyavr", + ["Afrikanda"] = "Afrikanda", + ["Kalevala"] = "Kalevala", + ["Koshka_Yavr"] = "Koshka Yavr", + ["Poduzhemye"] = "Poduzhemye", + ["Luostari"] = "Luostari", } --- Airbases of the Afghanistan map From b0546b1e608ad75d12551f67444bc9385bb27238 Mon Sep 17 00:00:00 2001 From: shaji Date: Fri, 20 Jun 2025 12:58:50 +0200 Subject: [PATCH 066/234] [ADDED] New Kola Airbases --- Moose Development/Moose/Wrapper/Airbase.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/Wrapper/Airbase.lua b/Moose Development/Moose/Wrapper/Airbase.lua index 175beb002..c716f72e9 100644 --- a/Moose Development/Moose/Wrapper/Airbase.lua +++ b/Moose Development/Moose/Wrapper/Airbase.lua @@ -833,7 +833,7 @@ AIRBASE.Kola = { ["Kalevala"] = "Kalevala", ["Koshka_Yavr"] = "Koshka Yavr", ["Poduzhemye"] = "Poduzhemye", - ["Luostari"] = "Luostari", + ["Luostari_Pechenga"] = "Luostari Pechenga", } --- Airbases of the Afghanistan map From 24b47b02e0d0f5d34d51a51946b7b5835173e4d0 Mon Sep 17 00:00:00 2001 From: Frank Date: Sun, 22 Jun 2025 22:29:52 +0200 Subject: [PATCH 067/234] AIRBOSS - Essex - Corsair --- Moose Development/Moose/Core/Database.lua | 2 +- Moose Development/Moose/Ops/Airboss.lua | 95 ++++++++++++++++++++++- 2 files changed, 93 insertions(+), 4 deletions(-) diff --git a/Moose Development/Moose/Core/Database.lua b/Moose Development/Moose/Core/Database.lua index 85bde137c..2d985a021 100644 --- a/Moose Development/Moose/Core/Database.lua +++ b/Moose Development/Moose/Core/Database.lua @@ -1699,7 +1699,7 @@ function DATABASE:_EventOnBirth( Event ) if PlayerName then -- Debug info. - self:I(string.format("Player '%s' joined unit '%s' of group '%s'", tostring(PlayerName), tostring(Event.IniDCSUnitName), tostring(Event.IniDCSGroupName))) + self:I(string.format("Player '%s' joined unit '%s' (%s) of group '%s'", tostring(PlayerName), tostring(Event.IniDCSUnitName), tostring(Event.IniTypeName), tostring(Event.IniDCSGroupName))) -- Add client in case it does not exist already. if client == nil or (client and client:CountPlayers() == 0) then diff --git a/Moose Development/Moose/Ops/Airboss.lua b/Moose Development/Moose/Ops/Airboss.lua index d6d7b03a7..8ab6156f6 100644 --- a/Moose Development/Moose/Ops/Airboss.lua +++ b/Moose Development/Moose/Ops/Airboss.lua @@ -1283,6 +1283,8 @@ AIRBOSS = { -- @field #string RHINOE F/A-18E Superhornet (mod). -- @field #string RHINOF F/A-18F Superhornet (mod). -- @field #string GROWLER FEA-18G Superhornet (mod). +-- @field #string CORSAIR F4U-1D Corsair. +-- @field #string CORSAIR_CW F4U-1D Corsair Mk.4 (clipped wing). AIRBOSS.AircraftCarrier={ AV8B="AV8BNA", HORNET="FA-18C_hornet", @@ -1299,6 +1301,8 @@ AIRBOSS.AircraftCarrier={ RHINOE="FA-18E", RHINOF="FA-18F", GROWLER="EA-18G", + CORSAIR="F4U-1D", + CORSAIR_CW="F4U-1D CW", } --- Carrier types. @@ -1310,6 +1314,7 @@ AIRBOSS.AircraftCarrier={ -- @field #string TRUMAN USS Harry S. Truman (CVN-75) [Super Carrier Module] -- @field #string FORRESTAL USS Forrestal (CV-59) [Heatblur Carrier Module] -- @field #string VINSON USS Carl Vinson (CVN-70) [Deprecated!] +-- @field #string ESSEX Essex class carrier (e.g. USS Yorktown (CV-10)) [Magnitude 3 Carrier Module] -- @field #string HERMES HMS Hermes (R12) [V/STOL Carrier] -- @field #string INVINCIBLE HMS Invincible (R05) [V/STOL Carrier] -- @field #string TARAWA USS Tarawa (LHA-1) [V/STOL Carrier] @@ -1325,6 +1330,7 @@ AIRBOSS.CarrierType = { STENNIS = "Stennis", FORRESTAL = "Forrestal", VINSON = "VINSON", + ESSEX = "Essex", HERMES = "HERMES81", INVINCIBLE = "hms_invincible", TARAWA = "LHA_Tarawa", @@ -2013,6 +2019,8 @@ function AIRBOSS:New( carriername, alias ) elseif self.carriertype == AIRBOSS.CarrierType.VINSON then -- Carl Vinson is legacy now. self:_InitStennis() + elseif self.carriertype == AIRBOSS.CarrierType.ESSEX then + self:_InitEssex() elseif self.carriertype == AIRBOSS.CarrierType.HERMES then -- Hermes parameters. self:_InitHermes() @@ -4627,6 +4635,51 @@ function AIRBOSS:_InitForrestal() end +--- Init parameters for Essec class carriers. +-- @param #AIRBOSS self +function AIRBOSS:_InitEssex() + + -- Init Nimitz as default. + self:_InitNimitz() + + -- Carrier Parameters. + self.carrierparam.sterndist = -126 + self.carrierparam.deckheight = 19.27 --DCS World\CoreMods\tech\M3 WWII PTO units\Database\Essex_Class_Carrier_1944.lua + + -- Total size of the carrier (approx as rectangle). + self.carrierparam.totlength = 268 + self.carrierparam.totwidthport = 23 + self.carrierparam.totwidthstarboard = 23 + + -- Landing runway. + self.carrierparam.rwyangle = 0.0 + self.carrierparam.rwylength = 265 + self.carrierparam.rwywidth = 20 + + -- Wires. + self.carrierparam.wire1 = 21.9 + self.carrierparam.wire2 = 28.3 + self.carrierparam.wire3 = 34.7 + self.carrierparam.wire4 = 41.1 + self.carrierparam.wire5 = 47.4 + self.carrierparam.wire6 = 53.7 + self.carrierparam.wire7 = 59.0 + + self.carrierparam.wire8 = 64.1 + self.carrierparam.wire9 = 72.7 + self.carrierparam.wire10 = 78.0 + self.carrierparam.wire11 = 85.5 + + self.carrierparam.wire12 = 105.9 + self.carrierparam.wire13 = 113.3 + self.carrierparam.wire14 = 121.0 + self.carrierparam.wire15 = 128.5 + + -- Landing distance. + self.carrierparam.landingdist = self.carrierparam.sterndist+self.carrierparam.wire3 + +end + --- Init parameters for R12 HMS Hermes carrier. -- @param #AIRBOSS self function AIRBOSS:_InitHermes() @@ -5329,7 +5382,8 @@ function AIRBOSS:_GetAircraftAoA( playerData ) local goshawk = playerData.actype == AIRBOSS.AircraftCarrier.T45C local skyhawk = playerData.actype == AIRBOSS.AircraftCarrier.A4EC local harrier = playerData.actype == AIRBOSS.AircraftCarrier.AV8B - local tomcat = playerData.actype == AIRBOSS.AircraftCarrier.F14A or playerData.actype == AIRBOSS.AircraftCarrier.F14B + local tomcat = playerData.actype == AIRBOSS.AircraftCarrier.F14A or playerData.actype == AIRBOSS.AircraftCarrier.F14B + local corsair = playerData.actype == AIRBOSS.AircraftCarrier.CORSAIR or playerData.actype == AIRBOSS.AircraftCarrier.CORSAIR_CW -- Table with AoA values. local aoa = {} -- #AIRBOSS.AircraftAoA @@ -5374,7 +5428,6 @@ function AIRBOSS:_GetAircraftAoA( playerData ) aoa.Fast = 8.25 -- =17.5/2 aoa.FAST = 8.00 -- =16.5/2 elseif harrier then - -- AV-8B Harrier parameters. Tuning done on the Fast AoA to allow for abeam and ninety at Nozzles 55. Pene testing aoa.SLOW = 16.0 aoa.Slow = 13.5 @@ -5383,7 +5436,15 @@ function AIRBOSS:_GetAircraftAoA( playerData ) aoa.OnSpeedMin = 9.5 aoa.Fast = 8.0 aoa.FAST = 7.5 - + elseif corsair then + -- F4U-1D Corsair parameters. + aoa.SLOW = 16.0 + aoa.Slow = 13.5 + aoa.OnSpeedMax = 12.5 + aoa.OnSpeed = 10.0 + aoa.OnSpeedMin = 9.5 + aoa.Fast = 8.0 + aoa.FAST = 7.5 end return aoa @@ -5496,6 +5557,7 @@ function AIRBOSS:_GetAircraftParameters( playerData, step ) local tomcat = playerData.actype == AIRBOSS.AircraftCarrier.F14A or playerData.actype == AIRBOSS.AircraftCarrier.F14B local harrier = playerData.actype == AIRBOSS.AircraftCarrier.AV8B local goshawk = playerData.actype == AIRBOSS.AircraftCarrier.T45C + local corsair = playerData.actype == AIRBOSS.AircraftCarrier.CORSAIR or playerData.actype == AIRBOSS.AircraftCarrier.CORSAIR_CW -- Return values. local alt @@ -5555,6 +5617,9 @@ function AIRBOSS:_GetAircraftParameters( playerData, step ) elseif goshawk then alt = UTILS.FeetToMeters( 800 ) speed = UTILS.KnotsToMps( 300 ) + elseif corsair then + alt = UTILS.FeetToMeters( 300 ) + speed = UTILS.KnotsToMps( 120 ) end elseif step == AIRBOSS.PatternStep.BREAKENTRY then @@ -5568,6 +5633,9 @@ function AIRBOSS:_GetAircraftParameters( playerData, step ) elseif goshawk then alt = UTILS.FeetToMeters( 800 ) speed = UTILS.KnotsToMps( 300 ) + elseif corsair then + alt = UTILS.FeetToMeters( 200 ) + speed = UTILS.KnotsToMps( 110 ) end elseif step == AIRBOSS.PatternStep.EARLYBREAK then @@ -5576,6 +5644,9 @@ function AIRBOSS:_GetAircraftParameters( playerData, step ) alt = UTILS.FeetToMeters( 800 ) elseif skyhawk then alt = UTILS.FeetToMeters( 600 ) + elseif corsair then + alt = UTILS.FeetToMeters( 200 ) + speed = UTILS.KnotsToMps( 100 ) end elseif step == AIRBOSS.PatternStep.LATEBREAK then @@ -5584,6 +5655,9 @@ function AIRBOSS:_GetAircraftParameters( playerData, step ) alt = UTILS.FeetToMeters( 800 ) elseif skyhawk then alt = UTILS.FeetToMeters( 600 ) + elseif corsair then + alt = UTILS.FeetToMeters( 150 ) + speed = UTILS.KnotsToMps( 100 ) end elseif step == AIRBOSS.PatternStep.ABEAM then @@ -5592,6 +5666,9 @@ function AIRBOSS:_GetAircraftParameters( playerData, step ) alt = UTILS.FeetToMeters( 600 ) elseif skyhawk then alt = UTILS.FeetToMeters( 500 ) + elseif corsair then + alt = UTILS.FeetToMeters( 150 ) + speed = UTILS.KnotsToMps( 90 ) end aoa = aoaac.OnSpeed @@ -5616,6 +5693,9 @@ function AIRBOSS:_GetAircraftParameters( playerData, step ) alt = UTILS.FeetToMeters( 500 ) elseif harrier then alt = UTILS.FeetToMeters( 425 ) + elseif corsair then + alt = UTILS.FeetToMeters( 90 ) + speed = UTILS.KnotsToMps( 90 ) end aoa = aoaac.OnSpeed @@ -5628,6 +5708,8 @@ function AIRBOSS:_GetAircraftParameters( playerData, step ) alt = UTILS.FeetToMeters( 430 ) -- Tomcat should be a bit higher as it intercepts the GS a bit higher. elseif skyhawk then alt = UTILS.FeetToMeters( 370 ) -- ? + elseif corsair then + alt = UTILS.FeetToMeters( 80 ) end -- Harrier wont get into wake pos. Runway is not angled and it stays port. @@ -5643,6 +5725,8 @@ function AIRBOSS:_GetAircraftParameters( playerData, step ) alt = UTILS.FeetToMeters( 300 ) -- ? elseif harrier then alt=UTILS.FeetToMeters(312)-- 300-325 ft + elseif corsair then + alt = UTILS.FeetToMeters( 80 ) end aoa = aoaac.OnSpeed @@ -6519,6 +6603,8 @@ function AIRBOSS:_LandAI( flight ) Speed = UTILS.KnotsToKmph( 175 ) elseif flight.actype == AIRBOSS.AircraftCarrier.S3B or flight.actype == AIRBOSS.AircraftCarrier.S3BTANKER then Speed = UTILS.KnotsToKmph( 140 ) + elseif flight.actype == AIRBOSS.AircraftCarrier.CORSAIR or flight.actype == AIRBOSS.AircraftCarrier.CORSAIR_CW then + Speed = UTILS.KnotsToKmph( 100 ) end -- Carrier position. @@ -10314,6 +10400,9 @@ function AIRBOSS:_GetSternCoord() elseif self.carriertype == AIRBOSS.CarrierType.FORRESTAL then -- Forrestal self.sterncoord:Translate( self.carrierparam.sterndist, hdg, true, true ):Translate( 7.5, FB + 90, true, true ) + elseif self.carriertype == AIRBOSS.CarrierType.ESSEX then + -- Forrestal + self.sterncoord:Translate( self.carrierparam.sterndist, hdg, true, true ):Translate( -1, FB + 90, true, true ) else -- Nimitz SC: translate 8 meters starboard wrt Final bearing. self.sterncoord:Translate( self.carrierparam.sterndist, hdg, true, true ):Translate( 9.5, FB + 90, true, true ) From 0d1147bac4aedbb6b274697c206ee7c6b409a669 Mon Sep 17 00:00:00 2001 From: leka1986 Date: Mon, 23 Jun 2025 18:28:02 +0200 Subject: [PATCH 068/234] Added the missing lines to check if the droped troop is engineer, then start the engineer instance. Added missing messages when dropping single crate type, ie truck for example. Added a call to refreshdropcratesmenu in the takeoff / land event. Drop and build is only created if fixedwing is on the ground. --- Moose Development/Moose/Ops/CTLD.lua | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/Moose Development/Moose/Ops/CTLD.lua b/Moose Development/Moose/Ops/CTLD.lua index 5b2ecc4ef..2dc395dab 100644 --- a/Moose Development/Moose/Ops/CTLD.lua +++ b/Moose Development/Moose/Ops/CTLD.lua @@ -2075,6 +2075,9 @@ function CTLD:_EventHandler(EventData) local _group = event.IniGroup local _unit = event.IniUnit self:_RefreshLoadCratesMenu(_group, _unit) + if self:IsFixedWing(_unit) and self.enableFixedWing then + self:_RefreshDropCratesMenu(_group, _unit) + end end elseif event.id == EVENTS.PlayerLeaveUnit or event.id == EVENTS.UnitLost then -- remove from pilot table @@ -4888,7 +4891,17 @@ function CTLD:_UnloadSingleCrateSet(Group, Unit, setIndex) cObj:SetWasDropped(true) cObj:SetHasMoved(true) end - +local cname = crateObj:GetName() or "Unknown" +local count = #chunk +if needed > 1 then +if count == needed then + self:_SendMessage(string.format("Dropped %d %s.", 1, cname), 10, false, Group) +else + self:_SendMessage(string.format("Dropped %d/%d crate(s) of %s.", count, needed, cname), 15, false, Group) +end +else +self:_SendMessage(string.format("Dropped %d %s(s).", count, cname), 10, false, Group) +end -- Rebuild the cargo list to remove the dropped crates local loadedData = self.Loaded_Cargo[unitName] if loadedData and loadedData.Cargo then @@ -5007,8 +5020,10 @@ function CTLD:_RefreshDropCratesMenu(Group, Unit) -------------------------------------------------------------------- local mAll=MENU_GROUP:New(Group,"Drop ALL crates",dropCratesMenu) MENU_GROUP_COMMAND:New(Group,"Drop",mAll,self._UnloadCrates,self,Group,Unit) - MENU_GROUP_COMMAND:New(Group,"Drop and build",mAll,self._DropAndBuild,self,Group,Unit) - + if not ( self:IsUnitInAir(Unit) and self:IsFixedWing(Unit) ) then + MENU_GROUP_COMMAND:New(Group,"Drop and build",mAll,self._DropAndBuild,self,Group,Unit) + end + self.CrateGroupList=self.CrateGroupList or{} self.CrateGroupList[Unit:GetName()]={} @@ -5029,7 +5044,9 @@ function CTLD:_RefreshDropCratesMenu(Group, Unit) local setIndex=#self.CrateGroupList[Unit:GetName()] local mSet=MENU_GROUP:New(Group,label,dropCratesMenu) MENU_GROUP_COMMAND:New(Group,"Drop",mSet,self._UnloadSingleCrateSet,self,Group,Unit,setIndex) + if not ( self:IsUnitInAir(Unit) and self:IsFixedWing(Unit) ) then MENU_GROUP_COMMAND:New(Group,"Drop and build",mSet,self._DropSingleAndBuild,self,Group,Unit,setIndex) + end i=i+needed else local chunk={} @@ -5156,6 +5173,8 @@ function CTLD:_UnloadSingleTroopByID(Group, Unit, chunkID) foundCargo:SetWasDropped(true) if cType == CTLD_CARGO.Enum.ENGINEERS then self.Engineers = self.Engineers + 1 + local grpname = self.DroppedTroops[self.TroopCounter]:GetName() + self.EngineersInField[self.Engineers] = CTLD_ENGINEERING:New(name, grpname) self:_SendMessage(string.format("Dropped Engineers %s into action!", name), 10, false, Group) else self:_SendMessage(string.format("Dropped Troops %s into action!", name), 10, false, Group) From 42e7e3f94f056528f6a057bcaf967087fb2f8608 Mon Sep 17 00:00:00 2001 From: Frank Date: Mon, 23 Jun 2025 22:28:48 +0200 Subject: [PATCH 069/234] Update Airboss.lua --- Moose Development/Moose/Ops/Airboss.lua | 35 ++++++++++++++----------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/Moose Development/Moose/Ops/Airboss.lua b/Moose Development/Moose/Ops/Airboss.lua index 8ab6156f6..a6a04c057 100644 --- a/Moose Development/Moose/Ops/Airboss.lua +++ b/Moose Development/Moose/Ops/Airboss.lua @@ -2874,23 +2874,28 @@ end function AIRBOSS:SetGlideslopeErrorThresholds(_max,_min, High, HIGH, Low, LOW) --Check if V/STOL Carrier - if self.carriertype == AIRBOSS.CarrierType.INVINCIBLE or self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then + if self.carriertype == AIRBOSS.CarrierType.INVINCIBLE or + self.carriertype == AIRBOSS.CarrierType.HERMES or + self.carriertype == AIRBOSS.CarrierType.TARAWA or + self.carriertype == AIRBOSS.CarrierType.AMERICA or + self.carriertype == AIRBOSS.CarrierType.JCARLOS or + self.carriertype == AIRBOSS.CarrierType.CANBERRA then - -- allow a larger GSE for V/STOL operations --Pene Testing - self.gle._max=_max or 0.7 - self.gle.High=High or 1.4 - self.gle.HIGH=HIGH or 1.9 - self.gle._min=_min or -0.5 - self.gle.Low=Low or -1.2 - self.gle.LOW=LOW or -1.5 - -- CVN values + -- allow a larger GSE for V/STOL operations --Pene Testing + self.gle._max=_max or 0.7 + self.gle.High=High or 1.4 + self.gle.HIGH=HIGH or 1.9 + self.gle._min=_min or -0.5 + self.gle.Low=Low or -1.2 + self.gle.LOW=LOW or -1.5 else - self.gle._max=_max or 0.4 - self.gle.High=High or 0.8 - self.gle.HIGH=HIGH or 1.5 - self.gle._min=_min or -0.3 - self.gle.Low=Low or -0.6 - self.gle.LOW=LOW or -0.9 + -- CVN values + self.gle._max=_max or 0.4 + self.gle.High=High or 0.8 + self.gle.HIGH=HIGH or 1.5 + self.gle._min=_min or -0.3 + self.gle.Low=Low or -0.6 + self.gle.LOW=LOW or -0.9 end return self From 28ae63bd8da5b8e1a3042403ec062430674945db Mon Sep 17 00:00:00 2001 From: Frank Date: Mon, 23 Jun 2025 22:39:52 +0200 Subject: [PATCH 070/234] Update Airboss.lua --- Moose Development/Moose/Ops/Airboss.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Moose Development/Moose/Ops/Airboss.lua b/Moose Development/Moose/Ops/Airboss.lua index a6a04c057..1754ab219 100644 --- a/Moose Development/Moose/Ops/Airboss.lua +++ b/Moose Development/Moose/Ops/Airboss.lua @@ -32,6 +32,7 @@ -- * [USS George Washington](https://en.wikipedia.org/wiki/USS_George_Washington_\(CVN-73\)) (CVN-73) [Super Carrier Module] -- * [USS Harry S. Truman](https://en.wikipedia.org/wiki/USS_Harry_S._Truman) (CVN-75) [Super Carrier Module] -- * [USS Forrestal](https://en.wikipedia.org/wiki/USS_Forrestal_\(CV-59\)) (CV-59) [Heatblur Carrier Module] +-- * [Essex Class](https://en.wikipedia.org/wiki/Essex-class_aircraft_carrier) (CV-11) [Magnitude 3 Carrier Module] -- * [HMS Hermes](https://en.wikipedia.org/wiki/HMS_Hermes_\(R12\)) (R12) -- * [HMS Invincible](https://en.wikipedia.org/wiki/HMS_Invincible_\(R05\)) (R05) -- * [USS Tarawa](https://en.wikipedia.org/wiki/USS_Tarawa_\(LHA-1\)) (LHA-1) @@ -47,6 +48,7 @@ -- * [AV-8B N/A Harrier](https://forums.eagle.ru/forumdisplay.php?f=555) (Player & AI) -- * [T-45C Goshawk](https://forum.dcs.world/topic/203816-vnao-t-45-goshawk/) (VNAO mod) (Player & AI) -- * [FE/A-18E/F/G Superhornet](https://forum.dcs.world/topic/316971-cjs-super-hornet-community-mod-v20-official-thread/) (CJS mod) (Player & AI) +-- * [F4U-1D Corsair](https://forum.dcs.world/forum/781-f4u-1d/) (Player & AI) -- * F/A-18C Hornet (AI) -- * F-14A Tomcat (AI) -- * E-2D Hawkeye (AI) @@ -1753,7 +1755,7 @@ AIRBOSS.MenuF10Root = nil --- Airboss class version. -- @field #string version -AIRBOSS.version = "1.3.3" +AIRBOSS.version = "1.4.0" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO list ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- From f1d4f1753a8ae78fd29688390c4a139d40c008d2 Mon Sep 17 00:00:00 2001 From: Thomas <72444570+Applevangelist@users.noreply.github.com> Date: Tue, 24 Jun 2025 16:28:46 +0200 Subject: [PATCH 071/234] Update Airbase.lua --- Moose Development/Moose/Wrapper/Airbase.lua | 29 +++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/Moose Development/Moose/Wrapper/Airbase.lua b/Moose Development/Moose/Wrapper/Airbase.lua index c716f72e9..520f8b923 100644 --- a/Moose Development/Moose/Wrapper/Airbase.lua +++ b/Moose Development/Moose/Wrapper/Airbase.lua @@ -611,6 +611,35 @@ AIRBASE.MarianaIslands = { ["Tinian_Intl"] = "Tinian Intl", } +--- Airbase of the Marianas WWII map +-- +-- * AIRBASE.MarianaIslandsWWII.Agana +-- * AIRBASE.MarianaIslandsWWII.Airfield_3 +-- * AIRBASE.MarianaIslandsWWII.Charon_Kanoa +-- * AIRBASE.MarianaIslandsWWII.Gurguan_Point +-- * AIRBASE.MarianaIslandsWWII.Isley +-- * AIRBASE.MarianaIslandsWWII.Kagman +-- * AIRBASE.MarianaIslandsWWII.Marpi +-- * AIRBASE.MarianaIslandsWWII.Orote +-- * AIRBASE.MarianaIslandsWWII.Pagan +-- * AIRBASE.MarianaIslandsWWII.Rota +-- * AIRBASE.MarianaIslandsWWII.Ushi +-- @field AIRBASE.MarianaIslandsWWII +AIRBASE.MarianaIslandsWWII = +{ + ["Agana"] = "Agana", + ["Airfield_3"] = "Airfield 3", + ["Charon_Kanoa"] = "Charon Kanoa", + ["Gurguan_Point"] = "Gurguan Point", + ["Isley"] = "Isley", + ["Kagman"] = "Kagman", + ["Marpi"] = "Marpi", + ["Orote"] = "Orote", + ["Pagan"] = "Pagan", + ["Rota"] = "Rota", + ["Ushi"] = "Ushi", +} + --- Airbases of the South Atlantic map: -- -- * AIRBASE.SouthAtlantic.Almirante_Schroeders From a2ab84c45a7eb77bdbf91f0c6aa1561b95dd5ff0 Mon Sep 17 00:00:00 2001 From: leka1986 <83298840+leka1986@users.noreply.github.com> Date: Tue, 24 Jun 2025 19:24:00 +0200 Subject: [PATCH 072/234] Update CTLD.lua Added Herc fix when dropping from air. Added CratesName in the OnAfterCratesBuildStarted parm --- Moose Development/Moose/Ops/CTLD.lua | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Moose Development/Moose/Ops/CTLD.lua b/Moose Development/Moose/Ops/CTLD.lua index 04f090672..75d09b498 100644 --- a/Moose Development/Moose/Ops/CTLD.lua +++ b/Moose Development/Moose/Ops/CTLD.lua @@ -1846,6 +1846,7 @@ function CTLD:New(Coalition, Prefixes, Alias) -- @param #string To State. -- @param Wrapper.Group#GROUP Group Group Object. -- @param Wrapper.Unit#UNIT Unit Unit Object. + -- @param CargoName The name of the cargo being built. -- @return #CTLD self --- FSM Function OnAfterCratesRepairStarted. Info event that a repair has been started. @@ -2827,8 +2828,12 @@ function CTLD:_GetCrates(Group, Unit, Cargo, number, drop, pack) if cratedistance > self.CrateDistance then cratedistance = self.CrateDistance end -- altered heading logic -- DONE: right standard deviation? - rheading = UTILS.RandomGaussian(0,30,-90,90,100) - rheading = math.fmod((heading + rheading), 360) + if self:IsUnitInAir(Unit) and self:IsFixedWing(Unit) then + rheading = math.random(20,60) + else + rheading = UTILS.RandomGaussian(0, 30, -90, 90, 100) + end + rheading=math.fmod((heading+rheading),360) cratecoord = position:Translate(cratedistance,rheading) else cratedistance = (row-1)*6 @@ -3965,7 +3970,7 @@ function CTLD:_BuildCrates(Group, Unit,Engineering,MultiDrop) local buildtimer = TIMER:New(self._BuildObjectFromCrates,self,Group,Unit,build,false,Group:GetCoordinate(),MultiDrop) buildtimer:Start(self.buildtime) self:_SendMessage(string.format("Build started, ready in %d seconds!",self.buildtime),15,false,Group) - self:__CratesBuildStarted(1,Group,Unit) + self:__CratesBuildStarted(1,Group,Unit,build.Name) self:_RefreshDropTroopsMenu(Group,Unit) else self:_BuildObjectFromCrates(Group,Unit,build,false,nil,MultiDrop) From 0ab6a10ec4a64704607625be05ca81f9b554c6ff Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sun, 29 Jun 2025 15:50:24 +0200 Subject: [PATCH 073/234] #AWACS - added FSM transitions for VID Success and Failure --- Moose Development/Moose/Ops/Awacs.lua | 32 +++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/Moose Development/Moose/Ops/Awacs.lua b/Moose Development/Moose/Ops/Awacs.lua index 09aa3324b..6533ace03 100644 --- a/Moose Development/Moose/Ops/Awacs.lua +++ b/Moose Development/Moose/Ops/Awacs.lua @@ -17,7 +17,7 @@ -- === -- -- ### Author: **applevangelist** --- @date Last Update Jan 2025 +-- @date Last Update July 2025 -- @module Ops.AWACS -- @image OPS_AWACS.jpg @@ -509,7 +509,7 @@ do -- @field #AWACS AWACS = { ClassName = "AWACS", -- #string - version = "0.2.71", -- #string + version = "0.2.72", -- #string lid = "", -- #string coalition = coalition.side.BLUE, -- #number coalitiontxt = "blue", -- #string @@ -1242,6 +1242,8 @@ function AWACS:New(Name,AirWing,Coalition,AirbaseName,AwacsOrbit,OpsZone,Station self:AddTransition("*", "Intercept", "*") self:AddTransition("*", "InterceptSuccess", "*") self:AddTransition("*", "InterceptFailure", "*") + self:AddTransition("*", "VIDSuccess", "*") + self:AddTransition("*", "VIDFailure", "*") self:AddTransition("*", "Stop", "Stopped") -- Stop FSM. @@ -1365,18 +1367,38 @@ function AWACS:New(Name,AirWing,Coalition,AirbaseName,AwacsOrbit,OpsZone,Station -- @param #string To To state. --- On After "InterceptSuccess" event. Intercept successful. - -- @function [parent=#AWACS] OnAfterIntercept + -- @function [parent=#AWACS] OnAfterInterceptSuccess -- @param #AWACS self -- @param #string From From state. -- @param #string Event Event. -- @param #string To To state. --- On After "InterceptFailure" event. Intercept failure. - -- @function [parent=#AWACS] OnAfterIntercept + -- @function [parent=#AWACS] OnAfterInterceptFailure -- @param #AWACS self -- @param #string From From state. -- @param #string Event Event. -- @param #string To To state. + + --- On After "VIDSuccess" event. Intercept successful. + -- @function [parent=#AWACS] OnAfterVIDSuccess + -- @param #AWACS self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @param #number GID Managed group ID (Player) + -- @param Wrapper.Group#GROUP Group (Player) Group done the VID + -- @param #AWACS.ManagedContact Contact The contact that was VID'd + + --- On After "VIDFailure" event. Intercept failure. + -- @function [parent=#AWACS] OnAfterVIDFailure + -- @param #AWACS self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @param #number GID Managed group ID (Player) + -- @param Wrapper.Group#GROUP Group (Player) Group done the VID + -- @param #AWACS.ManagedContact Contact The contact that was VID'd return self end @@ -3263,12 +3285,14 @@ function AWACS:_VID(Group,Declaration) local vidpos = self.gettext:GetEntry("VIDPOS",self.locale) text = string.format(vidpos,Callsign,self.callsigntxt, Declaration) self:T(text) + self:__VIDSuccess(3,GID,group,cluster) else -- too far away self:T("Contact VID not close enough") local vidneg = self.gettext:GetEntry("VIDNEG",self.locale) text = string.format(vidneg,Callsign,self.callsigntxt) self:T(text) + self:__VIDFailure(3,GID,group,cluster) end self:_NewRadioEntry(text,text,GID,Outcome,true,true,false,true) end From 9e0f03a3cdfe73af5aea8259bf02eaff8425bada Mon Sep 17 00:00:00 2001 From: smiki Date: Thu, 3 Jul 2025 08:44:41 +0200 Subject: [PATCH 074/234] [FIXED] Memory leaks --- .../Moose/Core/MarkerOps_Base.lua | 18 ++++++++++++------ Moose Development/Moose/Core/Zone.lua | 7 +------ .../Moose/Functional/Warehouse.lua | 2 +- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/Moose Development/Moose/Core/MarkerOps_Base.lua b/Moose Development/Moose/Core/MarkerOps_Base.lua index 4571eed25..d249a27cd 100644 --- a/Moose Development/Moose/Core/MarkerOps_Base.lua +++ b/Moose Development/Moose/Core/MarkerOps_Base.lua @@ -156,12 +156,6 @@ function MARKEROPS_BASE:OnEventMark(Event) end --position local vec3={y=Event.pos.y, x=Event.pos.x, z=Event.pos.z} - local coord=COORDINATE:NewFromVec3(vec3) - if self.debug then - local coordtext = coord:ToStringLLDDM() - local text = tostring(Event.text) - local m = MESSAGE:New(string.format("Mark added at %s with text: %s",coordtext,text),10,"Info",false):ToAll() - end local coalition = Event.MarkCoalition -- decision if Event.id==world.event.S_EVENT_MARK_ADDED then @@ -170,6 +164,12 @@ function MARKEROPS_BASE:OnEventMark(Event) local Eventtext = tostring(Event.text) if Eventtext~=nil then if self:_MatchTag(Eventtext) then + local coord=COORDINATE:NewFromVec3(vec3) + if self.debug then + local coordtext = coord:ToStringLLDDM() + local text = tostring(Event.text) + local m = MESSAGE:New(string.format("Mark added at %s with text: %s",coordtext,text),10,"Info",false):ToAll() + end local matchtable = self:_MatchKeywords(Eventtext) self:MarkAdded(Eventtext,matchtable,coord,Event.idx,coalition,Event.PlayerName,Event) end @@ -180,6 +180,12 @@ function MARKEROPS_BASE:OnEventMark(Event) local Eventtext = tostring(Event.text) if Eventtext~=nil then if self:_MatchTag(Eventtext) then + local coord=COORDINATE:NewFromVec3(vec3) + if self.debug then + local coordtext = coord:ToStringLLDDM() + local text = tostring(Event.text) + local m = MESSAGE:New(string.format("Mark added at %s with text: %s",coordtext,text),10,"Info",false):ToAll() + end local matchtable = self:_MatchKeywords(Eventtext) self:MarkChanged(Eventtext,matchtable,coord,Event.idx,coalition,Event.PlayerName,Event) end diff --git a/Moose Development/Moose/Core/Zone.lua b/Moose Development/Moose/Core/Zone.lua index 0ad088d6d..6664364ed 100644 --- a/Moose Development/Moose/Core/Zone.lua +++ b/Moose Development/Moose/Core/Zone.lua @@ -3204,12 +3204,7 @@ function ZONE_POLYGON:Scan( ObjectCategories, UnitCategories ) local vectors = self:GetBoundingSquare() - local minVec3 = {x=vectors.x1, y=0, z=vectors.y1} - local maxVec3 = {x=vectors.x2, y=0, z=vectors.y2} - - local minmarkcoord = COORDINATE:NewFromVec3(minVec3) - local maxmarkcoord = COORDINATE:NewFromVec3(maxVec3) - local ZoneRadius = minmarkcoord:Get2DDistance(maxmarkcoord)/2 + local ZoneRadius = UTILS.VecDist2D({x=vectors.x1, y=vectors.y1}, {x=vectors.x2, y=vectors.y2})/2 -- self:I("Scan Radius:" ..ZoneRadius) local CenterVec3 = self:GetCoordinate():GetVec3() diff --git a/Moose Development/Moose/Functional/Warehouse.lua b/Moose Development/Moose/Functional/Warehouse.lua index 29682074f..51e9ad1f9 100644 --- a/Moose Development/Moose/Functional/Warehouse.lua +++ b/Moose Development/Moose/Functional/Warehouse.lua @@ -6893,7 +6893,7 @@ function WAREHOUSE:_CheckConquered() for _,_unit in pairs(units) do local unit=_unit --Wrapper.Unit#UNIT - local distance=coord:Get2DDistance(unit:GetCoordinate()) + local distance=coord:Get2DDistance(unit:GetCoord()) -- Filter only alive groud units. Also check distance again, because the scan routine might give some larger distances. if unit:IsGround() and unit:IsAlive() and distance <= radius then From f9257b2b0dcbe9cb5064ebfb200a1002ab39c91a Mon Sep 17 00:00:00 2001 From: smiki Date: Thu, 3 Jul 2025 09:45:21 +0200 Subject: [PATCH 075/234] [FIXED] Memory leaks --- Moose Development/Moose/Functional/Warehouse.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/Functional/Warehouse.lua b/Moose Development/Moose/Functional/Warehouse.lua index 51e9ad1f9..2486e74b6 100644 --- a/Moose Development/Moose/Functional/Warehouse.lua +++ b/Moose Development/Moose/Functional/Warehouse.lua @@ -3153,7 +3153,7 @@ end -- @param #WAREHOUSE self -- @return Core.Point#COORDINATE The coordinate of the warehouse. function WAREHOUSE:GetCoordinate() - return self.warehouse:GetCoordinate() + return self.warehouse:GetCoord() end --- Get 3D vector of warehouse static. From 773461aad95f0defc0c09902bb59771a82f12cd1 Mon Sep 17 00:00:00 2001 From: smiki Date: Thu, 3 Jul 2025 09:54:07 +0200 Subject: [PATCH 076/234] [FIXED] Memory leaks --- Moose Development/Moose/Core/MarkerOps_Base.lua | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Moose Development/Moose/Core/MarkerOps_Base.lua b/Moose Development/Moose/Core/MarkerOps_Base.lua index d249a27cd..6de154d73 100644 --- a/Moose Development/Moose/Core/MarkerOps_Base.lua +++ b/Moose Development/Moose/Core/MarkerOps_Base.lua @@ -155,7 +155,6 @@ function MARKEROPS_BASE:OnEventMark(Event) return true end --position - local vec3={y=Event.pos.y, x=Event.pos.x, z=Event.pos.z} local coalition = Event.MarkCoalition -- decision if Event.id==world.event.S_EVENT_MARK_ADDED then @@ -164,7 +163,7 @@ function MARKEROPS_BASE:OnEventMark(Event) local Eventtext = tostring(Event.text) if Eventtext~=nil then if self:_MatchTag(Eventtext) then - local coord=COORDINATE:NewFromVec3(vec3) + local coord=COORDINATE:NewFromVec3({y=Event.pos.y, x=Event.pos.x, z=Event.pos.z}) if self.debug then local coordtext = coord:ToStringLLDDM() local text = tostring(Event.text) @@ -180,7 +179,7 @@ function MARKEROPS_BASE:OnEventMark(Event) local Eventtext = tostring(Event.text) if Eventtext~=nil then if self:_MatchTag(Eventtext) then - local coord=COORDINATE:NewFromVec3(vec3) + local coord=COORDINATE:NewFromVec3({y=Event.pos.y, x=Event.pos.x, z=Event.pos.z}) if self.debug then local coordtext = coord:ToStringLLDDM() local text = tostring(Event.text) From 068d21612f0e42b0a00b079d6ef734a9918dd6fc Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 3 Jul 2025 10:48:54 +0200 Subject: [PATCH 077/234] #MARKEROPS - do not crate a COORDINATE b4 you need it #UTILS - added * UTILS.ShowHelperGate(pos, heading) * UTILS.ShellZone * UTILS.RemoveObjects * UTILS.DestroyScenery --- .../Moose/Core/MarkerOps_Base.lua | 6 ++- Moose Development/Moose/Utilities/Utils.lua | 47 +++++++++++++++++++ Moose Development/Moose/Wrapper/Unit.lua | 7 +++ 3 files changed, 58 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Core/MarkerOps_Base.lua b/Moose Development/Moose/Core/MarkerOps_Base.lua index 4571eed25..d2f056757 100644 --- a/Moose Development/Moose/Core/MarkerOps_Base.lua +++ b/Moose Development/Moose/Core/MarkerOps_Base.lua @@ -50,7 +50,7 @@ MARKEROPS_BASE = { ClassName = "MARKEROPS", Tag = "mytag", Keywords = {}, - version = "0.1.3", + version = "0.1.4", debug = false, Casesensitive = true, } @@ -156,8 +156,8 @@ function MARKEROPS_BASE:OnEventMark(Event) end --position local vec3={y=Event.pos.y, x=Event.pos.x, z=Event.pos.z} - local coord=COORDINATE:NewFromVec3(vec3) if self.debug then + local coord=COORDINATE:NewFromVec3(vec3) local coordtext = coord:ToStringLLDDM() local text = tostring(Event.text) local m = MESSAGE:New(string.format("Mark added at %s with text: %s",coordtext,text),10,"Info",false):ToAll() @@ -171,6 +171,7 @@ function MARKEROPS_BASE:OnEventMark(Event) if Eventtext~=nil then if self:_MatchTag(Eventtext) then local matchtable = self:_MatchKeywords(Eventtext) + local coord=COORDINATE:NewFromVec3(vec3) self:MarkAdded(Eventtext,matchtable,coord,Event.idx,coalition,Event.PlayerName,Event) end end @@ -181,6 +182,7 @@ function MARKEROPS_BASE:OnEventMark(Event) if Eventtext~=nil then if self:_MatchTag(Eventtext) then local matchtable = self:_MatchKeywords(Eventtext) + local coord=COORDINATE:NewFromVec3(vec3) self:MarkChanged(Eventtext,matchtable,coord,Event.idx,coalition,Event.PlayerName,Event) end end diff --git a/Moose Development/Moose/Utilities/Utils.lua b/Moose Development/Moose/Utilities/Utils.lua index f0c7b4aaf..6429e01ed 100644 --- a/Moose Development/Moose/Utilities/Utils.lua +++ b/Moose Development/Moose/Utilities/Utils.lua @@ -4428,3 +4428,50 @@ end function UTILS.Weather.StopFogAnimation() return world.weather.setFogAnimation({}) end + +--- Find a ME created zone by its name +function UTILS.GetEnvZone(name) + for _,v in ipairs(env.mission.triggers.zones) do + if v.name == name then + return v + end + end +end + +--- Show a helper gate at a DCS#Vec3 position +-- @param DCS#Vec3 pos The position +-- @param number heading Heading in degrees, can be 0..359 degrees +function UTILS.ShowHelperGate(pos, heading) + net.dostring_in("mission",string.format("a_show_helper_gate(%s, %s, %s, %f)", pos.x, pos.y, pos.z, math.rad(heading))) +end + +--- Shell a zone, zone must ME created +-- @param #string name The name of the ME created zone +-- @param #number power Equals kg of TNT, e.g. 75 +-- @param #count Number of shells simulated +function UTILS.ShellZone(name, power, count) + local z = UTILS.GetEnvZone(name) + if z then + net.dostring_in("mission",string.format("a_shelling_zone(%d, %d, %d)", z.zoneId, power, count)) + end +end + +--- Remove objects from a zone, zone must ME created +-- @param #string name The name of the ME created zone +-- @param #number type Type of objects to remove can be 0:all, 1: trees, 2:objects +function UTILS.RemoveObjects(name, type) + local z = UTILS.GetEnvZone(name) + if z then + net.dostring_in("mission",string.format("a_remove_scene_objects(%d, %d)", z.zoneId, type)) + end +end + +--- Remove scenery objects from a zone, zone must ME created +-- @param #string name The name of the ME created zone +-- @param #number level Level of removal +function UTILS.DestroyScenery(name, level) + local z = UTILS.GetEnvZone(name) + if z then + net.dostring_in("mission",string.format("a_scenery_destruction_zone(%d, %d)", z.zoneId, level)) + end +end diff --git a/Moose Development/Moose/Wrapper/Unit.lua b/Moose Development/Moose/Wrapper/Unit.lua index 1a5e51011..20ce4837d 100644 --- a/Moose Development/Moose/Wrapper/Unit.lua +++ b/Moose Development/Moose/Wrapper/Unit.lua @@ -1924,3 +1924,10 @@ function UNIT:IsAAA() end return false end + +--- Set the relative life points of a UNIT object +-- @param #UNIT self +-- @param #number Percent Percent to set, can be 0..100. +function UNIT:SetLife(Percent) + net.dostring_in("mission",string.format("a_unit_set_life_percentage(%d, %f)", self:GetID(), Percent)) +end From 6a4bddde99ba5fea69bcd5805ae69939302bf180 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 3 Jul 2025 11:58:44 +0200 Subject: [PATCH 078/234] #SET - do not create a new SET on GetAliveSet is we only send back the object table --- Moose Development/Moose/Core/Set.lua | 47 ++++++++++++++++++---------- 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua index 6d41edf12..8d6b0c990 100644 --- a/Moose Development/Moose/Core/Set.lua +++ b/Moose Development/Moose/Core/Set.lua @@ -958,7 +958,26 @@ do -- SET_BASE return ObjectNames end + + --- Get a *new* set table that only contains alive objects. + -- @param #SET_BASE self + -- @return #table Set table of alive objects. + function SET_BASE:GetAliveSet() + --self:F2() + local AliveSet = {} + -- Clean the Set before returning with only the alive Objects. + for ObjectName, Object in pairs( self.Set ) do + if Object then + if Object:IsAlive() then + table.insert(AliveSet, ObjectName, Object) + end + end + end + + return AliveSet or {} + end + end do @@ -1125,25 +1144,25 @@ do end - --- Get a *new* set that only contains alive groups. + --- Get a *new* set table that only contains alive groups. -- @param #SET_GROUP self - -- @return #SET_GROUP Set of alive groups. + -- @return #table Set of alive groups. function SET_GROUP:GetAliveSet() --self:F2() - local AliveSet = SET_GROUP:New() - + --local AliveSet = SET_GROUP:New() + local AliveSet = {} -- Clean the Set before returning with only the alive Groups. for GroupName, GroupObject in pairs( self.Set ) do local GroupObject = GroupObject -- Wrapper.Group#GROUP if GroupObject then if GroupObject:IsAlive() then - AliveSet:Add( GroupName, GroupObject ) + table.insert(AliveSet, GroupName, GroupObject) end end end - return AliveSet.Set or {} + return AliveSet or {} end --- Returns a report of of unit types. @@ -2595,16 +2614,14 @@ do -- SET_UNIT --- Gets the alive set. -- @param #SET_UNIT self - -- @return #table Table of SET objects + -- @return #table Table of alive UNIT objects -- @return #SET_UNIT AliveSet function SET_UNIT:GetAliveSet() local AliveSet = SET_UNIT:New() -- Clean the Set before returning with only the alive Groups. - for GroupName, GroupObject in pairs(self.Set) do - local GroupObject=GroupObject --Wrapper.Client#CLIENT - + for GroupName, GroupObject in pairs(self.Set) do if GroupObject and GroupObject:IsAlive() then AliveSet:Add(GroupName, GroupObject) end @@ -4784,18 +4801,16 @@ do -- SET_CLIENT -- @return #table Table of SET objects function SET_CLIENT:GetAliveSet() - local AliveSet = SET_CLIENT:New() + local AliveSet = {} -- Clean the Set before returning with only the alive Groups. - for GroupName, GroupObject in pairs(self.Set) do - local GroupObject=GroupObject --Wrapper.Client#CLIENT - + for GroupName, GroupObject in pairs(self.Set) do if GroupObject and GroupObject:IsAlive() then - AliveSet:Add(GroupName, GroupObject) + table.insert(AliveSet, GroupName, GroupObject) end end - return AliveSet.Set or {} + return AliveSet or {} end --- [User] Add a custom condition function. From 4489efff941b174df4bbd1c9325c2d3a2832f76e Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 3 Jul 2025 14:57:48 +0200 Subject: [PATCH 079/234] #POSITIONABLE - make GetVec3/GetCoordinate a bit more robust --- .../Moose/Wrapper/Positionable.lua | 38 ++++++++++--------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/Moose Development/Moose/Wrapper/Positionable.lua b/Moose Development/Moose/Wrapper/Positionable.lua index 41857a215..65b145384 100644 --- a/Moose Development/Moose/Wrapper/Positionable.lua +++ b/Moose Development/Moose/Wrapper/Positionable.lua @@ -246,18 +246,20 @@ end function POSITIONABLE:GetVec3() local DCSPositionable = self:GetDCSObject() if DCSPositionable then - --local status, vec3 = pcall( - -- function() - -- local vec3 = DCSPositionable:getPoint() - -- return vec3 - --end - --) + local vec3 = DCSPositionable:getPoint() - --if status then - return vec3 - --else - --self:E( { "Cannot get Vec3 from DCS Object", Positionable = self, Alive = self:IsAlive() } ) - --end + + if not vec3 then + local pos = DCSPositionable:getPosition() + if pos and pos.p then + vec3 = pos.p + else + self:E( { "Cannot get the position from DCS Object for GetVec3", Positionable = self, Alive = self:IsAlive() } ) + end + end + + return vec3 + end -- ERROR! self:E( { "Cannot get the Positionable DCS Object for GetVec3", Positionable = self, Alive = self:IsAlive() } ) @@ -388,13 +390,13 @@ function POSITIONABLE:GetCoordinate() -- Get the current position. local PositionableVec3 = self:GetVec3() - - local coord=COORDINATE:NewFromVec3(PositionableVec3) - local heading = self:GetHeading() - coord.Heading = heading - -- Return a new coordiante object. - return coord - + if PositionableVec3 then + local coord=COORDINATE:NewFromVec3(PositionableVec3) + local heading = self:GetHeading() + coord.Heading = heading + -- Return a new coordiante object. + return coord + end end -- Error message. From 3543b2c79a26fa212e2d844e0a0000f74d0938c6 Mon Sep 17 00:00:00 2001 From: smiki Date: Thu, 3 Jul 2025 14:59:07 +0200 Subject: [PATCH 080/234] [FIXED] index `nil` at `MARKEROPS_BASE:OnEventMark` --- .../Moose/Core/MarkerOps_Base.lua | 39 +++++++------------ 1 file changed, 15 insertions(+), 24 deletions(-) diff --git a/Moose Development/Moose/Core/MarkerOps_Base.lua b/Moose Development/Moose/Core/MarkerOps_Base.lua index a8265a52e..222866321 100644 --- a/Moose Development/Moose/Core/MarkerOps_Base.lua +++ b/Moose Development/Moose/Core/MarkerOps_Base.lua @@ -154,14 +154,7 @@ function MARKEROPS_BASE:OnEventMark(Event) self:E("Skipping onEvent. Event or Event.idx unknown.") return true end - --position - if self.debug then - local vec3={y=Event.pos.y, x=Event.pos.x, z=Event.pos.z} - local coord=COORDINATE:NewFromVec3(vec3) - local coordtext = coord:ToStringLLDDM() - local text = tostring(Event.text) - local m = MESSAGE:New(string.format("Mark added at %s with text: %s",coordtext,text),10,"Info",false):ToAll() - end + local coalition = Event.MarkCoalition -- decision if Event.id==world.event.S_EVENT_MARK_ADDED then @@ -170,15 +163,14 @@ function MARKEROPS_BASE:OnEventMark(Event) local Eventtext = tostring(Event.text) if Eventtext~=nil then if self:_MatchTag(Eventtext) then - local coord=COORDINATE:NewFromVec3({y=Event.pos.y, x=Event.pos.x, z=Event.pos.z}) - if self.debug then - local coordtext = coord:ToStringLLDDM() - local text = tostring(Event.text) - local m = MESSAGE:New(string.format("Mark added at %s with text: %s",coordtext,text),10,"Info",false):ToAll() - end - local matchtable = self:_MatchKeywords(Eventtext) - local coord=COORDINATE:NewFromVec3(vec3) - self:MarkAdded(Eventtext,matchtable,coord,Event.idx,coalition,Event.PlayerName,Event) + local coord=COORDINATE:NewFromVec3({y=Event.pos.y, x=Event.pos.x, z=Event.pos.z}) + if self.debug then + local coordtext = coord:ToStringLLDDM() + local text = tostring(Event.text) + local m = MESSAGE:New(string.format("Mark added at %s with text: %s",coordtext,text),10,"Info",false):ToAll() + end + local matchtable = self:_MatchKeywords(Eventtext) + self:MarkAdded(Eventtext,matchtable,coord,Event.idx,coalition,Event.PlayerName,Event) end end elseif Event.id==world.event.S_EVENT_MARK_CHANGE then @@ -187,15 +179,14 @@ function MARKEROPS_BASE:OnEventMark(Event) local Eventtext = tostring(Event.text) if Eventtext~=nil then if self:_MatchTag(Eventtext) then - local coord=COORDINATE:NewFromVec3({y=Event.pos.y, x=Event.pos.x, z=Event.pos.z}) - if self.debug then + local coord=COORDINATE:NewFromVec3({y=Event.pos.y, x=Event.pos.x, z=Event.pos.z}) + if self.debug then local coordtext = coord:ToStringLLDDM() local text = tostring(Event.text) - local m = MESSAGE:New(string.format("Mark added at %s with text: %s",coordtext,text),10,"Info",false):ToAll() - end - local matchtable = self:_MatchKeywords(Eventtext) - local coord=COORDINATE:NewFromVec3(vec3) - self:MarkChanged(Eventtext,matchtable,coord,Event.idx,coalition,Event.PlayerName,Event) + local m = MESSAGE:New(string.format("Mark changed at %s with text: %s",coordtext,text),10,"Info",false):ToAll() + end + local matchtable = self:_MatchKeywords(Eventtext) + self:MarkChanged(Eventtext,matchtable,coord,Event.idx,coalition,Event.PlayerName,Event) end end elseif Event.id==world.event.S_EVENT_MARK_REMOVED then From 727cb3276cb69412b50ae7f277b0d6228b410359 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 3 Jul 2025 16:39:20 +0200 Subject: [PATCH 081/234] #SET fix for table insert of GetAliveSet --- Moose Development/Moose/Core/Set.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua index 8d6b0c990..7f863abf2 100644 --- a/Moose Development/Moose/Core/Set.lua +++ b/Moose Development/Moose/Core/Set.lua @@ -970,7 +970,7 @@ do -- SET_BASE for ObjectName, Object in pairs( self.Set ) do if Object then if Object:IsAlive() then - table.insert(AliveSet, ObjectName, Object) + AliveSet[#AliveSet+1] = Object end end end @@ -1157,7 +1157,7 @@ do local GroupObject = GroupObject -- Wrapper.Group#GROUP if GroupObject then if GroupObject:IsAlive() then - table.insert(AliveSet, GroupName, GroupObject) + AliveSet[GroupName] = GroupObject end end end @@ -2623,7 +2623,7 @@ do -- SET_UNIT -- Clean the Set before returning with only the alive Groups. for GroupName, GroupObject in pairs(self.Set) do if GroupObject and GroupObject:IsAlive() then - AliveSet:Add(GroupName, GroupObject) + AliveSet[GroupName] = GroupObject end end @@ -4806,7 +4806,7 @@ do -- SET_CLIENT -- Clean the Set before returning with only the alive Groups. for GroupName, GroupObject in pairs(self.Set) do if GroupObject and GroupObject:IsAlive() then - table.insert(AliveSet, GroupName, GroupObject) + AliveSet[GroupName] = GroupObject end end From 429db73854fd251a48c747acf2dcb6aa1ea43b35 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Fri, 4 Jul 2025 16:22:55 +0200 Subject: [PATCH 082/234] #AUFTRAG - fix condition for assets done test --- Moose Development/Moose/Ops/Auftrag.lua | 42 +++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/Moose Development/Moose/Ops/Auftrag.lua b/Moose Development/Moose/Ops/Auftrag.lua index ba5582a7e..4b768e84c 100644 --- a/Moose Development/Moose/Ops/Auftrag.lua +++ b/Moose Development/Moose/Ops/Auftrag.lua @@ -1715,6 +1715,42 @@ function AUFTRAG:NewSEAD(Target, Altitude) return mission end +--- **[AIR]** Create a SEAD in Zone mission. +-- @param #AUFTRAG self +-- @param Core.Zone#ZONE TargetZone The target zone to attack. +-- @param #number Altitude Engage altitude in feet. Default 25000 ft. +-- @param #table TargetTypes Table of string of DCS known target types, defaults to {"Air defence"}. See [DCS Target Attributes](https://wiki.hoggitworld.com/view/DCS_enum_attributes) +-- @param #number Duration Engage this much time when the AUFTRAG starts executing. +-- @return #AUFTRAG self +function AUFTRAG:NewSEADInZone(TargetZone, Altitude, TargetTypes, Duration) + + local mission=AUFTRAG:New(AUFTRAG.Type.SEAD) + + mission:_TargetFromObject(TargetZone) + + -- DCS Task options: + mission.engageWeaponType=ENUMS.WeaponFlag.Auto + mission.engageWeaponExpend=AI.Task.WeaponExpend.ALL + mission.engageAltitude=UTILS.FeetToMeters(Altitude or 25000) + mission.engageZone = TargetZone + mission.engageTargetTypes = TargetTypes or {"Air defence"} + + -- Mission options: + mission.missionTask=ENUMS.MissionTask.SEAD + mission.missionAltitude=mission.engageAltitude + mission.missionFraction=0.2 + mission.optionROE=ENUMS.ROE.OpenFire + mission.optionROT=ENUMS.ROT.EvadeFire + + mission.categories={AUFTRAG.Category.AIRCRAFT} + + mission.DCStask=mission:GetDCSMissionTask() + + mission:SetDuration(Duration or 1800) + + return mission +end + --- **[AIR]** Create a STRIKE mission. Flight will attack the closest map object to the specified coordinate. -- @param #AUFTRAG self -- @param Core.Point#COORDINATE Target The target coordinate. Can also be given as a GROUP, UNIT, STATIC, SET_GROUP, SET_UNIT, SET_STATIC or TARGET object. @@ -4825,10 +4861,10 @@ function AUFTRAG:CheckGroupsDone() if (self:IsStarted() or self:IsExecuting()) and self:CountOpsGroups()>0 then self:T(self.lid..string.format("CheckGroupsDone: Mission is STARTED state %s [FSM=%s] and count of alive OPSGROUP > zero. Mission NOT DONE!", self.status, self:GetState())) - return true + return false end - return true + return false end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -6330,7 +6366,7 @@ function AUFTRAG:GetDCSMissionTask() local unit = _unit -- Wrapper.Unit#UNTI if unit and unit:IsAlive() and unit:HasSEAD() then self:T("Adding UNIT for SEAD: "..unit:GetName()) - local task = CONTROLLABLE.TaskAttackUnit(nil,unit,GroupAttack,AI.Task.WeaponExpend.ALL,1,Direction,self.engageAltitude,4161536) + local task = CONTROLLABLE.TaskAttackUnit(nil,unit,GroupAttack,AI.Task.WeaponExpend.ALL,1,Direction,self.engageAltitude,2956984318) table.insert(DCStasks, task) SeadUnitSet:AddUnit(unit) end From f9f77bfa7b9acb49b47990d6f76cd015abfcb06e Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Fri, 4 Jul 2025 18:46:56 +0200 Subject: [PATCH 083/234] xxx --- Moose Development/Moose/Modules_local.lua | 1 - Moose Development/Moose/Ops/Auftrag.lua | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Moose Development/Moose/Modules_local.lua b/Moose Development/Moose/Modules_local.lua index 15c6bcba5..5a6b6c0e9 100644 --- a/Moose Development/Moose/Modules_local.lua +++ b/Moose Development/Moose/Modules_local.lua @@ -115,7 +115,6 @@ __Moose.Include( 'Ops\\Operation.lua' ) __Moose.Include( 'Ops\\FlightControl.lua' ) __Moose.Include( 'Ops\\PlayerRecce.lua' ) __Moose.Include( 'Ops\\EasyGCICAP.lua' ) -__Moose.Include( 'Ops\\EasyA2G.lua' ) __Moose.Include( 'AI\\AI_Balancer.lua' ) __Moose.Include( 'AI\\AI_Air.lua' ) diff --git a/Moose Development/Moose/Ops/Auftrag.lua b/Moose Development/Moose/Ops/Auftrag.lua index 4b768e84c..b9c580f50 100644 --- a/Moose Development/Moose/Ops/Auftrag.lua +++ b/Moose Development/Moose/Ops/Auftrag.lua @@ -1719,7 +1719,7 @@ end -- @param #AUFTRAG self -- @param Core.Zone#ZONE TargetZone The target zone to attack. -- @param #number Altitude Engage altitude in feet. Default 25000 ft. --- @param #table TargetTypes Table of string of DCS known target types, defaults to {"Air defence"}. See [DCS Target Attributes](https://wiki.hoggitworld.com/view/DCS_enum_attributes) +-- @param #table TargetTypes Table of string of DCS known target types, defaults to {"Air Defence"}. See [DCS Target Attributes](https://wiki.hoggitworld.com/view/DCS_enum_attributes) -- @param #number Duration Engage this much time when the AUFTRAG starts executing. -- @return #AUFTRAG self function AUFTRAG:NewSEADInZone(TargetZone, Altitude, TargetTypes, Duration) @@ -1733,7 +1733,7 @@ function AUFTRAG:NewSEADInZone(TargetZone, Altitude, TargetTypes, Duration) mission.engageWeaponExpend=AI.Task.WeaponExpend.ALL mission.engageAltitude=UTILS.FeetToMeters(Altitude or 25000) mission.engageZone = TargetZone - mission.engageTargetTypes = TargetTypes or {"Air defence"} + mission.engageTargetTypes = TargetTypes or {"Air Defence"} -- Mission options: mission.missionTask=ENUMS.MissionTask.SEAD From 69b3e9abad7110f6c72026c4f8eca3cb7c9d95ab Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Fri, 4 Jul 2025 18:47:08 +0200 Subject: [PATCH 084/234] Small fix --- Moose Development/Moose/Ops/Auftrag.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Ops/Auftrag.lua b/Moose Development/Moose/Ops/Auftrag.lua index 4b768e84c..b9c580f50 100644 --- a/Moose Development/Moose/Ops/Auftrag.lua +++ b/Moose Development/Moose/Ops/Auftrag.lua @@ -1719,7 +1719,7 @@ end -- @param #AUFTRAG self -- @param Core.Zone#ZONE TargetZone The target zone to attack. -- @param #number Altitude Engage altitude in feet. Default 25000 ft. --- @param #table TargetTypes Table of string of DCS known target types, defaults to {"Air defence"}. See [DCS Target Attributes](https://wiki.hoggitworld.com/view/DCS_enum_attributes) +-- @param #table TargetTypes Table of string of DCS known target types, defaults to {"Air Defence"}. See [DCS Target Attributes](https://wiki.hoggitworld.com/view/DCS_enum_attributes) -- @param #number Duration Engage this much time when the AUFTRAG starts executing. -- @return #AUFTRAG self function AUFTRAG:NewSEADInZone(TargetZone, Altitude, TargetTypes, Duration) @@ -1733,7 +1733,7 @@ function AUFTRAG:NewSEADInZone(TargetZone, Altitude, TargetTypes, Duration) mission.engageWeaponExpend=AI.Task.WeaponExpend.ALL mission.engageAltitude=UTILS.FeetToMeters(Altitude or 25000) mission.engageZone = TargetZone - mission.engageTargetTypes = TargetTypes or {"Air defence"} + mission.engageTargetTypes = TargetTypes or {"Air Defence"} -- Mission options: mission.missionTask=ENUMS.MissionTask.SEAD From da70f4ce6c76e3dd40e2bd66c74a84e2c75ff816 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sat, 5 Jul 2025 18:56:59 +0200 Subject: [PATCH 085/234] #DynamicSlots for dynamic FARPs --- Moose Development/Moose/Core/SpawnStatic.lua | 16 ++++++++-- Moose Development/Moose/Utilities/Utils.lua | 31 ++++++++++++++++++-- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/Moose Development/Moose/Core/SpawnStatic.lua b/Moose Development/Moose/Core/SpawnStatic.lua index 38f3b0f87..b41ac1b0c 100644 --- a/Moose Development/Moose/Core/SpawnStatic.lua +++ b/Moose Development/Moose/Core/SpawnStatic.lua @@ -302,12 +302,16 @@ end -- @param #number CallsignID Callsign ID. Default 1 (="London"). -- @param #number Frequency Frequency in MHz. Default 127.5 MHz. -- @param #number Modulation Modulation 0=AM, 1=FM. +-- @param #boolean DynamicSpawns If true, allow Dynamic Spawns +-- @param #boolean DynamicHotStarts If true, and DynamicSpawns is true, then allow Dynamic Spawns with hot starts. -- @return #SPAWNSTATIC self -function SPAWNSTATIC:InitFARP(CallsignID, Frequency, Modulation) +function SPAWNSTATIC:InitFARP(CallsignID, Frequency, Modulation, DynamicSpawns,DynamicHotStarts) self.InitFarp=true self.InitFarpCallsignID=CallsignID or 1 self.InitFarpFreq=Frequency or 127.5 self.InitFarpModu=Modulation or 0 + self.InitFarpDynamicSpawns = DynamicSpawns + self.InitFarpDynamicHotStarts = (DynamicSpawns == true and DynamicHotStarts == true) and true or nil return self end @@ -550,6 +554,13 @@ function SPAWNSTATIC:_SpawnStatic(Template, CountryID) TemplateGroup.x=Template.x TemplateGroup.y=Template.y TemplateGroup.name=Template.name + + if self.InitFarpDynamicSpawns == true then + TemplateGroup.units[1].dynamicSpawn = true + if self.InitFarpDynamicHotStarts == true then + TemplateGroup.units[1].allowHotStart = true + end + end self:T("Spawning FARP") self:T({Template=Template}) @@ -557,7 +568,8 @@ function SPAWNSTATIC:_SpawnStatic(Template, CountryID) -- ED's dirty way to spawn FARPS. Static=coalition.addGroup(CountryID, -1, TemplateGroup) - + --Static=coalition.addStaticObject(CountryID, Template) + -- Currently DCS 2.8 does not trigger birth events if FARPS are spawned! -- We create such an event. The airbase is registered in Core.Event local Event = { diff --git a/Moose Development/Moose/Utilities/Utils.lua b/Moose Development/Moose/Utilities/Utils.lua index 6429e01ed..17f6bc039 100644 --- a/Moose Development/Moose/Utilities/Utils.lua +++ b/Moose Development/Moose/Utilities/Utils.lua @@ -4143,9 +4143,14 @@ end -- @param #string VehicleTemplate, template name for additional vehicles. Can be nil for no additional vehicles. -- @param #number Liquids Tons of fuel to be added initially to the FARP. Defaults to 10 (tons). Set to 0 for no fill. -- @param #number Equipment Number of equipment items per known item to be added initially to the FARP. Defaults to 10 (items). Set to 0 for no fill. +-- @param #number Airframes Number of helicopter airframes per known type in Ops.CSAR#CSAR.AircraftType to be added initially to the FARP. Set to 0 for no airframes. +-- @param #string F10Text Text to display on F10 map if given. Handy to post things like the ADF beacon Frequency, Callsign and ATC Frequency. +-- @param #boolean DynamicSpawns If true, allow Dynamic Spawns from this FARP. +-- @param #boolean HotStart If true and DynamicSpawns is true, allow hot starts for Dynamic Spawns from this FARP. -- @return #list Table of spawned objects and vehicle object (if given). -- @return #string ADFBeaconName Name of the ADF beacon, to be able to remove/stop it later. -function UTILS.SpawnFARPAndFunctionalStatics(Name,Coordinate,FARPType,Coalition,Country,CallSign,Frequency,Modulation,ADF,SpawnRadius,VehicleTemplate,Liquids,Equipment) +-- @return #number MarkerID ID of the F10 Text, to be able to remove it later. +function UTILS.SpawnFARPAndFunctionalStatics(Name,Coordinate,FARPType,Coalition,Country,CallSign,Frequency,Modulation,ADF,SpawnRadius,VehicleTemplate,Liquids,Equipment,Airframes,F10Text,DynamicSpawns,HotStart) -- Set Defaults local farplocation = Coordinate @@ -4159,6 +4164,7 @@ function UTILS.SpawnFARPAndFunctionalStatics(Name,Coordinate,FARPType,Coalition, local liquids = Liquids or 10 liquids = liquids * 1000 -- tons to kg local equip = Equipment or 10 + local airframes = Airframes or 10 local statictypes = ENUMS.FARPObjectTypeNamesAndShape[farptype] or {TypeName="FARP", ShapeName="FARPS"} local STypeName = statictypes.TypeName local SShapeName = statictypes.ShapeName @@ -4168,7 +4174,7 @@ function UTILS.SpawnFARPAndFunctionalStatics(Name,Coordinate,FARPType,Coalition, -- Spawn FARP local newfarp = SPAWNSTATIC:NewFromType(STypeName,"Heliports",Country) -- "Invisible FARP" "FARP" newfarp:InitShape(SShapeName) -- "invisiblefarp" "FARPS" - newfarp:InitFARP(callsign,freq,mod) + newfarp:InitFARP(callsign,freq,mod,DynamicSpawns,HotStart) local spawnedfarp = newfarp:SpawnFromCoordinate(farplocation,0,Name) table.insert(ReturnObjects,spawnedfarp) -- Spawn Objects @@ -4221,6 +4227,12 @@ function UTILS.SpawnFARPAndFunctionalStatics(Name,Coordinate,FARPType,Coalition, end end + if airframes and airframes > 0 then + for typename in pairs (CSAR.AircraftType) do + newWH:SetItem(typename,airframes) + end + end + local ADFName if ADF and type(ADF) == "number" then local ADFFreq = ADF*1000 -- KHz to Hz @@ -4231,7 +4243,20 @@ function UTILS.SpawnFARPAndFunctionalStatics(Name,Coordinate,FARPType,Coalition, trigger.action.radioTransmission(Sound, vec3, 0, true, ADFFreq, 250, ADFName) end - return ReturnObjects, ADFName + local MarkerID = nil + if F10Text then + local Color = {0,0,1} + if Coalition == coalition.side.RED then + Color = {1,0,0} + elseif Coalition == coalition.side.NEUTRAL then + Color = {0,1,0} + end + local Alpha = 0.75 + local coordinate = Coordinate:Translate(600,0) + MarkerID = coordinate:TextToAll(F10Text,Coalition,Color,1,{1,1,1},Alpha,14,true) + end + + return ReturnObjects, ADFName, MarkerID end --- Converts a Vec2 to a Vec3. From 124ebd3240c642fb2203202a562a5a4e5e18c5f7 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sat, 5 Jul 2025 18:57:39 +0200 Subject: [PATCH 086/234] xxx --- Moose Development/Moose/Core/SpawnStatic.lua | 16 ++++++++-- Moose Development/Moose/Utilities/Utils.lua | 31 ++++++++++++++++++-- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/Moose Development/Moose/Core/SpawnStatic.lua b/Moose Development/Moose/Core/SpawnStatic.lua index 38f3b0f87..b41ac1b0c 100644 --- a/Moose Development/Moose/Core/SpawnStatic.lua +++ b/Moose Development/Moose/Core/SpawnStatic.lua @@ -302,12 +302,16 @@ end -- @param #number CallsignID Callsign ID. Default 1 (="London"). -- @param #number Frequency Frequency in MHz. Default 127.5 MHz. -- @param #number Modulation Modulation 0=AM, 1=FM. +-- @param #boolean DynamicSpawns If true, allow Dynamic Spawns +-- @param #boolean DynamicHotStarts If true, and DynamicSpawns is true, then allow Dynamic Spawns with hot starts. -- @return #SPAWNSTATIC self -function SPAWNSTATIC:InitFARP(CallsignID, Frequency, Modulation) +function SPAWNSTATIC:InitFARP(CallsignID, Frequency, Modulation, DynamicSpawns,DynamicHotStarts) self.InitFarp=true self.InitFarpCallsignID=CallsignID or 1 self.InitFarpFreq=Frequency or 127.5 self.InitFarpModu=Modulation or 0 + self.InitFarpDynamicSpawns = DynamicSpawns + self.InitFarpDynamicHotStarts = (DynamicSpawns == true and DynamicHotStarts == true) and true or nil return self end @@ -550,6 +554,13 @@ function SPAWNSTATIC:_SpawnStatic(Template, CountryID) TemplateGroup.x=Template.x TemplateGroup.y=Template.y TemplateGroup.name=Template.name + + if self.InitFarpDynamicSpawns == true then + TemplateGroup.units[1].dynamicSpawn = true + if self.InitFarpDynamicHotStarts == true then + TemplateGroup.units[1].allowHotStart = true + end + end self:T("Spawning FARP") self:T({Template=Template}) @@ -557,7 +568,8 @@ function SPAWNSTATIC:_SpawnStatic(Template, CountryID) -- ED's dirty way to spawn FARPS. Static=coalition.addGroup(CountryID, -1, TemplateGroup) - + --Static=coalition.addStaticObject(CountryID, Template) + -- Currently DCS 2.8 does not trigger birth events if FARPS are spawned! -- We create such an event. The airbase is registered in Core.Event local Event = { diff --git a/Moose Development/Moose/Utilities/Utils.lua b/Moose Development/Moose/Utilities/Utils.lua index 6429e01ed..17f6bc039 100644 --- a/Moose Development/Moose/Utilities/Utils.lua +++ b/Moose Development/Moose/Utilities/Utils.lua @@ -4143,9 +4143,14 @@ end -- @param #string VehicleTemplate, template name for additional vehicles. Can be nil for no additional vehicles. -- @param #number Liquids Tons of fuel to be added initially to the FARP. Defaults to 10 (tons). Set to 0 for no fill. -- @param #number Equipment Number of equipment items per known item to be added initially to the FARP. Defaults to 10 (items). Set to 0 for no fill. +-- @param #number Airframes Number of helicopter airframes per known type in Ops.CSAR#CSAR.AircraftType to be added initially to the FARP. Set to 0 for no airframes. +-- @param #string F10Text Text to display on F10 map if given. Handy to post things like the ADF beacon Frequency, Callsign and ATC Frequency. +-- @param #boolean DynamicSpawns If true, allow Dynamic Spawns from this FARP. +-- @param #boolean HotStart If true and DynamicSpawns is true, allow hot starts for Dynamic Spawns from this FARP. -- @return #list Table of spawned objects and vehicle object (if given). -- @return #string ADFBeaconName Name of the ADF beacon, to be able to remove/stop it later. -function UTILS.SpawnFARPAndFunctionalStatics(Name,Coordinate,FARPType,Coalition,Country,CallSign,Frequency,Modulation,ADF,SpawnRadius,VehicleTemplate,Liquids,Equipment) +-- @return #number MarkerID ID of the F10 Text, to be able to remove it later. +function UTILS.SpawnFARPAndFunctionalStatics(Name,Coordinate,FARPType,Coalition,Country,CallSign,Frequency,Modulation,ADF,SpawnRadius,VehicleTemplate,Liquids,Equipment,Airframes,F10Text,DynamicSpawns,HotStart) -- Set Defaults local farplocation = Coordinate @@ -4159,6 +4164,7 @@ function UTILS.SpawnFARPAndFunctionalStatics(Name,Coordinate,FARPType,Coalition, local liquids = Liquids or 10 liquids = liquids * 1000 -- tons to kg local equip = Equipment or 10 + local airframes = Airframes or 10 local statictypes = ENUMS.FARPObjectTypeNamesAndShape[farptype] or {TypeName="FARP", ShapeName="FARPS"} local STypeName = statictypes.TypeName local SShapeName = statictypes.ShapeName @@ -4168,7 +4174,7 @@ function UTILS.SpawnFARPAndFunctionalStatics(Name,Coordinate,FARPType,Coalition, -- Spawn FARP local newfarp = SPAWNSTATIC:NewFromType(STypeName,"Heliports",Country) -- "Invisible FARP" "FARP" newfarp:InitShape(SShapeName) -- "invisiblefarp" "FARPS" - newfarp:InitFARP(callsign,freq,mod) + newfarp:InitFARP(callsign,freq,mod,DynamicSpawns,HotStart) local spawnedfarp = newfarp:SpawnFromCoordinate(farplocation,0,Name) table.insert(ReturnObjects,spawnedfarp) -- Spawn Objects @@ -4221,6 +4227,12 @@ function UTILS.SpawnFARPAndFunctionalStatics(Name,Coordinate,FARPType,Coalition, end end + if airframes and airframes > 0 then + for typename in pairs (CSAR.AircraftType) do + newWH:SetItem(typename,airframes) + end + end + local ADFName if ADF and type(ADF) == "number" then local ADFFreq = ADF*1000 -- KHz to Hz @@ -4231,7 +4243,20 @@ function UTILS.SpawnFARPAndFunctionalStatics(Name,Coordinate,FARPType,Coalition, trigger.action.radioTransmission(Sound, vec3, 0, true, ADFFreq, 250, ADFName) end - return ReturnObjects, ADFName + local MarkerID = nil + if F10Text then + local Color = {0,0,1} + if Coalition == coalition.side.RED then + Color = {1,0,0} + elseif Coalition == coalition.side.NEUTRAL then + Color = {0,1,0} + end + local Alpha = 0.75 + local coordinate = Coordinate:Translate(600,0) + MarkerID = coordinate:TextToAll(F10Text,Coalition,Color,1,{1,1,1},Alpha,14,true) + end + + return ReturnObjects, ADFName, MarkerID end --- Converts a Vec2 to a Vec3. From 926a0733e4b5fd9b01a35e589f762d259446b2a4 Mon Sep 17 00:00:00 2001 From: Thomas <72444570+Applevangelist@users.noreply.github.com> Date: Wed, 9 Jul 2025 12:14:41 +0200 Subject: [PATCH 087/234] Controllable - add option prefer vertical landing Addrd --- .../Moose/Wrapper/Controllable.lua | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Moose Development/Moose/Wrapper/Controllable.lua b/Moose Development/Moose/Wrapper/Controllable.lua index b9f5a0d86..689d841a5 100644 --- a/Moose Development/Moose/Wrapper/Controllable.lua +++ b/Moose Development/Moose/Wrapper/Controllable.lua @@ -3629,6 +3629,26 @@ function CONTROLLABLE:OptionROTPassiveDefense() return nil end +--- Helicopter - prefer vertical landing. +-- @param #CONTROLLABLE self +-- @return #CONTROLLABLE self +function CONTROLLABLE:OptionPreferVerticalLanding() + self:F2( { self.ControllableName } ) + + local DCSControllable = self:GetDCSObject() + if DCSControllable then + local Controller = self:_GetController() + + if self:IsAir() then + Controller:setOption( AI.Option.Air.id.PREFER_VERTICAL, true ) + end + + return self + end + + return nil +end + --- Can the CONTROLLABLE evade on enemy fire? -- @param #CONTROLLABLE self -- @return #boolean From 1b6412821b71a38c3c3cab0a1adc0e83ddfda6b6 Mon Sep 17 00:00:00 2001 From: Thomas <72444570+Applevangelist@users.noreply.github.com> Date: Wed, 9 Jul 2025 12:15:34 +0200 Subject: [PATCH 088/234] Update Controllable.lua --- .../Moose/Wrapper/Controllable.lua | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Moose Development/Moose/Wrapper/Controllable.lua b/Moose Development/Moose/Wrapper/Controllable.lua index b9f5a0d86..689d841a5 100644 --- a/Moose Development/Moose/Wrapper/Controllable.lua +++ b/Moose Development/Moose/Wrapper/Controllable.lua @@ -3629,6 +3629,26 @@ function CONTROLLABLE:OptionROTPassiveDefense() return nil end +--- Helicopter - prefer vertical landing. +-- @param #CONTROLLABLE self +-- @return #CONTROLLABLE self +function CONTROLLABLE:OptionPreferVerticalLanding() + self:F2( { self.ControllableName } ) + + local DCSControllable = self:GetDCSObject() + if DCSControllable then + local Controller = self:_GetController() + + if self:IsAir() then + Controller:setOption( AI.Option.Air.id.PREFER_VERTICAL, true ) + end + + return self + end + + return nil +end + --- Can the CONTROLLABLE evade on enemy fire? -- @param #CONTROLLABLE self -- @return #boolean From 2e8875dd2f39a46d88f88b383937378668403579 Mon Sep 17 00:00:00 2001 From: Thomas <72444570+Applevangelist@users.noreply.github.com> Date: Mon, 14 Jul 2025 10:13:38 +0200 Subject: [PATCH 089/234] Update Auftrag.lua MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix catch all check groups ✅ --- Moose Development/Moose/Ops/Auftrag.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/Ops/Auftrag.lua b/Moose Development/Moose/Ops/Auftrag.lua index b9c580f50..b8223d117 100644 --- a/Moose Development/Moose/Ops/Auftrag.lua +++ b/Moose Development/Moose/Ops/Auftrag.lua @@ -4864,7 +4864,7 @@ function AUFTRAG:CheckGroupsDone() return false end - return false + return true end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- From 7b6bf7f39ba5c84957645d1dcc612bac33d2fa44 Mon Sep 17 00:00:00 2001 From: smiki Date: Mon, 14 Jul 2025 19:04:26 +0200 Subject: [PATCH 090/234] [FIXED] AUFTRAG and FSM state mismatch workaround for `AUFTRAG:CheckGroupsDone` --- Moose Development/Moose/Ops/Auftrag.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Moose Development/Moose/Ops/Auftrag.lua b/Moose Development/Moose/Ops/Auftrag.lua index b8223d117..cae2c17c4 100644 --- a/Moose Development/Moose/Ops/Auftrag.lua +++ b/Moose Development/Moose/Ops/Auftrag.lua @@ -4801,6 +4801,8 @@ end -- @return #boolean If `true`, all groups are done with the mission. function AUFTRAG:CheckGroupsDone() + local fsmState = self:GetState() + -- Check status of all OPS groups. for groupname,data in pairs(self.groupdata) do local groupdata=data --#AUFTRAG.GroupData @@ -4859,7 +4861,7 @@ function AUFTRAG:CheckGroupsDone() return true end - if (self:IsStarted() or self:IsExecuting()) and self:CountOpsGroups()>0 then + if (self:IsStarted() or self:IsExecuting()) and (fsmState == AUFTRAG.Status.STARTED or fsmState == AUFTRAG.Status.EXECUTING) and self:CountOpsGroups()>0 then self:T(self.lid..string.format("CheckGroupsDone: Mission is STARTED state %s [FSM=%s] and count of alive OPSGROUP > zero. Mission NOT DONE!", self.status, self:GetState())) return false end From ec6f190b68688e9a96c2f393f279aa5fde9c629e Mon Sep 17 00:00:00 2001 From: smiki Date: Tue, 15 Jul 2025 10:16:49 +0200 Subject: [PATCH 091/234] [ADDED] GROUP.Attribute.GROUND_SHORAD --- Moose Development/Moose/Wrapper/Group.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index 44f313f27..89ff5f7c3 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -230,6 +230,7 @@ GROUP.Attribute = { GROUND_EWR="Ground_EWR", GROUND_AAA="Ground_AAA", GROUND_SAM="Ground_SAM", + GROUND_SHORAD="Ground_SHORAD", GROUND_OTHER="Ground_OtherGround", NAVAL_AIRCRAFTCARRIER="Naval_AircraftCarrier", NAVAL_WARSHIP="Naval_WarShip", From 7d7488db6f37680c0e707a12acd2f99748bbb48e Mon Sep 17 00:00:00 2001 From: smiki Date: Tue, 15 Jul 2025 11:05:03 +0200 Subject: [PATCH 092/234] [ADDED] GROUP.Attribute.GROUND_SHORAD --- Moose Development/Moose/Wrapper/Group.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index 44f313f27..89ff5f7c3 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -230,6 +230,7 @@ GROUP.Attribute = { GROUND_EWR="Ground_EWR", GROUND_AAA="Ground_AAA", GROUND_SAM="Ground_SAM", + GROUND_SHORAD="Ground_SHORAD", GROUND_OTHER="Ground_OtherGround", NAVAL_AIRCRAFTCARRIER="Naval_AircraftCarrier", NAVAL_WARSHIP="Naval_WarShip", From 21c2bd1103c645e014be3964eb81ba54989100df Mon Sep 17 00:00:00 2001 From: smiki Date: Wed, 16 Jul 2025 23:17:47 +0200 Subject: [PATCH 093/234] [FIXED] AIRWING operational regardless of airbase coalition --- Moose Development/Moose/Ops/Legion.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/Ops/Legion.lua b/Moose Development/Moose/Ops/Legion.lua index 075866209..38490cbd0 100644 --- a/Moose Development/Moose/Ops/Legion.lua +++ b/Moose Development/Moose/Ops/Legion.lua @@ -2514,7 +2514,7 @@ function LEGION._GetCohorts(Legions, Cohorts, Operation, OpsQueue) local legion=_legion --Ops.Legion#LEGION -- Check that runway is operational. - local Runway=legion:IsAirwing() and legion:IsRunwayOperational() or true + local Runway=(legion:IsAirwing() and legion:IsRunwayOperational() and legion.airbase and legion.airbase:GetCoalition() == legion:GetCoalition())or true -- Legion has to be running. if legion:IsRunning() and Runway then From 2d96ba0f5670c51d03bb8877f53a8fc2d8aabbf2 Mon Sep 17 00:00:00 2001 From: smiki Date: Wed, 16 Jul 2025 23:39:04 +0200 Subject: [PATCH 094/234] [FIXED] AIRWING operational regardless of airbase coalition --- Moose Development/Moose/Ops/Commander.lua | 18 ++++++++++++------ Moose Development/Moose/Ops/Legion.lua | 9 ++++++--- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/Moose Development/Moose/Ops/Commander.lua b/Moose Development/Moose/Ops/Commander.lua index b7d30f298..a29b2538b 100644 --- a/Moose Development/Moose/Ops/Commander.lua +++ b/Moose Development/Moose/Ops/Commander.lua @@ -1670,9 +1670,12 @@ function COMMANDER:_GetCohorts(Legions, Cohorts, Operation) for _,_legion in pairs(Legions or {}) do local legion=_legion --Ops.Legion#LEGION - -- Check that runway is operational. - local Runway=legion:IsAirwing() and legion:IsRunwayOperational() or true - + -- Check that runway is operational. + local Runway=true + if legion:IsAirwing() then + Runway=legion:IsRunwayOperational() and legion.airbase and legion.airbase:GetCoalition() == legion:GetCoalition() + end + -- Legion has to be running. if legion:IsRunning() and Runway then @@ -1703,9 +1706,12 @@ function COMMANDER:_GetCohorts(Legions, Cohorts, Operation) for _,_legion in pairs(self.legions) do local legion=_legion --Ops.Legion#LEGION - -- Check that runway is operational. - local Runway=legion:IsAirwing() and legion:IsRunwayOperational() or true - + -- Check that runway is operational. + local Runway=true + if legion:IsAirwing() then + Runway=legion:IsRunwayOperational() and legion.airbase and legion.airbase:GetCoalition() == legion:GetCoalition() + end + -- Legion has to be running. if legion:IsRunning() and Runway then diff --git a/Moose Development/Moose/Ops/Legion.lua b/Moose Development/Moose/Ops/Legion.lua index 38490cbd0..b3c00592f 100644 --- a/Moose Development/Moose/Ops/Legion.lua +++ b/Moose Development/Moose/Ops/Legion.lua @@ -2513,9 +2513,12 @@ function LEGION._GetCohorts(Legions, Cohorts, Operation, OpsQueue) for _,_legion in pairs(Legions or {}) do local legion=_legion --Ops.Legion#LEGION - -- Check that runway is operational. - local Runway=(legion:IsAirwing() and legion:IsRunwayOperational() and legion.airbase and legion.airbase:GetCoalition() == legion:GetCoalition())or true - + -- Check that runway is operational. + local Runway=true + if legion:IsAirwing() then + Runway=legion:IsRunwayOperational() and legion.airbase and legion.airbase:GetCoalition() == legion:GetCoalition() + end + -- Legion has to be running. if legion:IsRunning() and Runway then From 9df3fcfdf7543a7ce86f1454737533e02912ad3d Mon Sep 17 00:00:00 2001 From: smiki Date: Thu, 17 Jul 2025 23:36:23 +0200 Subject: [PATCH 095/234] [FIXED] attempt to index local 'airbase' (a nil value) --- Moose Development/Moose/Ops/FlightGroup.lua | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Moose Development/Moose/Ops/FlightGroup.lua b/Moose Development/Moose/Ops/FlightGroup.lua index 41b2fb35a..ff56299b1 100644 --- a/Moose Development/Moose/Ops/FlightGroup.lua +++ b/Moose Development/Moose/Ops/FlightGroup.lua @@ -4497,6 +4497,11 @@ function FLIGHTGROUP:GetParkingSpot(element, maxdist, airbase) -- Airbase. airbase=airbase or self:GetClosestAirbase() + if airbase == nil then + self:T(self.lid.."No airbase found for element "..element.name) + return nil + end + -- Parking table of airbase. local parking=airbase.parking --:GetParkingSpotsTable() From be40d7be9a20cef1f587a797c15b17b2c54999f2 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Fri, 18 Jul 2025 18:09:57 +0200 Subject: [PATCH 096/234] #SPAWNSTATIC - NewFromStatic now creates a new template in the database under the new name - if not already there. This allows #WAREHOUSE static warehouses spawned that way to be respawned eg on coalition change. --- Moose Development/Moose/Core/SpawnStatic.lua | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/Moose Development/Moose/Core/SpawnStatic.lua b/Moose Development/Moose/Core/SpawnStatic.lua index b41ac1b0c..344d1a5d7 100644 --- a/Moose Development/Moose/Core/SpawnStatic.lua +++ b/Moose Development/Moose/Core/SpawnStatic.lua @@ -149,6 +149,7 @@ function SPAWNSTATIC:NewFromStatic(SpawnTemplateName, SpawnCountryID) self.CategoryID = CategoryID self.CoalitionID = CoalitionID self.SpawnIndex = 0 + self.StaticCopyFrom = SpawnTemplateName else error( "SPAWNSTATIC:New: There is no static declared in the mission editor with SpawnTemplatePrefix = '" .. tostring(SpawnTemplateName) .. "'" ) end @@ -607,6 +608,19 @@ function SPAWNSTATIC:_SpawnStatic(Template, CountryID) -- delay calling this for .3 seconds so that it hopefully comes after the BIRTH event of the group. self:ScheduleOnce(0.3, self.SpawnFunctionHook, mystatic, unpack(self.SpawnFunctionArguments)) end - + + if self.StaticCopyFrom ~= nil then + mystatic.StaticCopyFrom = self.StaticCopyFrom + if not _DATABASE.Templates.Statics[Template.name] then + local TemplateGroup={} + TemplateGroup.units={} + TemplateGroup.units[1]=Template + TemplateGroup.x=Template.x + TemplateGroup.y=Template.y + TemplateGroup.name=Template.name + _DATABASE:_RegisterStaticTemplate( TemplateGroup, self.CoalitionID, self.CategoryID, CountryID ) + end + end + return mystatic end From 0e836973fd3e925a47d8a0eac976a0b21f131cb8 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sat, 19 Jul 2025 16:04:49 +0200 Subject: [PATCH 097/234] #Fix SRS TTS folder path in documentation and defaults --- Moose Development/Moose/Core/Message.lua | 14 +++++++------- Moose Development/Moose/Ops/Airboss.lua | 4 ++-- Moose Development/Moose/Ops/CSAR.lua | 4 ++-- Moose Development/Moose/Sound/SRS.lua | 12 ++++++------ 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Moose Development/Moose/Core/Message.lua b/Moose Development/Moose/Core/Message.lua index ff74527f2..86dfd1858 100644 --- a/Moose Development/Moose/Core/Message.lua +++ b/Moose Development/Moose/Core/Message.lua @@ -452,7 +452,7 @@ end _MESSAGESRS = {} --- Set up MESSAGE generally to allow Text-To-Speech via SRS and TTS functions. `SetMSRS()` will try to use as many attributes configured with @{Sound.SRS#MSRS.LoadConfigFile}() as possible. --- @param #string PathToSRS (optional) Path to SRS Folder, defaults to "C:\\\\Program Files\\\\DCS-SimpleRadio-Standalone" or your configuration file setting. +-- @param #string PathToSRS (optional) Path to SRS TTS Folder, defaults to "C:\\\\Program Files\\\\DCS-SimpleRadio-Standalone\\ExternalAudio" or your configuration file setting. -- @param #number Port Port (optional) number of SRS, defaults to 5002 or your configuration file setting. -- @param #string PathToCredentials (optional) Path to credentials file for Google. -- @param #number Frequency Frequency in MHz. Can also be given as a #table of frequencies. @@ -468,13 +468,13 @@ _MESSAGESRS = {} -- @usage -- -- Mind the dot here, not using the colon this time around! -- -- Needed once only --- MESSAGE.SetMSRS("D:\\Program Files\\DCS-SimpleRadio-Standalone",5012,nil,127,radio.modulation.FM,"female","en-US",nil,coalition.side.BLUE) +-- MESSAGE.SetMSRS("D:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio",5012,nil,127,radio.modulation.FM,"female","en-US",nil,coalition.side.BLUE) -- -- later on in your code -- MESSAGE:New("Test message!",15,"SPAWN"):ToSRS() -- function MESSAGE.SetMSRS(PathToSRS,Port,PathToCredentials,Frequency,Modulation,Gender,Culture,Voice,Coalition,Volume,Label,Coordinate,Backend) - _MESSAGESRS.PathToSRS = PathToSRS or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone" + _MESSAGESRS.PathToSRS = PathToSRS or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio" _MESSAGESRS.frequency = Frequency or MSRS.frequencies or 243 _MESSAGESRS.modulation = Modulation or MSRS.modulations or radio.modulation.AM @@ -535,7 +535,7 @@ end -- @usage -- -- Mind the dot here, not using the colon this time around! -- -- Needed once only --- MESSAGE.SetMSRS("D:\\Program Files\\DCS-SimpleRadio-Standalone",5012,nil,127,radio.modulation.FM,"female","en-US",nil,coalition.side.BLUE) +-- MESSAGE.SetMSRS("D:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio",5012,nil,127,radio.modulation.FM,"female","en-US",nil,coalition.side.BLUE) -- -- later on in your code -- MESSAGE:New("Test message!",15,"SPAWN"):ToSRS() -- @@ -567,7 +567,7 @@ end -- @usage -- -- Mind the dot here, not using the colon this time around! -- -- Needed once only --- MESSAGE.SetMSRS("D:\\Program Files\\DCS-SimpleRadio-Standalone",5012,nil,127,radio.modulation.FM,"female","en-US",nil,coalition.side.BLUE) +-- MESSAGE.SetMSRS("D:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio",5012,nil,127,radio.modulation.FM,"female","en-US",nil,coalition.side.BLUE) -- -- later on in your code -- MESSAGE:New("Test message!",15,"SPAWN"):ToSRSBlue() -- @@ -589,7 +589,7 @@ end -- @usage -- -- Mind the dot here, not using the colon this time around! -- -- Needed once only --- MESSAGE.SetMSRS("D:\\Program Files\\DCS-SimpleRadio-Standalone",5012,nil,127,radio.modulation.FM,"female","en-US",nil,coalition.side.RED) +-- MESSAGE.SetMSRS("D:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio",5012,nil,127,radio.modulation.FM,"female","en-US",nil,coalition.side.RED) -- -- later on in your code -- MESSAGE:New("Test message!",15,"SPAWN"):ToSRSRed() -- @@ -611,7 +611,7 @@ end -- @usage -- -- Mind the dot here, not using the colon this time around! -- -- Needed once only --- MESSAGE.SetMSRS("D:\\Program Files\\DCS-SimpleRadio-Standalone",5012,nil,127,radio.modulation.FM,"female","en-US",nil,coalition.side.NEUTRAL) +-- MESSAGE.SetMSRS("D:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio",5012,nil,127,radio.modulation.FM,"female","en-US",nil,coalition.side.NEUTRAL) -- -- later on in your code -- MESSAGE:New("Test message!",15,"SPAWN"):ToSRSAll() -- diff --git a/Moose Development/Moose/Ops/Airboss.lua b/Moose Development/Moose/Ops/Airboss.lua index 1754ab219..d47e6da06 100644 --- a/Moose Development/Moose/Ops/Airboss.lua +++ b/Moose Development/Moose/Ops/Airboss.lua @@ -3080,12 +3080,12 @@ end --- Set up SRS for usage without sound files -- @param #AIRBOSS self --- @param #string PathToSRS Path to SRS folder, e.g. "C:\\Program Files\\DCS-SimpleRadio-Standalone". +-- @param #string PathToSRS Path to SRS TTS folder, e.g. "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio". -- @param #number Port Port of the SRS server, defaults to 5002. -- @param #string Culture (Optional, Airboss Culture) Culture, defaults to "en-US". -- @param #string Gender (Optional, Airboss Gender) Gender, e.g. "male" or "female". Defaults to "male". -- @param #string Voice (Optional, Airboss Voice) Set to use a specific voice. Will **override gender and culture** settings. --- @param #string GoogleCreds (Optional) Path to Google credentials, e.g. "C:\\Program Files\\DCS-SimpleRadio-Standalone\\yourgooglekey.json". +-- @param #string GoogleCreds (Optional) Path to Google credentials, e.g. "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio\\yourgooglekey.json". -- @param #number Volume (Optional) E.g. 0.75. Defaults to 1.0 (loudest). -- @param #table AltBackend (Optional) See MSRS for details. -- @return #AIRBOSS self diff --git a/Moose Development/Moose/Ops/CSAR.lua b/Moose Development/Moose/Ops/CSAR.lua index 817cd19b9..8dede4270 100644 --- a/Moose Development/Moose/Ops/CSAR.lua +++ b/Moose Development/Moose/Ops/CSAR.lua @@ -130,7 +130,7 @@ -- ## 2.2 SRS Features and Other Features -- -- mycsar.useSRS = false -- Set true to use FF\'s SRS integration --- mycsar.SRSPath = "C:\\Progra~1\\DCS-SimpleRadio-Standalone\\" -- adjust your own path in your SRS installation -- server(!) +-- mycsar.SRSPath = "C:\\Progra~1\\DCS-SimpleRadio-Standalone\\ExternalAudio\\" -- adjust your own path in your SRS installation -- server(!) -- mycsar.SRSchannel = 300 -- radio channel -- mycsar.SRSModulation = radio.modulation.AM -- modulation -- mycsar.SRSport = 5002 -- and SRS Server port @@ -481,7 +481,7 @@ function CSAR:New(Coalition, Template, Alias) -- for this to work you need to de-sanitize your mission environment in \Scripts\MissionScripting.lua -- needs SRS => 1.9.6 to work (works on the *server* side) self.useSRS = false -- Use FF\'s SRS integration - self.SRSPath = "E:\\Program Files\\DCS-SimpleRadio-Standalone" -- adjust your own path in your server(!) + self.SRSPath = "E:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio" -- adjust your own path in your server(!) self.SRSchannel = 300 -- radio channel self.SRSModulation = radio.modulation.AM -- modulation self.SRSport = 5002 -- port diff --git a/Moose Development/Moose/Sound/SRS.lua b/Moose Development/Moose/Sound/SRS.lua index 526094f5a..5b9358b2f 100644 --- a/Moose Development/Moose/Sound/SRS.lua +++ b/Moose Development/Moose/Sound/SRS.lua @@ -632,7 +632,7 @@ end -- set the path to the exe file via @{#MSRS.SetPath}. -- -- @param #MSRS self --- @param #string Path Path to SRS directory. Default `C:\\Program Files\\DCS-SimpleRadio-Standalone`. +-- @param #string Path Path to SRS directory. Default `C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio`. -- @param #number Frequency Radio frequency in MHz. Default 143.00 MHz. Can also be given as a #table of multiple frequencies. -- @param #number Modulation Radio modulation: 0=AM (default), 1=FM. See `radio.modulation.AM` and `radio.modulation.FM` enumerators. Can also be given as a #table of multiple modulations. -- @param #string Backend Backend used: `MSRS.Backend.SRSEXE` (default) or `MSRS.Backend.GRPC`. @@ -767,13 +767,13 @@ end --- Set path to SRS install directory. More precisely, path to where the `DCS-SR-ExternalAudio.exe` is located. -- @param #MSRS self --- @param #string Path Path to the directory, where the sound file is located. Default is `C:\\Program Files\\DCS-SimpleRadio-Standalone`. +-- @param #string Path Path to the directory, where the sound file is located. Default is `C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio`. -- @return #MSRS self function MSRS:SetPath(Path) self:F( {Path=Path} ) -- Set path. - self.path=Path or "C:\\Program Files\\DCS-SimpleRadio-Standalone" + self.path=Path or "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio" -- Remove (back)slashes. local n=1 ; local nmax=1000 @@ -1817,7 +1817,7 @@ end -- -- -- Moose MSRS default Config -- MSRS_Config = { --- Path = "C:\\Program Files\\DCS-SimpleRadio-Standalone", -- Path to SRS install directory. +-- Path = "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio", -- Path to SRS install directory. -- Port = 5002, -- Port of SRS server. Default 5002. -- Backend = "srsexe", -- Interface to SRS: "srsexe" or "grpc". -- Frequency = {127, 243}, -- Default frequences. Must be a table 1..n entries! @@ -1837,7 +1837,7 @@ end -- -- Google Cloud -- gcloud = { -- voice = "en-GB-Standard-A", -- The Google Cloud voice to use (see https://cloud.google.com/text-to-speech/docs/voices). --- credentials="C:\\Program Files\\DCS-SimpleRadio-Standalone\\yourfilename.json", -- Full path to credentials JSON file (only for SRS-TTS.exe backend) +-- credentials="C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio\\yourfilename.json", -- Full path to credentials JSON file (only for SRS-TTS.exe backend) -- key="Your access Key", -- Google API access key (only for DCS-gRPC backend) -- }, -- -- Amazon Web Service @@ -1905,7 +1905,7 @@ function MSRS:LoadConfigFile(Path,Filename) local Self = self or MSRS --#MSRS - Self.path = MSRS_Config.Path or "C:\\Program Files\\DCS-SimpleRadio-Standalone" + Self.path = MSRS_Config.Path or "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio" Self.port = MSRS_Config.Port or 5002 Self.backend = MSRS_Config.Backend or MSRS.Backend.SRSEXE Self.frequencies = MSRS_Config.Frequency or {127,243} From 8a0e9a3400e587c13015ac4e89196cdcb758dc6b Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sat, 19 Jul 2025 16:05:06 +0200 Subject: [PATCH 098/234] #Fix SRS TTS folder path in documentation and defaults --- Moose Development/Moose/Functional/Autolase.lua | 4 ++-- Moose Development/Moose/Ops/Airboss.lua | 4 ++-- Moose Development/Moose/Ops/Awacs.lua | 10 +++++----- Moose Development/Moose/Ops/FlightGroup.lua | 2 +- Moose Development/Moose/Ops/PlayerRecce.lua | 4 ++-- Moose Development/Moose/Ops/PlayerTask.lua | 8 ++++---- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Moose Development/Moose/Functional/Autolase.lua b/Moose Development/Moose/Functional/Autolase.lua index 9fed56cfc..1e43a737c 100644 --- a/Moose Development/Moose/Functional/Autolase.lua +++ b/Moose Development/Moose/Functional/Autolase.lua @@ -493,7 +493,7 @@ end --- (User) Function enable sending messages via SRS. -- @param #AUTOLASE self -- @param #boolean OnOff Switch usage on and off --- @param #string Path Path to SRS directory, e.g. C:\\Program Files\\DCS-SimpleRadio-Standalone +-- @param #string Path Path to SRS TTS directory, e.g. C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio -- @param #number Frequency Frequency to send, e.g. 243 -- @param #number Modulation Modulation i.e. radio.modulation.AM or radio.modulation.FM -- @param #string Label (Optional) Short label to be used on the SRS Client Overlay @@ -508,7 +508,7 @@ end function AUTOLASE:SetUsingSRS(OnOff,Path,Frequency,Modulation,Label,Gender,Culture,Port,Voice,Volume,PathToGoogleKey) if OnOff then self.useSRS = true - self.SRSPath = Path or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone" + self.SRSPath = Path or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio" self.SRSFreq = Frequency or 271 self.SRSMod = Modulation or radio.modulation.AM self.Gender = Gender or MSRS.gender or "male" diff --git a/Moose Development/Moose/Ops/Airboss.lua b/Moose Development/Moose/Ops/Airboss.lua index 1754ab219..d47e6da06 100644 --- a/Moose Development/Moose/Ops/Airboss.lua +++ b/Moose Development/Moose/Ops/Airboss.lua @@ -3080,12 +3080,12 @@ end --- Set up SRS for usage without sound files -- @param #AIRBOSS self --- @param #string PathToSRS Path to SRS folder, e.g. "C:\\Program Files\\DCS-SimpleRadio-Standalone". +-- @param #string PathToSRS Path to SRS TTS folder, e.g. "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio". -- @param #number Port Port of the SRS server, defaults to 5002. -- @param #string Culture (Optional, Airboss Culture) Culture, defaults to "en-US". -- @param #string Gender (Optional, Airboss Gender) Gender, e.g. "male" or "female". Defaults to "male". -- @param #string Voice (Optional, Airboss Voice) Set to use a specific voice. Will **override gender and culture** settings. --- @param #string GoogleCreds (Optional) Path to Google credentials, e.g. "C:\\Program Files\\DCS-SimpleRadio-Standalone\\yourgooglekey.json". +-- @param #string GoogleCreds (Optional) Path to Google credentials, e.g. "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio\\yourgooglekey.json". -- @param #number Volume (Optional) E.g. 0.75. Defaults to 1.0 (loudest). -- @param #table AltBackend (Optional) See MSRS for details. -- @return #AIRBOSS self diff --git a/Moose Development/Moose/Ops/Awacs.lua b/Moose Development/Moose/Ops/Awacs.lua index 6533ace03..c4d4632fa 100644 --- a/Moose Development/Moose/Ops/Awacs.lua +++ b/Moose Development/Moose/Ops/Awacs.lua @@ -237,7 +237,7 @@ do -- -- Callsign will be "Focus". We'll be a Angels 30, doing 300 knots, orbit leg to 88deg with a length of 25nm. -- testawacs:SetAwacsDetails(CALLSIGN.AWACS.Focus,1,30,300,88,25) -- -- Set up SRS on port 5010 - change the below to your path and port --- testawacs:SetSRS("C:\\Program Files\\DCS-SimpleRadio-Standalone","female","en-GB",5010) +-- testawacs:SetSRS("C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio","female","en-GB",5010) -- -- Add a "red" border we don't want to cross, set up in the mission editor with a late activated helo named "Red Border#ZONE_POLYGON" -- testawacs:SetRejectionZone(ZONE:FindByName("Red Border")) -- -- Our CAP flight will have the callsign "Ford", we want 4 AI planes, Time-On-Station is four hours, doing 300 kn IAS. @@ -255,7 +255,7 @@ do -- -- The CAP station zone is called "Fremont". We will be on 255 AM. Note the Orbit Zone is given as *nil* in the `New()`-Statement -- local testawacs = AWACS:New("GCI Senaki",AwacsAW,"blue",AIRBASE.Caucasus.Senaki_Kolkhi,nil,ZONE:FindByName("Rock"),"Fremont",255,radio.modulation.AM ) -- -- Set up SRS on port 5010 - change the below to your path and port --- testawacs:SetSRS("C:\\Program Files\\DCS-SimpleRadio-Standalone","female","en-GB",5010) +-- testawacs:SetSRS("C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio","female","en-GB",5010) -- -- Add a "red" border we don't want to cross, set up in the mission editor with a late activated helo named "Red Border#ZONE_POLYGON" -- testawacs:SetRejectionZone(ZONE:FindByName("Red Border")) -- -- Our CAP flight will have the callsign "Ford", we want 4 AI planes, Time-On-Station is four hours, doing 300 kn IAS. @@ -1123,7 +1123,7 @@ function AWACS:New(Name,AirWing,Coalition,AirbaseName,AwacsOrbit,OpsZone,Station self.EscortMissionReplacement = {} -- SRS - self.PathToSRS = "C:\\Program Files\\DCS-SimpleRadio-Standalone" + self.PathToSRS = "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio" self.Gender = "female" self.Culture = "en-GB" self.Voice = nil @@ -2113,7 +2113,7 @@ end --- [User] Set AWACS SRS TTS details - see @{Sound.SRS} for details. `SetSRS()` will try to use as many attributes configured with @{Sound.SRS#MSRS.LoadConfigFile}() as possible. -- @param #AWACS self --- @param #string PathToSRS Defaults to "C:\\Program Files\\DCS-SimpleRadio-Standalone" +-- @param #string PathToSRS Defaults to "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio" -- @param #string Gender Defaults to "male" -- @param #string Culture Defaults to "en-US" -- @param #number Port Defaults to 5002 @@ -2126,7 +2126,7 @@ end -- @return #AWACS self function AWACS:SetSRS(PathToSRS,Gender,Culture,Port,Voice,Volume,PathToGoogleKey,AccessKey,Backend) self:T(self.lid.."SetSRS") - self.PathToSRS = PathToSRS or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone" + self.PathToSRS = PathToSRS or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio" self.Gender = Gender or MSRS.gender or "male" self.Culture = Culture or MSRS.culture or "en-US" self.Port = Port or MSRS.port or 5002 diff --git a/Moose Development/Moose/Ops/FlightGroup.lua b/Moose Development/Moose/Ops/FlightGroup.lua index 41b2fb35a..33307d155 100644 --- a/Moose Development/Moose/Ops/FlightGroup.lua +++ b/Moose Development/Moose/Ops/FlightGroup.lua @@ -3079,7 +3079,7 @@ function FLIGHTGROUP:onbeforeLandAtAirbase(From, Event, To, airbase) local Tsuspend=nil if airbase==nil then - self:T(self.lid.."ERROR: Airbase is nil in LandAtAirase() call!") + self:T(self.lid.."ERROR: Airbase is nil in LandAtAirbase() call!") allowed=false end diff --git a/Moose Development/Moose/Ops/PlayerRecce.lua b/Moose Development/Moose/Ops/PlayerRecce.lua index e178b58f0..544c25034 100644 --- a/Moose Development/Moose/Ops/PlayerRecce.lua +++ b/Moose Development/Moose/Ops/PlayerRecce.lua @@ -1544,7 +1544,7 @@ end -- @param #PLAYERRECCE self -- @param #number Frequency Frequency to be used. Can also be given as a table of multiple frequencies, e.g. 271 or {127,251}. There needs to be exactly the same number of modulations! -- @param #number Modulation Modulation to be used. Can also be given as a table of multiple modulations, e.g. radio.modulation.AM or {radio.modulation.FM,radio.modulation.AM}. There needs to be exactly the same number of frequencies! --- @param #string PathToSRS Defaults to "C:\\Program Files\\DCS-SimpleRadio-Standalone" +-- @param #string PathToSRS Defaults to "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio" -- @param #string Gender (Optional) Defaults to "male" -- @param #string Culture (Optional) Defaults to "en-US" -- @param #number Port (Optional) Defaults to 5002 @@ -1556,7 +1556,7 @@ end -- @return #PLAYERRECCE self function PLAYERRECCE:SetSRS(Frequency,Modulation,PathToSRS,Gender,Culture,Port,Voice,Volume,PathToGoogleKey,Backend) self:T(self.lid.."SetSRS") - self.PathToSRS = PathToSRS or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone" -- + self.PathToSRS = PathToSRS or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio" -- self.Gender = Gender or MSRS.gender or "male" -- self.Culture = Culture or MSRS.culture or "en-US" -- self.Port = Port or MSRS.port or 5002 -- diff --git a/Moose Development/Moose/Ops/PlayerTask.lua b/Moose Development/Moose/Ops/PlayerTask.lua index 7c912235f..7ce6d57c2 100644 --- a/Moose Development/Moose/Ops/PlayerTask.lua +++ b/Moose Development/Moose/Ops/PlayerTask.lua @@ -1440,9 +1440,9 @@ do -- taskmanager:AddRejectZone(ZONE:FindByName("RejectZone")) -- -- -- Set up using SRS for messaging --- local hereSRSPath = "C:\\Program Files\\DCS-SimpleRadio-Standalone" +-- local hereSRSPath = "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio" -- local hereSRSPort = 5002 --- -- local hereSRSGoogle = "C:\\Program Files\\DCS-SimpleRadio-Standalone\\yourkey.json" +-- -- local hereSRSGoogle = "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio\\yourkey.json" -- taskmanager:SetSRS({130,255},{radio.modulation.AM,radio.modulation.AM},hereSRSPath,"female","en-GB",hereSRSPort,"Microsoft Hazel Desktop",0.7,hereSRSGoogle) -- -- -- Controller will announce itself under these broadcast frequencies, handy to use cold-start frequencies here of your aircraft @@ -4606,7 +4606,7 @@ end -- @param #PLAYERTASKCONTROLLER self -- @param #number Frequency Frequency to be used. Can also be given as a table of multiple frequencies, e.g. 271 or {127,251}. There needs to be exactly the same number of modulations! -- @param #number Modulation Modulation to be used. Can also be given as a table of multiple modulations, e.g. radio.modulation.AM or {radio.modulation.FM,radio.modulation.AM}. There needs to be exactly the same number of frequencies! --- @param #string PathToSRS Defaults to "C:\\Program Files\\DCS-SimpleRadio-Standalone" +-- @param #string PathToSRS Defaults to "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio" -- @param #string Gender (Optional) Defaults to "male" -- @param #string Culture (Optional) Defaults to "en-US" -- @param #number Port (Optional) Defaults to 5002 @@ -4620,7 +4620,7 @@ end -- @return #PLAYERTASKCONTROLLER self function PLAYERTASKCONTROLLER:SetSRS(Frequency,Modulation,PathToSRS,Gender,Culture,Port,Voice,Volume,PathToGoogleKey,AccessKey,Coordinate,Backend) self:T(self.lid.."SetSRS") - self.PathToSRS = PathToSRS or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone" -- + self.PathToSRS = PathToSRS or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio" -- self.Gender = Gender or MSRS.gender or "male" -- self.Culture = Culture or MSRS.culture or "en-US" -- self.Port = Port or MSRS.port or 5002 -- From d5c34a37b02040718017cc5f281bfc21910db0df Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sat, 19 Jul 2025 16:05:28 +0200 Subject: [PATCH 099/234] #AICSAR - Added functionality to use rescue zones instead of pure distance. Fixed helo not despawning after landing back at base. --- Moose Development/Moose/Functional/AICSAR.lua | 70 ++++++++++++++----- 1 file changed, 52 insertions(+), 18 deletions(-) diff --git a/Moose Development/Moose/Functional/AICSAR.lua b/Moose Development/Moose/Functional/AICSAR.lua index a05f47127..7ec2f73dc 100644 --- a/Moose Development/Moose/Functional/AICSAR.lua +++ b/Moose Development/Moose/Functional/AICSAR.lua @@ -22,7 +22,7 @@ -- === -- -- ### Author: **Applevangelist** --- Last Update Sept 2023 +-- Last Update July 2025 -- -- === -- @module Functional.AICSAR @@ -57,6 +57,8 @@ -- @field #number Speed Default speed setting for the helicopter FLIGHTGROUP is 100kn. -- @field #boolean UseEventEject In case Event LandingAfterEjection isn't working, use set this to true. -- @field #number Delay In case of UseEventEject wait this long until we spawn a landed pilot. +-- @field #boolean UseRescueZone If true, use a rescue zone and not the max distance to FARP/MASH +-- @field Core.Zone#ZONE_RADIUS RescueZone Use this zone as operational area for the AICSAR instance. -- @extends Core.Fsm#FSM @@ -153,10 +155,10 @@ -- To set up AICSAR for SRS TTS output, add e.g. the following to your script: -- -- -- setup for google TTS, radio 243 AM, SRS server port 5002 with a google standard-quality voice (google cloud account required) --- my_aicsar:SetSRSTTSRadio(true,"C:\\Program Files\\DCS-SimpleRadio-Standalone",243,radio.modulation.AM,5002,MSRS.Voices.Google.Standard.en_US_Standard_D,"en-US","female","C:\\Program Files\\DCS-SimpleRadio-Standalone\\google.json") +-- my_aicsar:SetSRSTTSRadio(true,"C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio",243,radio.modulation.AM,5002,MSRS.Voices.Google.Standard.en_US_Standard_D,"en-US","female","C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio\\google.json") -- -- -- alternatively for MS Desktop TTS (voices need to be installed locally first!) --- my_aicsar:SetSRSTTSRadio(true,"C:\\Program Files\\DCS-SimpleRadio-Standalone",243,radio.modulation.AM,5002,MSRS.Voices.Microsoft.Hazel,"en-GB","female") +-- my_aicsar:SetSRSTTSRadio(true,"C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio",243,radio.modulation.AM,5002,MSRS.Voices.Microsoft.Hazel,"en-GB","female") -- -- -- define a different voice for the downed pilot(s) -- my_aicsar:SetPilotTTSVoice(MSRS.Voices.Google.Standard.en_AU_Standard_D,"en-AU","male") @@ -177,7 +179,7 @@ -- -- Switch on radio transmissions via **either** SRS **or** "normal" DCS radio e.g. like so: -- --- my_aicsar:SetSRSRadio(true,"C:\\Program Files\\DCS-SimpleRadio-Standalone",270,radio.modulation.AM,nil,5002) +-- my_aicsar:SetSRSRadio(true,"C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio",270,radio.modulation.AM,nil,5002) -- -- or -- @@ -191,7 +193,7 @@ -- @field #AICSAR AICSAR = { ClassName = "AICSAR", - version = "0.1.16", + version = "0.1.18", lid = "", coalition = coalition.side.BLUE, template = "", @@ -236,6 +238,8 @@ AICSAR = { Altitude = 1500, UseEventEject = false, Delay = 100, + UseRescueZone = false, + RescueZone = nil, } -- TODO Messages @@ -304,8 +308,9 @@ AICSAR.RadioLength = { -- @param #string Helotemplate Helicopter template name. -- @param Wrapper.Airbase#AIRBASE FARP FARP object or Airbase from where to start. -- @param Core.Zone#ZONE MASHZone Zone where to drop pilots after rescue. +-- @param #number Helonumber Max number of alive Ai Helos at the same time. Defaults to three. -- @return #AICSAR self -function AICSAR:New(Alias,Coalition,Pilottemplate,Helotemplate,FARP,MASHZone) +function AICSAR:New(Alias,Coalition,Pilottemplate,Helotemplate,FARP,MASHZone,Helonumber) -- Inherit everything from FSM class. local self=BASE:Inherit(self, FSM:New()) @@ -373,7 +378,7 @@ function AICSAR:New(Alias,Coalition,Pilottemplate,Helotemplate,FARP,MASHZone) -- limit number of available helos at the same time self.limithelos = true - self.helonumber = 3 + self.helonumber = Helonumber or 3 -- localization self:InitLocalization() @@ -524,10 +529,20 @@ function AICSAR:InitLocalization() return self end +--- [User] Use a defined zone as area of operation and not the distance to FARP. +-- @param #AICSAR self +-- @param Core.Zone#ZONE Zone The operational zone to use. Downed pilots in this area will be rescued. Can be any known #ZONE type. +-- @return #AICSAR self +function AICSAR:SetUsingRescueZone(Zone) + self.UseRescueZone = true + self.RescueZone = Zone + return self +end + --- [User] Switch sound output on and use SRS output for sound files. -- @param #AICSAR self -- @param #boolean OnOff Switch on (true) or off (false). --- @param #string Path Path to your SRS Server Component, e.g. "C:\\\\Program Files\\\\DCS-SimpleRadio-Standalone" +-- @param #string Path Path to your SRS Server External Audio Component, e.g. "C:\\\\Program Files\\\\DCS-SimpleRadio-Standalone\\\\ExternalAudio" -- @param #number Frequency Defaults to 243 (guard) -- @param #number Modulation Radio modulation. Defaults to radio.modulation.AM -- @param #string SoundPath Where to find the audio files. Defaults to nil, i.e. add messages via "Sound to..." in the Mission Editor. @@ -538,7 +553,7 @@ function AICSAR:SetSRSRadio(OnOff,Path,Frequency,Modulation,SoundPath,Port) self.SRSRadio = OnOff and true self.SRSTTSRadio = false self.SRSFrequency = Frequency or 243 - self.SRSPath = Path or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone" + self.SRSPath = Path or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio" self.SRS:SetLabel("ACSR") self.SRS:SetCoalition(self.coalition) self.SRSModulation = Modulation or radio.modulation.AM @@ -556,7 +571,7 @@ end -- See `AICSAR:SetPilotTTSVoice()` and `AICSAR:SetOperatorTTSVoice()` -- @param #AICSAR self -- @param #boolean OnOff Switch on (true) or off (false). --- @param #string Path Path to your SRS Server Component, e.g. "E:\\\\Program Files\\\\DCS-SimpleRadio-Standalone" +-- @param #string Path Path to your SRS Server Component, e.g. "E:\\\\Program Files\\\\DCS-SimpleRadio-Standalone\\ExternalAudio" -- @param #number Frequency (Optional) Defaults to 243 (guard) -- @param #number Modulation (Optional) Radio modulation. Defaults to radio.modulation.AM -- @param #number Port (Optional) Port of the SRS, defaults to 5002. @@ -570,7 +585,7 @@ function AICSAR:SetSRSTTSRadio(OnOff,Path,Frequency,Modulation,Port,Voice,Cultur self.SRSTTSRadio = OnOff and true self.SRSRadio = false self.SRSFrequency = Frequency or 243 - self.SRSPath = Path or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone" + self.SRSPath = Path or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio" self.SRSModulation = Modulation or radio.modulation.AM self.SRSPort = Port or MSRS.port or 5002 if OnOff then @@ -693,7 +708,7 @@ function AICSAR:_EjectEventHandler(EventData) local _LandingPos = COORDINATE:NewFromVec3(_event.initiator:getPosition().p) local _country = _event.initiator:getCountry() local _coalition = coalition.getCountryCoalition( _country ) - local data = UTILS.DeepCopy(EventData) + --local data = UTILS.DeepCopy(EventData) Unit.destroy(_event.initiator) -- shagrat remove static Pilot model self:ScheduleOnce(self.Delay,self._DelayedSpawnPilot,self,_LandingPos,_coalition) end @@ -708,7 +723,14 @@ end -- @return #AICSAR self function AICSAR:_DelayedSpawnPilot(_LandingPos,_coalition) - local distancetofarp = _LandingPos:Get2DDistance(self.farp:GetCoordinate()) + local distancetofarp = _LandingPos:Get2DDistance(self.farp:GetCoordinate()) + if self.UseRescueZone == true and self.RescueZone ~= nil then + if self.RescueZone:IsCoordinateInZone(_LandingPos) then + distancetofarp = self.maxdistance - 10 + else + distancetofarp = self.maxdistance + 10 + end + end -- Mayday Message local Text,Soundfile,Soundlength,Subtitle = self.gettext:GetEntry("PILOTDOWN",self.locale) local text = "" @@ -795,7 +817,13 @@ function AICSAR:_EventHandler(EventData, FromEject) -- DONE: add distance check local distancetofarp = _LandingPos:Get2DDistance(self.farp:GetCoordinate()) - + if self.UseRescueZone == true and self.RescueZone ~= nil then + if self.RescueZone:IsCoordinateInZone(_LandingPos) then + distancetofarp = self.maxdistance - 10 + else + distancetofarp = self.maxdistance + 10 + end + end -- Mayday Message local Text,Soundfile,Soundlength,Subtitle = self.gettext:GetEntry("PILOTDOWN",self.locale) local text = "" @@ -817,7 +845,6 @@ function AICSAR:_EventHandler(EventData, FromEject) if _coalition == self.coalition then if self.verbose then MESSAGE:New(msgtxt,15,"AICSAR"):ToCoalition(self.coalition) - -- MESSAGE:New(msgtxt,15,"AICSAR"):ToLog() end if self.SRSRadio then local sound = SOUNDFILE:New(Soundfile,self.SRSSoundPath,Soundlength) @@ -869,6 +896,7 @@ function AICSAR:_GetFlight() :InitUnControlled(true) :OnSpawnGroup( function(Group) + Group:OptionPreferVerticalLanding() self:__HeloOnDuty(1,Group) end ) @@ -892,7 +920,7 @@ function AICSAR:_InitMission(Pilot,Index) --local pilotset = SET_GROUP:New() --pilotset:AddGroup(Pilot) - -- Cargo transport assignment. + -- Cargo transport assignment. local opstransport=OPSTRANSPORT:New(Pilot, pickupzone, self.farpzone) --opstransport:SetVerbosity(3) @@ -934,6 +962,10 @@ function AICSAR:_InitMission(Pilot,Index) helo:__UnloadingDone(5) end + function helo:OnAfterLandAtAirbase(From,Event,To,airbase) + helo:Despawn(2) + end + self.helos[Index] = helo return self @@ -984,7 +1016,9 @@ function AICSAR:_CheckHelos() local name = helo:GetName() self:T("Helo group "..name.." in state "..state) if state == "Arrived" then - helo:__Stop(5) + --helo:__Stop(5) + helo.OnAfterDead = nil + helo:Despawn(35) self.helos[_index] = nil end else @@ -1025,7 +1059,7 @@ function AICSAR:_CheckQueue(OpsGroup) if self:_CheckInMashZone(_pilot) then self:T("Pilot" .. _pilot.GroupName .. " rescued!") if OpsGroup then - OpsGroup:Despawn(10) + --OpsGroup:Despawn(10) else _pilot:Destroy(true,10) end From c9ac6d73e638dddddba46cb473aa206691d2bc03 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sat, 19 Jul 2025 18:36:03 +0200 Subject: [PATCH 100/234] #MANTIS - Better documented use of SA-10B/C/12/23 naming usage with launcher differences. --- Moose Development/Moose/Functional/Mantis.lua | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Moose Development/Moose/Functional/Mantis.lua b/Moose Development/Moose/Functional/Mantis.lua index 8ec4939d7..a10b90272 100644 --- a/Moose Development/Moose/Functional/Mantis.lua +++ b/Moose Development/Moose/Functional/Mantis.lua @@ -22,7 +22,7 @@ -- @module Functional.Mantis -- @image Functional.Mantis.jpg -- --- Last Update: May 2025 +-- Last Update: July 2025 ------------------------------------------------------------------------- --- **MANTIS** class, extends Core.Base#BASE @@ -125,10 +125,10 @@ -- * SA-2 (with V759 missile, e.g. "Red SAM SA-2 HDS") -- * SA-2 (with HQ-2 launcher, use HQ-2 in the group name, e.g. "Red SAM HQ-2" ) -- * SA-3 (with V601P missile, e.g. "Red SAM SA-3 HDS") --- * SA-10B (overlap with other SA-10 types, e.g. "Red SAM SA-10B HDS") --- * SA-10C (overlap with other SA-10 types, e.g. "Red SAM SA-10C HDS") --- * SA-12 (launcher dependent range, e.g. "Red SAM SA-12 HDS") --- * SA-23 (launcher dependent range, e.g. "Red SAM SA-23 HDS") +-- * SA-10B (overlap with other SA-10 types, e.g. "Red SAM SA-10B HDS" with 5P85CE launcher) +-- * SA-10C (overlap with other SA-10 types, e.g. "Red SAM SA-10C HDS" with 5P85SE launcher) +-- * SA-12 (launcher dependent range, e.g. "Red SAM SA-12 HDS 2" for the 9A82 variant and "Red SAM SA-12 HDS 1" for the 9A83 variant) +-- * SA-23 (launcher dependent range, e.g. "Red SAM SA-23 HDS 2" for the 9A82ME variant and "Red SAM SA-23 HDS 2" for the 9A83ME variant) -- -- The other HDS types work like the rest of the known SAM systems. -- @@ -406,10 +406,10 @@ MANTIS.SamDataHDS = { -- group name MUST contain HDS to ID launcher type correctly! ["SA-2 HDS"] = { Range=56, Blindspot=7, Height=30, Type="Medium", Radar="V759" }, ["SA-3 HDS"] = { Range=20, Blindspot=6, Height=30, Type="Short", Radar="V-601P" }, - ["SA-10C HDS 2"] = { Range=90, Blindspot=5, Height=25, Type="Long" , Radar="5P85DE ln"}, -- V55RUD - ["SA-10C HDS 1"] = { Range=90, Blindspot=5, Height=25, Type="Long" , Radar="5P85CE ln"}, -- V55RUD - ["SA-12 HDS 2"] = { Range=100, Blindspot=10, Height=25, Type="Long" , Radar="S-300V 9A82 l"}, - ["SA-12 HDS 1"] = { Range=75, Blindspot=1, Height=25, Type="Long" , Radar="S-300V 9A83 l"}, + ["SA-10B HDS"] = { Range=90, Blindspot=5, Height=25, Type="Long" , Radar="5P85CE ln"}, -- V55RUD + ["SA-10C HDS"] = { Range=75, Blindspot=5, Height=25, Type="Long" , Radar="5P85SE ln"}, -- V55RUD + ["SA-12 HDS 2"] = { Range=100, Blindspot=13, Height=30, Type="Long" , Radar="S-300V 9A82 l"}, + ["SA-12 HDS 1"] = { Range=75, Blindspot=6, Height=25, Type="Long" , Radar="S-300V 9A83 l"}, ["SA-23 HDS 2"] = { Range=200, Blindspot=5, Height=37, Type="Long", Radar="S-300VM 9A82ME" }, ["SA-23 HDS 1"] = { Range=100, Blindspot=1, Height=50, Type="Long", Radar="S-300VM 9A83ME" }, ["HQ-2 HDS"] = { Range=50, Blindspot=6, Height=35, Type="Medium", Radar="HQ_2_Guideline_LN" }, @@ -682,7 +682,7 @@ do -- TODO Version -- @field #string version - self.version="0.9.30" + self.version="0.9.31" self:I(string.format("***** Starting MANTIS Version %s *****", self.version)) --- FSM Functions --- @@ -1798,7 +1798,7 @@ do if self.Shorad and self.Shorad.ActiveGroups and self.Shorad.ActiveGroups[name] then activeshorad = true end - if IsInZone and not suppressed and not activeshorad then --check any target in zone and not currently managed by SEAD + if IsInZone and (not suppressed) and (not activeshorad) then --check any target in zone and not currently managed by SEAD if samgroup:IsAlive() then -- switch on SAM local switch = false @@ -1830,7 +1830,7 @@ do -- link in to SHORAD if available -- DONE: Test integration fully if self.ShoradLink and (Distance < self.ShoradActDistance or Distance < blind ) then -- don't give SHORAD position away too early - local Shorad = self.Shorad + local Shorad = self.Shorad --Functional.Shorad#SHORAD local radius = self.checkradius local ontime = self.ShoradTime Shorad:WakeUpShorad(name, radius, ontime) From 2f806801bc91dbcbbc089c1442759618c668019f Mon Sep 17 00:00:00 2001 From: smiki Date: Sun, 20 Jul 2025 11:48:35 +0200 Subject: [PATCH 101/234] [ADDED] `AUFTRAG:SetRepeatDelay` --- Moose Development/Moose/Ops/Auftrag.lua | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Ops/Auftrag.lua b/Moose Development/Moose/Ops/Auftrag.lua index cae2c17c4..e2e94d412 100644 --- a/Moose Development/Moose/Ops/Auftrag.lua +++ b/Moose Development/Moose/Ops/Auftrag.lua @@ -397,6 +397,7 @@ AUFTRAG = { conditionPush = {}, conditionSuccessSet = false, conditionFailureSet = false, + repeatDelay = 1, } --- Global mission counter. @@ -3002,6 +3003,16 @@ function AUFTRAG:SetRepeat(Nrepeat) return self end + +--- **[LEGION, COMMANDER, CHIEF]** Set the repeat delay in seconds after a mission is successful/failed. Only valid if the mission is handled by a LEGION (AIRWING, BRIGADE, FLEET) or higher level. +-- @param #AUFTRAG self +-- @param #number Nrepeat Repeat delay in seconds. Default 1. +-- @return #AUFTRAG self +function AUFTRAG:SetRepeatDelay(RepeatDelay) + self.repeatDelay = RepeatDelay + return self +end + --- **[LEGION, COMMANDER, CHIEF]** Set how many times the mission is repeated if it fails. Only valid if the mission is handled by a LEGION (AIRWING, BRIGADE, FLEET) or higher level. -- @param #AUFTRAG self -- @param #number Nrepeat Number of repeats. Default 0. @@ -5203,7 +5214,7 @@ function AUFTRAG:onafterSuccess(From, Event, To) -- Repeat mission. self:T(self.lid..string.format("Mission SUCCESS! Repeating mission for the %d time (max %d times) ==> Repeat mission!", self.repeated+1, N)) - self:Repeat() + self:__Repeat(self.repeatDelay) else @@ -5245,7 +5256,7 @@ function AUFTRAG:onafterFailed(From, Event, To) -- Repeat mission. self:T(self.lid..string.format("Mission FAILED! Repeating mission for the %d time (max %d times) ==> Repeat mission!", self.repeated+1, N)) - self:Repeat() + self:__Repeat(self.repeatDelay) else From b5a19528a148f484fdc86cb16cc5048c26632dfa Mon Sep 17 00:00:00 2001 From: smiki Date: Sun, 20 Jul 2025 12:11:57 +0200 Subject: [PATCH 102/234] [ADDED] `COMMANDER:SetMaxMissionsStartPerCycle` --- Moose Development/Moose/Ops/Commander.lua | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/Moose Development/Moose/Ops/Commander.lua b/Moose Development/Moose/Ops/Commander.lua index a29b2538b..f9037e678 100644 --- a/Moose Development/Moose/Ops/Commander.lua +++ b/Moose Development/Moose/Ops/Commander.lua @@ -136,6 +136,7 @@ COMMANDER = { awacsZones = {}, tankerZones = {}, limitMission = {}, + MaxMissionsAssignPerCycle = 1, } --- COMMANDER class version. @@ -1535,6 +1536,8 @@ function COMMANDER:CheckMissionQueue() end end + local missionsStarted = 0 + -- Loop over missions in queue. for _,_mission in pairs(self.missionqueue) do local mission=_mission --Ops.Auftrag#AUFTRAG @@ -1594,9 +1597,12 @@ function COMMANDER:CheckMissionQueue() -- Recruited assets but no requested escort available. Unrecruit assets! LEGION.UnRecruitAssets(assets, mission) end - - -- Only ONE mission is assigned. - return + + missionsStarted = missionsStarted + 1 + if missionsStarted >= self.maxMissionsAssignPerCycle then + return + end + end else @@ -1611,6 +1617,16 @@ function COMMANDER:CheckMissionQueue() end +--- Set how many missions can be assigned in a single status iteration. (eg. This is useful for persistent missions where you need to load all AUFTRAGs on mission start and then change it back to default) +--- Warning: Increasing this value will increase the number of missions started per iteration and thus may lead to performance issues if too many missions are started at once. +-- @param #COMMANDER self +-- @param #number Number of missions assigned per status iteration. Default is 1. +-- @return #COMMANDER self. +function COMMANDER:SetMaxMissionsAssignPerCycle(MaxMissionsAssignPerCycle) + self.maxMissionsAssignPerCycle = MaxMissionsAssignPerCycle or 1 + return self +end + --- Get cohorts. -- @param #COMMANDER self -- @param #table Legions Special legions. From aa8f3a824c3351fb26fcea5563c3883df6c209c1 Mon Sep 17 00:00:00 2001 From: smiki Date: Sun, 20 Jul 2025 12:12:31 +0200 Subject: [PATCH 103/234] [ADDED] `COMMANDER:SetMaxMissionsStartPerCycle` --- Moose Development/Moose/Ops/Commander.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Moose Development/Moose/Ops/Commander.lua b/Moose Development/Moose/Ops/Commander.lua index f9037e678..22a198b0e 100644 --- a/Moose Development/Moose/Ops/Commander.lua +++ b/Moose Development/Moose/Ops/Commander.lua @@ -1536,7 +1536,7 @@ function COMMANDER:CheckMissionQueue() end end - local missionsStarted = 0 + local missionsAssigned = 0 -- Loop over missions in queue. for _,_mission in pairs(self.missionqueue) do @@ -1598,8 +1598,8 @@ function COMMANDER:CheckMissionQueue() LEGION.UnRecruitAssets(assets, mission) end - missionsStarted = missionsStarted + 1 - if missionsStarted >= self.maxMissionsAssignPerCycle then + missionsAssigned = missionsAssigned + 1 + if missionsAssigned >= self.maxMissionsAssignPerCycle then return end From 1b18ae15972a9137eb254a61a3a8dceabb159ac0 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sun, 20 Jul 2025 14:03:33 +0200 Subject: [PATCH 104/234] #MANTIS - Added SAMP/T, SA-17 data correction, HDS explanations expanded --- Moose Development/Moose/Functional/Mantis.lua | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/Moose Development/Moose/Functional/Mantis.lua b/Moose Development/Moose/Functional/Mantis.lua index a10b90272..4b761e99f 100644 --- a/Moose Development/Moose/Functional/Mantis.lua +++ b/Moose Development/Moose/Functional/Mantis.lua @@ -111,7 +111,7 @@ -- * Silkworm (though strictly speaking this is a surface to ship missile) -- * SA-2, SA-3, SA-5, SA-6, SA-7, SA-8, SA-9, SA-10, SA-11, SA-13, SA-15, SA-19 -- * From IDF mod: STUNNER IDFA, TAMIR IDFA (Note all caps!) --- * From HDS (see note on HDS below): SA-2, SA-3, SA-10B, SA-10C, SA-12, SA-17, SA-20A, SA-20B, SA-23, HQ-2 +-- * From HDS (see note on HDS below): SA-2, SA-3, SA-10B, SA-10C, SA-12, SA-17, SA-20A, SA-20B, SA-23, HQ-2, SAMP/T Block 1, SAMP/T Block 1INT, SAMP/T Block2 -- -- * From SMA: RBS98M, RBS70, RBS90, RBS90M, RBS103A, RBS103B, RBS103AM, RBS103BM, Lvkv9040M -- **NOTE** If you are using the Swedish Military Assets (SMA), please note that the **group name** for RBS-SAM types also needs to contain the keyword "SMA" @@ -128,7 +128,8 @@ -- * SA-10B (overlap with other SA-10 types, e.g. "Red SAM SA-10B HDS" with 5P85CE launcher) -- * SA-10C (overlap with other SA-10 types, e.g. "Red SAM SA-10C HDS" with 5P85SE launcher) -- * SA-12 (launcher dependent range, e.g. "Red SAM SA-12 HDS 2" for the 9A82 variant and "Red SAM SA-12 HDS 1" for the 9A83 variant) --- * SA-23 (launcher dependent range, e.g. "Red SAM SA-23 HDS 2" for the 9A82ME variant and "Red SAM SA-23 HDS 2" for the 9A83ME variant) +-- * SA-23 (launcher dependent range, e.g. "Red SAM SA-23 HDS 2" for the 9A82ME variant and "Red SAM SA-23 HDS 1" for the 9A83ME variant) +-- * SAMP/T (launcher dependent range, e.g. "Blue SAM SAMPT Block 1 HDS" for Block 1, "Blue SAM SAMPT Block 1INT HDS", "Blue SAM SAMPT Block 2 HDS") -- -- The other HDS types work like the rest of the known SAM systems. -- @@ -274,6 +275,7 @@ MANTIS = { ClassName = "MANTIS", name = "mymantis", + version = "0.9.32", SAM_Templates_Prefix = "", SAM_Group = nil, EWR_Templates_Prefix = "", @@ -385,7 +387,7 @@ MANTIS.SamData = { ["HEMTT_C-RAM_Phalanx"] = { Range=2, Blindspot=0, Height=2, Type="Point", Radar="HEMTT_C-RAM_Phalanx", Point="true" }, -- units from HDS Mod, multi launcher options is tricky ["SA-10B"] = { Range=75, Blindspot=0, Height=18, Type="Medium" , Radar="SA-10B"}, - ["SA-17"] = { Range=50, Blindspot=3, Height=30, Type="Medium", Radar="SA-17" }, + ["SA-17"] = { Range=50, Blindspot=3, Height=50, Type="Medium", Radar="SA-17" }, ["SA-20A"] = { Range=150, Blindspot=5, Height=27, Type="Long" , Radar="S-300PMU1"}, ["SA-20B"] = { Range=200, Blindspot=4, Height=27, Type="Long" , Radar="S-300PMU2"}, ["HQ-2"] = { Range=50, Blindspot=6, Height=35, Type="Medium", Radar="HQ_2_Guideline_LN" }, @@ -408,11 +410,15 @@ MANTIS.SamDataHDS = { ["SA-3 HDS"] = { Range=20, Blindspot=6, Height=30, Type="Short", Radar="V-601P" }, ["SA-10B HDS"] = { Range=90, Blindspot=5, Height=25, Type="Long" , Radar="5P85CE ln"}, -- V55RUD ["SA-10C HDS"] = { Range=75, Blindspot=5, Height=25, Type="Long" , Radar="5P85SE ln"}, -- V55RUD + ["SA-17 HDS"] = { Range=50, Blindspot=3, Height=50, Type="Medium", Radar="SA-17 " }, ["SA-12 HDS 2"] = { Range=100, Blindspot=13, Height=30, Type="Long" , Radar="S-300V 9A82 l"}, ["SA-12 HDS 1"] = { Range=75, Blindspot=6, Height=25, Type="Long" , Radar="S-300V 9A83 l"}, ["SA-23 HDS 2"] = { Range=200, Blindspot=5, Height=37, Type="Long", Radar="S-300VM 9A82ME" }, ["SA-23 HDS 1"] = { Range=100, Blindspot=1, Height=50, Type="Long", Radar="S-300VM 9A83ME" }, ["HQ-2 HDS"] = { Range=50, Blindspot=6, Height=35, Type="Medium", Radar="HQ_2_Guideline_LN" }, + ["SAMPT Block 1 HDS"] = { Range=120, Blindspot=1, Height=20, Type="long", Radar="SAMPT_MLT_Blk1" }, -- Block 1 Launcher + ["SAMPT Block 1INT HDS"] = { Range=150, Blindspot=1, Height=25, Type="long", Radar="SAMPT_MLT_Blk1NT" }, -- Block 1-INT Launcher + ["SAMPT Block 2 HDS"] = { Range=200, Blindspot=10, Height=70, Type="long", Radar="SAMPT_MLT_Blk2" }, -- Block 2 Launcher } --- SAM data SMA @@ -680,9 +686,6 @@ do -- counter for SAM table updates self.checkcounter = 1 - -- TODO Version - -- @field #string version - self.version="0.9.31" self:I(string.format("***** Starting MANTIS Version %s *****", self.version)) --- FSM Functions --- @@ -2110,7 +2113,7 @@ do if self.debug and self.verbose then self:I(self.lid .. "Status Report") for _name,_state in pairs(self.SamStateTracker) do - self:I(string.format("Site %s\tStatus %s",_name,_state)) + self:I(string.format("Site %s | Status %s",_name,_state)) end end local interval = self.detectinterval * -1 From 0b37c909b32ba88e56dbe45f5adfc1d591458b4f Mon Sep 17 00:00:00 2001 From: frankiep95 <38260710+frankiep95@users.noreply.github.com> Date: Sun, 20 Jul 2025 16:58:33 -0400 Subject: [PATCH 105/234] Added VNAO Edits --- Moose Development/Moose/Ops/Airboss.lua | 851 ++++++++++++++++++++---- 1 file changed, 728 insertions(+), 123 deletions(-) diff --git a/Moose Development/Moose/Ops/Airboss.lua b/Moose Development/Moose/Ops/Airboss.lua index d47e6da06..fcf723279 100644 --- a/Moose Development/Moose/Ops/Airboss.lua +++ b/Moose Development/Moose/Ops/Airboss.lua @@ -1444,6 +1444,7 @@ AIRBOSS.PatternStep = { GROOVE_IC = "Groove In Close", GROOVE_AR = "Groove At the Ramp", GROOVE_IW = "Groove In the Wires", + GROOVE_IWs = "Groove In the Wires stopped?", -- VNAO Edit - Added GROOVE_AL = "Groove Abeam Landing Spot", GROOVE_LC = "Groove Level Cross", BOLTER = "Bolter Pattern", @@ -3080,12 +3081,12 @@ end --- Set up SRS for usage without sound files -- @param #AIRBOSS self --- @param #string PathToSRS Path to SRS TTS folder, e.g. "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio". +-- @param #string PathToSRS Path to SRS folder, e.g. "C:\\Program Files\\DCS-SimpleRadio-Standalone". -- @param #number Port Port of the SRS server, defaults to 5002. -- @param #string Culture (Optional, Airboss Culture) Culture, defaults to "en-US". -- @param #string Gender (Optional, Airboss Gender) Gender, e.g. "male" or "female". Defaults to "male". -- @param #string Voice (Optional, Airboss Voice) Set to use a specific voice. Will **override gender and culture** settings. --- @param #string GoogleCreds (Optional) Path to Google credentials, e.g. "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio\\yourgooglekey.json". +-- @param #string GoogleCreds (Optional) Path to Google credentials, e.g. "C:\\Program Files\\DCS-SimpleRadio-Standalone\\yourgooglekey.json". -- @param #number Volume (Optional) E.g. 0.75. Defaults to 1.0 (loudest). -- @param #table AltBackend (Optional) See MSRS for details. -- @return #AIRBOSS self @@ -4502,7 +4503,7 @@ function AIRBOSS:_InitStennis() -- Early break. self.BreakEarly.name = "Early Break" self.BreakEarly.Xmin = -UTILS.NMToMeters( 1 ) -- Not more than 1 NM behind the boat. Last check was at 0. - self.BreakEarly.Xmax = UTILS.NMToMeters( 5 ) -- Not more than 5 NM in front of the boat. Enough for late breaks? + self.BreakEarly.Xmax = UTILS.NMToMeters( 7 ) -- Not more than 5 NM in front of the boat. Enough for late breaks? -- VNAO EDIT - original value 5 self.BreakEarly.Zmin = -UTILS.NMToMeters( 2 ) -- Not more than 2 NM port. self.BreakEarly.Zmax = UTILS.NMToMeters( 1 ) -- Not more than 1 NM starboard. self.BreakEarly.LimitXmin = 0 -- Check and next step 0.2 NM port and in front of boat. @@ -4513,7 +4514,7 @@ function AIRBOSS:_InitStennis() -- Late break. self.BreakLate.name = "Late Break" self.BreakLate.Xmin = -UTILS.NMToMeters( 1 ) -- Not more than 1 NM behind the boat. Last check was at 0. - self.BreakLate.Xmax = UTILS.NMToMeters( 5 ) -- Not more than 5 NM in front of the boat. Enough for late breaks? + self.BreakLate.Xmax = UTILS.NMToMeters( 7 ) -- Not more than 5 NM in front of the boat. Enough for late breaks? -- VNAO EDIT - original value 5 self.BreakLate.Zmin = -UTILS.NMToMeters( 2 ) -- Not more than 2 NM port. self.BreakLate.Zmax = UTILS.NMToMeters( 1 ) -- Not more than 1 NM starboard. self.BreakLate.LimitXmin = 0 -- Check and next step 0.8 NM port and in front of boat. @@ -4524,7 +4525,7 @@ function AIRBOSS:_InitStennis() -- Abeam position. self.Abeam.name = "Abeam Position" self.Abeam.Xmin = -UTILS.NMToMeters( 5 ) -- Not more then 5 NM astern of boat. Should be LIG call anyway. - self.Abeam.Xmax = UTILS.NMToMeters( 5 ) -- Not more then 5 NM ahead of boat. + self.Abeam.Xmax = UTILS.NMToMeters( 7 ) -- Not more then 5 NM ahead of boat. --VNAO EDIT - original value 5 self.Abeam.Zmin = -UTILS.NMToMeters( 2 ) -- Not more than 2 NM port. self.Abeam.Zmax = 500 -- Not more than 500 m starboard. Must be port! self.Abeam.LimitXmin = -200 -- Check and next step 200 meters behind the ship. @@ -4603,7 +4604,7 @@ function AIRBOSS:_InitNimitz() self.carrierparam.wire1 = 55 -- Distance from stern to first wire. self.carrierparam.wire2 = 67 self.carrierparam.wire3 = 79 - self.carrierparam.wire4 = 92 + self.carrierparam.wire4 = 96 -- VNAO Edit - original value was 92 -- Landing distance. self.carrierparam.landingdist = self.carrierparam.sterndist+self.carrierparam.wire3 @@ -5096,6 +5097,7 @@ function AIRBOSS:SetVoiceOversLSOByRaynor( mizfolder ) self.LSOCall.N8.duration = 0.38 self.LSOCall.N9.duration = 0.34 self.LSOCall.PADDLESCONTACT.duration = 0.91 + self.LSOCall.POWERsoft.duration=0.9 -- VNAO Edit - Added self.LSOCall.POWER.duration = 0.45 self.LSOCall.RADIOCHECK.duration = 0.90 self.LSOCall.RIGHTFORLINEUP.duration = 0.70 @@ -5154,6 +5156,7 @@ function AIRBOSS:SetVoiceOversLSOByFF( mizfolder ) self.LSOCall.N9.duration = 0.40 self.LSOCall.PADDLESCONTACT.duration = 1.00 self.LSOCall.POWER.duration = 0.50 + self.LSOCall.POWERsoft.duration=0.9 -- VNAO Edit - Added self.LSOCall.RADIOCHECK.duration = 1.10 self.LSOCall.RIGHTFORLINEUP.duration = 0.80 self.LSOCall.ROGERBALL.duration = 1.00 @@ -5246,6 +5249,7 @@ function AIRBOSS:_InitVoiceOvers() HIGH = { file = "LSO-High", suffix = "ogg", loud = true, subtitle = "You're high", duration = 0.65, subduration = 1 }, LOW = { file = "LSO-Low", suffix = "ogg", loud = true, subtitle = "You're low", duration = 0.50, subduration = 1 }, POWER = { file = "LSO-Power", suffix = "ogg", loud = true, subtitle = "Power", duration = 0.50, subduration = 1 }, -- duration 0.45 was too short + POWERsoft={ file="LSO-Power-soft", suffix="ogg", loud=false, subtitle="Power-soft", duration=0.90, subduration=1 }, -- VNAO Edit - Added SLOW = { file = "LSO-Slow", suffix = "ogg", loud = true, subtitle = "You're slow", duration = 0.65, subduration = 1 }, FAST = { file = "LSO-Fast", suffix = "ogg", loud = true, subtitle = "You're fast", duration = 0.70, subduration = 1 }, ROGERBALL = { file = "LSO-RogerBall", suffix = "ogg", loud = false, subtitle = "Roger ball", duration = 1.00, subduration = 2 }, @@ -5407,13 +5411,13 @@ function AIRBOSS:_GetAircraftAoA( playerData ) elseif tomcat then -- F-14A/B Tomcat parameters (taken from NATOPS). Converted from units 0-30 to degrees. -- Currently assuming a linear relationship with 0=-10 degrees and 30=+40 degrees as stated in NATOPS. - aoa.SLOW = self:_AoAUnit2Deg( playerData, 17.0 ) -- 18.33 --17.0 units - aoa.Slow = self:_AoAUnit2Deg( playerData, 16.0 ) -- 16.67 --16.0 units - aoa.OnSpeedMax = self:_AoAUnit2Deg( playerData, 15.5 ) -- 15.83 --15.5 units + aoa.SLOW = self:_AoAUnit2Deg( playerData, 17.5 ) -- 18.33 --17.0 units -- VNAO Edit - Original value 17 + aoa.Slow = self:_AoAUnit2Deg( playerData, 16.5 ) -- 16.67 --16.0 units -- VNAO Edit - Original value 16 + aoa.OnSpeedMax = self:_AoAUnit2Deg( playerData, 16.0 ) -- 15.83 --15.5 units -- VNAO Edit - Original value 15.5 aoa.OnSpeed = self:_AoAUnit2Deg( playerData, 15.0 ) -- 15.0 --15.0 units - aoa.OnSpeedMin = self:_AoAUnit2Deg( playerData, 14.5 ) -- 14.17 --14.5 units - aoa.Fast = self:_AoAUnit2Deg( playerData, 14.0 ) -- 13.33 --14.0 units - aoa.FAST = self:_AoAUnit2Deg( playerData, 13.0 ) -- 11.67 --13.0 units + aoa.OnSpeedMin = self:_AoAUnit2Deg( playerData, 14.0 ) -- 14.17 --14.5 units -- VNAO Edit - Original value 14.5 + aoa.Fast = self:_AoAUnit2Deg( playerData, 13.5 ) -- 13.33 --14.0 units -- VNAO Edit - Original value 14 + aoa.FAST = self:_AoAUnit2Deg( playerData, 12.5 ) -- 11.67 --13.0 units -- VNAO Edit - Original value 13 elseif goshawk then -- T-45C Goshawk parameters. aoa.SLOW = 8.00 -- 19 @@ -5427,13 +5431,13 @@ function AIRBOSS:_GetAircraftAoA( playerData ) -- A-4E-C Skyhawk parameters from https://forums.eagle.ru/showpost.php?p=3703467&postcount=390 -- Note that these are arbitrary UNITS and not degrees. We need a conversion formula! -- Github repo suggests they simply use a factor of two to get from degrees to units. - aoa.SLOW = 9.50 -- =19.0/2 - aoa.Slow = 9.25 -- =18.5/2 - aoa.OnSpeedMax = 9.00 -- =18.0/2 - aoa.OnSpeed = 8.75 -- =17.5/2 8.1 - aoa.OnSpeedMin = 8.50 -- =17.0/2 - aoa.Fast = 8.25 -- =17.5/2 - aoa.FAST = 8.00 -- =16.5/2 + aoa.SLOW = 10.50 -- =19.0/2 -- VNAO Edit - Original value 9.50 + aoa.Slow = 9.50 -- =18.5/2 -- VNAO Edit - Original value 9.25 + aoa.OnSpeedMax = 9.25 -- =18.0/2 -- VNAO Edit - Original value 9.00 + aoa.OnSpeed = 8.75 -- =17.5/2 8.1 -- VNAO Edit - Original value 8.75 + aoa.OnSpeedMin = 8.25 -- =17.0/2 -- VNAO Edit - Original value 8.50 + aoa.Fast = 8.00 -- =17.5/2 -- VNAO Edit - Original value 8.25 + aoa.FAST = 7.00 -- =16.5/2 -- VNAO Edit - Original value 8.0 elseif harrier then -- AV-8B Harrier parameters. Tuning done on the Fast AoA to allow for abeam and ninety at Nozzles 55. Pene testing aoa.SLOW = 16.0 @@ -8075,6 +8079,32 @@ function AIRBOSS:_CheckPlayerStatus() -- TODO: This might cause problems if the CCA is set to be very small! if unit:IsInZone( self.zoneCCA ) then + -- VNAO Edit - Added wrapped up call to LSO grading + if playerData.step==AIRBOSS.PatternStep.WAKE then-- VNAO Edit - Added + if math.abs(playerData.unit:GetRoll())>35 and math.abs(playerData.unit:GetRoll())<=40 then-- VNAO Edit - Added + playerData.wrappedUpAtWakeLittle = true -- VNAO Edit - Added + elseif math.abs(playerData.unit:GetRoll()) >40 and math.abs(playerData.unit:GetRoll())<=45 then-- VNAO Edit - Added + playerData.wrappedUpAtWakeFull = true-- VNAO Edit - Added + elseif math.abs(playerData.unit:GetRoll()) >45 then-- VNAO Edit - Added + playerData.wrappedUpAtWakeUnderline = true -- VNAO Edit - Added + elseif math.abs(playerData.unit:GetRoll()) <20 and math.abs(playerData.unit:GetRoll()) >=10 then -- VNAO Edit - Added a new AA comment based on discussion with Lipps today, and going to replace the AA at the X with the original LUL comments + playerData.AAatWakeLittle = true -- VNAO Edit - Added + elseif math.abs(playerData.unit:GetRoll()) <10 and math.abs(playerData.unit:GetRoll()) >=2 then -- VNAO Edit - Added a new AA comment based on discussion with Lipps today, and going to replace the AA at the X with the original LUL comments + playerData.AAatWakeFull = true -- VNAO Edit - Added + elseif math.abs(playerData.unit:GetRoll()) <2 then -- VNAO Edit - Added a new AA comment based on discussion with Lipps today, and going to replace the AA at the X with the original LUL comments + playerData.AAatWakeUnderline = true -- VNAO Edit - Added + else -- VNAO Edit - Added + end -- VNAO Edit - Added + + if math.abs(playerData.unit:GetAoA())>= 15 then -- VNAO Edit - Added + playerData.AFU = true -- VNAO Edit - Added + elseif math.abs(playerData.unit:GetAoA())<= 5 then -- VNAO Edit - Added + playerData.AFU = true -- VNAO Edit - Added + else -- VNAO Edit - Added + end -- VNAO Edit - Added + end-- VNAO Edit - Added + + -- Display aircraft attitude and other parameters as message text. if playerData.attitudemonitor then self:_AttitudeMonitor( playerData ) @@ -8306,7 +8336,7 @@ function AIRBOSS:_SetTimeInGroove( playerData ) -- Set time in the groove if playerData.TIG0 then - playerData.Tgroove = timer.getTime() - playerData.TIG0 + playerData.Tgroove = timer.getTime() - playerData.TIG0 - 1.5 -- VNAO Edit - Subtracting an extra 1.5 else playerData.Tgroove = 999 end @@ -9427,7 +9457,19 @@ function AIRBOSS:_DirtyUp( playerData ) if inzone then -- Hint for player about altitude, AoA etc. - self:_PlayerHint( playerData ) + playerData.Tgroove = timer.getTime() - playerData.TIG0 - 1.5 -- VNAO Edit - Subtracting an extra 1.5 + + -- VNAO Edit - Added wrapped up call to LSO grading + playerData.wrappedUpAtWakeLittle = false -- VNAO Edit - Added + playerData.wrappedUpAtWakeFull = false -- VNAO Edit - Added + playerData.wrappedUpAtWakeUnderline = false -- VNAO Edit - Added + playerData.wrappedUpAtStartLittle = false -- VNAO Edit - Added + playerData.wrappedUpAtStartFull = false -- VNAO Edit - Added + playerData.wrappedUpAtStartUnderline = false -- VNAO Edit - Added + playerData.AAatWakeLittle = false -- VNAO Edit - Added + playerData.AAatWakeFull = false -- VNAO Edit - Added + playerData.AAatWakeUnderline = false -- VNAO Edit - Added + playerData.AFU = false -- VNAO Edit - Added -- Radio call "Say/Fly needles". Delayed by 10/15 seconds. if playerData.actype == AIRBOSS.AircraftCarrier.HORNET @@ -9522,7 +9564,7 @@ end --- Break entry for case I/II recoveries. -- @param #AIRBOSS self -- @param #AIRBOSS.PlayerData playerData Player data table. -function AIRBOSS:_BreakEntry( playerData ) +function AIRBOSS:_BreakEntry( playerData ) --Adam Edits begin 7/24/23 -- Get distances between carrier and player unit (parallel and perpendicular to direction of movement of carrier) local X, Z = self:_GetDistances( playerData.unit ) @@ -9533,17 +9575,111 @@ function AIRBOSS:_BreakEntry( playerData ) return end + local stern = self:_GetSternCoord() + local coord = playerData.unit:GetCoordinate() + local dist = coord:Get2DDistance( stern ) + + --adam edits + local playerCallsign = playerData.unit:GetCallsign() + --trigger.action.outText(' Hornet is hook down on pre-break entry for testing hook argument ', 5) + --trigger.action.outText(' Hornet callsign is '..playerCallsign, 5) + local playerName = playerData.name + local unit = playerData.unit + + --local playerName = unit:GetName() + --trigger.action.outText(' Hornet name is '..playerName, 5) + local unitClient = Unit.getByName(unit:GetName()) + local hookArgument = unitClient:getDrawArgumentValue(25) + local hookArgument_Tomcat = unitClient:getDrawArgumentValue(1305) + local speedMPS = playerData.unit:GetVelocityMPS() + local speedKTS = UTILS.MpsToKnots( speedMPS ) + local player_alt = playerData.unit:GetAltitude() + + player_alt_feet = player_alt * 3.28 + player_alt_feet = player_alt_feet/10 + player_alt_feet = math.floor(player_alt_feet)*10 + + local player_velocity_round = speedKTS * 1.00 + player_velocity_round = player_velocity_round/10 + player_velocity_round = math.floor(player_velocity_round)*10 + + local player_alt_feet = player_alt * 3.28 + player_alt_feet = player_alt_feet/10 + player_alt_feet = math.floor(player_alt_feet)*10 + + local Play_SH_Sound = USERSOUND:New( "Airboss Soundfiles/GreatBallsOfFire.ogg" ) + local Play_666SH_Sound = USERSOUND:New( "Airboss Soundfiles/Runninwiththedevil.ogg" ) + local playerType = playerData.actype + + + + if dist <1000 and clientSHBFlag == false then + + if speedKTS > 450 and speedKTS < 590 then + if player_alt_feet < 1500 then + if hookArgument > 0 or hookArgument_Tomcat > 0 then + --trigger.action.outText(' 1 - Hornet is hook down so SHB!!!! Hook argument is: '..hookArgument, 5) + playerData.shb = true + trigger.action.outText(playerName..' performing a Sierra Hotel Break in a '..playerType, 10) + local sh_message_to_discord = ('**'..playerName..' is performing a Sierra Hotel Break in a '..playerType..' at '..player_velocity_round..' knots and '..player_alt_feet..' feet!**') + HypeMan.sendBotMessage(sh_message_to_discord) + Play_SH_Sound:ToAll() + clientSHBFlag = true + else + --trigger.action.outText(' Hornet is hook up on initial and just fast so no SHB. Hook argument is: '..hookArgument, 5) + playerData.shb = false + end + -- Next step: Early Break. + else + end + elseif speedKTS > 589 then + if player_alt_feet < 625 and player_alt_feet >575 then --SHB 666 + if hookArgument > 0 or hookArgument_Tomcat > 0 then + --trigger.action.outText(' 1 - Hornet is hook down so SHB!!!! Hook argument is: '..hookArgument, 5) + playerData.shb = true + trigger.action.outText(playerName..' performing a 666 Sierra Hotel Break in a '..playerType, 10) + local sh_message_to_discord = ('**'..playerName..' is performing a 666 Sierra Hotel Break in a '..playerType..' at '..player_velocity_round..' knots and '..player_alt_feet..' feet!**') + HypeMan.sendBotMessage(sh_message_to_discord) + Play_666SH_Sound:ToAll() + clientSHBFlag = true + else + --trigger.action.outText(' Hornet is hook up on initial and just fast so no SHB. Hook argument is: '..hookArgument, 5) + playerData.shb = false + end + else + if hookArgument > 0 or hookArgument_Tomcat > 0 then + --trigger.action.outText(' 1 - Hornet is hook down so SHB!!!! Hook argument is: '..hookArgument, 5) + playerData.shb = true + trigger.action.outText(playerName..' performing a Sierra Hotel Break in a '..playerType, 10) + local sh_message_to_discord = ('**'..playerName..' is performing a Sierra Hotel Break in a '..playerType..' at '..player_velocity_round..' knots and '..player_alt_feet..' feet!**') + HypeMan.sendBotMessage(sh_message_to_discord) + Play_SH_Sound:ToAll() + clientSHBFlag = true + else + --trigger.action.outText(' Hornet is hook up on initial and just fast so no SHB. Hook argument is: '..hookArgument, 5) + playerData.shb = false + end + end + else + --trigger.action.outText(' Hornet is less than 400 kts so not SHB.... ', 5) + end + else + --trigger.action.outText(' ******TEST OF of Break Entry and distance to CVN is: '..dist, 5) + + end + + -- Check if we are in front of the boat (diffX > 0). if self:_CheckLimits( X, Z, self.BreakEntry ) then + --trigger.action.outText(' 2 - Hornet is hook down on break entry for testing hook argument ', 5) -- Hint for player about altitude, AoA etc. self:_PlayerHint( playerData ) - - -- Next step: Early Break. self:_SetPlayerStep( playerData, AIRBOSS.PatternStep.EARLYBREAK ) + clientSHBFlag = false end -end +end--Adam Edits end 7/24/23 --- Break. -- @param #AIRBOSS self @@ -9679,6 +9815,18 @@ end -- @param #AIRBOSS.PlayerData playerData Player data table. function AIRBOSS:_Ninety( playerData ) + -- VNAO Edit - Added wrapped up call to LSO grading + playerData.wrappedUpAtWakeLittle = false -- VNAO Edit - Added + playerData.wrappedUpAtWakeFull = false -- VNAO Edit - Added + playerData.wrappedUpAtWakeUnderline = false -- VNAO Edit - Added + playerData.wrappedUpAtStartLittle = false -- VNAO Edit - Added + playerData.wrappedUpAtStartFull = false -- VNAO Edit - Added + playerData.wrappedUpAtStartUnderline = false -- VNAO Edit - Added + playerData.AAatWakeLittle = false -- VNAO Edit - Added + playerData.AAatWakeFull = false -- VNAO Edit - Added + playerData.AAatWakeUnderline = false -- VNAO Edit - Added + playerData.AFU = false -- VNAO Edit - Added + -- Get distances between carrier and player unit (parallel and perpendicular to direction of movement of carrier) local X, Z = self:_GetDistances( playerData.unit ) @@ -9782,6 +9930,9 @@ function AIRBOSS:_GetGrooveData( playerData ) groovedata.AoA = playerData.unit:GetAoA() groovedata.GSE = self:_Glideslope( playerData.unit ) groovedata.LUE = self:_Lineup( playerData.unit, true ) + groovedata.LUEwire = self:_LineupWIRE( playerData.unit, true ) -- VNAO Edit - Added + groovedata.LeftNozzle = self:_NozzleArgumentLeft( playerData.unit ) -- VNAO Edit - Added + groovedata.RightNozzle = self:_NozzleArgumentRight( playerData.unit ) -- VNAO Edit - Added groovedata.Roll = playerData.unit:GetRoll() groovedata.Pitch = playerData.unit:GetPitch() groovedata.Yaw = playerData.unit:GetYaw() @@ -9863,6 +10014,7 @@ function AIRBOSS:_Groove( playerData ) local RIM = UTILS.NMToMeters( 0.500 ) -- In the Middle 0.50 = 926 m (middle one third of the glideslope) local RIC = UTILS.NMToMeters( 0.250 ) -- In Close 0.25 = 463 m (last one third of the glideslope) local RAR = UTILS.NMToMeters( 0.040 ) -- At the Ramp. 0.04 = 75 m + local RIW = UTILS.NMToMeters( -0.020 ) -- In the wires. 0.04 = 75 m -- VNAO Edit - Added -- Groove data. local groovedata = self:_GetGrooveData( playerData ) @@ -9886,7 +10038,8 @@ function AIRBOSS:_Groove( playerData ) local glideslopeError = groovedata.GSE local AoA = groovedata.AoA - if rho <= RXX and playerData.step == AIRBOSS.PatternStep.GROOVE_XX and (math.abs( groovedata.Roll ) <= 4.0 and playerData.unit:IsInZone( self:_GetZoneLineup() )) then + -- if rho <= RXX and playerData.step == AIRBOSS.PatternStep.GROOVE_XX and (math.abs( groovedata.Roll ) <= 4.0 or playerData.unit:IsInZone( self:_GetZoneLineup() )) then -- VNAO Edit - Commented out + if rho <= RXX and playerData.step == AIRBOSS.PatternStep.GROOVE_XX and (math.abs( groovedata.Roll ) <= 3.5 or playerData.unit:IsInZone( self:_GetZoneLineup() )) then -- VNAO Edit - Added -- Start time in groove playerData.TIG0 = timer.getTime() @@ -9936,7 +10089,8 @@ function AIRBOSS:_Groove( playerData ) else self:_SetPlayerStep( playerData, AIRBOSS.PatternStep.GROOVE_IW ) end - + elseif rho <= RIW and playerData.step == AIRBOSS.PatternStep.GROOVE_IW then -- VNAO Edit - Added + playerData.groove.IW = UTILS.DeepCopy( groovedata ) -- VNAO Edit - Added elseif rho <= RAR and playerData.step == AIRBOSS.PatternStep.GROOVE_AL then -- Store data. @@ -10071,6 +10225,58 @@ function AIRBOSS:_Groove( playerData ) -- Distance in NM. local d = UTILS.MetersToNM( rho ) + -- VNAO Edit - Added wrapped up call to LSO grading + if playerData.case ~=3 then -- VNAO Edit - Added + -- env.info("ADAM AIRBOSS EDIT- function AIRBOSS:_Groove(playerData) - playerData.case ~= 3, proceeding with checks") -- VNAO Edit - Added + if playerData.wrappedUpAtWakeUnderline == true or playerData.wrappedUpAtStartUnderline == true then -- VNAO Edit - Added + gd.WrappedUp="_WU_" -- VNAO Edit - Added + -- env.info("ADAM AIRBOSS EDIT- function AIRBOSS:_Groove(playerData) - UNDERLINE WU comment should be added for player: "..playerData.name) -- VNAO Edit - Added + elseif playerData.wrappedUpAtWakeUnderline == false and playerData.wrappedUpAtStartUnderline == false then -- VNAO Edit - Added + if playerData.wrappedUpAtWakeFull == true or playerData.wrappedUpAtStartFull == true then -- VNAO Edit - Added + gd.WrappedUp="WU" -- VNAO Edit - Added + -- env.info("ADAM AIRBOSS EDIT- function AIRBOSS:_Groove(playerData) - FULL WU comment should be added for player: "..playerData.name) -- VNAO Edit - Added + elseif playerData.wrappedUpAtStartFull == false then -- VNAO Edit - Added + if playerData.wrappedUpAtWakeLittle == true or playerData.wrappedUpAtStartLittle == true then -- VNAO Edit - Added + gd.WrappedUp="(WU)" -- VNAO Edit - Added + -- env.info("ADAM AIRBOSS EDIT- function AIRBOSS:_Groove(playerData) - little WU comment should be added for player: "..playerData.name) -- VNAO Edit - Added + end -- VNAO Edit - Added + end -- VNAO Edit - Added + else -- VNAO Edit - Added + -- gd.WrappedUp="" -- VNAO Edit - Added + -- env.info("ADAM AIRBOSS EDIT- function AIRBOSS:_Groove(playerData) - NO WU comment should be added for player: "..playerData.name) -- VNAO Edit - Added + end -- VNAO Edit - Added + + if playerData.AAatWakeUnderline == true then -- VNAO Edit - Added + gd.AngledApch="_AA_" -- VNAO Edit - Added + -- env.info("ADAM AIRBOSS EDIT- function AIRBOSS:_Groove(playerData) - UNDERLINE AA comment should be added for player: "..playerData.name) -- VNAO Edit - Added + elseif playerData.AAatWakeUnderline == false then -- VNAO Edit - Added + if playerData.AAatWakeFull == true then -- VNAO Edit - Added + gd.AngledApch="AA" -- VNAO Edit - Added + -- env.info("ADAM AIRBOSS EDIT- function AIRBOSS:_Groove(playerData) - FULL AA comment should be added for player: "..playerData.name) -- VNAO Edit - Added + elseif playerData.AAatWakeFull == false then -- VNAO Edit - Added + if playerData.AAatWakeLittle == true then -- VNAO Edit - Added + gd.AngledApch="(AA)" -- VNAO Edit - Added + -- env.info("ADAM AIRBOSS EDIT- function AIRBOSS:_Groove(playerData) - little AA comment should be added for player: "..playerData.name) -- VNAO Edit - Added + end -- VNAO Edit - Added + end -- VNAO Edit - Added + else -- VNAO Edit - Added + -- gd.AngledApch="" -- VNAO Edit - Added + -- env.info("ADAM AIRBOSS EDIT- function AIRBOSS:_Groove(playerData) - NO AA comment should be added for player: "..playerData.name) -- VNAO Edit - Added + end -- VNAO Edit - Added + + if playerData.AFU == true then -- VNAO Edit - Added + gd.AFU="AFU" -- VNAO Edit - Added + -- env.info("ADAM AIRBOSS EDIT- function AIRBOSS:_Groove(playerData) - AFU comment should be added for player: "..playerData.name) -- VNAO Edit - Added + else -- VNAO Edit - Added + -- env.info("ADAM AIRBOSS EDIT- function AIRBOSS:_Groove(playerData) - NO AFU comment should be added for player: "..playerData.name) -- VNAO Edit - Added + end -- VNAO Edit - Added + else -- VNAO Edit - Added + -- gd.WrappedUp="" -- VNAO Edit - Added + -- gd.AngledApch="" -- VNAO Edit - Added + --gd.AFU="" -- VNAO Edit - Added + -- env.info("ADAM AIRBOSS EDIT- function AIRBOSS:_Groove(playerData) - CASE 3, don't add WU, AA or AFU comments at all for player: "..playerData.name) -- VNAO Edit - Added + end + -- Drift on lineup. if rho >= RAR and rho <= RIM then if gd.LUE > 0.22 and lineupError < -0.22 then @@ -10608,13 +10814,13 @@ function AIRBOSS:_Trapped( playerData ) -- Message to player. local text = string.format( "Trapped %d-wire.", wire ) if wire == 3 then - text = text .. " Well done!" + text = text .. " " -- VNAO Edit - Removed comment text elseif wire == 2 then - text = text .. " Not bad, maybe you even get the 3rd next time." + text = text .. " " -- VNAO Edit - Removed comment text elseif wire == 4 then - text = text .. " That was scary. You can do better than this!" + text = text .. " " -- VNAO Edit - Removed comment text elseif wire == 1 then - text = text .. " Try harder next time!" + text = text .. " " -- VNAO Edit - Removed comment text end -- Message to player. @@ -11363,6 +11569,41 @@ function AIRBOSS:_AttitudeMonitor( playerData ) text = text .. string.format( "\nGamma=%.1f° | Rho=%.1f°", relhead, phi ) end + -- VNAO Edit: for testing the damn line up in the wires! + -- VNAO Edit: F-14A Nozzle: R-433, L-434, R Burner- 435, L Burner - 436 + local lueWire = self:_LineupWIRE( playerData.unit, true ) + text = text .. string.format( "\nLineUpForWireCalls=%.2f° | lineup for Groove calls=%.2f°", lueWire or 0, lue or 0)-- VNAO Edit - Added + + local unitClient = Unit.getByName(unit:GetName()) -- VNAO Edit - Added + local hornet = playerData.actype == AIRBOSS.AircraftCarrier.HORNET -- VNAO Edit - Added + local tomcat = playerData.actype == AIRBOSS.AircraftCarrier.F14A or playerData.actype == AIRBOSS.AircraftCarrier.F14B -- VNAO Edit - Added + + if hornet then -- VNAO Edit - Added + local nozzlePosL = 0 -- VNAO Edit - Added + local burnerPosL = unitClient:getDrawArgumentValue(28) -- VNAO Edit - Added + if burnerPosL < 0.2 then -- VNAO Edit - Added + nozzlePosL = unitClient:getDrawArgumentValue(89) -- VNAO Edit - Added + else -- VNAO Edit - Added + nozzlePosL = 0 -- VNAO Edit - Added + end -- VNAO Edit - Added + + local nozzlePosR = 0 -- VNAO Edit - Added + local burnerPosR = unitClient:getDrawArgumentValue(29) -- VNAO Edit - Added + if burnerPosR < 0.2 then -- VNAO Edit - Added + nozzlePosR = unitClient:getDrawArgumentValue(90) -- VNAO Edit - Added + else -- VNAO Edit - Added + nozzlePosR = 0 -- VNAO Edit - Added + end -- VNAO Edit - Added + + text = text .. string.format( "\n Left Nozzle position=%.2f | Right Nozzle position=%.2f ", nozzlePosL, nozzlePosR ) -- VNAO Edit - Added + end -- VNAO Edit - Added + + if tomcat then -- VNAO Edit - Added + local nozzlePosL = unitClient:getDrawArgumentValue(434) -- VNAO Edit - Added + local nozzlePosR = unitClient:getDrawArgumentValue(433) -- VNAO Edit - Added + text = text .. string.format( "\n Left Nozzle position=%.2f | Right Nozzle position=%.2f ", nozzlePosL, nozzlePosR ) -- VNAO Edit - Added + end -- VNAO Edit - Added + MESSAGE:New( text, 1, nil, true ):ToClient( playerData.client ) end @@ -11495,6 +11736,111 @@ function AIRBOSS:_Lineup( unit, runway ) return lineup end +-- VNAO Edit - Added this function +--- Get line up of player wrt to carrier. +-- @param #AIRBOSS self +-- @param Wrapper.Unit#UNIT unit Aircraft unit. +-- @param #boolean runway If true, include angled runway. +-- @return #number Line up with runway heading in degrees. 0 degrees = perfect line up. +1 too far left. -1 too far right. +function AIRBOSS:_LineupWIRE( unit, runway ) -- VNAO Edit - Added + + -- Landing coordinate + local landingcoord = self:_GetOptLandingCoordinateWIRE() -- VNAO Edit - Added + + -- Vector to landing coord. + local A = landingcoord:GetVec3() -- VNAO Edit - Added + + -- Vector to player. + local B = unit:GetVec3() -- VNAO Edit - Added + + -- Vector from player to carrier. + local C = UTILS.VecSubstract( A, B ) -- VNAO Edit - Added + + -- Only in 2D plane. + C.y = 0.0 -- VNAO Edit - Added + + -- Orientation of carrier. + local X = self.carrier:GetOrientationX() -- VNAO Edit - Added + X.y = 0.0 -- VNAO Edit - Added + + -- Rotate orientation to angled runway. + if runway then -- VNAO Edit - Added + X = UTILS.Rotate2D( X, -self.carrierparam.rwyangle ) -- VNAO Edit - Added + end -- VNAO Edit - Added + + -- Projection of player pos on x component. + local x = UTILS.VecDot( X, C ) -- VNAO Edit - Added + + -- Orientation of carrier. + local Z = self.carrier:GetOrientationZ() -- VNAO Edit - Added + Z.y = 0.0 -- VNAO Edit - Added + + -- Rotate orientation to angled runway. + if runway then -- VNAO Edit - Added + Z = UTILS.Rotate2D( Z, -self.carrierparam.rwyangle ) -- VNAO Edit - Added + end -- VNAO Edit - Added + + -- Projection of player pos on z component. + local z = UTILS.VecDot( Z, C ) -- VNAO Edit - Added + + --- + local lineup = math.deg( math.atan2( z, x ) ) -- VNAO Edit - Added + + return lineup -- VNAO Edit - Added +end -- VNAO Edit - Added + +-- VNAO Edit - Added this function +--- Get L/R Nozzle Position from Argument and L/R Burner Argument +-- @param #AIRBOSS self +-- @param Wrapper.Unit#UNIT unit Aircraft unit. +-- @return #number Left Nozzle position argument +function AIRBOSS:_NozzleArgumentLeft( unit ) -- VNAO Edit - Added + --Arguments for HORNET L burner and R burner are 28 and 29 respectively and >.2 indicates burner active + --Nozzle position greater than 0.3 for the hornet indicates either idle or burner + --if Lnoz > 0.6 and Rnoz > 0.6 is current check for EG + local unitClient = Unit.getByName(unit:GetName()) -- VNAO Edit - Added + local typeName = unit:GetTypeName() -- VNAO Edit - Added + local nozzlePosL = 0 -- VNAO Edit - Added + local burnerPosL = 0 -- VNAO Edit - Added + if typeName == "FA-18C_hornet" then -- VNAO Edit - Added + burnerPosL = unitClient:getDrawArgumentValue(28) -- VNAO Edit - Added + if burnerPosL < 0.2 then -- VNAO Edit - Added + nozzlePosL = unitClient:getDrawArgumentValue(89) -- VNAO Edit - Added + else -- VNAO Edit - Added + nozzlePosL = 0 -- VNAO Edit - Added + end -- VNAO Edit - Added + elseif typeName == "F-14A-135-GR" or typeName == "F-14B" then -- VNAO Edit - Added + nozzlePosL = unitClient:getDrawArgumentValue(434) -- VNAO Edit - Added + end -- VNAO Edit - Added + + return nozzlePosL -- VNAO Edit - Added +end -- VNAO Edit - Added + +-- VNAO Edit - Added this function +--- Get L/R Nozzle Position from Argument and L/R Burner Argument +-- @param #AIRBOSS self +-- @param Wrapper.Unit#UNIT unit Aircraft unit. +-- @return #number Right Nozzle position argument +function AIRBOSS:_NozzleArgumentRight( unit ) -- VNAO Edit - Added + local unitClient = Unit.getByName(unit:GetName()) -- VNAO Edit - Added + local typeName = unit:GetTypeName() -- VNAO Edit - Added + local nozzlePosR = 0 -- VNAO Edit - Added + local burnerPosR = 0 -- VNAO Edit - Added + + if typeName == "FA-18C_hornet" then -- VNAO Edit - Added + burnerPosR = unitClient:getDrawArgumentValue(29) -- VNAO Edit - Added + if burnerPosR < 0.2 then -- VNAO Edit - Added + nozzlePosR = unitClient:getDrawArgumentValue(90) -- VNAO Edit - Added + else -- VNAO Edit - Added + nozzlePosR = 0 -- VNAO Edit - Added + end -- VNAO Edit - Added + elseif typeName == "F-14A-135-GR" or typeName == "F-14B" then -- VNAO Edit - Added + nozzlePosR = unitClient:getDrawArgumentValue(433) -- VNAO Edit - Added + end -- VNAO Edit - Added + return nozzlePosR -- VNAO Edit - Added +end -- VNAO Edit - Added + + --- Get altitude of aircraft wrt carrier deck. Should give zero when the aircraft touched down. -- @param #AIRBOSS self -- @param Wrapper.Unit#UNIT unit Aircraft unit. @@ -11560,6 +11906,39 @@ function AIRBOSS:_GetOptLandingCoordinate() return self.landingcoord end +-- VNAO Edit - dded this whole function +--- Get optimal landing position of the aircraft. Usually between second and third wire. In case of Tarawa, Canberrra, Juan Carlos and America we take the abeam landing spot 120 ft above and 21 ft abeam the 7.5 position, for the Juan Carlos I, HMS Invincible, and HMS Hermes and Invincible it is 120 ft above and 21 ft abeam the 5 position. For CASE III it is 120ft directly above the landing spot. +-- @param #AIRBOSS self +-- @return Core.Point#COORDINATE Optimal landing coordinate. +function AIRBOSS:_GetOptLandingCoordinateWIRE() + + -- Start with stern coordiante. + self.landingcoord:UpdateFromCoordinate( self:_GetSternCoord() ) + + -- Final bearing. + local FB=self:GetFinalBearing(false) + + -- Cse + local case=self.case + + -- set Case III V/STOL abeam landing spot over deck -- Pene Testing + + + + -- Ideally we want to land between 2nd and 3rd wire. + if self.carrierparam.wire3 then + -- We take the position of the 3rd wire to approximately account for the length of the aircraft. + self.landingcoord:Translate( self.carrierparam.wire3 + 500, FB, true, true )-- adding 80 meter to wire to see if this is far enough to keep tracking a good lineup error (50 meters not enough), went from 250 meters to 500 meters 12/23/23, the more distance out front the less the error sensitivity down deck. I've checked the location of the landing spot 500 meters out front of 3 wire on CL with flares and smoke, appears to be dead on. Not sure why there's still this small difference between lined up left and right differences. + end + + -- Add 2 meters to account for aircraft height. + self.landingcoord.y = self.landingcoord.y + 2 + + + --self.landingcoord:FlareGreen() --for testing the lineup spot translated out in front of the carrier landing area by 500 meters. Appears good. + return self.landingcoord +end + --- Get landing spot on Tarawa and others. -- @param #AIRBOSS self -- @return Core.Point#COORDINATE Primary landing spot coordinate. @@ -11861,7 +12240,8 @@ function AIRBOSS:GetHeadingIntoWind_new( vdeck, magnetic, coord ) local magvar= magnetic and self.magvar or 0 -- Ship heading so cross wind is min for the given wind. - local intowind = (540 + (windto - magvar + math.deg(theta) )) % 360 + -- local intowind = (540 + (windto - magvar + math.deg(theta) )) % 360 -- VNAO Edit: Using old heading into wind algorithm + local intowind = self:GetHeadingIntoWind_old(vdeck) -- VNAO Edit: Using old heading into wind algorithm return intowind, v end @@ -12137,6 +12517,10 @@ function AIRBOSS:_LSOadvice( playerData, glideslopeError, lineupError ) -- "Power." self:RadioTransmission( self.LSORadio, self.LSOCall.POWER, false, nil, nil, true ) advice = advice + self.LSOCall.POWER.duration + elseif glideslopeError= 25 then --Circuit added + grade = "_LIG_" --Circuit added + -- Time in groove for AV-8B elseif playerData.actype == AIRBOSS.AircraftCarrier.AV8B and t < 55 then -- VSTOL Late Hover stop selection too fast to Abeam LDG Spot AV-8B. grade = "FAST V/STOL Groove" @@ -12253,7 +12644,7 @@ function AIRBOSS:_EvalGrooveTime( playerData ) end -- The unicorn! - if t >= 16.4 and t <= 16.6 then + if t >= 16.49 and t <= 16.6 then grade = "_OK_" end @@ -12277,21 +12668,28 @@ function AIRBOSS:_LSOgrade( playerData ) local function count( base, pattern ) return select( 2, string.gsub( base, pattern, "" ) ) end - + local TIG = "" -- Analyse flight data and convert to LSO text. + if playerData.Tgroove and playerData.Tgroove <= 360 and playerData.case < 3 then --Circuit Added + TIG = self:_EvalGrooveTime( playerData ) --Circuit Added + end --Circuit Added local GXX, nXX = self:_Flightdata2Text( playerData, AIRBOSS.GroovePos.XX ) local GIM, nIM = self:_Flightdata2Text( playerData, AIRBOSS.GroovePos.IM ) local GIC, nIC = self:_Flightdata2Text( playerData, AIRBOSS.GroovePos.IC ) local GAR, nAR = self:_Flightdata2Text( playerData, AIRBOSS.GroovePos.AR ) + local GIW, nIW = self:_Flightdata2Text( playerData, AIRBOSS.GroovePos.IW ) -- VNAO Edit - Added -- VTOL approach, which is graded differently (currently only Harrier). local vtol=playerData.actype==AIRBOSS.AircraftCarrier.AV8B -- Put everything together. - local G = GXX .. " " .. GIM .. " " .. " " .. GIC .. " " .. GAR + local G = GXX .. " " .. GIM .. " " .. " " .. GIC .. " " .. GAR .. " " .. GIW .. " " .. TIG -- VNAO Edit - Added .. " " .. GIW Circuit added TIG + + local gradeWithDeviations = GXX .. "[" .. nXX .. "] " .. GIM .. "[" .. nIM .. "] " .. GIC .. "[" .. nIC .. "] " .. GAR .. "[" .. nAR .. "] " .. GIW .. "[" .. nIW .. "]" -- VNAO Edit - Added + env.info("LSO Grade [with deviation count]: " .. gradeWithDeviations) -- VNAO Edit - Added -- Count number of minor/small nS, normal nN and major/large deviations nL. - local N=nXX+nIM+nIC+nAR + local N=nXX+nIM+nIC+nAR+nIW -- VNAO Edit - Added +nIW local nL=count(G, '_')/2 local nS=count(G, '%(') local nN=N-nS-nL @@ -12299,17 +12697,30 @@ function AIRBOSS:_LSOgrade( playerData ) -- Groove time 15-18.99 sec for a unicorn. Or 60-65 for V/STOL unicorn. local Tgroove=playerData.Tgroove - local TgrooveUnicorn=Tgroove and (Tgroove>=15.0 and Tgroove<=18.99) or false + local TgrooveUnicorn=Tgroove and (Tgroove>=16.49 and Tgroove<=16.59) or false -- VNAO Edit - Original values 15.0/18.99 local TgrooveVstolUnicorn=Tgroove and (Tgroove>=60.0 and Tgroove<=65.0)and playerData.actype==AIRBOSS.AircraftCarrier.AV8B or false local grade local points - if N == 0 and (TgrooveUnicorn or TgrooveVstolUnicorn or playerData.case==3) then - -- No deviations, should be REALLY RARE! - grade = "_OK_" - points = 5.0 - G = "Unicorn" - else + -- if N == 0 and (TgrooveUnicorn or TgrooveVstolUnicorn or playerData.case==3) then -- VNAO Edit - Removed TgrooveUnicorn and case 3 as a factor + if N == 0 and TgrooveVstolUnicorn then -- VNAO Edit - Removed TgrooveUnicorn and case 3 as a factor + -- No deviations, should be REALLY RARE! + grade = "_OK_" + points = 5.0 + G = "Unicorn" + end -- VNAO Edit - Added + if N==0 and TgrooveUnicorn then -- VNAO Edit - Added + -- No deviations, should be REALLY RARE! -- VNAO Edit - Added + if playerData.wire == 3 then -- VNAO Edit - Added + grade="_OK_" -- VNAO Edit - Added + points=5.0 -- VNAO Edit - Added + G="Unicorn" -- VNAO Edit - Added + else -- VNAO Edit - Added + grade="OK" -- VNAO Edit - Added + points=4.0 -- VNAO Edit - Added + end -- VNAO Edit - Added + + else if vtol then @@ -12384,6 +12795,7 @@ function AIRBOSS:_LSOgrade( playerData ) text = text .. "# of normal deviations = " .. nN .. "\n" text = text .. "# of small deviations ( = " .. nS .. "\n" self:T2( self.lid .. text ) + env.info(text)-- VNAO Edit - Added -- Special cases. if playerData.wop then @@ -12452,6 +12864,20 @@ function AIRBOSS:_LSOgrade( playerData ) end end + + -- VNAO EDIT: Subtract 1pt from overall grade if it is a 1 wire. If it's already a 1pt pass, ignore. + if playerData.wire == 1 and points > 1 then -- VNAO EDIT: added + if points == 4 then -- VNAO EDIT: added + points = 3 -- VNAO EDIT: added + grade = "(OK)" -- VNAO EDIT: added + elseif points == 3 then -- VNAO EDIT: added + points = 2 -- VNAO EDIT: added + grade = "--" -- VNAO EDIT: added + end -- VNAO EDIT: added + end -- VNAO EDIT: added + + env.info("Returning: " .. grade .. " " .. points .. " " .. G) + return grade, points, G end @@ -12485,26 +12911,34 @@ function AIRBOSS:_Flightdata2Text( playerData, groovestep ) local AOA = fdata.AoA local GSE = fdata.GSE local LUE = fdata.LUE + local LUEwire = fdata.LUEwire -- VNAO Edit - Added + local Lnoz = fdata.LeftNozzle -- VNAO Edit - Added + local Rnoz = fdata.RightNozzle -- VNAO Edit - Added local ROL = fdata.Roll + local GT = fdata.GT -- Circuit Added -- Aircraft specific AoA values. local acaoa = self:_GetAircraftAoA( playerData ) -- Angled Approach. - local P = nil - if step == AIRBOSS.PatternStep.GROOVE_XX and ROL <= 4.0 and playerData.case < 3 then - if LUE > self.lue.RIGHT then - P = underline( "AA" ) - elseif LUE > self.lue.RightMed then - P = "AA " - elseif LUE > self.lue.Right then - P = little( "AA" ) + -- VNAO Edit - changed this to regualr LUL at X, made my own Angled Approach check starting at the wake based on angle of bank less than 15 degrees/10 degrees/2 degrees + local P = nil -- VNAO Edit - Added + if step == AIRBOSS.PatternStep.GROOVE_XX and ROL <= 3.5 and playerData.case < 3 then -- VNAO Edit - Changed, original ROL val 4.0 + if LUE > 3.2 then -- VNAO Edit - Original value self.lue.RIGHT + -- P = underline( "AA" ) + P = underline( "LUL") -- VNAO Edit - Added + elseif LUE > 2.2 then -- VNAO Edit - Original value self.lue.RightMed + -- P = "AA " + P="LUL" -- VNAO Edit - Added + elseif LUE > 1.2 then -- VNAO Edit - Original value self.lue.Right + -- P = little( "AA" ) + P= little( "LUL") -- VNAO Edit - Added end end -- Overshoot Start. local O = nil - if step == AIRBOSS.PatternStep.GROOVE_XX then + if step == AIRBOSS.PatternStep.GROOVE_XX and playerData.case < 3 then -- VNAO Edit - Added case 3 check if LUE < self.lue.LEFT then O = underline( "OS" ) elseif LUE < self.lue.Left then @@ -12516,100 +12950,262 @@ function AIRBOSS:_Flightdata2Text( playerData, groovestep ) -- Speed via AoA. Depends on aircraft type. local S = nil - if AOA > acaoa.SLOW then - S = underline( "SLO" ) - elseif AOA > acaoa.Slow then - S = "SLO" - elseif AOA > acaoa.OnSpeedMax then - S = little( "SLO" ) - elseif AOA < acaoa.FAST then - S = underline( "F" ) - elseif AOA < acaoa.Fast then - S = "F" - elseif AOA < acaoa.OnSpeedMin then - S = little( "F" ) - end + if step~=AIRBOSS.PatternStep.GROOVE_IW then -- VNAO Edit - Added To avoid getting an AOA or GS grade in the wires... let's just check left or right in the wires + if AIRBOSS.PatternStep.GROOVE_AR and playerData.waveoff == true and playerData.owo == true then -- VNAO Edit - Added + -- env.info('Adam MOOSE Edit -AR and waved off so do not add AOA or GS errors to comments ') -- VNAO Edit - Added + else -- VNAO Edit - Added + -- Speed via AoA. Depends on aircraft type. + if AOA > acaoa.SLOW then + S = underline( "SLO" ) + elseif AOA > acaoa.Slow then + S = "SLO" + elseif AOA > acaoa.OnSpeedMax then + S = little( "SLO" ) + elseif AOA < acaoa.FAST then + S = underline( "F" ) + elseif AOA < acaoa.Fast then + S = "F" + elseif AOA < acaoa.OnSpeedMin then + S = little( "F" ) + end - -- Glideslope/altitude. Good [-0.3, 0.4] asymmetric! - local A = nil - if GSE > self.gle.HIGH then - A = underline( "H" ) - elseif GSE > self.gle.High then - A = "H" - elseif GSE > self.gle._max then - A = little( "H" ) - elseif GSE < self.gle.LOW then - A = underline( "LO" ) - elseif GSE < self.gle.Low then - A = "LO" - elseif GSE < self.gle._min then - A = little( "LO" ) - end + -- Glideslope/altitude. Good [-0.3, 0.4] asymmetric! + local A = nil + if GSE > self.gle.HIGH then + A = underline( "H" ) + elseif GSE > self.gle.High then + A = "H" + elseif GSE > self.gle._max then + A = little( "H" ) + elseif GSE < self.gle.LOW then + A = underline( "LO" ) + elseif GSE < self.gle.Low then + A = "LO" + elseif GSE < self.gle._min then + A = little( "LO" ) + end + end -- VNAO Edit - Added + end -- VNAO Edit - Added + + local stepMod=self:_GS(step) -- VNAO Edit - Added - -- Line up. XX Step replaced by Overshoot start (OS). Good [-0.5, 0.5] local D = nil - if LUE > self.lue.RIGHT then - D = underline( "LUL" ) - elseif LUE > self.lue.Right then - D = "LUL" - elseif LUE > self.lue._max then - D = little( "LUL" ) - elseif playerData.case < 3 then - if LUE < self.lue.LEFT and step ~= AIRBOSS.PatternStep.GROOVE_XX then - D = underline( "LUR" ) - elseif LUE < self.lue.Left and step ~= AIRBOSS.PatternStep.GROOVE_XX then - D = "LUR" - elseif LUE < self.lue._min and step ~= AIRBOSS.PatternStep.GROOVE_XX then - D = little( "LUR" ) - end - elseif playerData.case == 3 then - if LUE < self.lue.LEFT then - D = underline( "LUR" ) - elseif LUE < self.lue.Left then - D = "LUR" - elseif LUE < self.lue._min then - D = little( "LUR" ) - end + local DW = nil + local Rol = nil -- VNAO Edit - Added + local Noz = nil -- VNAO Edit - Added + -- VNAO Edit - Now replacing LUL with AA at Groove start for case 1 and 2, to fix problem with getting a full LUL with an (AA) and still getting a 4.0 OK + -- if playerData.case < 3 then -- VNAO Edit - Added + if AIRBOSS.PatternStep.GROOVE_AR and playerData.waveoff == true and playerData.owo == true then + -- env.info('Adam MOOSE Edit -AR and waved off so do not add LU errors to comments ') + else + if LUE > self.lue.RIGHT and step ~= AIRBOSS.PatternStep.GROOVE_XX and step~=AIRBOSS.PatternStep.GROOVE_IW then -- VNAO Edit - Changed + D = underline( "LUL" ) -- VNAO Edit - Changed + elseif LUE > self.lue.Right and step ~= AIRBOSS.PatternStep.GROOVE_XX and step~=AIRBOSS.PatternStep.GROOVE_IW then -- VNAO Edit - Changed + D = "LUL" -- VNAO Edit - Changed + elseif LUE > self.lue._max and step ~= AIRBOSS.PatternStep.GROOVE_XX and step~=AIRBOSS.PatternStep.GROOVE_IW then -- VNAO Edit - Changed + D = little( "LUL" ) -- VNAO Edit - Changed + elseif LUE < self.lue.LEFT and step ~= AIRBOSS.PatternStep.GROOVE_XX and step~=AIRBOSS.PatternStep.GROOVE_IW then -- VNAO Edit - Changed + D = underline( "LUR" ) -- VNAO Edit - Changed + elseif LUE < self.lue.Left and step ~= AIRBOSS.PatternStep.GROOVE_XX and step~=AIRBOSS.PatternStep.GROOVE_IW then -- VNAO Edit - Changed + D = "LUR" -- VNAO Edit - Changed + elseif LUE < self.lue._min and step ~= AIRBOSS.PatternStep.GROOVE_XX and step~=AIRBOSS.PatternStep.GROOVE_IW then -- VNAO Edit - Changed + D = little( "LUR" ) -- VNAO Edit - Changed + end -- VNAO Edit - Changed end + --[[ + elseif playerData.case == 3 then -- VNAO Edit - Changed + if LUE>self.lue.RIGHT then -- VNAO Edit - Changed + D=underline("LUL") -- VNAO Edit - Changed + elseif LUE>self.lue.Right then -- VNAO Edit - Changed + D="LUL" -- VNAO Edit - Changed + elseif LUE>self.lue._max then -- VNAO Edit - Changed + D=little("LUL") -- VNAO Edit - Changed + elseif LUE < self.lue.LEFT then -- VNAO Edit - Changed + D = underline( "LUR" ) -- VNAO Edit - Changed + elseif LUE < self.lue.Left then -- VNAO Edit - Changed + D = "LUR" -- VNAO Edit - Changed + elseif LUE < self.lue._min then -- VNAO Edit - Changed + D = little( "LUR" ) -- VNAO Edit - Changed + end -- VNAO Edit - Changed + end -- VNAO Edit - Changed +--]] + if step == AIRBOSS.PatternStep.GROOVE_IW and playerData.waveoff == false and playerData.owo == false then -- VNAO Edit - Added check for waveoff so we don't get any IN THE WIRE comments if its a WO + -- env.info('Adam MOOSE Edit -IW code: checking for Landing Left or Landing Right, lue: '..LUEwire) + -- env.info("Adam MOOSE Edit -IW code: ROLL IN THE WIRES: "..ROL) + + if LUEwire>1.2 then -- VNAO Edit - Added by using real time attitude monitor and using the ladders as a reference for distance down the deck, focusing on ladder rungs 4-8 but using specifiically values at ((rung 4 12/24/23) 12/24/23), average rung 3 and 4 after testing 12/27 + -- env.info("Adam MOOSE Edit -IW code: Line up > 1.2, _LL_") + DW=underline("LL")-- VNAO Edit - Added + elseif LUEwire>0.4 then -- VNAO Edit - Added by using real time attitude monitor and using the ladders as a reference for distance down the deck, focusing on ladder rungs 4-8 but using specifiically values at (rung 4 12/24/23), average rung 3 and 4 after testing 12/27 + -- env.info("Adam MOOSE Edit -IW code: Line up > 0.4, LL") + DW="LL"-- VNAO Edit - Added + elseif LUEwire>0.25 then -- VNAO Edit - Added by using real time attitude monitor and using the ladders as a reference for distance down the deck, focusing on ladder rungs 4-8 but using specifiically values at (rung 4 12/24/23), average rung 3 and 4 after testing 12/27 + -- env.info("Adam MOOSE Edit -IW code: Line up > 0.25, (LL)") + DW=little("LL")-- VNAO Edit - Added + elseif LUEwire<-1.17 then -- VNAO Edit - Added by using real time attitude monitor and using the ladders as a reference for distance down the deck, focusing on ladder rungs 4-8 but using specifiically values at (rung 4 12/24/23), average rung 3 and 4 after testing 12/27 + -- env.info("Adam MOOSE Edit -IW code: Line up < -1.17, _LR_") + DW=underline("LR")-- VNAO Edit - Added + elseif LUEwire<-0.46 then -- VNAO Edit - Added by using real time attitude monitor and using the ladders as a reference for distance down the deck, focusing on ladder rungs 4-8 but using specifiically values at (rung 4 12/24/23), average rung 3 and 4 after testing 12/27 + -- env.info("Adam MOOSE Edit -IW code: Line up < -0.46, LR") + DW="LR"-- VNAO Edit - Added + elseif LUEwire<-0.25 then -- VNAO Edit - Added by using real time attitude monitor and using the ladders as a reference for distance down the deck, focusing on ladder rungs 4-8 but using specifiically values at (rung 4 12/24/23), average rung 3 and 4 after testing 12/27 + -- env.info("Adam MOOSE Edit -IW code: Line up < -0.25, (LR)") + DW=little("LR")-- VNAO Edit - Added + else-- VNAO Edit - Added + -- env.info('Adam MOOSE Edit -IW code: checking for Landing Left or Landing Right: NO LINEUP ERROR DECTECTED ') + -- env.info("Adam MOOSE Edit -IW code: NO LINEUP ERORR DECTECTED ") + end-- VNAO Edit - Added + + if ROL > 5 and ROL <= 10 then-- VNAO Edit - Added + -- env.info("Adam MOOSE Edit -IW code: ROLL GREATER THAN 5 DEGREES, maybe a (LRWD) ") + Rol=little("LRWD")-- VNAO Edit - Added + elseif ROL > 10 and ROL <= 15 then-- VNAO Edit - Added + -- env.info("Adam MOOSE Edit -IW code: ROLL GREATER THAN 10 DEGREES, maybe a LRWD ") + Rol=("LRWD")-- VNAO Edit - Added + elseif ROL > 15 then-- VNAO Edit - Added + -- env.info("Adam MOOSE Edit -IW code: ROLL GREATER THAN 20 DEGREES, maybe a _LRWD_ ") + Rol=underline("LRWD")-- VNAO Edit - Added + elseif ROL < -5 and ROL >= -10 then-- VNAO Edit - Added + -- env.info("Adam MOOSE Edit -IW code: ROLL GREATER THAN 5 DEGREES, maybe a (LLWD) ") + Rol=little("LLWD")-- VNAO Edit - Added + elseif ROL < -10 and ROL >= -15 then-- VNAO Edit - Added + -- env.info("Adam MOOSE Edit -IW code: ROLL GREATER THAN 10 DEGREES, maybe a LLWD ") + Rol=("LLWD")-- VNAO Edit - Added + elseif ROL < -15 then-- VNAO Edit - Added + -- env.info("Adam MOOSE Edit -IW code: ROLL GREATER THAN 20 DEGREES, maybe a _LLWD_ ") + Rol=underline("LLWD")-- VNAO Edit - Added + else-- VNAO Edit - Added + -- env.info("Adam MOOSE Edit -IW code: ROLL is acceptable, less than 5 degrees left or right ") + end-- VNAO Edit - Added + + + + local hornet = playerData.actype == AIRBOSS.AircraftCarrier.HORNET-- VNAO Edit - Added + local tomcat = playerData.actype == AIRBOSS.AircraftCarrier.F14A or playerData.actype == AIRBOSS.AircraftCarrier.F14B-- VNAO Edit - Added + + if hornet then-- VNAO Edit - Added + if Lnoz > 0.6 and Rnoz > 0.6 then -- VNAO Edit - Added check them both, it's possilbe there could be a single engine landing and one is in idle perhaps? + -- env.info("Adam MOOSE Edit -IW code: Throttles maybe close to idle? EGIW? L:"..Lnoz.." R: "..Rnoz) + Noz = underline("EG")-- VNAO Edit - Added + else-- VNAO Edit - Added + -- env.info("Adam MOOSE Edit -IW code: Throttles ok position- L:"..Lnoz.." R: "..Rnoz) + end-- VNAO Edit - Added + end-- VNAO Edit - Added + + --[[ if tomcat then-- VNAO Edit - Added + if Lnoz > 0.9 and Rnoz > 0.9 then -- VNAO Edit - Added Appears that when engines are idle nozzle arguments are Zero. Anything more than idle is close to 1 (0.95 to be exact) and Burner reduces to 0.3 + -- env.info("Adam MOOSE Edit -IW code: Throttles maybe close to idle? EGIW? L:"..Lnoz.." R: "..Rnoz) + Noz = underline("EG")-- VNAO Edit - Added + else-- VNAO Edit - Added + -- env.info("Adam MOOSE Edit -IW code: Throttles ok position- L:"..Lnoz.." R: "..Rnoz) + end-- VNAO Edit - Added + end-- VNAO Edit - Added ]] + + if playerData.Tgroove and playerData.Tgroove <= 360 and playerData.case < 3 then --Circuit Added + local grooveTime = playerData.Tgroove --Circuit Added + if grooveTime > 19 or grooveTime < 15 then --Circuit Added + GT = "" --Circuit Added + end --Circuit Added + end --Circuit Added + + end-- VNAO Edit - Added -- Compile. local G = "" local n = 0 - -- Fly trough. + + -- VNAO Edit - Added WU, AA and AFU calls to LSO grading + if stepMod == "XX" then -- VNAO Edit - Added + if playerData.case < 3 then -- VNAO Edit - Added + if fdata.WrappedUp then -- VNAO Edit - Added + env.info("Adding WrappedUp deviation.") + G=G..fdata.WrappedUp -- VNAO Edit - Added + n=n + 1 -- VNAO Edit - Added + -- env.info('MOOSE/AIRBOSS- MOD - GRADE.... you`RE GETTING WU`D') + end -- VNAO Edit - Added + if fdata.AngledApch then -- VNAO Edit - Added + env.info("Adding AngledApch deviation.") + G=G..fdata.AngledApch -- VNAO Edit - Added + n=n+1 -- VNAO Edit - Added + -- env.info('Adam MOOSE Edit -AA code: Function- _Flightdata2Text: Trying to add AA comment only to the "Start" in comments for player: '..playerData.name) + -- env.info('MOOSE/AIRBOSS- MOD - GRADE.... you`RE GETTING AA`D') + end -- VNAO Edit - Added + if fdata.AFU then -- VNAO Edit - Added + env.info("Adding AFU deviation.") + G=G..fdata.AFU -- VNAO Edit - Added + n=n+1 -- VNAO Edit - Added + -- env.info('Adam MOOSE Edit -AFU code: Function- _Flightdata2Text: Trying to add AFU comment only to the "Start" in comments for player: '..playerData.name) + -- env.info('MOOSE/AIRBOSS- MOD - GRADE....you`RE GETTING AFU`D') + end + end -- VNAO Edit - Added + end -- VNAO Edit - Added + + -- Fly through. if fdata.FlyThrough then G = G .. fdata.FlyThrough end -- Angled Approach - doesn't affect score, advisory only. - if P then - G = G .. P - n = n - end + -- if P then -- VNAO Edit - Commented out + -- G = G .. P -- VNAO Edit - Commented out + -- n = n + 1 -- VNAO Edit - Added + 1 -- VNAO Edit - Commented out + -- end -- VNAO Edit - Commented out -- Speed. if S then + env.info("Adding speed deviation.")--VNAO Added G = G .. S n = n + 1 end -- Glide slope. if A then + env.info("Adding altitude deviation.")--VNAO Added G = G .. A n = n + 1 end -- Line up. if D then + env.info("Adding line up deviation.")--VNAO Added G = G .. D n = n + 1 end -- Drift in Lineup if fdata.Drift then + env.info("Adding drift deviation.")--VNAO Added G = G .. fdata.Drift n = n -- Drift doesn't affect score, advisory only. end -- Overshoot. if O then + env.info("Adding overshoot deviation.")--VNAO Added G = G .. O n = n + 1 end + if DW then -- VNAO Edit - Added + -- env.info("Adam MOOSE Edit -IW code:TRYING TO ADD COMMENT LANDED LEFT/RIGHT OF CENTER LINE ") -- VNAO Edit - Added + env.info("Adding landed L/R deviation.") + G = G .. DW -- VNAO Edit - Added + n = n + 1 -- VNAO Edit - Added + end -- VNAO Edit - Added + + if Rol then -- VNAO Edit - Added + -- env.info("Adam MOOSE Edit -IW code:TRYING TO ADD COMMENT LANDED LEFT/RIGHT WING DOWN ") -- VNAO Edit - Added + env.info("Adding landed rol deviation.") + G = G .. Rol -- VNAO Edit - Added + n = n + 1 -- VNAO Edit - Added + end -- VNAO Edit - Added + + if Noz then -- VNAO Edit - Added + -- env.info("Adam MOOSE Edit -IW code:TRYING TO ADD COMMENT EG ") -- VNAO Edit - Added + env.info("Adding eased guns deviation.") + G = G .. Noz -- VNAO Edit - Added + n = n + 1-- try to add 3 to get an automatic no grade. -- VNAO Edit - Added + end -- VNAO Edit - Added + + if GT then --Circuit Added + G = G .. GT --Circuit Added + n = n + 1 --Circuit Added + end --Circuit Added + -- Add current step. local step = self:_GS( step ) step = step:gsub( "XX", "X" ) @@ -13324,6 +13920,7 @@ function AIRBOSS:_Debrief( playerData ) Points = points end + -- My LSO grade. local mygrade = {} -- #AIRBOSS.LSOgrade mygrade.grade = grade @@ -13380,7 +13977,8 @@ function AIRBOSS:_Debrief( playerData ) -- Time in the groove. Only Case I/II and not pattern WO. if playerData.Tgroove and playerData.Tgroove <= 360 and playerData.case < 3 then - text = text .. string.format( "\nTime in the groove %.1f seconds: %s", playerData.Tgroove, self:_EvalGrooveTime( playerData ) ) + -- text = text .. string.format( "\nTime in the groove %.1f seconds: %s", playerData.Tgroove, self:_EvalGrooveTime( playerData ) ) --Circuit changed removed groove comment + text = text .. string.format( "\nTime in the groove %.1f seconds.", playerData.Tgroove ) end end @@ -16835,6 +17433,17 @@ function AIRBOSS:_RequestEmergency( _unitName ) -- Cleared. text = "affirmative, you can bypass the pattern and are cleared for final approach!" + -- VNAO Edit - Added wrapped up call to LSO grading + playerData.wrappedUpAtWakeLittle = false -- VNAO Edit - Added + playerData.wrappedUpAtWakeFull = false -- VNAO Edit - Added + playerData.wrappedUpAtWakeUnderline = false -- VNAO Edit - Added + playerData.wrappedUpAtStartLittle = false -- VNAO Edit - Added + playerData.wrappedUpAtStartFull = false -- VNAO Edit - Added + playerData.wrappedUpAtStartUnderline = false -- VNAO Edit - Added + playerData.AAatWakeLittle = false -- VNAO Edit - Added + playerData.AAatWakeFull = false -- VNAO Edit - Added + playerData.AAatWakeUnderline = false -- VNAO Edit - Added + -- Now, if player is in the marshal or waiting queue he will be removed. But the new leader should stay in or not. local lead = self:_GetFlightLead( playerData ) @@ -18717,8 +19326,4 @@ function AIRBOSS:onafterLSOGrade(From, Event, To, playerData, grade) self.funkmanSocket:SendTable(result) end -end - ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +end \ No newline at end of file From 8c92a578ed14c0456cfe52055da429bd9af67a65 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Mon, 21 Jul 2025 14:50:04 +0200 Subject: [PATCH 106/234] #UTILS - added UTILS.SpawnMASHStatics() --- Moose Development/Moose/Utilities/Utils.lua | 113 ++++++++++++++++++++ 1 file changed, 113 insertions(+) diff --git a/Moose Development/Moose/Utilities/Utils.lua b/Moose Development/Moose/Utilities/Utils.lua index 17f6bc039..b6ac21de1 100644 --- a/Moose Development/Moose/Utilities/Utils.lua +++ b/Moose Development/Moose/Utilities/Utils.lua @@ -4259,6 +4259,119 @@ function UTILS.SpawnFARPAndFunctionalStatics(Name,Coordinate,FARPType,Coalition, return ReturnObjects, ADFName, MarkerID end +--- Spawn a MASH at a given coordinate, optionally, add an ADF Beacon. +-- @param #string Name Unique Name of the Mash. +-- @param Core.Point#COORDINATE Coordinate Coordinate where to spawn the MASH. Can be given as a Core.Zone#ZONE object, in this case we take the center coordinate. +-- @param #number Country Country ID the MASH belongs to, e.g. country.id.USA or country.id.RUSSIA. +-- @param #number ADF (Optional) ADF Frequency in kHz (Kilohertz), if given activate an ADF Beacon at the location of the MASH. +-- @param #string Livery (Optional) The livery of the static CH-47, defaults to dark green. +-- @param #table Templates (Optional) You can hand in your own template table of numbered(!) entries. Each entry consist of a relative(!) x,y position and data of a +-- static, shape_name is optional. Also, livery_id is optional, but is applied to the helicopter static only. +-- @usage +-- -- MASH Template example, this one is the built in one used in the function: +-- MASHTemplates = { +-- [1]={category='Infantry',type='Soldier M4',shape_name='none',heading=0,x=0.000000,y=0.000000,}, +-- [2]={category='Infantry',type='Soldier M4',shape_name='none',heading=0,x=0.313533,y=8.778935,}, +-- [3]={category='Infantry',type='Soldier M4',shape_name='none',heading=0,x=16.303737,y=20.379671,}, +-- [4]={category='Helicopters',type='CH-47Fbl1',shape_name='none',heading=0,x=-20.047735,y=-63.166179,livery_id = "us army dark green",}, +-- [5]={category='Infantry',type='Soldier M4',shape_name='none',heading=0,x=26.650339,y=20.066138,}, +-- [6]={category='Heliports',type='FARP_SINGLE_01',shape_name='FARP_SINGLE_01',heading=0,x=-25.432292,y=9.077099,}, +-- [7]={category='Heliports',type='FARP_SINGLE_01',shape_name='FARP_SINGLE_01',heading=0,x=-12.717421,y=-3.216114,}, +-- [8]={category='Heliports',type='FARP_SINGLE_01',shape_name='FARP_SINGLE_01',heading=0,x=-25.439281,y=-3.216114,}, +-- [9]={category='Heliports',type='FARP_SINGLE_01',shape_name='FARP_SINGLE_01',heading=0,x=-12.717421,y=9.155603,}, +-- [10]={category='Fortifications',type='TACAN_beacon',shape_name='none',heading=0,x=-2.329847,y=-16.579903,}, +-- [11]={category='Fortifications',type='FARP Fuel Depot',shape_name='GSM Rus',heading=0,x=2.222011,y=4.487030,}, +-- [12]={category='Fortifications',type='APFC fuel',shape_name='M92_APFCfuel',heading=0,x=3.614927,y=0.367838,}, +-- [13]={category='Fortifications',type='Camouflage03',shape_name='M92_Camouflage03',heading=0,x=21.544148,y=21.998879,}, +-- [14]={category='Fortifications',type='Container_generator',shape_name='M92_Container_generator',heading=0,x=20.989192,y=37.314334,}, +-- [15]={category='Fortifications',type='FireExtinguisher02',shape_name='M92_FireExtinguisher02',heading=0,x=3.988003,y=8.362333,}, +-- [16]={category='Fortifications',type='FireExtinguisher02',shape_name='M92_FireExtinguisher02',heading=0,x=-3.953195,y=12.945844,}, +-- [17]={category='Fortifications',type='Windsock',shape_name='H-Windsock_RW',heading=0,x=-18.944173,y=-33.042196,}, +-- [18]={category='Fortifications',type='Tent04',shape_name='M92_Tent04',heading=0,x=21.220671,y=30.247529,}, +-- } +-- +function UTILS.SpawnMASHStatics(Name,Coordinate,Country,ADF,Livery,Templates) + + -- Basic objects table + + local MASHTemplates = { + [1]={category='Infantry',type='Soldier M4',shape_name='none',heading=0,x=0.000000,y=0.000000,}, + [2]={category='Infantry',type='Soldier M4',shape_name='none',heading=0,x=0.313533,y=8.778935,}, + [3]={category='Infantry',type='Soldier M4',shape_name='none',heading=0,x=16.303737,y=20.379671,}, + [4]={category='Helicopters',type='CH-47Fbl1',shape_name='none',heading=0,x=-20.047735,y=-63.166179,livery_id = "us army dark green",}, + [5]={category='Infantry',type='Soldier M4',shape_name='none',heading=0,x=26.650339,y=20.066138,}, + [6]={category='Heliports',type='FARP_SINGLE_01',shape_name='FARP_SINGLE_01',heading=0,x=-25.432292,y=9.077099,}, + [7]={category='Heliports',type='FARP_SINGLE_01',shape_name='FARP_SINGLE_01',heading=0,x=-12.717421,y=-3.216114,}, + [8]={category='Heliports',type='FARP_SINGLE_01',shape_name='FARP_SINGLE_01',heading=0,x=-25.439281,y=-3.216114,}, + [9]={category='Heliports',type='FARP_SINGLE_01',shape_name='FARP_SINGLE_01',heading=0,x=-12.717421,y=9.155603,}, + [10]={category='Fortifications',type='TACAN_beacon',shape_name='none',heading=0,x=-2.329847,y=-16.579903,}, + [11]={category='Fortifications',type='FARP Fuel Depot',shape_name='GSM Rus',heading=0,x=2.222011,y=4.487030,}, + [12]={category='Fortifications',type='APFC fuel',shape_name='M92_APFCfuel',heading=0,x=3.614927,y=0.367838,}, + [13]={category='Fortifications',type='Camouflage03',shape_name='M92_Camouflage03',heading=0,x=21.544148,y=21.998879,}, + [14]={category='Fortifications',type='Container_generator',shape_name='M92_Container_generator',heading=0,x=20.989192,y=37.314334,}, + [15]={category='Fortifications',type='FireExtinguisher02',shape_name='M92_FireExtinguisher02',heading=0,x=3.988003,y=8.362333,}, + [16]={category='Fortifications',type='FireExtinguisher02',shape_name='M92_FireExtinguisher02',heading=0,x=-3.953195,y=12.945844,}, + [17]={category='Fortifications',type='Windsock',shape_name='H-Windsock_RW',heading=0,x=-18.944173,y=-33.042196,}, + [18]={category='Fortifications',type='Tent04',shape_name='M92_Tent04',heading=0,x=21.220671,y=30.247529,}, + } + + if Templates then MASHTemplates=Templates end + + -- locals + local name = Name or "Florence Nightingale" + local positionVec2 + local positionVec3 + local ReturnStatics = {} + local CountryID = Country or country.id.USA + local livery = "us army dark green" + + -- check for coordinate or zone + if type(Coordinate) == "table" then + if Coordinate:IsInstanceOf("COORDINATE") or Coordinate:IsInstanceOf("ZONE_BASE") then + positionVec2 = Coordinate:GetVec2() + positionVec3 = Coordinate:GetVec3() + end + else + BASE:E("Spawn MASH - no ZONE or COORDINATE handed!") + return + end + + -- position + local BaseX = positionVec2.x + local BaseY = positionVec2.y + + -- Statics + for id,object in pairs(MASHTemplates) do + local NewName = string.format("%s#%3d",name,id) + local vec2 = {x=BaseX+object.x,y=BaseY+object.y} + local Coordinate=COORDINATE:NewFromVec2(vec2) + local static = SPAWNSTATIC:NewFromType(object.type,object.category,CountryID) + if object.shape_name and object.shape_name ~= "none" then + static:InitShape(object.shape_name) + end + if object.category == "Helicopters" then + if object.livery_id ~= nil then + livery = object.livery_id + end + static:InitLivery(livery) + end + static:SpawnFromCoordinate(Coordinate,object.heading,NewName) + table.insert(ReturnStatics,static) + end + + -- Beacon + local ADFName + if ADF and type(ADF) == "number" then + local ADFFreq = ADF*1000 -- KHz to Hz + local Sound = "l10n/DEFAULT/beacon.ogg" + ADFName = Name .. " ADF "..tostring(ADF).."KHz" + --BASE:I(string.format("Adding MASH Beacon %d KHz Name %s",ADF,ADFName)) + trigger.action.radioTransmission(Sound, positionVec3, 0, true, ADFFreq, 250, ADFName) + end + + return ReturnStatics, ADFName +end + --- Converts a Vec2 to a Vec3. -- @param vec the 2D vector -- @param y optional new y axis (altitude) value. If omitted it's 0. From 7ae4cdc8f1b27380f33ddd11a6a6d80c853fbf7c Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Mon, 21 Jul 2025 15:02:45 +0200 Subject: [PATCH 107/234] #Documentation --- Moose Development/Moose/Utilities/Utils.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Moose Development/Moose/Utilities/Utils.lua b/Moose Development/Moose/Utilities/Utils.lua index b6ac21de1..00ed738b2 100644 --- a/Moose Development/Moose/Utilities/Utils.lua +++ b/Moose Development/Moose/Utilities/Utils.lua @@ -4267,6 +4267,8 @@ end -- @param #string Livery (Optional) The livery of the static CH-47, defaults to dark green. -- @param #table Templates (Optional) You can hand in your own template table of numbered(!) entries. Each entry consist of a relative(!) x,y position and data of a -- static, shape_name is optional. Also, livery_id is optional, but is applied to the helicopter static only. +-- @return #table Table of Wrapper.Static#STATIC objects that were spawned. +-- @return #string ADFName Name of the ADF Beacon to remove it later. -- @usage -- -- MASH Template example, this one is the built in one used in the function: -- MASHTemplates = { From 2ee0597d48f81f3d71bd860c3c1723af2e799fa6 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Tue, 22 Jul 2025 13:08:12 +0200 Subject: [PATCH 108/234] #CTLD - added FSM event "CratesPacked" #UTILS - more options for MASH building --- Moose Development/Moose/Ops/CTLD.lua | 28 +++++++++++++++++++-- Moose Development/Moose/Utilities/Utils.lua | 25 ++++++++++++++---- 2 files changed, 46 insertions(+), 7 deletions(-) diff --git a/Moose Development/Moose/Ops/CTLD.lua b/Moose Development/Moose/Ops/CTLD.lua index 75d09b498..51896bab7 100644 --- a/Moose Development/Moose/Ops/CTLD.lua +++ b/Moose Development/Moose/Ops/CTLD.lua @@ -25,7 +25,7 @@ -- @module Ops.CTLD -- @image OPS_CTLD.jpg --- Last Update May 2025 +-- Last Update July 2025 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -1414,7 +1414,7 @@ CTLD.FixedWingTypes = { --- CTLD class version. -- @field #string version -CTLD.version="1.3.35" +CTLD.version="1.3.36" --- Instantiate a new CTLD. -- @param #CTLD self @@ -1481,6 +1481,7 @@ function CTLD:New(Coalition, Prefixes, Alias) self:AddTransition("*", "CratesRepaired", "*") -- CTLD repair event. self:AddTransition("*", "CratesBuildStarted", "*") -- CTLD build event. self:AddTransition("*", "CratesRepairStarted", "*") -- CTLD repair event. + self:AddTransition("*", "CratesPacked", "*") -- CTLD repack event. self:AddTransition("*", "HelicopterLost", "*") -- CTLD lost event. self:AddTransition("*", "Load", "*") -- CTLD load event. self:AddTransition("*", "Loaded", "*") -- CTLD load event. @@ -1759,6 +1760,17 @@ function CTLD:New(Coalition, Prefixes, Alias) -- @param Wrapper.Unit#UNIT Unit Unit Object. -- @param Wrapper.Group#GROUP Vehicle The #GROUP object of the vehicle or FOB repaired. -- @return #CTLD self + + --- FSM Function OnBeforeCratesPacked. + -- @function [parent=#CTLD] OnBeforeCratesPacked + -- @param #CTLD self + -- @param #string From State. + -- @param #string Event Trigger. + -- @param #string To State. + -- @param Wrapper.Group#GROUP Group Group Object. + -- @param Wrapper.Unit#UNIT Unit Unit Object. + -- @param #CTLD_CARGO Cargo Cargo crate that was repacked. + -- @return #CTLD self --- FSM Function OnBeforeTroopsRTB. -- @function [parent=#CTLD] OnBeforeTroopsRTB @@ -1889,6 +1901,17 @@ function CTLD:New(Coalition, Prefixes, Alias) -- @param Wrapper.Unit#UNIT Unit Unit Object. -- @param Wrapper.Group#GROUP Vehicle The #GROUP object of the vehicle or FOB repaired. -- @return #CTLD self + + --- FSM Function OnAfterCratesPacked. + -- @function [parent=#CTLD] OnAfterCratesPacked + -- @param #CTLD self + -- @param #string From State. + -- @param #string Event Trigger. + -- @param #string To State. + -- @param Wrapper.Group#GROUP Group Group Object. + -- @param Wrapper.Unit#UNIT Unit Unit Object. + -- @param #CTLD_CARGO Cargo Cargo crate that was repacked. + -- @return #CTLD self --- FSM Function OnAfterTroopsRTB. -- @function [parent=#CTLD] OnAfterTroopsRTB @@ -4012,6 +4035,7 @@ function CTLD:_PackCratesNearby(Group, Unit) _Group:Destroy() -- if a match is found destroy the Wrapper.Group#GROUP near the player self:_GetCrates(Group, Unit, _entry, nil, false, true) -- spawn the appropriate crates near the player self:_RefreshLoadCratesMenu(Group,Unit) -- call the refresher to show the crates in the menu + self:__CratesPacked(1,Group,Unit,_entry) return true end end diff --git a/Moose Development/Moose/Utilities/Utils.lua b/Moose Development/Moose/Utilities/Utils.lua index 00ed738b2..b184e46aa 100644 --- a/Moose Development/Moose/Utilities/Utils.lua +++ b/Moose Development/Moose/Utilities/Utils.lua @@ -4265,6 +4265,10 @@ end -- @param #number Country Country ID the MASH belongs to, e.g. country.id.USA or country.id.RUSSIA. -- @param #number ADF (Optional) ADF Frequency in kHz (Kilohertz), if given activate an ADF Beacon at the location of the MASH. -- @param #string Livery (Optional) The livery of the static CH-47, defaults to dark green. +-- @param #boolean DeployHelo (Optional) If true, deploy the helicopter static. +-- @param #number MASHRadio MASH Radio Frequency, defaults to 127.5. +-- @param #number MASHRadioModulation MASH Radio Modulation, defaults to radio.modulation.AM. +-- @param #number MASHCallsign Defaults to CALLSIGN.FARP.Berlin. -- @param #table Templates (Optional) You can hand in your own template table of numbered(!) entries. Each entry consist of a relative(!) x,y position and data of a -- static, shape_name is optional. Also, livery_id is optional, but is applied to the helicopter static only. -- @return #table Table of Wrapper.Static#STATIC objects that were spawned. @@ -4292,7 +4296,7 @@ end -- [18]={category='Fortifications',type='Tent04',shape_name='M92_Tent04',heading=0,x=21.220671,y=30.247529,}, -- } -- -function UTILS.SpawnMASHStatics(Name,Coordinate,Country,ADF,Livery,Templates) +function UTILS.SpawnMASHStatics(Name,Coordinate,Country,ADF,Livery,DeployHelo,MASHRadio,MASHRadioModulation,MASHCallsign,Templates) -- Basic objects table @@ -4326,6 +4330,9 @@ function UTILS.SpawnMASHStatics(Name,Coordinate,Country,ADF,Livery,Templates) local ReturnStatics = {} local CountryID = Country or country.id.USA local livery = "us army dark green" + local MASHRadio = MASHRadio or 127.5 + local MASHRadioModulation = MASHRadioModulation or radio.modulation.AM + local MASHCallsign = MASHCallsign or CALLSIGN.FARP.Berlin -- check for coordinate or zone if type(Coordinate) == "table" then @@ -4341,7 +4348,7 @@ function UTILS.SpawnMASHStatics(Name,Coordinate,Country,ADF,Livery,Templates) -- position local BaseX = positionVec2.x local BaseY = positionVec2.y - + -- Statics for id,object in pairs(MASHTemplates) do local NewName = string.format("%s#%3d",name,id) @@ -4351,14 +4358,22 @@ function UTILS.SpawnMASHStatics(Name,Coordinate,Country,ADF,Livery,Templates) if object.shape_name and object.shape_name ~= "none" then static:InitShape(object.shape_name) end - if object.category == "Helicopters" then + if object.category == "Helicopters" and DeployHelo == true then if object.livery_id ~= nil then livery = object.livery_id end static:InitLivery(livery) + local newstatic = static:SpawnFromCoordinate(Coordinate,object.heading,NewName) + table.insert(ReturnStatics,newstatic) + elseif object.category == "Heliports" then + static:InitFARP(MASHCallsign,MASHRadio,MASHRadioModulation,false,false) + local newstatic = static:SpawnFromCoordinate(Coordinate,object.heading,NewName) + table.insert(ReturnStatics,newstatic) + elseif object.category ~= "Helicopters" and object.category ~= "Heliports" then + local newstatic = static:SpawnFromCoordinate(Coordinate,object.heading,NewName) + table.insert(ReturnStatics,newstatic) end - static:SpawnFromCoordinate(Coordinate,object.heading,NewName) - table.insert(ReturnStatics,static) + end -- Beacon From ada38fa3ea593eebfd0028a9764ac3b18fb63d5a Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Tue, 22 Jul 2025 13:08:46 +0200 Subject: [PATCH 109/234] #AIRBOSS - SRS 2.2.x path in documentation --- Moose Development/Moose/Ops/Airboss.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Ops/Airboss.lua b/Moose Development/Moose/Ops/Airboss.lua index fcf723279..7f2a4b6d8 100644 --- a/Moose Development/Moose/Ops/Airboss.lua +++ b/Moose Development/Moose/Ops/Airboss.lua @@ -1756,7 +1756,7 @@ AIRBOSS.MenuF10Root = nil --- Airboss class version. -- @field #string version -AIRBOSS.version = "1.4.0" +AIRBOSS.version = "1.4.1" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO list ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -3081,7 +3081,7 @@ end --- Set up SRS for usage without sound files -- @param #AIRBOSS self --- @param #string PathToSRS Path to SRS folder, e.g. "C:\\Program Files\\DCS-SimpleRadio-Standalone". +-- @param #string PathToSRS Path to SRS folder, e.g. "C:\\Program Files\\DCS-SimpleRadio\\ExternalAudio". -- @param #number Port Port of the SRS server, defaults to 5002. -- @param #string Culture (Optional, Airboss Culture) Culture, defaults to "en-US". -- @param #string Gender (Optional, Airboss Gender) Gender, e.g. "male" or "female". Defaults to "male". From 2f9c384ac024c17d9d6ebb6572c00ef3e708edc8 Mon Sep 17 00:00:00 2001 From: smiki Date: Tue, 22 Jul 2025 18:45:02 +0200 Subject: [PATCH 110/234] [FIXED] COMMANDER.maxMissionsAssignPerCycle typo --- Moose Development/Moose/Ops/Commander.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Ops/Commander.lua b/Moose Development/Moose/Ops/Commander.lua index 22a198b0e..89a2f50c0 100644 --- a/Moose Development/Moose/Ops/Commander.lua +++ b/Moose Development/Moose/Ops/Commander.lua @@ -136,7 +136,7 @@ COMMANDER = { awacsZones = {}, tankerZones = {}, limitMission = {}, - MaxMissionsAssignPerCycle = 1, + maxMissionsAssignPerCycle = 1, } --- COMMANDER class version. @@ -1599,7 +1599,7 @@ function COMMANDER:CheckMissionQueue() end missionsAssigned = missionsAssigned + 1 - if missionsAssigned >= self.maxMissionsAssignPerCycle then + if missionsAssigned >= (self.maxMissionsAssignPerCycle or 1) then return end From ac8cc408c1ef619b870ce27118d1d877a8dc7d0c Mon Sep 17 00:00:00 2001 From: smiki Date: Wed, 23 Jul 2025 11:48:07 +0200 Subject: [PATCH 111/234] [FIXED] `Disposition.getSimpleZones` --- Moose Development/Moose/Core/Point.lua | 16 +++++++++ Moose Development/Moose/Core/Zone.lua | 36 +++++++++++++++++++++ Moose Development/Moose/Utilities/Utils.lua | 10 ++++++ 3 files changed, 62 insertions(+) diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index a74356985..557180a32 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -3797,6 +3797,22 @@ do -- COORDINATE function COORDINATE:GetRandomPointVec3InRadius( OuterRadius, InnerRadius ) return COORDINATE:NewFromVec3( self:GetRandomVec3InRadius( OuterRadius, InnerRadius ) ) end + + +--- Search for clear zones in a given area. A powerful and efficient function using Disposition to find clear areas for spawning ground units avoiding trees, water and map scenery. +-- @param #number SearchRadius Radius of the search area. +-- @param #number PosRadius Required clear radius around each position. +-- @param #number NumPositions Number of positions to find. +-- @return #table A table of Core.Point#COORDINATE that are clear of map objects within the given PosRadius. + function COORDINATE:GetSimpleZones(SearchRadius, PosRadius, NumPositions) + local clearPositions = UTILS.GetSimpleZones(self:GetVec3(), SearchRadius, PosRadius, NumPositions) + local coords = {} + for _, pos in ipairs(clearPositions) do + local coord = COORDINATE:NewFromVec2(pos) + table.insert(coords, coord) + end + return coords + end end diff --git a/Moose Development/Moose/Core/Zone.lua b/Moose Development/Moose/Core/Zone.lua index 6664364ed..134cbf23b 100644 --- a/Moose Development/Moose/Core/Zone.lua +++ b/Moose Development/Moose/Core/Zone.lua @@ -1509,6 +1509,42 @@ function ZONE_RADIUS:IsVec3InZone( Vec3 ) return InZone end +--- Search for clear ground spawn zones within this zone. A powerful and efficient function using Disposition to find clear areas for spawning ground units avoiding trees, water and map scenery. +-- @param #number PosRadius Required clear radius around each position. +-- @param #number NumPositions Number of positions to find. +-- @return #table A table of DCS#Vec2 positions that are clear of map objects within the given PosRadius. nil if no clear positions are found. +function ZONE_RADIUS:GetClearZonePositions(PosRadius, NumPositions) + local clearPositions = UTILS.GetSimpleZones(self:GetVec3(), self:GetRadius(), PosRadius, NumPositions) + if clearPositions or #clearPositions > 0 then + local validZones = {} + for _, vec2 in pairs(clearPositions) do + if self.zone:IsVec2InZone(vec2) then + table.insert(validZones, vec2) + end + end + if #validZones > 0 then + return validZones + end + end + return nil +end + + +--- Search for a random clear ground spawn coordinate within this zone. A powerful and efficient function using Disposition to find clear areas for spawning ground units avoiding trees, water and map scenery. +-- @param #number PosRadius (Optional) Required clear radius around each position. (Default is math.min(Radius/10, 200)) +-- @param #number NumPositions (Optional) Number of positions to find. (Default 50) +-- @return Core.Point#COORDINATE A random coordinate for a clear zone. nil if no clear positions are found. +-- @return #number Assigned radius for the found zones. nil if no clear positions are found. +function ZONE_RADIUS:GetRandomClearZoneCoordinate(PosRadius, NumPositions) + local radius = PosRadius or math.min(self.Radius/10, 200) + local clearPositions = self:GetClearZonePositions(radius, NumPositions or 50) + if clearPositions or #clearPositions > 0 then + local randomPosition = clearPositions[math.random(1, #clearPositions)] + return COORDINATE:NewFromVec2(randomPosition), radius + end + return nil +end + --- Returns a random Vec2 location within the zone. -- @param #ZONE_RADIUS self -- @param #number inner (Optional) Minimal distance from the center of the zone. Default is 0. diff --git a/Moose Development/Moose/Utilities/Utils.lua b/Moose Development/Moose/Utilities/Utils.lua index b184e46aa..aeddb7fa9 100644 --- a/Moose Development/Moose/Utilities/Utils.lua +++ b/Moose Development/Moose/Utilities/Utils.lua @@ -4630,3 +4630,13 @@ function UTILS.DestroyScenery(name, level) net.dostring_in("mission",string.format("a_scenery_destruction_zone(%d, %d)", z.zoneId, level)) end end + +--- Search for clear zones in a given area. A powerful and efficient function using Disposition to find clear areas for spawning ground units avoiding trees, water and map scenery. +-- @param DCS##Vec3 Center position vector for the search area. +-- @param #number SearchRadius Radius of the search area. +-- @param #number PosRadius Required clear radius around each position. +-- @param #number NumPositions Number of positions to find. +-- @return #table A table of DCS#Vec2 positions that are clear of map objects within the given PosRadius. +function UTILS.GetSimpleZones(Vec3, SearchRadius, PosRadius, NumPositions) + return Disposition.getSimpleZones(Vec3, SearchRadius, PosRadius, NumPositions) +end From c1e8ee12e0bd0ccb03944cef5ca682e91e933a16 Mon Sep 17 00:00:00 2001 From: smiki Date: Wed, 23 Jul 2025 11:48:33 +0200 Subject: [PATCH 112/234] [ADDED] `Disposition.getSimpleZones` --- Moose Development/Moose/Core/Zone.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/Moose Development/Moose/Core/Zone.lua b/Moose Development/Moose/Core/Zone.lua index 134cbf23b..d663bc93b 100644 --- a/Moose Development/Moose/Core/Zone.lua +++ b/Moose Development/Moose/Core/Zone.lua @@ -1542,6 +1542,7 @@ function ZONE_RADIUS:GetRandomClearZoneCoordinate(PosRadius, NumPositions) local randomPosition = clearPositions[math.random(1, #clearPositions)] return COORDINATE:NewFromVec2(randomPosition), radius end + return nil end From 03763e16d6c240f1f5781ad8ee46b1c1b6012852 Mon Sep 17 00:00:00 2001 From: smiki Date: Wed, 23 Jul 2025 12:19:00 +0200 Subject: [PATCH 113/234] [ADDED] `Disposition.getSimpleZones` --- Moose Development/Moose/Core/Zone.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/Core/Zone.lua b/Moose Development/Moose/Core/Zone.lua index d663bc93b..a44698097 100644 --- a/Moose Development/Moose/Core/Zone.lua +++ b/Moose Development/Moose/Core/Zone.lua @@ -1518,7 +1518,7 @@ function ZONE_RADIUS:GetClearZonePositions(PosRadius, NumPositions) if clearPositions or #clearPositions > 0 then local validZones = {} for _, vec2 in pairs(clearPositions) do - if self.zone:IsVec2InZone(vec2) then + if self:IsVec2InZone(vec2) then table.insert(validZones, vec2) end end From 11b0ce6275a931467e241e7e1badb9d3b994b5b9 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Wed, 23 Jul 2025 12:34:52 +0200 Subject: [PATCH 114/234] #AIRBASE - remove some differences between data produced by _InitRunways and GetRunwayData --- Moose Development/Moose/Wrapper/Airbase.lua | 55 ++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/Moose Development/Moose/Wrapper/Airbase.lua b/Moose Development/Moose/Wrapper/Airbase.lua index 520f8b923..80c4d20cb 100644 --- a/Moose Development/Moose/Wrapper/Airbase.lua +++ b/Moose Development/Moose/Wrapper/Airbase.lua @@ -1467,7 +1467,7 @@ function AIRBASE:Register(AirbaseName) self.descriptors=self:GetDesc() -- Debug info. - --self:I({airbase=AirbaseName, descriptors=self.descriptors}) + --self:T({airbase=AirbaseName, descriptors=self.descriptors}) -- Category. self.category=self.descriptors and self.descriptors.category or Airbase.Category.AIRDROME @@ -2634,6 +2634,7 @@ function AIRBASE:_InitRunways(IncludeInverse) --runway.name=string.format("%02d", tonumber(name)) runway.magheading=tonumber(runway.name)*10 + runway.idx=runway.magheading runway.heading=heading runway.width=width or 0 runway.length=length or 0 @@ -2946,6 +2947,7 @@ function AIRBASE:GetRunwayData(magvar, mark) local runway={} --#AIRBASE.Runway runway.heading=hdg runway.idx=idx + runway.magheading=idx runway.length=c1:Get2DDistance(c2) runway.position=c1 runway.endpoint=c2 @@ -2961,6 +2963,57 @@ function AIRBASE:GetRunwayData(magvar, mark) -- Add runway. table.insert(runways, runway) + end + + -- Look for identical (parallel) runways, e.g. 03L and 03R at Nellis. + local rpairs={} + for i,_ri in pairs(runways) do + local ri=_ri --#AIRBASE.Runway + for j,_rj in pairs(runways) do + local rj=_rj --#AIRBASE.Runway + if i 0 + return ((b.z - a.z)*(c.x - a.x) - (b.x - a.x)*(c.z - a.z)) > 0 + end + + for i,j in pairs(rpairs) do + local ri=runways[i] --#AIRBASE.Runway + local rj=runways[j] --#AIRBASE.Runway + + -- Draw arrow. + --ri.center:ArrowToAll(rj.center) + + local c0=ri.center + + -- Vector in the direction of the runway. + local a=UTILS.VecTranslate(c0, 1000, ri.heading) + + -- Vector from runway i to runway j. + local b=UTILS.VecSubstract(rj.center, ri.center) + b=UTILS.VecAdd(ri.center, b) + + -- Check if rj is left of ri. + local left=isLeft(c0, a, b) + + --env.info(string.format("Found pair %s: i=%d, j=%d, left==%s", ri.name, i, j, tostring(left))) + + if left then + ri.isLeft=false + rj.isLeft=true + else + ri.isLeft=true + rj.isLeft=false + end + + --break end return runways From 367014ebf3ee7c195c842bee35551a6289c2c510 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Wed, 23 Jul 2025 15:47:56 +0200 Subject: [PATCH 115/234] xxx --- Moose Development/Moose/Wrapper/Airbase.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Moose Development/Moose/Wrapper/Airbase.lua b/Moose Development/Moose/Wrapper/Airbase.lua index 80c4d20cb..a24c00cbe 100644 --- a/Moose Development/Moose/Wrapper/Airbase.lua +++ b/Moose Development/Moose/Wrapper/Airbase.lua @@ -2991,14 +2991,14 @@ function AIRBASE:GetRunwayData(magvar, mark) -- Draw arrow. --ri.center:ArrowToAll(rj.center) - local c0=ri.center + local c0=ri.position -- Vector in the direction of the runway. local a=UTILS.VecTranslate(c0, 1000, ri.heading) -- Vector from runway i to runway j. - local b=UTILS.VecSubstract(rj.center, ri.center) - b=UTILS.VecAdd(ri.center, b) + local b=UTILS.VecSubstract(rj.position, ri.position) + b=UTILS.VecAdd(ri.position, b) -- Check if rj is left of ri. local left=isLeft(c0, a, b) From a462c5a4937a153e10f4e43dcdec752fca594048 Mon Sep 17 00:00:00 2001 From: smiki Date: Thu, 24 Jul 2025 01:51:10 +0200 Subject: [PATCH 116/234] [Fixed] `Disposition.getSimpleZones` --- Moose Development/Moose/Core/Point.lua | 17 ++++++++++------- Moose Development/Moose/Core/Zone.lua | 4 ++-- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index 557180a32..fc77cdeb6 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -3803,17 +3803,20 @@ do -- COORDINATE -- @param #number SearchRadius Radius of the search area. -- @param #number PosRadius Required clear radius around each position. -- @param #number NumPositions Number of positions to find. --- @return #table A table of Core.Point#COORDINATE that are clear of map objects within the given PosRadius. +-- @return #table A table of Core.Point#COORDINATE that are clear of map objects within the given PosRadius. nil if no positions are found. function COORDINATE:GetSimpleZones(SearchRadius, PosRadius, NumPositions) local clearPositions = UTILS.GetSimpleZones(self:GetVec3(), SearchRadius, PosRadius, NumPositions) - local coords = {} - for _, pos in ipairs(clearPositions) do - local coord = COORDINATE:NewFromVec2(pos) - table.insert(coords, coord) + if clearPositions and #clearPositions > 0 then + local coords = {} + for _, pos in pairs(clearPositions) do + local coord = COORDINATE:NewFromVec2(pos) + table.insert(coords, coord) + end + return coords end - return coords + return nil end - + end do diff --git a/Moose Development/Moose/Core/Zone.lua b/Moose Development/Moose/Core/Zone.lua index a44698097..401aab808 100644 --- a/Moose Development/Moose/Core/Zone.lua +++ b/Moose Development/Moose/Core/Zone.lua @@ -1515,7 +1515,7 @@ end -- @return #table A table of DCS#Vec2 positions that are clear of map objects within the given PosRadius. nil if no clear positions are found. function ZONE_RADIUS:GetClearZonePositions(PosRadius, NumPositions) local clearPositions = UTILS.GetSimpleZones(self:GetVec3(), self:GetRadius(), PosRadius, NumPositions) - if clearPositions or #clearPositions > 0 then + if clearPositions and #clearPositions > 0 then local validZones = {} for _, vec2 in pairs(clearPositions) do if self:IsVec2InZone(vec2) then @@ -1538,7 +1538,7 @@ end function ZONE_RADIUS:GetRandomClearZoneCoordinate(PosRadius, NumPositions) local radius = PosRadius or math.min(self.Radius/10, 200) local clearPositions = self:GetClearZonePositions(radius, NumPositions or 50) - if clearPositions or #clearPositions > 0 then + if clearPositions and #clearPositions > 0 then local randomPosition = clearPositions[math.random(1, #clearPositions)] return COORDINATE:NewFromVec2(randomPosition), radius end From 4e56078d2a0bc6b8eab33b4fcfc1d660dc30e578 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 24 Jul 2025 16:17:04 +0200 Subject: [PATCH 117/234] #CONTROLLABLE - added options for landing approaches * Prefer vertical for helos and for aircraft * Straight in * Overhead break * Force pair * Restrict pair --- .../Moose/Wrapper/Controllable.lua | 59 ++++++++++++++++++- 1 file changed, 56 insertions(+), 3 deletions(-) diff --git a/Moose Development/Moose/Wrapper/Controllable.lua b/Moose Development/Moose/Wrapper/Controllable.lua index 689d841a5..20f35ee09 100644 --- a/Moose Development/Moose/Wrapper/Controllable.lua +++ b/Moose Development/Moose/Wrapper/Controllable.lua @@ -168,16 +168,25 @@ -- * @{#CONTROLLABLE.OptionAlarmStateGreen} -- * @{#CONTROLLABLE.OptionAlarmStateRed} -- --- ## 5.4) Jettison weapons: +-- ## 5.4) [AIR] Jettison weapons: -- -- * @{#CONTROLLABLE.OptionAllowJettisonWeaponsOnThreat} -- * @{#CONTROLLABLE.OptionKeepWeaponsOnThreat} -- --- ## 5.5) Air-2-Air missile attack range: +-- ## 5.5) [AIR] Air-2-Air missile attack range: -- * @{#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. +-- +-- # 7) [HELICOPTER] Units prefer vertical landing and takeoffs: +-- * @{#CONTROLLABLE.OptionPreferVerticalLanding}(): Set aircraft to prefer vertical landing and takeoff. +-- +-- # 8) [AIRCRAFT] Landing approach options +-- * @{#CONTROLLABLE.SetOptionLandingStraightIn}(): Landing approach straight in. +-- * @{#CONTROLLABLE.SetOptionLandingForcePair}(): Landing approach in pairs for groups > 1 unit. +-- * @{#CONTROLLABLE.SetOptionLandingRestrictPair}(): Landing approach single. +-- * @{#CONTROLLABLE.SetOptionLandingOverheadBreak}(): Landing approach overhead break. -- -- @field #CONTROLLABLE CONTROLLABLE = { @@ -1432,7 +1441,7 @@ end -- @param #number Speed The speed [m/s] flying when holding the position. -- @return #CONTROLLABLE self function CONTROLLABLE:TaskOrbitCircleAtVec2( Point, Altitude, Speed ) - self:F2( { self.ControllableName, Point, Altitude, Speed } ) + --self:F2( { self.ControllableName, Point, Altitude, Speed } ) local DCSTask = { id = 'Orbit', @@ -4203,6 +4212,50 @@ function CONTROLLABLE:OptionEngageRange( EngageRange ) return nil end +--- [AIR] Set how the AI lands on an airfield. Here: Straight in. +-- @param #CONTROLLABLE self +-- @return #CONTROLLABLE self +function CONTROLLABLE:SetOptionLandingStraightIn() + self:F2( { self.ControllableName } ) + if self:IsAir() then + self:SetOption("36","0") + end + return self +end + +--- [AIR] Set how the AI lands on an airfield. Here: In pairs (if > 1 aircraft in group) +-- @param #CONTROLLABLE self +-- @return #CONTROLLABLE self +function CONTROLLABLE:SetOptionLandingForcePair() + self:F2( { self.ControllableName } ) + if self:IsAir() then + self:SetOption("36","1") + end + return self +end + +--- [AIR] Set how the AI lands on an airfield. Here: No landing in pairs. +-- @param #CONTROLLABLE self +-- @return #CONTROLLABLE self +function CONTROLLABLE:SetOptionLandingRestrictPair() + self:F2( { self.ControllableName } ) + if self:IsAir() then + self:SetOption("36","2") + end + return self +end + +--- [AIR] Set how the AI lands on an airfield. Here: Overhead break. +-- @param #CONTROLLABLE self +-- @return #CONTROLLABLE self +function CONTROLLABLE:SetOptionLandingOverheadBreak() + self:F2( { self.ControllableName } ) + if self:IsAir() then + self:SetOption("36","3") + end + return self +end + --- [AIR] Set how the AI uses the onboard radar. -- @param #CONTROLLABLE self -- @param #number Option Options are: `NEVER = 0, FOR_ATTACK_ONLY = 1,FOR_SEARCH_IF_REQUIRED = 2, FOR_CONTINUOUS_SEARCH = 3` From 7a833365ce0d7b7e5a2034741be49bae7a90efad Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 24 Jul 2025 16:21:04 +0200 Subject: [PATCH 118/234] #CONTROLLABLE - added options for landing approaches * Prefer vertical for helos and for aircraft * Straight in * Overhead break * Force pair * Restrict pair You can also set these on AirWing and FlightGroup levels #AUFTRAG - added dive bomb option to NewBombing --- Moose Development/Moose/Ops/AirWing.lua | 56 ++++++++++++++++++++- Moose Development/Moose/Ops/Auftrag.lua | 6 ++- Moose Development/Moose/Ops/FlightGroup.lua | 55 ++++++++++++++++++++ 3 files changed, 114 insertions(+), 3 deletions(-) diff --git a/Moose Development/Moose/Ops/AirWing.lua b/Moose Development/Moose/Ops/AirWing.lua index f181b02ea..4447ed86b 100644 --- a/Moose Development/Moose/Ops/AirWing.lua +++ b/Moose Development/Moose/Ops/AirWing.lua @@ -974,6 +974,46 @@ function AIRWING:SetTakeoffAir() return self end +--- Set the aircraft of the AirWing to land straight in. +-- @param #AIRWING self +-- @return #FLIGHTGROUP self +function AIRWING:SetLandingStraightIn() + self.OptionLandingStraightIn = true + return self +end + +--- Set the aircraft of the AirWing to land in pairs for groups > 1 aircraft. +-- @param #AIRWING self +-- @return #AIRWING self +function AIRWING:SetLandingForcePair() + self.OptionLandingForcePair = true + return self +end + +--- Set the aircraft of the AirWing to NOT land in pairs. +-- @param #AIRWING self +-- @return #AIRWING self +function AIRWING:SetLandingRestrictPair() + self.OptionLandingRestrictPair = true + return self +end + +--- Set the aircraft of the AirWing to land after overhead break. +-- @param #AIRWING self +-- @return #AIRWING self +function AIRWING:SetLandingOverheadBreak() + self.OptionLandingOverheadBreak = true + return self +end + +--- [Helicopter] Set the aircraft of the AirWing to prefer vertical takeoff and landing. +-- @param #AIRWING self +-- @return #AIRWING self +function AIRWING:SetOptionPreferVerticalLanding() + self.OptionPreferVerticalLanding = true + return self +end + --- Set despawn after landing. Aircraft will be despawned after the landing event. -- Can help to avoid DCS AI taxiing issues. -- @param #AIRWING self @@ -1464,7 +1504,21 @@ function AIRWING:onafterFlightOnMission(From, Event, To, FlightGroup, Mission) self:T(self.lid..string.format("Group %s on %s mission %s", FlightGroup:GetName(), Mission:GetType(), Mission:GetName())) if self.UseConnectedOpsAwacs and self.ConnectedOpsAwacs then self.ConnectedOpsAwacs:__FlightOnMission(2,FlightGroup,Mission) - end + end + -- Landing Options + if self.OptionLandingForcePair then + FlightGroup:SetOptionLandingForcePair() + elseif self.OptionLandingOverheadBreak then + FlightGroup:SetOptionLandingOverheadBreak() + elseif self.OptionLandingRestrictPair then + FlightGroup:SetOptionLandingRestrictPair() + elseif self.OptionLandingStraightIn then + FlightGroup:SetOptionLandingStraightIn() + end + -- Landing Options Helo + if self.OptionPreferVerticalLanding then + FlightGroup:SetOptionPreferVertical() + end end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- diff --git a/Moose Development/Moose/Ops/Auftrag.lua b/Moose Development/Moose/Ops/Auftrag.lua index e2e94d412..f0c2a1eaf 100644 --- a/Moose Development/Moose/Ops/Auftrag.lua +++ b/Moose Development/Moose/Ops/Auftrag.lua @@ -1789,8 +1789,9 @@ end -- @param Core.Point#COORDINATE Target Target coordinate. Can also be specified as a GROUP, UNIT, STATIC, SET_GROUP, SET_UNIT, SET_STATIC or TARGET object. -- @param #number Altitude Engage altitude in feet. Default 25000 ft. -- @param #number EngageWeaponType Which weapon to use. Defaults to auto, ie ENUMS.WeaponFlag.Auto. See ENUMS.WeaponFlag for options. +-- @param #boolean Divebomb If true, use a dive bombing attack approach. -- @return #AUFTRAG self -function AUFTRAG:NewBOMBING(Target, Altitude, EngageWeaponType) +function AUFTRAG:NewBOMBING(Target, Altitude, EngageWeaponType, Divebomb) local mission=AUFTRAG:New(AUFTRAG.Type.BOMBING) @@ -1807,6 +1808,7 @@ function AUFTRAG:NewBOMBING(Target, Altitude, EngageWeaponType) mission.missionFraction=0.5 mission.optionROE=ENUMS.ROE.OpenFire mission.optionROT=ENUMS.ROT.NoReaction -- No reaction is better. + mission.optionDivebomb = Divebomb or nil -- Evaluate result after 5 min. We might need time until the bombs have dropped and targets have been detroyed. mission.dTevaluate=5*60 @@ -6164,7 +6166,7 @@ function AUFTRAG:GetDCSMissionTask() local coords = self.engageTarget:GetCoordinates() for _, coord in pairs(coords) do - local DCStask = CONTROLLABLE.TaskBombing(nil, coord:GetVec2(), self.engageAsGroup, self.engageWeaponExpend, self.engageQuantity, self.engageDirection, self.engageAltitude, self.engageWeaponType) + local DCStask = CONTROLLABLE.TaskBombing(nil, coord:GetVec2(), self.engageAsGroup, self.engageWeaponExpend, self.engageQuantity, self.engageDirection, self.engageAltitude, self.engageWeaponType, self.optionDivebomb) table.insert(DCStasks, DCStask) end diff --git a/Moose Development/Moose/Ops/FlightGroup.lua b/Moose Development/Moose/Ops/FlightGroup.lua index 58aba8276..93ab210ae 100644 --- a/Moose Development/Moose/Ops/FlightGroup.lua +++ b/Moose Development/Moose/Ops/FlightGroup.lua @@ -779,6 +779,61 @@ function FLIGHTGROUP:SetJettisonWeapons(Switch) return self end +--- Set the aircraft to land straight in. +-- @param #FLIGHTGROUP self +-- @return #FLIGHTGROUP self +function FLIGHTGROUP:SetOptionLandingStraightIn() + self.OptionLandingStraightIn = true + if self:GetGroup():IsAlive() then + self:GetGroup():SetOptionLandingStraightIn() + end + return self +end + +--- Set the aircraft to land in pairs. +-- @param #FLIGHTGROUP self +-- @return #FLIGHTGROUP self +function FLIGHTGROUP:SetOptionLandingForcePair() + self.OptionLandingForcePair = true + if self:GetGroup():IsAlive() then + self:GetGroup():SetOptionLandingForcePair() + end + return self +end + +--- Set the aircraft to NOT land in pairs. +-- @param #FLIGHTGROUP self +-- @return #FLIGHTGROUP self +function FLIGHTGROUP:SetOptionLandingRestrictPair() + self.OptionLandingRestrictPair = true + if self:GetGroup():IsAlive() then + self:GetGroup():SetOptionLandingRestrictPair() + end + return self +end + +--- Set the aircraft to land after overhead break. +-- @param #FLIGHTGROUP self +-- @return #FLIGHTGROUP self +function FLIGHTGROUP:SetOptionLandingOverheadBreak() + self.OptionLandingOverheadBreak = true + if self:GetGroup():IsAlive() then + self:GetGroup():SetOptionLandingOverheadBreak() + end + return self +end + +--- [HELICOPTER] Set the aircraft to prefer takeoff and landing vertically. +-- @param #FLIGHTGROUP self +-- @return #FLIGHTGROUP self +function FLIGHTGROUP:SetOptionPreferVertical() + self.OptionPreferVertical = true + if self:GetGroup():IsAlive() then + self:GetGroup():OptionPreferVerticalLanding() + end + return self +end + --- Set if group is ready for taxi/takeoff if controlled by a `FLIGHTCONTROL`. -- @param #FLIGHTGROUP self -- @param #boolean ReadyTO If `true`, flight is ready for takeoff. From 7279da7f09c465dcb5c6f840e81a55f919337457 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 24 Jul 2025 18:26:28 +0200 Subject: [PATCH 119/234] xx --- Moose Development/Moose/Core/Database.lua | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Moose Development/Moose/Core/Database.lua b/Moose Development/Moose/Core/Database.lua index 2d985a021..a8c814260 100644 --- a/Moose Development/Moose/Core/Database.lua +++ b/Moose Development/Moose/Core/Database.lua @@ -1112,7 +1112,7 @@ function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionSide, Category self:E("WARNING: Invalid STN "..tostring(UnitTemplate.AddPropAircraft.STN_L16).." for ".. UnitTemplate.name) else self.STNS[stn] = UnitTemplate.name - self:I("Register STN "..tostring(UnitTemplate.AddPropAircraft.STN_L16).." for ".. UnitTemplate.name) + self:T("Register STN "..tostring(UnitTemplate.AddPropAircraft.STN_L16).." for ".. UnitTemplate.name) end end if UnitTemplate.AddPropAircraft.SADL_TN then @@ -1121,7 +1121,7 @@ function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionSide, Category self:E("WARNING: Invalid SADL "..tostring(UnitTemplate.AddPropAircraft.SADL_TN).." for ".. UnitTemplate.name) else self.SADL[sadl] = UnitTemplate.name - self:I("Register SADL "..tostring(UnitTemplate.AddPropAircraft.SADL_TN).." for ".. UnitTemplate.name) + self:T("Register SADL "..tostring(UnitTemplate.AddPropAircraft.SADL_TN).." for ".. UnitTemplate.name) end end end @@ -1382,7 +1382,7 @@ function DATABASE:GetCoalitionFromClientTemplate( ClientName ) if self.Templates.ClientsByName[ClientName] then return self.Templates.ClientsByName[ClientName].CoalitionID end - self:E("WARNING: Template does not exist for client "..tostring(ClientName)) + self:T("WARNING: Template does not exist for client "..tostring(ClientName)) return nil end @@ -1394,7 +1394,7 @@ function DATABASE:GetCategoryFromClientTemplate( ClientName ) if self.Templates.ClientsByName[ClientName] then return self.Templates.ClientsByName[ClientName].CategoryID end - self:E("WARNING: Template does not exist for client "..tostring(ClientName)) + self:T("WARNING: Template does not exist for client "..tostring(ClientName)) return nil end @@ -1406,7 +1406,7 @@ function DATABASE:GetCountryFromClientTemplate( ClientName ) if self.Templates.ClientsByName[ClientName] then return self.Templates.ClientsByName[ClientName].CountryID end - self:E("WARNING: Template does not exist for client "..tostring(ClientName)) + self:T("WARNING: Template does not exist for client "..tostring(ClientName)) return nil end From 40253ea8bb02298e0fff0a4e3e0050616a887ef8 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 24 Jul 2025 18:27:44 +0200 Subject: [PATCH 120/234] xx --- Moose Development/Moose/Core/Database.lua | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Moose Development/Moose/Core/Database.lua b/Moose Development/Moose/Core/Database.lua index 2d985a021..a8c814260 100644 --- a/Moose Development/Moose/Core/Database.lua +++ b/Moose Development/Moose/Core/Database.lua @@ -1112,7 +1112,7 @@ function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionSide, Category self:E("WARNING: Invalid STN "..tostring(UnitTemplate.AddPropAircraft.STN_L16).." for ".. UnitTemplate.name) else self.STNS[stn] = UnitTemplate.name - self:I("Register STN "..tostring(UnitTemplate.AddPropAircraft.STN_L16).." for ".. UnitTemplate.name) + self:T("Register STN "..tostring(UnitTemplate.AddPropAircraft.STN_L16).." for ".. UnitTemplate.name) end end if UnitTemplate.AddPropAircraft.SADL_TN then @@ -1121,7 +1121,7 @@ function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionSide, Category self:E("WARNING: Invalid SADL "..tostring(UnitTemplate.AddPropAircraft.SADL_TN).." for ".. UnitTemplate.name) else self.SADL[sadl] = UnitTemplate.name - self:I("Register SADL "..tostring(UnitTemplate.AddPropAircraft.SADL_TN).." for ".. UnitTemplate.name) + self:T("Register SADL "..tostring(UnitTemplate.AddPropAircraft.SADL_TN).." for ".. UnitTemplate.name) end end end @@ -1382,7 +1382,7 @@ function DATABASE:GetCoalitionFromClientTemplate( ClientName ) if self.Templates.ClientsByName[ClientName] then return self.Templates.ClientsByName[ClientName].CoalitionID end - self:E("WARNING: Template does not exist for client "..tostring(ClientName)) + self:T("WARNING: Template does not exist for client "..tostring(ClientName)) return nil end @@ -1394,7 +1394,7 @@ function DATABASE:GetCategoryFromClientTemplate( ClientName ) if self.Templates.ClientsByName[ClientName] then return self.Templates.ClientsByName[ClientName].CategoryID end - self:E("WARNING: Template does not exist for client "..tostring(ClientName)) + self:T("WARNING: Template does not exist for client "..tostring(ClientName)) return nil end @@ -1406,7 +1406,7 @@ function DATABASE:GetCountryFromClientTemplate( ClientName ) if self.Templates.ClientsByName[ClientName] then return self.Templates.ClientsByName[ClientName].CountryID end - self:E("WARNING: Template does not exist for client "..tostring(ClientName)) + self:T("WARNING: Template does not exist for client "..tostring(ClientName)) return nil end From 74712b6e27770abed1e6996c8e3112ba40fbed6b Mon Sep 17 00:00:00 2001 From: smiki Date: Fri, 25 Jul 2025 14:17:03 +0200 Subject: [PATCH 121/234] [ADDED] `Disposition.getSimpleZones` to ZONE_POLYGON_BASE to support all zone types --- Moose Development/Moose/Core/Zone.lua | 41 ++++++++++----------- Moose Development/Moose/Utilities/Utils.lua | 39 ++++++++++++++++++++ 2 files changed, 59 insertions(+), 21 deletions(-) diff --git a/Moose Development/Moose/Core/Zone.lua b/Moose Development/Moose/Core/Zone.lua index 401aab808..7095d9f62 100644 --- a/Moose Development/Moose/Core/Zone.lua +++ b/Moose Development/Moose/Core/Zone.lua @@ -1514,19 +1514,7 @@ end -- @param #number NumPositions Number of positions to find. -- @return #table A table of DCS#Vec2 positions that are clear of map objects within the given PosRadius. nil if no clear positions are found. function ZONE_RADIUS:GetClearZonePositions(PosRadius, NumPositions) - local clearPositions = UTILS.GetSimpleZones(self:GetVec3(), self:GetRadius(), PosRadius, NumPositions) - if clearPositions and #clearPositions > 0 then - local validZones = {} - for _, vec2 in pairs(clearPositions) do - if self:IsVec2InZone(vec2) then - table.insert(validZones, vec2) - end - end - if #validZones > 0 then - return validZones - end - end - return nil + return UTILS.GetClearZonePositions(self, PosRadius, NumPositions) end @@ -1536,14 +1524,7 @@ end -- @return Core.Point#COORDINATE A random coordinate for a clear zone. nil if no clear positions are found. -- @return #number Assigned radius for the found zones. nil if no clear positions are found. function ZONE_RADIUS:GetRandomClearZoneCoordinate(PosRadius, NumPositions) - local radius = PosRadius or math.min(self.Radius/10, 200) - local clearPositions = self:GetClearZonePositions(radius, NumPositions or 50) - if clearPositions and #clearPositions > 0 then - local randomPosition = clearPositions[math.random(1, #clearPositions)] - return COORDINATE:NewFromVec2(randomPosition), radius - end - - return nil + return UTILS.GetRandomClearZoneCoordinate(self, PosRadius, NumPositions) end --- Returns a random Vec2 location within the zone. @@ -2524,6 +2505,24 @@ function ZONE_POLYGON_BASE:Flush() return self end +--- Search for clear ground spawn zones within this zone. A powerful and efficient function using Disposition to find clear areas for spawning ground units avoiding trees, water and map scenery. +-- @param #number PosRadius Required clear radius around each position. +-- @param #number NumPositions Number of positions to find. +-- @return #table A table of DCS#Vec2 positions that are clear of map objects within the given PosRadius. nil if no clear positions are found. +function ZONE_POLYGON_BASE:GetClearZonePositions(PosRadius, NumPositions) + return UTILS.GetClearZonePositions(self, PosRadius, NumPositions) +end + + +--- Search for a random clear ground spawn coordinate within this zone. A powerful and efficient function using Disposition to find clear areas for spawning ground units avoiding trees, water and map scenery. +-- @param #number PosRadius (Optional) Required clear radius around each position. (Default is math.min(Radius/10, 200)) +-- @param #number NumPositions (Optional) Number of positions to find. (Default 50) +-- @return Core.Point#COORDINATE A random coordinate for a clear zone. nil if no clear positions are found. +-- @return #number Assigned radius for the found zones. nil if no clear positions are found. +function ZONE_POLYGON_BASE:GetRandomClearZoneCoordinate(PosRadius, NumPositions) + return UTILS.GetRandomClearZoneCoordinate(self, PosRadius, NumPositions) +end + --- Smokes the zone boundaries in a color. -- @param #ZONE_POLYGON_BASE self -- @param #boolean UnBound If true, the tyres will be destroyed. diff --git a/Moose Development/Moose/Utilities/Utils.lua b/Moose Development/Moose/Utilities/Utils.lua index aeddb7fa9..f1a4d3e6c 100644 --- a/Moose Development/Moose/Utilities/Utils.lua +++ b/Moose Development/Moose/Utilities/Utils.lua @@ -4640,3 +4640,42 @@ end function UTILS.GetSimpleZones(Vec3, SearchRadius, PosRadius, NumPositions) return Disposition.getSimpleZones(Vec3, SearchRadius, PosRadius, NumPositions) end + +--- Search for clear ground spawn zones within this zone. A powerful and efficient function using Disposition to find clear areas for spawning ground units avoiding trees, water and map scenery. +-- @param Core.Zone#ZONE Zone to search. +-- @param #number (Optional) PosRadius Required clear radius around each position. (Default is math.min(Radius/10, 200)) +-- @param #number (Optional) NumPositions Number of positions to find. (Default 50) +-- @return #table A table of DCS#Vec2 positions that are clear of map objects within the given PosRadius. nil if no clear positions are found. +function UTILS.GetClearZonePositions(Zone, PosRadius, NumPositions) + local radius = PosRadius or math.min(Zone:GetRadius()/10, 200) + local clearPositions = UTILS.GetSimpleZones(Zone:GetVec3(), Zone:GetRadius(), radius, NumPositions or 50) + if clearPositions and #clearPositions > 0 then + local validZones = {} + for _, vec2 in pairs(clearPositions) do + if Zone:IsVec2InZone(vec2) then + table.insert(validZones, vec2) + end + end + if #validZones > 0 then + return validZones, radius + end + end + return nil +end + + +--- Search for a random clear ground spawn coordinate within this zone. A powerful and efficient function using Disposition to find clear areas for spawning ground units avoiding trees, water and map scenery. +-- @param Core.Zone#ZONE Zone to search. +-- @param #number PosRadius (Optional) Required clear radius around each position. (Default is math.min(Radius/10, 200)) +-- @param #number NumPositions (Optional) Number of positions to find. (Default 50) +-- @return Core.Point#COORDINATE A random coordinate for a clear zone. nil if no clear positions are found. +-- @return #number Assigned radius for the found zones. nil if no clear positions are found. +function UTILS.GetRandomClearZoneCoordinate(Zone, PosRadius, NumPositions) + local clearPositions = UTILS.GetClearZonePositions(Zone, PosRadius, NumPositions) + if clearPositions and #clearPositions > 0 then + local randomPosition, radius = clearPositions[math.random(1, #clearPositions)] + return COORDINATE:NewFromVec2(randomPosition), radius + end + + return nil +end From 30203668e4d3765a08cc1dc05957fb066a7e9962 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Fri, 25 Jul 2025 14:52:07 +0200 Subject: [PATCH 122/234] Revert "#UTILS - Added FindNearestPointOnCircle()" This reverts commit 2cc1ddd4679b0e3fb7a5f72ea5e4822112e2f2d1. --- Moose Development/Moose/Utilities/Utils.lua | 39 --------------------- 1 file changed, 39 deletions(-) diff --git a/Moose Development/Moose/Utilities/Utils.lua b/Moose Development/Moose/Utilities/Utils.lua index f1a4d3e6c..aeddb7fa9 100644 --- a/Moose Development/Moose/Utilities/Utils.lua +++ b/Moose Development/Moose/Utilities/Utils.lua @@ -4640,42 +4640,3 @@ end function UTILS.GetSimpleZones(Vec3, SearchRadius, PosRadius, NumPositions) return Disposition.getSimpleZones(Vec3, SearchRadius, PosRadius, NumPositions) end - ---- Search for clear ground spawn zones within this zone. A powerful and efficient function using Disposition to find clear areas for spawning ground units avoiding trees, water and map scenery. --- @param Core.Zone#ZONE Zone to search. --- @param #number (Optional) PosRadius Required clear radius around each position. (Default is math.min(Radius/10, 200)) --- @param #number (Optional) NumPositions Number of positions to find. (Default 50) --- @return #table A table of DCS#Vec2 positions that are clear of map objects within the given PosRadius. nil if no clear positions are found. -function UTILS.GetClearZonePositions(Zone, PosRadius, NumPositions) - local radius = PosRadius or math.min(Zone:GetRadius()/10, 200) - local clearPositions = UTILS.GetSimpleZones(Zone:GetVec3(), Zone:GetRadius(), radius, NumPositions or 50) - if clearPositions and #clearPositions > 0 then - local validZones = {} - for _, vec2 in pairs(clearPositions) do - if Zone:IsVec2InZone(vec2) then - table.insert(validZones, vec2) - end - end - if #validZones > 0 then - return validZones, radius - end - end - return nil -end - - ---- Search for a random clear ground spawn coordinate within this zone. A powerful and efficient function using Disposition to find clear areas for spawning ground units avoiding trees, water and map scenery. --- @param Core.Zone#ZONE Zone to search. --- @param #number PosRadius (Optional) Required clear radius around each position. (Default is math.min(Radius/10, 200)) --- @param #number NumPositions (Optional) Number of positions to find. (Default 50) --- @return Core.Point#COORDINATE A random coordinate for a clear zone. nil if no clear positions are found. --- @return #number Assigned radius for the found zones. nil if no clear positions are found. -function UTILS.GetRandomClearZoneCoordinate(Zone, PosRadius, NumPositions) - local clearPositions = UTILS.GetClearZonePositions(Zone, PosRadius, NumPositions) - if clearPositions and #clearPositions > 0 then - local randomPosition, radius = clearPositions[math.random(1, #clearPositions)] - return COORDINATE:NewFromVec2(randomPosition), radius - end - - return nil -end From b2a084d669649eb522b115af38b3c6a8c7bf51ba Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Fri, 25 Jul 2025 14:54:53 +0200 Subject: [PATCH 123/234] xx --- Moose Development/Moose/Utilities/Utils.lua | 39 +++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/Moose Development/Moose/Utilities/Utils.lua b/Moose Development/Moose/Utilities/Utils.lua index aeddb7fa9..f1a4d3e6c 100644 --- a/Moose Development/Moose/Utilities/Utils.lua +++ b/Moose Development/Moose/Utilities/Utils.lua @@ -4640,3 +4640,42 @@ end function UTILS.GetSimpleZones(Vec3, SearchRadius, PosRadius, NumPositions) return Disposition.getSimpleZones(Vec3, SearchRadius, PosRadius, NumPositions) end + +--- Search for clear ground spawn zones within this zone. A powerful and efficient function using Disposition to find clear areas for spawning ground units avoiding trees, water and map scenery. +-- @param Core.Zone#ZONE Zone to search. +-- @param #number (Optional) PosRadius Required clear radius around each position. (Default is math.min(Radius/10, 200)) +-- @param #number (Optional) NumPositions Number of positions to find. (Default 50) +-- @return #table A table of DCS#Vec2 positions that are clear of map objects within the given PosRadius. nil if no clear positions are found. +function UTILS.GetClearZonePositions(Zone, PosRadius, NumPositions) + local radius = PosRadius or math.min(Zone:GetRadius()/10, 200) + local clearPositions = UTILS.GetSimpleZones(Zone:GetVec3(), Zone:GetRadius(), radius, NumPositions or 50) + if clearPositions and #clearPositions > 0 then + local validZones = {} + for _, vec2 in pairs(clearPositions) do + if Zone:IsVec2InZone(vec2) then + table.insert(validZones, vec2) + end + end + if #validZones > 0 then + return validZones, radius + end + end + return nil +end + + +--- Search for a random clear ground spawn coordinate within this zone. A powerful and efficient function using Disposition to find clear areas for spawning ground units avoiding trees, water and map scenery. +-- @param Core.Zone#ZONE Zone to search. +-- @param #number PosRadius (Optional) Required clear radius around each position. (Default is math.min(Radius/10, 200)) +-- @param #number NumPositions (Optional) Number of positions to find. (Default 50) +-- @return Core.Point#COORDINATE A random coordinate for a clear zone. nil if no clear positions are found. +-- @return #number Assigned radius for the found zones. nil if no clear positions are found. +function UTILS.GetRandomClearZoneCoordinate(Zone, PosRadius, NumPositions) + local clearPositions = UTILS.GetClearZonePositions(Zone, PosRadius, NumPositions) + if clearPositions and #clearPositions > 0 then + local randomPosition, radius = clearPositions[math.random(1, #clearPositions)] + return COORDINATE:NewFromVec2(randomPosition), radius + end + + return nil +end From 7d3fc1740a16553105a0fd9505bdbf44d7a1d989 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Fri, 25 Jul 2025 14:57:58 +0200 Subject: [PATCH 124/234] xx --- Moose Development/Moose/Utilities/Utils.lua | 39 +++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/Moose Development/Moose/Utilities/Utils.lua b/Moose Development/Moose/Utilities/Utils.lua index f1a4d3e6c..ac71ae3f6 100644 --- a/Moose Development/Moose/Utilities/Utils.lua +++ b/Moose Development/Moose/Utilities/Utils.lua @@ -4679,3 +4679,42 @@ function UTILS.GetRandomClearZoneCoordinate(Zone, PosRadius, NumPositions) return nil end + +--- Find the point on the radius of a circle closest to a point outside of the radius. +-- @param DCS#Vec2 Vec1 Simple Vec2 marking the middle of the circle. +-- @param #number Radius The radius of the circle. +-- @param DCS#Vec2 Vec2 Simple Vec2 marking the point outside of the circle. +-- @return DCS#Vec2 Vec2 point on the radius. +function UTILS.FindNearestPointOnCircle(Vec1,Radius,Vec2) + local r = Radius + local cx = Vec1.x or 1 + local cy = Vec1.y or 1 + local px = Vec2.x or 1 + local py = Vec2.y or 1 + + -- Berechne den Vektor vom Mittelpunkt zum externen Punkt + local dx = px - cx + local dy = py - cy + + -- Berechne die Länge des Vektors + local dist = math.sqrt(dx * dx + dy * dy) + + -- Wenn der Punkt im Mittelpunkt liegt, wähle einen Punkt auf der X-Achse + if dist == 0 then + return {x=cx + r, y=cy} + end + + -- Normalisiere den Vektor (richtungsweise Vektor mit Länge 1) + local norm_dx = dx / dist + local norm_dy = dy / dist + + -- Berechne den Punkt auf dem Rand des Kreises + local qx = cx + r * norm_dx + local qy = cy + r * norm_dy + + local shift_factor = 1 + qx = qx + shift_factor * norm_dx + qy = qy + shift_factor * norm_dy + + return {x=qx, y=qy} +end From 23ff128ac894447f96a3e1c647fc2fb96c524eae Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Fri, 25 Jul 2025 19:05:01 +0200 Subject: [PATCH 125/234] #ZONE added ZONE_BASE:FindNearestCoordinateOnRadius() --- Moose Development/Moose/Core/ScheduleDispatcher.lua | 2 +- Moose Development/Moose/Core/Zone.lua | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Moose Development/Moose/Core/ScheduleDispatcher.lua b/Moose Development/Moose/Core/ScheduleDispatcher.lua index 023c20c95..8e062d82b 100644 --- a/Moose Development/Moose/Core/ScheduleDispatcher.lua +++ b/Moose Development/Moose/Core/ScheduleDispatcher.lua @@ -175,7 +175,7 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr local Name = Info.name or "?" local ErrorHandler = function( errmsg ) - env.info( "Error in timer function: " .. errmsg ) + env.info( "Error in timer function: " .. errmsg or "" ) if BASE.Debug ~= nil then env.info( BASE.Debug.traceback() ) end diff --git a/Moose Development/Moose/Core/Zone.lua b/Moose Development/Moose/Core/Zone.lua index 7095d9f62..8cdafb401 100644 --- a/Moose Development/Moose/Core/Zone.lua +++ b/Moose Development/Moose/Core/Zone.lua @@ -534,6 +534,19 @@ function ZONE_BASE:GetZoneProbability() return self.ZoneProbability end +--- Get the coordinate on the radius of the zone nearest to Outsidecoordinate. Useto e.g. find an ingress point. +-- @param #ZONE_BASE self +-- @param Core.Point#COORDINATE Outsidecoordinate The coordinate outside of the zone from where to look. +-- @return Core.Point#COORDINATE CoordinateOnRadius +function ZONE_BASE:FindNearestCoordinateOnRadius(Outsidecoordinate) + local Vec1 = self:GetVec2() + local Radius = self:GetRadius() + local Vec2 = Outsidecoordinate:GetVec2() + local Point = UTILS.FindNearestPointOnCircle(Vec1,Radius,Vec2) + local rc = COORDINATE:NewFromVec2(Point) + return rc +end + --- Get the zone taking into account the randomization probability of a zone to be selected. -- @param #ZONE_BASE self -- @return #ZONE_BASE The zone is selected taking into account the randomization probability factor. From 04ceda693b2701ed5130c3ee9820b1cf39fbcbf4 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Fri, 25 Jul 2025 19:05:40 +0200 Subject: [PATCH 126/234] #AUTOLASE - switch off increased ground awareness as default --- Moose Development/Moose/Functional/Autolase.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Moose Development/Moose/Functional/Autolase.lua b/Moose Development/Moose/Functional/Autolase.lua index 1e43a737c..1772e24a3 100644 --- a/Moose Development/Moose/Functional/Autolase.lua +++ b/Moose Development/Moose/Functional/Autolase.lua @@ -105,7 +105,7 @@ AUTOLASE = { debug = false, smokemenu = true, RoundingPrecision = 0, - increasegroundawareness = true, + increasegroundawareness = false, MonitorFrequency = 30, } @@ -216,7 +216,7 @@ function AUTOLASE:New(RecceSet, Coalition, Alias, PilotSet) self.smokemenu = true self.threatmenu = true self.RoundingPrecision = 0 - self.increasegroundawareness = true + self.increasegroundawareness = false self.MonitorFrequency = 30 self:EnableSmokeMenu({Angle=math.random(0,359),Distance=math.random(10,20)}) @@ -1020,7 +1020,7 @@ function AUTOLASE:_Prescient() self:T(self.lid.."Checking possibly visible STATICs for Recce "..unit:GetName()) for _,_static in pairs(Statics) do -- DCS static object here local static = STATIC:Find(_static) - if static and static:GetCoalition() ~= self.coalition then + if static and static:GetCoalition() ~= self.coalition and static:GetCoordinate() then local IsLOS = position:IsLOS(static:GetCoordinate()) if IsLOS then unit:KnowUnit(static,true,true) From 9db1d38a1551614d161e323fa7aac673eb2a419a Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Fri, 25 Jul 2025 19:06:12 +0200 Subject: [PATCH 127/234] #TIRESIAS - some optimization --- .../Moose/Functional/Tiresias.lua | 973 ++++++++++-------- 1 file changed, 523 insertions(+), 450 deletions(-) diff --git a/Moose Development/Moose/Functional/Tiresias.lua b/Moose Development/Moose/Functional/Tiresias.lua index 74c2b930e..51cc395f4 100644 --- a/Moose Development/Moose/Functional/Tiresias.lua +++ b/Moose Development/Moose/Functional/Tiresias.lua @@ -1,521 +1,589 @@ ---- **Functional** - TIRESIAS - manages AI behaviour. --- --- === --- --- The @{#TIRESIAS} class is working in the back to keep your large-scale ground units in check. --- --- ## Features: --- --- * Designed to keep CPU and Network usage lower on missions with a lot of ground units. --- * Does not affect ships to keep the Navy guys happy. --- * Does not affect OpsGroup type groups. --- * Distinguishes between SAM groups, AAA groups and other ground groups. --- * Exceptions can be defined to keep certain actions going. --- * Works coalition-independent in the back --- * Easy setup. --- --- === --- --- ## Missions: --- --- ### [TIRESIAS](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master) --- --- === --- --- ### Author : **applevangelist ** --- --- @module Functional.Tiresias --- @image Functional.Tiresias.jpg --- --- Last Update: Dec 2023 +----- **Functional** - TIRESIAS - manages AI behaviour (OPTIMIZED VERSION). -------------------------------------------------------------------------- ---- **TIRESIAS** class, extends Core.Base#BASE --- @type TIRESIAS --- @field #string ClassName --- @field #booelan debug --- @field #string version --- @field #number Interval --- @field Core.Set#SET_GROUP GroundSet --- @field #number Coalition --- @field Core.Set#SET_GROUP VehicleSet --- @field Core.Set#SET_GROUP AAASet --- @field Core.Set#SET_GROUP SAMSet --- @field Core.Set#SET_GROUP ExceptionSet --- @field Core.Set#SET_OPSGROUP OpsGroupSet --- @field #number AAARange --- @field #number HeloSwitchRange --- @field #number PlaneSwitchRange --- @field Core.Set#SET_GROUP FlightSet --- @field #boolean SwitchAAA --- @extends Core.Fsm#FSM +---- === + +--- The @{#TIRESIAS} class is working in the back to keep your large-scale ground units in check. +-- +-- -- Features: +-- +-- * Designed to keep CPU and Network usage lower on missions with a lot of ground units. +-- * Does not affect ships to keep the Navy guys happy. +-- * Does not affect OpsGroup type groups. +-- * Distinguishes between SAM groups, AAA groups and other ground groups. +-- * Exceptions can be defined to keep certain actions going. +-- * Works coalition-independent in the back +-- * Easy setup. +-- +-- === +-- +-- ## Optimizations Applied: +-- +-- * Cached frequently used functions and constants +-- * Reduced string concatenations and formatting +-- * Optimized loop structures and conditions +-- * Pre-allocated tables where possible +-- * Reduced function call overhead +-- * Improved memory management +-- +---- === +-- +---- #-- Author : **applevangelist ** (Optimized by AI) --- --- @type TIRESIAS.Data --- @field #string type --- @field #number range --- @field #boolean invisible --- @field #boolean AIOff --- @field #boolean exception +-- - @module Functional.Tiresias +-- - @image Functional.Tiresias.jpg +--- Last Update: Dec 2023 (Optimized July 2025) ---- *Tiresias, Greek demi-god and shapeshifter, blinded by the Gods, works as oracle for you.* (Wiki) +--- **TIRESIAS** class, extends Core.Base#BASE +-- @type TIRESIAS +-- @field #string ClassName +-- @field #boolean debug +-- @field #string version +-- @field #number Interval +-- @field Core.Set#SET_GROUP GroundSet +-- @field #number Coalition +-- @field Core.Set#SET_GROUP VehicleSet +-- @field Core.Set#SET_GROUP AAASet +-- @field Core.Set#SET_GROUP SAMSet +-- @field Core.Set#SET_GROUP ExceptionSet +-- @field Core.Set#SET_OPSGROUP OpsGroupSet +-- @field #number AAARange +-- @field #number HeloSwitchRange +-- @field #number PlaneSwitchRange +-- @field Core.Set#SET_GROUP FlightSet +-- @field #boolean SwitchAAA +-- @field #string lid +-- @field #table _cached_zones +-- @extends Core.Fsm#FSM + +--- +-- @type TIRESIAS.Data +-- @field #string type +-- @field #number range +-- @field #boolean invisible +-- @field #boolean AIOff +-- @field #boolean exception + +--- +-- *Tiresias, Greek demi-god and shapeshifter, blinded by the Gods, works as oracle for you.* (Wiki) -- --- === +-- === -- --- ## TIRESIAS Concept --- --- * Designed to keep CPU and Network usage lower on missions with a lot of ground units. --- * Does not affect ships to keep the Navy guys happy. --- * Does not affect OpsGroup type groups. --- * Distinguishes between SAM groups, AAA groups and other ground groups. --- * Exceptions can be defined in SET_GROUP objects to keep certain actions going. --- * Works coalition-independent in the back --- * Easy setup. --- --- ## Setup --- --- Setup is a one-liner: --- --- local blinder = TIRESIAS:New() --- --- Optionally you can set up exceptions, e.g. for convoys driving around --- --- local exceptionset = SET_GROUP:New():FilterCoalitions("red"):FilterPrefixes("Convoy"):FilterStart() --- local blinder = TIRESIAS:New() --- blinder:AddExceptionSet(exceptionset) --- --- Options --- --- -- Setup different radius for activation around helo and airplane groups (applies to AI and humans) --- blinder:SetActivationRanges(10,25) -- defaults are 10, and 25 +-- ## TIRESIAS Concept -- --- -- Setup engagement ranges for AAA (non-advanced SAM units like Flaks etc) and if you want them to be AIOff --- blinder:SetAAARanges(60,true) -- defaults are 60, and true +-- * Designed to keep CPU and Network usage lower on missions with a lot of ground units. +-- * Does not affect ships to keep the Navy guys happy. +-- * Does not affect OpsGroup type groups. +-- * Distinguishes between SAM groups, AAA groups and other ground groups. +-- * Exceptions can be defined in SET_GROUP objects to keep certain actions going. +-- * Works coalition-independent in the back +-- * Easy setup. -- --- @field #TIRESIAS +-- ## Setup +-- -- Setup is a one-liner: +-- +-- local blinder = TIRESIAS:New() +-- +-- -- Optionally you can set up exceptions, e.g. for convoys driving around +-- +-- local exceptionset = SET_GROUP:New():FilterCoalitions(" red" ):FilterPrefixes(" Convoy" ):FilterStart() +-- local blinder = TIRESIAS:New() +-- blinder:AddExceptionSet(exceptionset) +-- +-- -- Options +-- +-- -- Setup different radius for activation around helo and airplane groups (applies to AI and humans) +-- blinder:SetActivationRanges(10,25) -- defaults are 10, and 25 +-- +-- -- Setup engagement ranges for AAA (non-advanced SAM units like Flaks etc) and if you want them to be AIOff +-- blinder:SetAAARanges(60,true) -- defaults are 60, and true +-- +--- +-- @field #TIRESIAS TIRESIAS = { - ClassName = "TIRESIAS", - debug = false, - version = "0.0.5", - Interval = 20, - GroundSet = nil, - VehicleSet = nil, - AAASet = nil, - SAMSet = nil, - ExceptionSet = nil, - AAARange = 60, -- 60% - HeloSwitchRange = 10, -- NM - PlaneSwitchRange = 25, -- NM - SwitchAAA = true, -} + ClassName = "TIRESIAS", + debug = true, + version = " 0.0.6-OPT" , + Interval = 20, + GroundSet = nil, + VehicleSet = nil, + AAASet = nil, + SAMSet = nil, + ExceptionSet = nil, + AAARange = 60, -- 60% + HeloSwitchRange = 10, -- NM + PlaneSwitchRange = 25, -- NM + SwitchAAA = true, + _cached_zones = {}, -- Cache for zone objects + } ---- [USER] Create a new Tiresias object and start it up. --- @param #TIRESIAS self --- @return #TIRESIAS self +--- +-- [USER] Create a new Tiresias object and start it up. +-- @param #TIRESIAS self +-- @return #TIRESIAS self function TIRESIAS:New() - -- Inherit everything from FSM class. - local self = BASE:Inherit(self, FSM:New()) -- #TIRESIAS - - --- FSM Functions --- - - -- Start State. - self:SetStartState("Stopped") - - -- Add FSM transitions. - -- From State --> Event --> To State - self:AddTransition("Stopped", "Start", "Running") -- Start FSM. - self:AddTransition("*", "Status", "*") -- TIRESIAS status update. - self:AddTransition("*", "Stop", "Stopped") -- Stop FSM. - - self.ExceptionSet = SET_GROUP:New():Clear(false) - - self:HandleEvent(EVENTS.PlayerEnterAircraft,self._EventHandler) - - self.lid = string.format("TIRESIAS %s | ",self.version) - - self:I(self.lid.."Managing ground groups!") - - --- Triggers the FSM event "Stop". Stops TIRESIAS and all its event handlers. - -- @function [parent=#TIRESIAS] Stop - -- @param #TIRESIAS self - - --- Triggers the FSM event "Stop" after a delay. Stops TIRESIAS and all its event handlers. - -- @function [parent=#TIRESIAS] __Stop - -- @param #TIRESIAS self - -- @param #number delay Delay in seconds. - - --- Triggers the FSM event "Start". Starts TIRESIAS and all its event handlers. Note - `:New()` already starts the instance. - -- @function [parent=#TIRESIAS] Start - -- @param #TIRESIAS self - - --- Triggers the FSM event "Start" after a delay. Starts TIRESIAS and all its event handlers. Note - `:New()` already starts the instance. - -- @function [parent=#TIRESIAS] __Start - -- @param #TIRESIAS self - -- @param #number delay Delay in seconds. - - self:__Start(1) + -- Inherit everything from FSM class. + local self = BASE:Inherit(self, FSM:New()) -- #TIRESIAS + + --- FSM Functions --- + + -- Start State. + self:SetStartState("Stopped") + + -- Add FSM transitions. + -- From State --> Event --> To State + self:AddTransition("Stopped", "Start", "Running") -- Start FSM. + self:AddTransition("*", "Status", "*") -- TIRESIAS status update. + self:AddTransition("*", "Stop", "Stopped") -- Stop FSM. + + self.ExceptionSet = nil --SET_GROUP:New():Clear(false) + self._cached_zones = {} -- Initialize zone cache + + self:HandleEvent(EVENTS.PlayerEnterAircraft, self._EventHandler) + + -- Cache the log identifier to avoid string concatenation in loops + self.lid = "TIRESIAS " .. self.version .. " | " + + self:I(self.lid .. "Managing ground groups!") + + --- Triggers the FSM event "Stop". Stops TIRESIAS and all its event handlers. + -- @function [parent=#TIRESIAS] Stop + -- @param #TIRESIAS self + + --- Triggers the FSM event "Stop" after a delay. Stops TIRESIAS and all its event handlers. + -- @function [parent=#TIRESIAS] __Stop + -- @param #TIRESIAS self + -- @param #number delay Delay in seconds. + + --- Triggers the FSM event "Start". Starts TIRESIAS and all its event handlers. Note - `:New()` already starts the instance. + -- @function [parent=#TIRESIAS] Start + -- @param #TIRESIAS self + + --- Triggers the FSM event "Start" after a delay. Starts TIRESIAS and all its event handlers. Note - `:New()` already starts the instance. + -- @function [parent=#TIRESIAS] __Start + -- @param #TIRESIAS self + -- @param #number delay Delay in seconds. + + self:__Start(1) + return self end -------------------------------------------------------------------------------------------------------------- --- --- Helper Functions --- -------------------------------------------------------------------------------------------------------------- +----- ----[USER] Set activation radius for Helos and Planes in Nautical Miles. --- @param #TIRESIAS self --- @param #number HeloMiles Radius around a Helicopter in which AI ground units will be activated. Defaults to 10NM. --- @param #number PlaneMiles Radius around an Airplane in which AI ground units will be activated. Defaults to 25NM. --- @return #TIRESIAS self -function TIRESIAS:SetActivationRanges(HeloMiles,PlaneMiles) +--- +-- Helper Functions +--- + +--- [USER] Set activation radius for Helos and Planes in Nautical Miles. +-- @param #TIRESIAS self +-- @param #number HeloMiles Radius around a Helicopter in which AI ground units will be activated. Defaults to 10NM. +-- @param #number PlaneMiles Radius around an Airplane in which AI ground units will be activated. Defaults to 25NM. +-- @return #TIRESIAS self +function TIRESIAS:SetActivationRanges(HeloMiles, PlaneMiles) self.HeloSwitchRange = HeloMiles or 10 self.PlaneSwitchRange = PlaneMiles or 25 + -- Clear zone cache when ranges change + self._cached_zones = {} return self end ---[USER] Set AAA Ranges - AAA equals non-SAM systems which qualify as AAA in DCS world. --- @param #TIRESIAS self --- @param #number FiringRange The engagement range that AAA units will be set to. Can be 0 to 100 (percent). Defaults to 60. --- @param #boolean SwitchAAA Decide if these system will have their AI switched off, too. Defaults to true. --- @return #TIRESIAS self -function TIRESIAS:SetAAARanges(FiringRange,SwitchAAA) +-- @param #TIRESIAS self +-- @param #number FiringRange The engagement range that AAA units will be set to. Can be 0 to 100 (percent). Defaults to 60. +-- @param #boolean SwitchAAA Decide if these system will have their AI switched off, too. Defaults to true. +-- @return #TIRESIAS self +function TIRESIAS:SetAAARanges(FiringRange, SwitchAAA) self.AAARange = FiringRange or 60 self.SwitchAAA = (SwitchAAA == false) and false or true return self end --- [USER] Add a SET_GROUP of GROUP objects as exceptions. Can be done multiple times. Does **not** work work for GROUP objects spawned into the SET after start, i.e. the groups need to exist in the game already. --- @param #TIRESIAS self --- @param Core.Set#SET_GROUP Set to add to the exception list. --- @return #TIRESIAS self +-- @param #TIRESIAS self +-- @param Core.Set#SET_GROUP Set to add to the exception list. +-- @return #TIRESIAS self function TIRESIAS:AddExceptionSet(Set) - self:T(self.lid.."AddExceptionSet") + self:T(self.lid .. " AddExceptionSet" ) + + if not self.ExceptionSet then + self.ExceptionSet = SET_GROUP:New() + end + local exceptions = self.ExceptionSet + + -- Cache the exception data structure for reuse + local exception_data = { + type = " Exception" , + exception = true, + } + Set:ForEachGroupAlive( function(grp) - if not grp.Tiresias then - grp.Tiresias = { -- #TIRESIAS.Data - type = "Exception", - exception = true, - } - exceptions:AddGroup(grp,true) + local inAAASet = self.AAASet:IsIncludeObject(grp) + local inVehSet = self.VehicleSet:IsIncludeObject(grp) + local inSAMSet = self.SAMSet:IsIncludeObject(grp) + if grp:IsGround() and (not grp.Tiresias) and (not inAAASet) and (not inVehSet) and (not inSAMSet) then + grp.Tiresias = exception_data + exceptions:AddGroup(grp, true) + BASE:T(" TIRESIAS: Added exception group: " .. grp:GetName()) end - BASE:T("TIRESIAS: Added exception group: "..grp:GetName()) end - ) + ) return self end ---- [INTERNAL] Filter Function --- @param Wrapper.Group#GROUP Group --- @return #boolean isin +--- [INTERNAL] Filter Function - Optimized with cached calls +-- @param Wrapper.Group#GROUP Group +-- @return #boolean isin function TIRESIAS._FilterNotAAA(Group) - local grp = Group -- Wrapper.Group#GROUP - local isaaa = grp:IsAAA() - if isaaa == true and grp:IsGround() and not grp:IsShip() then - return false -- remove from SET - else - return true -- keep in SET + local grp = Group -- Wrapper.Group#GROUP + -- Cache method calls to reduce overhead + local is_air = grp:IsAir() + local is_ship = grp:IsShip() + local is_AAA = grp:IsAAA() + if is_air or grp:IsShip() then -- air or ship - no AAA + return true -- keep in SET end + return not is_AAA -- remove AAA, keep others end ---- [INTERNAL] Filter Function --- @param Wrapper.Group#GROUP Group --- @return #boolean isin +--- [INTERNAL] Filter Function - Optimized with cached calls +-- @param Wrapper.Group#GROUP Group +-- @return #boolean isin function TIRESIAS._FilterNotSAM(Group) - local grp = Group -- Wrapper.Group#GROUP - local issam = grp:IsSAM() - if issam == true and grp:IsGround() and not grp:IsShip() then - return false -- remove from SET - else - return true -- keep in SET + local grp = Group -- Wrapper.Group#GROUP + -- Cache method calls to reduce overhead + local is_air = grp:IsGround() + local is_ship = grp:IsShip() + local is_SAM = grp:IsSAM() + if is_air or grp:IsShip() then + return true -- keep in SET end + return not is_SAM -- remove SAM, keep others end ---- [INTERNAL] Filter Function --- @param Wrapper.Group#GROUP Group --- @return #boolean isin +--- [INTERNAL] Filter Function - Optimized with cached calls +-- @param Wrapper.Group#GROUP Group +-- @return #boolean isin function TIRESIAS._FilterAAA(Group) - local grp = Group -- Wrapper.Group#GROUP - local isaaa = grp:IsAAA() - if isaaa == true and grp:IsGround() and not grp:IsShip() then - return true -- remove from SET - else - return false -- keep in SET + local grp = Group -- Wrapper.Group#GROUP + -- Cache method calls to reduce overhead + local is_ground = grp:IsGround() + if (not is_ground) or grp:IsShip() then + return false -- not AAA end + return grp:IsAAA() -- only AAA end ---- [INTERNAL] Filter Function --- @param Wrapper.Group#GROUP Group --- @return #boolean isin +--- [INTERNAL] Filter Function - Optimized with cached calls +-- @param Wrapper.Group#GROUP Group +-- @return #boolean isin function TIRESIAS._FilterSAM(Group) - local grp = Group -- Wrapper.Group#GROUP - local issam = grp:IsSAM() - if issam == true and grp:IsGround() and not grp:IsShip() then - return true -- remove from SET - else - return false -- keep in SET + local grp = Group -- Wrapper.Group#GROUP + -- Cache method calls to reduce overhead + local is_ground = grp:IsGround() + if (not is_ground) or grp:IsShip() then + return false -- not SAM end + return grp:IsSAM() -- only SAM end ---- [INTERNAL] Init Groups --- @param #TIRESIAS self --- @return #TIRESIAS self +--- [INTERNAL] Init Groups - Optimized with reduced function calls +-- @param #TIRESIAS self +-- @return #TIRESIAS self function TIRESIAS:_InitGroups() - self:T(self.lid.."_InitGroups") - -- Set all groups invisible/motionless - local EngageRange = self.AAARange - local SwitchAAA = self.SwitchAAA - --- AAA - self.AAASet:ForEachGroupAlive( - function(grp) - if not grp.Tiresias then - grp:OptionEngageRange(EngageRange) +self:T(self.lid .. " _InitGroups" ) + +-- Cache frequently used values +local EngageRange = self.AAARange +local SwitchAAA = self.SwitchAAA + +-- Pre-create data structures to avoid repeated table creation +local aaa_data_template = { + type = " AAA" , + invisible = true, + range = EngageRange, + exception = false, + AIOff = SwitchAAA, + } + +local vehicle_data_template = { + type = " Vehicle" , + invisible = true, + AIOff = true, + exception = false, + } + +local sam_data_template = { + type = " SAM" , + invisible = true, + exception = false, + } + +--- AAA - Optimized loop +self.AAASet:ForEachGroupAlive( + function(grp) + local tiresias_data = grp.Tiresias + if not tiresias_data then + grp:OptionEngageRange(EngageRange) + grp:SetCommandInvisible(true) + if SwitchAAA then + grp:SetAIOff() + grp:EnableEmission(false) + end + grp.Tiresias = aaa_data_template + elseif not tiresias_data.exception == true then + if not tiresias_data.invisible == true then grp:SetCommandInvisible(true) - if SwitchAAA then + tiresias_data.invisible = true + if SwitchAAA == true then grp:SetAIOff() grp:EnableEmission(false) - end - grp.Tiresias = { -- #TIRESIAS.Data - type = "AAA", - invisible = true, - range = EngageRange, - exception = false, - AIOff = SwitchAAA, - } - end - if grp.Tiresias and (not grp.Tiresias.exception == true) then - if grp.Tiresias.invisible == false then - grp:SetCommandInvisible(true) - grp.Tiresias.invisible = true - if SwitchAAA then - grp:SetAIOff() - grp:EnableEmission(false) - grp.Tiresias.AIOff = true - end + tiresias_data.AIOff = true end end - --BASE:I(string.format("Init/Switch off AAA %s (Exception %s)",grp:GetName(),tostring(grp.Tiresias.exception))) end + end ) - --- Vehicles - self.VehicleSet:ForEachGroupAlive( - function(grp) - if not grp.Tiresias then + +--- Vehicles - Optimized loop +self.VehicleSet:ForEachGroupAlive( + function(grp) + local tiresias_data = grp.Tiresias + if not tiresias_data then + grp:SetAIOff() + grp:SetCommandInvisible(true) + grp.Tiresias = vehicle_data_template + elseif not tiresias_data.exception == true then + if not tiresias_data.invisible then + grp:SetCommandInvisible(true) grp:SetAIOff() - grp:SetCommandInvisible(true) - grp.Tiresias = { -- #TIRESIAS.Data - type = "Vehicle", - invisible = true, - AIOff = true, - exception = false, - } + tiresias_data.invisible = true + tiresias_data.AIOff = true end - if grp.Tiresias and (not grp.Tiresias.exception == true) then - if grp.Tiresias and grp.Tiresias.invisible == false then - grp:SetCommandInvisible(true) - grp:SetAIOff() - grp.Tiresias.invisible = true - grp.Tiresias.AIOff = true - end - end - --BASE:I(string.format("Init/Switch off Vehicle %s (Exception %s)",grp:GetName(),tostring(grp.Tiresias.exception))) - end + end + end ) - --- SAM - self.SAMSet:ForEachGroupAlive( - function(grp) - if not grp.Tiresias then + +--- SAM - Optimized loop +self.SAMSet:ForEachGroupAlive( + function(grp) + local tiresias_data = grp.Tiresias + if not tiresias_data then + grp:SetCommandInvisible(true) + grp.Tiresias = sam_data_template + elseif not tiresias_data.exception == true then + if not tiresias_data.invisible then grp:SetCommandInvisible(true) - grp.Tiresias = { -- #TIRESIAS.Data - type = "SAM", - invisible = true, - exception = false, - } + tiresias_data.invisible = true end - if grp.Tiresias and (not grp.Tiresias.exception == true) then - if grp.Tiresias and grp.Tiresias.invisible == false then - grp:SetCommandInvisible(true) - grp.Tiresias.invisible = true - end - end - --BASE:I(string.format("Init/Switch off SAM %s (Exception %s)",grp:GetName(),tostring(grp.Tiresias.exception))) end + end ) - return self + +return self end ---- [INTERNAL] Event handler function --- @param #TIRESIAS self --- @param Core.Event#EVENTDATA EventData --- @return #TIRESIAS self +--- [INTERNAL] Event handler function - Optimized +-- @param #TIRESIAS self +-- @param Core.Event#EVENTDATA EventData +-- @return #TIRESIAS self function TIRESIAS:_EventHandler(EventData) - self:T(string.format("%s Event = %d",self.lid, EventData.id)) - local event = EventData -- Core.Event#EVENTDATA + self:T(string.format(" %s Event = %d" , self.lid, EventData.id)) + + local event = EventData -- Core.Event#EVENTDATA if event.id == EVENTS.PlayerEnterAircraft or event.id == EVENTS.PlayerEnterUnit then - --local _coalition = event.IniCoalition - --if _coalition ~= self.Coalition then - -- return --ignore! - --end - local unitname = event.IniUnitName or "none" - local _unit = event.IniUnit local _group = event.IniGroup if _group and _group:IsAlive() then - local radius = self.PlaneSwitchRange - if _group:IsHelicopter() then - radius = self.HeloSwitchRange - end - self:_SwitchOnGroups(_group,radius) + -- Cache the radius calculation + local radius = _group:IsHelicopter() and self.HeloSwitchRange or self.PlaneSwitchRange + self:_SwitchOnGroups(_group, radius) end end return self end ---- [INTERNAL] Switch Groups Behaviour --- @param #TIRESIAS self --- @param Wrapper.Group#GROUP group --- @param #number radius Radius in NM --- @return #TIRESIAS self -function TIRESIAS:_SwitchOnGroups(group,radius) - self:T(self.lid.."_SwitchOnGroups "..group:GetName().." Radius "..radius.." NM") - local zone = ZONE_GROUP:New("Zone-"..group:GetName(),group,UTILS.NMToMeters(radius)) +--- [INTERNAL] Switch Groups Behaviour - Optimized with zone caching +-- @param #TIRESIAS self +-- @param Wrapper.Group#GROUP group +-- @param #number radius Radius in NM +-- @return #TIRESIAS self +function TIRESIAS:_SwitchOnGroups(group, radius) + self:T(self.lid .. " _SwitchOnGroups " .. group:GetName() .. " Radius " .. radius .. " NM" ) + + -- Use cached zones to reduce object creation + local group_name = group:GetName() + local cache_key = group_name .. " _" .. radius + local zone = self._cached_zones[cache_key] + + if not zone then + zone = ZONE_GROUP:New(" Zone-" .. group_name, group, UTILS.NMToMeters(radius)) + self._cached_zones[cache_key] = zone + else + -- Update zone center to current group position + zone:UpdateFromGroup(group) + end + local ground = SET_GROUP:New():FilterCategoryGround():FilterZones({zone}):FilterOnce() local count = ground:CountAlive() + if self.debug then - local text = string.format("There are %d groups around this plane or helo!",count) - self:I(text) + self:I(string.format(" There are %d groups around this plane or helo!" , count)) end + + if count > 0 then + -- Cache values outside the loop local SwitchAAA = self.SwitchAAA - if ground:CountAlive() > 0 then - ground:ForEachGroupAlive( - function(grp) - local name = grp:GetName() - if grp:GetCoalition() ~= group:GetCoalition() - and grp.Tiresias and grp.Tiresias.type and (not grp.Tiresias.exception == true ) then - if grp.Tiresias.invisible == true then - grp:SetCommandInvisible(false) - grp.Tiresias.invisible = false - end - if grp.Tiresias.type == "Vehicle" and grp.Tiresias.AIOff and grp.Tiresias.AIOff == true then - grp:SetAIOn() - grp.Tiresias.AIOff = false - end - if SwitchAAA and grp.Tiresias.type == "AAA" and grp.Tiresias.AIOff and grp.Tiresias.AIOff == true then - grp:SetAIOn() - grp:EnableEmission(true) - grp.Tiresias.AIOff = false - end - --BASE:I(string.format("TIRESIAS - Switch on %s %s (Exception %s)",tostring(grp.Tiresias.type),grp:GetName(),tostring(grp.Tiresias.exception))) - else - BASE:T("TIRESIAS - This group "..tostring(name).. " has not been initialized or is an exception!") + local group_coalition = group:GetCoalition() + + ground:ForEachGroupAlive( + function(grp) + local tiresias_data = grp.Tiresias + if grp:GetCoalition() ~= group_coalition + and tiresias_data + and tiresias_data.type + and not tiresias_data.exception == true then + + -- Make group visible if invisible + if tiresias_data.invisible == true then + grp:SetCommandInvisible(false) + tiresias_data.invisible = false end + + -- Handle AI activation based on type + local grp_type = tiresias_data.type + if grp_type == "Vehicle" and tiresias_data.AIOff == true then + grp:SetAIOn() + tiresias_data.AIOff = false + elseif SwitchAAA == true and grp_type == "AAA" and tiresias_data.AIOff == true then + grp:SetAIOn() + grp:EnableEmission(true) + tiresias_data.AIOff = false + end + else + BASE:T("TIRESIAS - This group " .. tostring(grp:GetName()) .. " has not been initialized or is an exception!") end - ) + end + ) + end return self end -------------------------------------------------------------------------------------------------------------- --- --- FSM Functions --- -------------------------------------------------------------------------------------------------------------- +----- ---- [INTERNAL] FSM Function --- @param #TIRESIAS self --- @param #string From --- @param #string Event --- @param #string To --- @return #TIRESIAS self +--- +-- FSM Functions +---- + +--- [INTERNAL] FSM Function - Optimized initialization +-- @param #TIRESIAS self +-- @param #string From +-- @param #string Event +-- @param #string To +-- @return #TIRESIAS self function TIRESIAS:onafterStart(From, Event, To) - self:T({From, Event, To}) - - local VehicleSet = SET_GROUP:New():FilterCategoryGround():FilterFunction(TIRESIAS._FilterNotAAA):FilterFunction(TIRESIAS._FilterNotSAM):FilterStart() - local AAASet = SET_GROUP:New():FilterCategoryGround():FilterFunction(TIRESIAS._FilterAAA):FilterStart() - local SAMSet = SET_GROUP:New():FilterCategoryGround():FilterFunction(TIRESIAS._FilterSAM):FilterStart() - local OpsGroupSet = SET_OPSGROUP:New():FilterActive(true):FilterStart() - self.FlightSet = SET_GROUP:New():FilterCategories({"plane","helicopter"}):FilterStart() - - local EngageRange = self.AAARange - - local ExceptionSet = self.ExceptionSet - if self.ExceptionSet then - function ExceptionSet:OnAfterAdded(From,Event,To,ObjectName,Object) - BASE:I("TIRESIAS: EXCEPTION Object Added: "..Object:GetName()) - if Object and Object:IsAlive() then - Object.Tiresias = { -- #TIRESIAS.Data - type = "Exception", - exception = true, - } +self:T({From, Event, To}) + +-- Create sets with optimized filters +local VehicleSet = SET_GROUP:New():FilterCategoryGround():FilterFunction(TIRESIAS._FilterNotAAA):FilterFunction(TIRESIAS._FilterNotSAM):FilterStart() +local AAASet = SET_GROUP:New():FilterCategoryGround():FilterFunction(TIRESIAS._FilterAAA):FilterStart() +local SAMSet = SET_GROUP:New():FilterCategoryGround():FilterFunction(TIRESIAS._FilterSAM):FilterStart() +local OpsGroupSet = SET_OPSGROUP:New():FilterActive(true):FilterStart() +self.FlightSet = SET_GROUP:New():FilterCategories({" plane" ," helicopter" }):FilterStart() + +-- Cache frequently used values +local EngageRange = self.AAARange +local SwitchAAA = self.SwitchAAA +local ExceptionSet = self.ExceptionSet + +-- Pre-create data templates to reduce object creation +local exception_data = { + type = " Exception" , + exception = true, + } + +local vehicle_data = { + type = " Vehicle" , + invisible = true, + AIOff = true, + exception = false, + } + +local aaa_data = { + type = " AAA" , + invisible = true, + range = EngageRange, + exception = false, + AIOff = SwitchAAA, + } + +local sam_data = { + type = " SAM" , + invisible = true, + exception = false, + } + +if ExceptionSet then + function ExceptionSet:OnAfterAdded(From, Event, To, ObjectName, Object) + BASE:I(" TIRESIAS: EXCEPTION Object Added: " .. Object:GetName()) + if Object and Object:IsAlive() then + Object.Tiresias = exception_data Object:SetAIOn() Object:SetCommandInvisible(false) Object:EnableEmission(true) - end - end - - local OGS = OpsGroupSet:GetAliveSet() - for _,_OG in pairs(OGS or {}) do - local OG = _OG -- Ops.OpsGroup#OPSGROUP - local grp = OG:GetGroup() - ExceptionSet:AddGroup(grp,true) - end - - function OpsGroupSet:OnAfterAdded(From,Event,To,ObjectName,Object) - local grp = Object:GetGroup() - ExceptionSet:AddGroup(grp,true) end end + + -- Process existing OpsGroups more efficiently + local OGS = OpsGroupSet:GetAliveSet() + for _, _OG in pairs(OGS or {}) do + local OG = _OG -- Ops.OpsGroup#OPSGROUP + local grp = OG:GetGroup() + ExceptionSet:AddGroup(grp, true) + end - function VehicleSet:OnAfterAdded(From,Event,To,ObjectName,Object) - BASE:I("TIRESIAS: VEHCILE Object Added: "..Object:GetName()) - if Object and Object:IsAlive() then + function OpsGroupSet:OnAfterAdded(From, Event, To, ObjectName, Object) + local grp = Object:GetGroup() + ExceptionSet:AddGroup(grp, true) + end +end + +-- Optimized event handlers with pre-created data objects +function VehicleSet:OnAfterAdded(From, Event, To, ObjectName, Object) + BASE:T(" TIRESIAS: VEHICLE Object Added: " .. Object:GetName()) + if Object and Object:IsAlive() then + Object:SetAIOff() + Object:SetCommandInvisible(true) + Object.Tiresias = vehicle_data + end +end + +function AAASet:OnAfterAdded(From, Event, To, ObjectName, Object) + if Object and Object:IsAlive() then + BASE:I(" TIRESIAS: AAA Object Added: " .. Object:GetName()) + Object:OptionEngageRange(EngageRange) + Object:SetCommandInvisible(true) + if SwitchAAA then Object:SetAIOff() - Object:SetCommandInvisible(true) - Object.Tiresias = { -- #TIRESIAS.Data - type = "Vehicle", - invisible = true, - AIOff = true, - exception = false, - } + Object:EnableEmission(false) end + Object.Tiresias = aaa_data end +end - local SwitchAAA = self.SwitchAAA - - function AAASet:OnAfterAdded(From,Event,To,ObjectName,Object) - if Object and Object:IsAlive() then - BASE:I("TIRESIAS: AAA Object Added: "..Object:GetName()) - Object:OptionEngageRange(EngageRange) - Object:SetCommandInvisible(true) - if SwitchAAA then - Object:SetAIOff() - Object:EnableEmission(false) - end - Object.Tiresias = { -- #TIRESIAS.Data - type = "AAA", - invisible = true, - range = EngageRange, - exception = false, - AIOff = SwitchAAA, - } - end - end - - function SAMSet:OnAfterAdded(From,Event,To,ObjectName,Object) - if Object and Object:IsAlive() then - BASE:I("TIRESIAS: SAM Object Added: "..Object:GetName()) - Object:SetCommandInvisible(true) - Object.Tiresias = { -- #TIRESIAS.Data - type = "SAM", - invisible = true, - exception = false, - } - end +function SAMSet:OnAfterAdded(From, Event, To, ObjectName, Object) + if Object and Object:IsAlive() then + BASE:T(" TIRESIAS: SAM Object Added: " .. Object:GetName()) + Object:SetCommandInvisible(true) + Object.Tiresias = sam_data end +end + -- Store references self.VehicleSet = VehicleSet self.AAASet = AAASet self.SAMSet = SAMSet @@ -523,71 +591,76 @@ function TIRESIAS:onafterStart(From, Event, To) self:_InitGroups() - self:__Status(1) + self:__Status(1) return self end --- [INTERNAL] FSM Function --- @param #TIRESIAS self --- @param #string From --- @param #string Event --- @param #string To --- @return #TIRESIAS self +-- @param #TIRESIAS self +-- @param #string From +-- @param #string Event +-- @param #string To +-- @return #TIRESIAS self function TIRESIAS:onbeforeStatus(From, Event, To) self:T({From, Event, To}) - if self:GetState() == "Stopped" then - return false - end - return self + return self:GetState() ~= " Stopped" end ---- [INTERNAL] FSM Function --- @param #TIRESIAS self --- @param #string From --- @param #string Event --- @param #string To --- @return #TIRESIAS self +--- [INTERNAL] FSM Function - Optimized status processing +-- @param #TIRESIAS self +-- @param #string From +-- @param #string Event +-- @param #string To +-- @return #TIRESIAS self function TIRESIAS:onafterStatus(From, Event, To) self:T({From, Event, To}) - if self.debug then + + if self.debug then local count = self.VehicleSet:CountAlive() local AAAcount = self.AAASet:CountAlive() local SAMcount = self.SAMSet:CountAlive() - local text = string.format("Overall: %d | Vehicles: %d | AAA: %d | SAM: %d",count+AAAcount+SAMcount,count,AAAcount,SAMcount) - self:I(text) + self:I(string.format(" Overall: %d | Vehicles: %d | AAA: %d | SAM: %d" , + count + AAAcount + SAMcount, count, AAAcount, SAMcount)) end + self:_InitGroups() - if self.FlightSet:CountAlive() > 0 then + + -- Process flight groups more efficiently + local flight_count = self.FlightSet:CountAlive() + if flight_count > 0 then local Set = self.FlightSet:GetAliveSet() - for _,_plane in pairs(Set) do + -- Cache range values outside loop + local helo_range = self.HeloSwitchRange + local plane_range = self.PlaneSwitchRange + + for _, _plane in pairs(Set or {}) do local plane = _plane -- Wrapper.Group#GROUP - local radius = self.PlaneSwitchRange - if plane:IsHelicopter() then - radius = self.HeloSwitchRange - end - self:_SwitchOnGroups(_plane,radius) + local radius = plane:IsHelicopter() and helo_range or plane_range + self:_SwitchOnGroups(plane, radius) end end - if self:GetState() ~= "Stopped" then + + if self:GetState() ~= " Stopped" then self:__Status(self.Interval) end + return self end --- [INTERNAL] FSM Function --- @param #TIRESIAS self --- @param #string From --- @param #string Event --- @param #string To --- @return #TIRESIAS self +-- @param #TIRESIAS self +-- @param #string From +-- @param #string Event +-- @param #string To +-- @return #TIRESIAS self function TIRESIAS:onafterStop(From, Event, To) self:T({From, Event, To}) self:UnHandleEvent(EVENTS.PlayerEnterAircraft) + -- Clear zone cache on stop to free memory + self._cached_zones = {} return self end -------------------------------------------------------------------------------------------------------------- --- --- End --- -------------------------------------------------------------------------------------------------------------- +----- +---- End +----- \ No newline at end of file From a5726c0ed81f16c9f34eae473358881ff6814fe2 Mon Sep 17 00:00:00 2001 From: smiki Date: Fri, 25 Jul 2025 23:27:01 +0200 Subject: [PATCH 128/234] [ADDED] `UTILS.ShowPicture`. Overlay pictures for players. Refactoring --- Moose Development/Moose/Core/Zone.lua | 4 +++ Moose Development/Moose/Utilities/Utils.lua | 27 +++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/Moose Development/Moose/Core/Zone.lua b/Moose Development/Moose/Core/Zone.lua index 7095d9f62..3e15506fb 100644 --- a/Moose Development/Moose/Core/Zone.lua +++ b/Moose Development/Moose/Core/Zone.lua @@ -1510,6 +1510,7 @@ function ZONE_RADIUS:IsVec3InZone( Vec3 ) end --- Search for clear ground spawn zones within this zone. A powerful and efficient function using Disposition to find clear areas for spawning ground units avoiding trees, water and map scenery. +-- @param #ZONE_RADIUS self -- @param #number PosRadius Required clear radius around each position. -- @param #number NumPositions Number of positions to find. -- @return #table A table of DCS#Vec2 positions that are clear of map objects within the given PosRadius. nil if no clear positions are found. @@ -1519,6 +1520,7 @@ end --- Search for a random clear ground spawn coordinate within this zone. A powerful and efficient function using Disposition to find clear areas for spawning ground units avoiding trees, water and map scenery. +-- @param #ZONE_RADIUS self -- @param #number PosRadius (Optional) Required clear radius around each position. (Default is math.min(Radius/10, 200)) -- @param #number NumPositions (Optional) Number of positions to find. (Default 50) -- @return Core.Point#COORDINATE A random coordinate for a clear zone. nil if no clear positions are found. @@ -2506,6 +2508,7 @@ function ZONE_POLYGON_BASE:Flush() end --- Search for clear ground spawn zones within this zone. A powerful and efficient function using Disposition to find clear areas for spawning ground units avoiding trees, water and map scenery. +-- @param #ZONE_POLYGON_BASE self -- @param #number PosRadius Required clear radius around each position. -- @param #number NumPositions Number of positions to find. -- @return #table A table of DCS#Vec2 positions that are clear of map objects within the given PosRadius. nil if no clear positions are found. @@ -2515,6 +2518,7 @@ end --- Search for a random clear ground spawn coordinate within this zone. A powerful and efficient function using Disposition to find clear areas for spawning ground units avoiding trees, water and map scenery. +-- @param #ZONE_POLYGON_BASE self -- @param #number PosRadius (Optional) Required clear radius around each position. (Default is math.min(Radius/10, 200)) -- @param #number NumPositions (Optional) Number of positions to find. (Default 50) -- @return Core.Point#COORDINATE A random coordinate for a clear zone. nil if no clear positions are found. diff --git a/Moose Development/Moose/Utilities/Utils.lua b/Moose Development/Moose/Utilities/Utils.lua index f1a4d3e6c..b69300f1a 100644 --- a/Moose Development/Moose/Utilities/Utils.lua +++ b/Moose Development/Moose/Utilities/Utils.lua @@ -4593,6 +4593,33 @@ function UTILS.GetEnvZone(name) end end +--- net.dostring_in +function UTILS.DoStringIn(State,DoString) + return net.dostring_in(State,DoString) +end + +--- Show a picture on the screen +-- @param #string FileName File name of the picture +-- @param #number Duration Duration in seconds, defaults to 10 +-- @param #boolean ClearView If true, clears the view before showing the picture, defaults to false +-- @param #number StartDelay Delay in seconds before showing the picture, defaults to 0 +-- @param #number HorizontalAlign Horizontal alignment of the picture, defaults to 1 (left), can be 0 (center) or 2 (right) +-- @param #number VerticalAlign Vertical alignment of the picture, defaults to 1 (top), can be 0 (center) or 2 (bottom) +-- @param #number Size Size of the picture in percent, defaults to 100 +-- @param #number SizeUnits Size units, defaults to 0 (percent), can be 1 (pixels) +function UTILS.ShowPicture(FileName, Duration, ClearView, StartDelay, HorizontalAlign, VerticalAlign, Size, SizeUnits) + ClearView = ClearView or false + StartDelay = StartDelay or 0 + HorizontalAlign = HorizontalAlign or 1 + VerticalAlign = VerticalAlign or 1 + Size = Size or 100 + SizeUnits = SizeUnits or 0 + + if ClearView then ClearView = "true" else ClearView = "false" end + + net.dostring_in("mission", string.format("a_out_picture(getValueResourceByKey(\"%s\"), %d, %s, %d, \"%d\", \"%d\", %d, \"%d\")", FileName, Duration or 10, ClearView, StartDelay, HorizontalAlign, VerticalAlign, Size, SizeUnits)) +end + --- Show a helper gate at a DCS#Vec3 position -- @param DCS#Vec3 pos The position -- @param number heading Heading in degrees, can be 0..359 degrees From 5e724e7a3fc4daa89422bcbcfe0850d43fa5ab79 Mon Sep 17 00:00:00 2001 From: smiki Date: Fri, 25 Jul 2025 23:39:53 +0200 Subject: [PATCH 129/234] [ADDED] `COORDINATE:GetLandProfile` --- Moose Development/Moose/Core/Point.lua | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index fc77cdeb6..0d3c7f21d 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -837,6 +837,26 @@ do -- COORDINATE return land.getHeight( Vec2 ) end + --- Returns a table of `Vec3` points representing the terrain profile between two points. + -- @param #COORDINATE self + -- @param Destination DCS#Vec3 Ending point of the profile. + -- @return #table DCS#Vec3 table of the profile + function COORDINATE:GetLandProfileVec3(Destination) + return land.profile(self:GetVec3(), Destination) + end + + --- Returns a table of `Vec3` points representing the terrain profile between two points. + -- @param #COORDINATE self + -- @param Destination #COORDINATE Ending coordinate of the profile. + -- @return #table #COORDINATE table of the profile + function COORDINATE:GetLandProfileCoordinates(Destination) + local points = self:GetLandProfileVec3(Destination:GetVec3()) + local coords = {} + for _, point in ipairs(points) do + table.insert(coords, COORDINATE:NewFromVec3(point)) + end + return coords + end --- Set the heading of the coordinate, if applicable. -- @param #COORDINATE self From b6b668687354a2678df671d87e5f5d78e19d3a45 Mon Sep 17 00:00:00 2001 From: smiki Date: Fri, 25 Jul 2025 23:43:00 +0200 Subject: [PATCH 130/234] [ADDED] `COORDINATE:GetLandProfile` --- Moose Development/Moose/Core/Point.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index 0d3c7f21d..09af3b47e 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -837,7 +837,7 @@ do -- COORDINATE return land.getHeight( Vec2 ) end - --- Returns a table of `Vec3` points representing the terrain profile between two points. + --- Returns a table of DCS#Vec3 points representing the terrain profile between two points. -- @param #COORDINATE self -- @param Destination DCS#Vec3 Ending point of the profile. -- @return #table DCS#Vec3 table of the profile @@ -845,7 +845,7 @@ do -- COORDINATE return land.profile(self:GetVec3(), Destination) end - --- Returns a table of `Vec3` points representing the terrain profile between two points. + --- Returns a table of #COORDINATE representing the terrain profile between two points. -- @param #COORDINATE self -- @param Destination #COORDINATE Ending coordinate of the profile. -- @return #table #COORDINATE table of the profile From cc60e8590157297b03ebcfe84f0b8bc33a6caf98 Mon Sep 17 00:00:00 2001 From: smiki Date: Sun, 27 Jul 2025 13:18:56 +0200 Subject: [PATCH 131/234] [ADDED] `UTILS.LoadMission` and `UTILS.SetMissionBriefing` --- Moose Development/Moose/Utilities/Utils.lua | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Moose Development/Moose/Utilities/Utils.lua b/Moose Development/Moose/Utilities/Utils.lua index 42a7f779b..11dcdcbb1 100644 --- a/Moose Development/Moose/Utilities/Utils.lua +++ b/Moose Development/Moose/Utilities/Utils.lua @@ -4620,6 +4620,24 @@ function UTILS.ShowPicture(FileName, Duration, ClearView, StartDelay, Horizontal net.dostring_in("mission", string.format("a_out_picture(getValueResourceByKey(\"%s\"), %d, %s, %d, \"%d\", \"%d\", %d, \"%d\")", FileName, Duration or 10, ClearView, StartDelay, HorizontalAlign, VerticalAlign, Size, SizeUnits)) end +--- Load a mission file. This will replace the current mission with the one given carrying along the online clients. +-- @param #string FileName Mission filename +function UTILS.LoadMission(FileName) + net.dostring_in("mission", string.format("a_load_mission(\"%s\")", FileName)) +end + +--- Set the mission briefing for a coalition. +-- @param #number Coalition Briefing coalition ID, can be coalition.side.BLUE, coalition.side.RED or coalition.side.NEUTRAL +-- @param #string Text Briefing text, can contain newlines, will be converted formatted properly for DCS +-- @param #string Picture Picture filename, can be a file in the DEFAULT folder inside the .miz +function UTILS.SetMissionBriefing(Coalition, Text, Picture) + Text = Text or "" + Text = Text:gsub("\n", "\\n") + Picture = Picture or "" + local coalName = string.lower(UTILS.GetCoalitionName(Coalition)) + net.dostring_in("mission", string.format("a_set_briefing(\"%s\", getValueResourceByKey(\"%s\"), \"%s\")", coalName, Picture, Text)) +end + --- Show a helper gate at a DCS#Vec3 position -- @param DCS#Vec3 pos The position -- @param number heading Heading in degrees, can be 0..359 degrees From b9be3aa7f888cf1b3f92704bf13d4884d708e4bb Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sun, 27 Jul 2025 14:50:45 +0200 Subject: [PATCH 132/234] xx --- Moose Development/Moose/Ops/CSAR.lua | 1694 +++++++++++++------------- 1 file changed, 847 insertions(+), 847 deletions(-) diff --git a/Moose Development/Moose/Ops/CSAR.lua b/Moose Development/Moose/Ops/CSAR.lua index 8dede4270..ce21f7121 100644 --- a/Moose Development/Moose/Ops/CSAR.lua +++ b/Moose Development/Moose/Ops/CSAR.lua @@ -1,25 +1,25 @@ --- **Ops** - Combat Search and Rescue. -- -- === --- +-- -- **CSAR** - MOOSE based Helicopter CSAR Operations. --- +-- -- === --- +-- -- ## Missions:--- **Ops** -- Combat Search and Rescue. -- -- === --- +-- -- **CSAR** - MOOSE based Helicopter CSAR Operations. --- +-- -- === --- +-- -- ## Missions: -- -- ### [CSAR - Combat Search & Rescue](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/Ops/CSAR) --- +-- -- === --- +-- -- **Main Features:** -- -- * MOOSE-based Helicopter CSAR Operations for Players. @@ -49,24 +49,24 @@ -- === -- -- # CSAR Concept --- +-- -- * MOOSE-based Helicopter CSAR Operations for Players. -- * Object oriented refactoring of Ciribob\'s fantastic CSAR script. --- * No need for extra MIST loading. +-- * No need for extra MIST loading. -- * Additional events to tailor your mission. -- * Optional SpawnCASEVAC to create casualties without beacon (e.g. handling dead ground vehicles and create CASVAC requests). --- +-- -- ## 0. Prerequisites --- +-- -- You need to load an .ogg soundfile for the pilot\'s beacons into the mission, e.g. "beacon.ogg", use a once trigger, "sound to country" for that. -- Create a late-activated single infantry unit as template in the mission editor and name it e.g. "Downed Pilot". --- +-- -- Example sound files are here: [Moose Sound](https://github.com/FlightControl-Master/MOOSE_SOUND/tree/master/CTLD%20CSAR) --- +-- -- ## 1. Basic Setup --- +-- -- A basic setup example is the following: --- +-- -- -- Instantiate and start a CSAR for the blue side, with template "Downed Pilot" and alias "Luftrettung" -- local my_csar = CSAR:New(coalition.side.BLUE,"Downed Pilot","Luftrettung") -- -- options @@ -74,9 +74,9 @@ -- my_csar.invisiblecrew = false -- downed pilot spawn is visible -- -- start the FSM -- my_csar:__Start(5) --- +-- -- ## 2. Options --- +-- -- The following options are available (with their defaults). Only set the ones you want changed: -- -- mycsar.allowDownedPilotCAcontrol = false -- Set to false if you don\'t want to allow control by Combined Arms. @@ -87,7 +87,7 @@ -- mycsar.coordtype = 1 -- Use Lat/Long DDM (0), Lat/Long DMS (1), MGRS (2), Bullseye imperial (3) or Bullseye metric (4) for coordinates. -- mycsar.csarOncrash = false -- (WIP) If set to true, will generate a downed pilot when a plane crashes as well. -- mycsar.enableForAI = false -- set to false to disable AI pilots from being rescued. --- mycsar.pilotRuntoExtractPoint = true -- Downed pilot will run to the rescue helicopter up to mycsar.extractDistance in meters. +-- mycsar.pilotRuntoExtractPoint = true -- Downed pilot will run to the rescue helicopter up to mycsar.extractDistance in meters. -- mycsar.extractDistance = 500 -- Distance the downed pilot will start to run to the rescue helicopter. -- mycsar.immortalcrew = true -- Set to true to make wounded crew immortal. -- mycsar.invisiblecrew = false -- Set to true to make wounded crew insvisible. @@ -95,14 +95,14 @@ -- mycsar.mashprefix = {"MASH"} -- prefixes of #GROUP objects used as MASHes. Will also try to add ZONE and STATIC objects with this prefix once at startup. -- mycsar.max_units = 6 -- max number of pilots that can be carried if #CSAR.AircraftType is undefined. -- mycsar.messageTime = 15 -- Time to show messages for in seconds. Doubled for long messages. --- mycsar.radioSound = "beacon.ogg" -- the name of the sound file to use for the pilots\' radio beacons. +-- mycsar.radioSound = "beacon.ogg" -- the name of the sound file to use for the pilots\' radio beacons. -- mycsar.smokecolor = 4 -- Color of smokemarker, 0 is green, 1 is red, 2 is white, 3 is orange and 4 is blue. -- mycsar.useprefix = true -- Requires CSAR helicopter #GROUP names to have the prefix(es) defined below. --- mycsar.csarPrefix = { "helicargo", "MEDEVAC"} -- #GROUP name prefixes used for useprefix=true - DO NOT use # in helicopter names in the Mission Editor! +-- mycsar.csarPrefix = { "helicargo", "MEDEVAC"} -- #GROUP name prefixes used for useprefix=true - DO NOT use # in helicopter names in the Mission Editor! -- mycsar.verbose = 0 -- set to > 1 for stats output for debugging. -- -- limit amount of downed pilots spawned by **ejection** events -- mycsar.limitmaxdownedpilots = true --- mycsar.maxdownedpilots = 10 +-- mycsar.maxdownedpilots = 10 -- -- allow to set far/near distance for approach and optionally pilot must open doors -- mycsar.approachdist_far = 5000 -- switch do 10 sec interval approach mode, meters -- mycsar.approachdist_near = 3000 -- switch to 5 sec interval approach mode, meters @@ -119,16 +119,16 @@ -- mycsar.PilotWeight = 80 -- Loaded pilots weigh 80kgs each -- mycsar.AllowIRStrobe = false -- Allow a menu item to request an IR strobe to find a downed pilot at night (requires NVGs to see it). -- mycsar.IRStrobeRuntime = 300 -- If an IR Strobe is activated, it runs for 300 seconds (5 mins). --- +-- -- ## 2.1 Create own SET_GROUP to manage CTLD Pilot groups --- +-- -- -- Parameter: Set The SET_GROUP object created by the mission designer/user to represent the CSAR pilot groups. -- -- Needs to be set before starting the CSAR instance. -- local myset = SET_GROUP:New():FilterPrefixes("Helikopter"):FilterCoalitions("red"):FilterStart() -- mycsar:SetOwnSetPilotGroups(myset) --- +-- -- ## 2.2 SRS Features and Other Features --- +-- -- mycsar.useSRS = false -- Set true to use FF\'s SRS integration -- mycsar.SRSPath = "C:\\Progra~1\\DCS-SimpleRadio-Standalone\\ExternalAudio\\" -- adjust your own path in your SRS installation -- server(!) -- mycsar.SRSchannel = 300 -- radio channel @@ -147,88 +147,88 @@ -- mycsar.wetfeettemplate = "man in floating thingy" -- if you use a mod to have a pilot in a rescue float, put the template name in here for wet feet spawns. Note: in conjunction with csarUsePara this might create dual ejected pilots in edge cases. -- mycsar.allowbronco = false -- set to true to use the Bronco mod as a CSAR plane -- mycsar.CreateRadioBeacons = true -- set to false to disallow creating ADF radio beacons. --- +-- -- ## 3. Results --- +-- -- Number of successful landings with save pilots and aggregated number of saved pilots is stored in these variables in the object: --- +-- -- mycsar.rescues -- number of successful landings *with* saved pilots -- mycsar.rescuedpilots -- aggregated number of pilots rescued from the field (of *all* players) --- +-- -- ## 4. Events -- -- The class comes with a number of FSM-based events that missions designers can use to shape their mission. -- These are: --- --- ### 4.1. PilotDown. --- +-- +-- ### 4.1. PilotDown. +-- -- The event is triggered when a new downed pilot is detected. Use e.g. `function my_csar:OnAfterPilotDown(...)` to link into this event: --- +-- -- function my_csar:OnAfterPilotDown(from, event, to, spawnedgroup, frequency, groupname, coordinates_text) -- ... your code here ... -- end --- --- ### 4.2. Approach. --- +-- +-- ### 4.2. Approach. +-- -- A CSAR helicpoter is closing in on a downed pilot. Use e.g. `function my_csar:OnAfterApproach(...)` to link into this event: --- +-- -- function my_csar:OnAfterApproach(from, event, to, heliname, groupname) -- ... your code here ... -- end --- --- ### 4.3. Boarded. --- +-- +-- ### 4.3. Boarded. +-- -- The pilot has been boarded to the helicopter. Use e.g. `function my_csar:OnAfterBoarded(...)` to link into this event: --- +-- -- function my_csar:OnAfterBoarded(from, event, to, heliname, groupname, description) -- ... your code here ... -- end --- --- ### 4.4. Returning. --- +-- +-- ### 4.4. Returning. +-- -- The CSAR helicopter is ready to return to an Airbase, FARP or MASH. Use e.g. `function my_csar:OnAfterReturning(...)` to link into this event: --- +-- -- function my_csar:OnAfterReturning(from, event, to, heliname, groupname) -- ... your code here ... -- end --- --- ### 4.5. Rescued. --- +-- +-- ### 4.5. Rescued. +-- -- The CSAR helicopter has landed close to an Airbase/MASH/FARP and the pilots are safe. Use e.g. `function my_csar:OnAfterRescued(...)` to link into this event: --- +-- -- function my_csar:OnAfterRescued(from, event, to, heliunit, heliname, pilotssaved) -- ... your code here ... --- end +-- end -- -- ## 5. Spawn downed pilots at location to be picked up. --- +-- -- If missions designers want to spawn downed pilots into the field, e.g. at mission begin to give the helicopter guys works, they can do this like so: --- +-- -- -- Create downed "Pilot Wagner" in #ZONE "CSAR_Start_1" at a random point for the blue coalition -- my_csar:SpawnCSARAtZone( "CSAR_Start_1", coalition.side.BLUE, "Pilot Wagner", true ) -- -- --Create a casualty and CASEVAC request from a "Point" (VEC2) for the blue coalition --shagrat --- my_csar:SpawnCASEVAC(Point, coalition.side.BLUE) --- +-- my_csar:SpawnCASEVAC(Point, coalition.side.BLUE) +-- -- ## 6. Save and load downed pilots - Persistance --- +-- -- You can save and later load back downed pilots to make your mission persistent. -- For this to work, you need to de-sanitize **io** and **lfs** in your MissionScripting.lua, which is located in your DCS installtion folder under Scripts. -- There is a risk involved in doing that; if you do not know what that means, this is possibly not for you. --- +-- -- Use the following options to manage your saves: --- +-- -- mycsar.enableLoadSave = true -- allow auto-saving and loading of files -- mycsar.saveinterval = 600 -- save every 10 minutes -- mycsar.filename = "missionsave.csv" -- example filename -- mycsar.filepath = "C:\\Users\\myname\\Saved Games\\DCS\Missions\\MyMission" -- example path --- +-- -- Then use an initial load at the beginning of your mission: --- +-- -- mycsar:__Load(10) --- +-- -- **Caveat:** --- Dropped troop noMessage and forcedesc parameters aren't saved. +-- Dropped troop noMessage and forcedesc parameters aren't saved. -- -- @field #CSAR CSAR = { @@ -254,7 +254,7 @@ CSAR = { hoverStatus = {}, -- tracks status of a helis hover above a downed pilot pilotDisabled = {}, -- tracks what aircraft a pilot is disabled for pilotLives = {}, -- tracks how many lives a pilot has - useprefix = true, -- Use the Prefixed defined below, Requires Unit have the Prefix defined below + useprefix = true, -- Use the Prefixed defined below, Requires Unit have the Prefix defined below csarPrefix = {}, template = nil, mash = {}, @@ -300,10 +300,10 @@ CSAR.AircraftType["SA342L"] = 4 CSAR.AircraftType["SA342M"] = 4 CSAR.AircraftType["UH-1H"] = 8 CSAR.AircraftType["Mi-8MTV2"] = 12 -CSAR.AircraftType["Mi-8MT"] = 12 -CSAR.AircraftType["Mi-24P"] = 8 +CSAR.AircraftType["Mi-8MT"] = 12 +CSAR.AircraftType["Mi-24P"] = 8 CSAR.AircraftType["Mi-24V"] = 8 -CSAR.AircraftType["Bell-47"] = 2 +CSAR.AircraftType["Bell-47"] = 2 CSAR.AircraftType["UH-60L"] = 10 CSAR.AircraftType["AH-64D_BLK_II"] = 2 CSAR.AircraftType["Bronco-OV-10A"] = 2 @@ -334,12 +334,12 @@ CSAR.version="1.0.33" -- @param #string Alias An *optional* alias how this object is called in the logs etc. -- @return #CSAR self function CSAR:New(Coalition, Template, Alias) - + -- Inherit everything from FSM class. local self=BASE:Inherit(self, FSM:New()) -- #CSAR - + BASE:T({Coalition, Template, Alias}) - + --set Coalition if Coalition and type(Coalition)=="string" then if Coalition=="blue" then @@ -358,12 +358,12 @@ function CSAR:New(Coalition, Template, Alias) self.coalition = Coalition self.coalitiontxt = string.lower(UTILS.GetCoalitionName(self.coalition)) end - + -- Set alias. if Alias then self.alias=tostring(Alias) else - self.alias="Red Cross" + self.alias="Red Cross" if self.coalition then if self.coalition==coalition.side.RED then self.alias="IFRC" @@ -372,10 +372,10 @@ function CSAR:New(Coalition, Template, Alias) end end end - + -- Set some string id for output to DCS.log file. self.lid=string.format("%s (%s) | ", self.alias, self.coalition and UTILS.GetCoalitionName(self.coalition) or "unknown") - + -- Start State. self:SetStartState("Stopped") @@ -385,12 +385,12 @@ function CSAR:New(Coalition, Template, Alias) self:AddTransition("*", "Status", "*") -- CSAR status update. self:AddTransition("*", "PilotDown", "*") -- Downed Pilot added self:AddTransition("*", "Approach", "*") -- CSAR heli closing in. - self:AddTransition("*", "Landed", "*") -- CSAR heli landed + self:AddTransition("*", "Landed", "*") -- CSAR heli landed self:AddTransition("*", "Boarded", "*") -- Pilot boarded. self:AddTransition("*", "Returning", "*") -- CSAR able to return to base. self:AddTransition("*", "Rescued", "*") -- Pilot at MASH. self:AddTransition("*", "KIA", "*") -- Pilot killed in action. - self:AddTransition("*", "Load", "*") -- CSAR load event. + self:AddTransition("*", "Load", "*") -- CSAR load event. self:AddTransition("*", "Save", "*") -- CSAR save event. self:AddTransition("*", "Stop", "Stopped") -- Stop FSM. @@ -411,7 +411,7 @@ function CSAR:New(Coalition, Template, Alias) self.woundedGroups = {} -- contains the new group of units self.downedPilots = {} -- Replacement woundedGroups self.downedpilotcounter = 1 - + -- settings, counters etc self.rescues = 0 -- counter for successful rescue landings at FARP/AFB/MASH self.rescuedpilots = 0 -- counter for saved pilots @@ -421,9 +421,9 @@ function CSAR:New(Coalition, Template, Alias) self.smokecolor = 4 -- Color of smokemarker for blue side, 0 is green, 1 is red, 2 is white, 3 is orange and 4 is blue self.coordtype = 2 -- Use Lat/Long DDM (0), Lat/Long DMS (1), MGRS (2), Bullseye imperial (3) or Bullseye metric (4) for coordinates. self.immortalcrew = true -- Set to true to make wounded crew immortal - self.invisiblecrew = false -- Set to true to make wounded crew insvisible - self.messageTime = 15 -- Time to show longer messages for in seconds - self.pilotRuntoExtractPoint = true -- Downed Pilot will run to the rescue helicopter up to self.extractDistance METERS + self.invisiblecrew = false -- Set to true to make wounded crew insvisible + self.messageTime = 15 -- Time to show longer messages for in seconds + self.pilotRuntoExtractPoint = true -- Downed Pilot will run to the rescue helicopter up to self.extractDistance METERS self.loadDistance = 75 -- configure distance for pilot to get in helicopter in meters. self.extractDistance = 500 -- Distance the Downed pilot will run to the rescue helicopter self.loadtimemax = 135 -- seconds @@ -432,11 +432,11 @@ function CSAR:New(Coalition, Template, Alias) self.allowFARPRescue = true --allows pilot to be rescued by landing at a FARP or Airbase self.FARPRescueDistance = 1000 -- you need to be this close to a FARP or Airport for the pilot to be rescued. self.max_units = 6 --max number of pilots that can be carried - self.useprefix = true -- Use the Prefixed defined below, Requires Unit have the Prefix defined below + self.useprefix = true -- Use the Prefixed defined below, Requires Unit have the Prefix defined below self.csarPrefix = { "helicargo", "MEDEVAC"} -- prefixes used for useprefix=true - DON\'T use # in names! self.template = Template or "generic" -- template for downed pilot self.mashprefix = {"MASH"} -- prefixes used to find MASHes - + self.autosmoke = false -- automatically smoke location when heli is near self.autosmokedistance = 2000 -- distance for autosmoke -- added 0.1.4 @@ -449,34 +449,34 @@ function CSAR:New(Coalition, Template, Alias) self.approachdist_near = 3000 -- switch to 5 sec interval approach mode, meters self.pilotmustopendoors = false -- switch to true to enable check on open doors self.suppressmessages = false - + -- added 0.1.11r1 self.rescuehoverheight = 20 self.rescuehoverdistance = 10 - + -- added 0.1.12 self.countryblue= country.id.USA self.countryred = country.id.RUSSIA self.countryneutral = country.id.UN_PEACEKEEPERS - + -- added 0.1.3 self.csarUsePara = false -- shagrat set to true, will use the LandingAfterEjection Event instead of Ejection - + -- added 0.1.4 self.wetfeettemplate = nil self.usewetfeet = false - + -- added 1.0.15 self.allowbronco = false -- set to true to use the Bronco mod as a CSAR plane - + self.ADFRadioPwr = 500 - + -- added 1.0.16 self.PilotWeight = 80 - + -- Own SET_GROUP if any self.UserSetGroup = nil - + -- WARNING - here\'ll be dragons -- for this to work you need to de-sanitize your mission environment in \Scripts\MissionScripting.lua -- needs SRS => 1.9.6 to work (works on the *server* side) @@ -493,20 +493,20 @@ function CSAR:New(Coalition, Template, Alias) self.CSARVoice = MSRS.Voices.Google.Standard.en_US_Standard_A self.CSARVoiceMS = MSRS.Voices.Microsoft.Hedda self.coordinate = nil -- Core.Point#COORDINATE - + local AliaS = string.gsub(self.alias," ","_") self.filename = string.format("CSAR_%s_Persist.csv",AliaS) - + -- load and save downed pilots self.enableLoadSave = false self.filepath = nil self.saveinterval = 600 - + ------------------------ --- Pseudo Functions --- ------------------------ - - --- Triggers the FSM event "Start". Starts the CSAR. Initializes parameters and starts event handlers. + + --- Triggers the FSM event "Start". Starts the CSAR. Initializes parameters and starts event handlers. -- @function [parent=#CSAR] Start -- @param #CSAR self @@ -531,7 +531,7 @@ function CSAR:New(Coalition, Template, Alias) -- @function [parent=#CSAR] __Status -- @param #CSAR self -- @param #number delay Delay in seconds. - -- + -- -- --- Triggers the FSM event "Load". -- @function [parent=#CSAR] Load -- @param #CSAR self @@ -540,7 +540,7 @@ function CSAR:New(Coalition, Template, Alias) -- @function [parent=#CSAR] __Load -- @param #CSAR self -- @param #number delay Delay in seconds. - + --- Triggers the FSM event "Save". -- @function [parent=#CSAR] Load -- @param #CSAR self @@ -549,7 +549,7 @@ function CSAR:New(Coalition, Template, Alias) -- @function [parent=#CSAR] __Save -- @param #CSAR self -- @param #number delay Delay in seconds. - + --- On After "PilotDown" event. Downed Pilot detected. -- @function [parent=#CSAR] OnAfterPilotDown -- @param #CSAR self @@ -561,7 +561,7 @@ function CSAR:New(Coalition, Template, Alias) -- @param #string Leadername Name of the #UNIT of the downed pilot. -- @param #string CoordinatesText String of the position of the pilot. Format determined by self.coordtype. -- @param #string Playername Player name if any given. Might be nil! - + --- On After "Aproach" event. Heli close to downed Pilot. -- @function [parent=#CSAR] OnAfterApproach -- @param #CSAR self @@ -570,8 +570,8 @@ function CSAR:New(Coalition, Template, Alias) -- @param #string To To state. -- @param #string Heliname Name of the helicopter group. -- @param #string Woundedgroupname Name of the downed pilot\'s group. - - --- On After "Landed" event. Heli landed at an airbase. + + --- On After "Landed" event. Heli landed at an airbase. -- @function [parent=#CSAR] OnAfterLanded -- @param #CSAR self -- @param #string From From state. @@ -579,8 +579,8 @@ function CSAR:New(Coalition, Template, Alias) -- @param #string To To state. -- @param #string HeliName Name of the #UNIT which has landed. -- @param Wrapper.Airbase#AIRBASE Airbase Airbase where the heli landed. - - --- On After "Boarded" event. Downed pilot boarded heli. + + --- On After "Boarded" event. Downed pilot boarded heli. -- @function [parent=#CSAR] OnAfterBoarded -- @param #CSAR self -- @param #string From From state. @@ -590,7 +590,7 @@ function CSAR:New(Coalition, Template, Alias) -- @param #string Woundedgroupname Name of the downed pilot\'s group. -- @param #string Description Descriptive name of the group. - --- On After "Returning" event. Heli can return home with downed pilot(s). + --- On After "Returning" event. Heli can return home with downed pilot(s). -- @function [parent=#CSAR] OnAfterReturning -- @param #CSAR self -- @param #string From From state. @@ -598,8 +598,8 @@ function CSAR:New(Coalition, Template, Alias) -- @param #string To To state. -- @param #string Heliname Name of the helicopter group. -- @param #string Woundedgroupname Name of the downed pilot\'s group. - - --- On After "Rescued" event. Pilot(s) have been brought to the MASH/FARP/AFB. + + --- On After "Rescued" event. Pilot(s) have been brought to the MASH/FARP/AFB. -- @function [parent=#CSAR] OnAfterRescued -- @param #CSAR self -- @param #string From From state. @@ -608,7 +608,7 @@ function CSAR:New(Coalition, Template, Alias) -- @param Wrapper.Unit#UNIT HeliUnit Unit of the helicopter. -- @param #string HeliName Name of the helicopter group. -- @param #number PilotsSaved Number of the saved pilots on board when landing. - + --- On After "KIA" event. Pilot is dead. -- @function [parent=#CSAR] OnAfterKIA -- @param #CSAR self @@ -616,7 +616,7 @@ function CSAR:New(Coalition, Template, Alias) -- @param #string Event Event. -- @param #string To To state. -- @param #string Pilotname Name of the pilot KIA. - + --- FSM Function OnAfterLoad. -- @function [parent=#CSAR] OnAfterLoad -- @param #CSAR self @@ -625,7 +625,7 @@ function CSAR:New(Coalition, Template, Alias) -- @param #string To To state. -- @param #string path (Optional) Path where the file is located. Default is the DCS root installation folder or your "Saved Games\\DCS" folder if the lfs module is desanitized. -- @param #string filename (Optional) File name for loading. Default is "CSAR__Persist.csv". - + --- FSM Function OnAfterSave. -- @function [parent=#CSAR] OnAfterSave -- @param #CSAR self @@ -634,7 +634,7 @@ function CSAR:New(Coalition, Template, Alias) -- @param #string To To state. -- @param #string path (Optional) Path where the file is saved. Default is the DCS root installation folder or your "Saved Games\\DCS" folder if the lfs module is desanitized. -- @param #string filename (Optional) File name for saving. Default is "CSAR__Persist.csv". - + return self end @@ -656,7 +656,7 @@ end -- @return #CSAR self. function CSAR:_CreateDownedPilotTrack(Group,Groupname,Side,OriginalUnit,Description,Typename,Frequency,Playername,Wetfeet,BeaconName) self:T({"_CreateDownedPilotTrack",Groupname,Side,OriginalUnit,Description,Typename,Frequency,Playername}) - + -- create new entry local DownedPilot = {} -- #CSAR.DownedPilot DownedPilot.desc = Description or "" @@ -672,7 +672,7 @@ function CSAR:_CreateDownedPilotTrack(Group,Groupname,Side,OriginalUnit,Descript DownedPilot.alive = true DownedPilot.wetfeet = Wetfeet or false DownedPilot.BeaconName = BeaconName - + -- Add Pilot local PilotTable = self.downedPilots local counter = self.downedpilotcounter @@ -688,14 +688,14 @@ end --- (Internal) Count pilots on board. -- @param #CSAR self -- @param #string _heliName --- @return #number count +-- @return #number count function CSAR:_PilotsOnboard(_heliName) self:T(self.lid .. " _PilotsOnboard") - local count = 0 + local count = 0 if self.inTransitGroups[_heliName] then - for _, _group in pairs(self.inTransitGroups[_heliName]) do - count = count + 1 - end + for _, _group in pairs(self.inTransitGroups[_heliName]) do + count = count + 1 + end end return count end @@ -705,15 +705,15 @@ end -- @param #string _unitname Name of unit. -- @return #boolean Outcome function CSAR:_DoubleEjection(_unitname) - if self.lastCrash[_unitname] then - local _time = self.lastCrash[_unitname] - if timer.getTime() - _time < 10 then - self:E(self.lid.."Caught double ejection!") - return true - end + if self.lastCrash[_unitname] then + local _time = self.lastCrash[_unitname] + if timer.getTime() - _time < 10 then + self:E(self.lid.."Caught double ejection!") + return true end - self.lastCrash[_unitname] = timer.getTime() - return false + end + self.lastCrash[_unitname] = timer.getTime() + return false end --- (User) Add a PLAYERTASK - FSM events will check success @@ -744,8 +744,8 @@ function CSAR:_SpawnPilotInField(country,point,frequency,wetfeet) for i=1,10 do math.random(i,10000) end - if point:IsSurfaceTypeWater() or wetfeet then - point.y = 0 + if point:IsSurfaceTypeWater() or wetfeet then + point.y = 0 end local template = self.template if self.usewetfeet and wetfeet then @@ -770,29 +770,29 @@ end function CSAR:_AddSpecialOptions(group) self:T(self.lid.." _AddSpecialOptions") self:T({group}) - + local immortalcrew = self.immortalcrew local invisiblecrew = self.invisiblecrew if immortalcrew then local _setImmortal = { - id = 'SetImmortal', - params = { - value = true - } + id = 'SetImmortal', + params = { + value = true + } } group:SetCommand(_setImmortal) end if invisiblecrew then local _setInvisible = { - id = 'SetInvisible', - params = { - value = true - } + id = 'SetInvisible', + params = { + value = true + } } - group:SetCommand(_setInvisible) + group:SetCommand(_setInvisible) end - + group:OptionAlarmStateGreen() group:OptionROEHoldFire() return self @@ -807,7 +807,7 @@ end -- @param #string _unitName Unitname -- @param #string _playerName Playername -- @param #number _freq Frequency --- @param #boolean noMessage +-- @param #boolean noMessage -- @param #string _description Description -- @param #boolean forcedesc Use the description only for the pilot track entry -- @return Wrapper.Group#GROUP PilotInField Pilot GROUP object @@ -818,31 +818,31 @@ function CSAR:_AddCsar(_coalition , _country, _point, _typeName, _unitName, _pla local template = self.template local wetfeet = false - + local surface = _point:GetSurfaceType() if surface == land.SurfaceType.WATER then wetfeet = true end - + if not _freq then _freq = self:_GenerateADFFrequency() if not _freq then _freq = 333000 end --noob catch - end - + end + local _spawnedGroup, _alias = self:_SpawnPilotInField(_country,_point,_freq,wetfeet) - + local _typeName = _typeName or "Pilot" - + if not noMessage then if _freq ~= 0 then --shagrat different CASEVAC msg - self:_DisplayToAllSAR("MAYDAY MAYDAY! " .. _typeName .. " is down. ", self.coalition, self.messageTime) - else - self:_DisplayToAllSAR("Troops In Contact. " .. _typeName .. " requests CASEVAC. ", self.coalition, self.messageTime) + self:_DisplayToAllSAR("MAYDAY MAYDAY! " .. _typeName .. " is down. ", self.coalition, self.messageTime) + else + self:_DisplayToAllSAR("Troops In Contact. " .. _typeName .. " requests CASEVAC. ", self.coalition, self.messageTime) + end end - end - + local BeaconName - + if _playerName then BeaconName = _playerName..math.random(1,10000) elseif _unitName then @@ -850,37 +850,37 @@ function CSAR:_AddCsar(_coalition , _country, _point, _typeName, _unitName, _pla else BeaconName = "Ghost-1-1"..math.random(1,10000) end - - if (_freq and _freq ~= 0) then --shagrat only add beacon if _freq is NOT 0 + + if (_freq and _freq ~= 0) then --shagrat only add beacon if _freq is NOT 0 self:_AddBeaconToGroup(_spawnedGroup, _freq, BeaconName) end - + self:_AddSpecialOptions(_spawnedGroup) local _text = _description if not forcedesc then if _playerName ~= nil then - if _freq ~= 0 then --shagrat - _text = "Pilot " .. _playerName - else - _text = "TIC - " .. _playerName - end + if _freq ~= 0 then --shagrat + _text = "Pilot " .. _playerName + else + _text = "TIC - " .. _playerName + end elseif _unitName ~= nil then - if _freq ~= 0 then --shagrat - _text = "AI Pilot of " .. _unitName - else - _text = "TIC - " .. _unitName + if _freq ~= 0 then --shagrat + _text = "AI Pilot of " .. _unitName + else + _text = "TIC - " .. _unitName + end end end - end self:T({_spawnedGroup, _alias}) - + local _GroupName = _spawnedGroup:GetName() or _alias self:_CreateDownedPilotTrack(_spawnedGroup,_GroupName,_coalition,_unitName,_text,_typeName,_freq,_playerName,wetfeet,BeaconName) self:_InitSARForPilot(_spawnedGroup, _unitName, _freq, noMessage, _playerName) --shagrat use unitName to have the aircraft callsign / descriptive "name" etc. - + return _spawnedGroup, _alias end @@ -897,7 +897,7 @@ end function CSAR:_SpawnCsarAtZone( _zone, _coalition, _description, _randomPoint, _nomessage, unitname, typename, forcedesc) self:T(self.lid .. " _SpawnCsarAtZone") local freq = self:_GenerateADFFrequency() - + local _triggerZone = nil if type(_zone) == "string" then _triggerZone = ZONE:New(_zone) -- trigger to use as reference position @@ -906,16 +906,16 @@ function CSAR:_SpawnCsarAtZone( _zone, _coalition, _description, _randomPoint, _ _triggerZone = _zone -- is already a zone end end - + if _triggerZone == nil then self:E(self.lid.."ERROR: Can\'t find zone called " .. _zone, 10) return end - + local _description = _description or "PoW" local unitname = unitname or "Old Rusty" local typename = typename or "Phantom II" - + local pos = {} if _randomPoint then local _pos = _triggerZone:GetRandomPointVec3() @@ -923,7 +923,7 @@ function CSAR:_SpawnCsarAtZone( _zone, _coalition, _description, _randomPoint, _ else pos = _triggerZone:GetCoordinate() end - + local _country = 0 if _coalition == coalition.side.BLUE then _country = self.countryblue @@ -932,9 +932,9 @@ function CSAR:_SpawnCsarAtZone( _zone, _coalition, _description, _randomPoint, _ else _country = self.countryneutral end - + self:_AddCsar(_coalition, _country, pos, typename, unitname, _description, freq, _nomessage, _description, forcedesc) - + return self end @@ -949,7 +949,7 @@ end -- @param #string Typename (optional) Type of plane. -- @param #boolean Forcedesc (optional) Force to use the **description passed only** for the pilot track entry. Use to have fully custom names. -- @usage If missions designers want to spawn downed pilots into the field, e.g. at mission begin, to give the helicopter guys work, they can do this like so: --- +-- -- -- Create downed "Pilot Wagner" in #ZONE "CSAR_Start_1" at a random point for the blue coalition -- my_csar:SpawnCSARAtZone( "CSAR_Start_1", coalition.side.BLUE, "Wagner", true, false, "Charly-1-1", "F5E" ) function CSAR:SpawnCSARAtZone(Zone, Coalition, Description, RandomPoint, Nomessage, Unitname, Typename, Forcedesc) @@ -968,14 +968,14 @@ end -- @param #boolean forcedesc (optional) Force to use the description passed only for the pilot track entry. Use to have fully custom names. function CSAR:_SpawnCASEVAC( _Point, _coalition, _description, _nomessage, unitname, typename, forcedesc) --shagrat added internal Function _SpawnCASEVAC self:T(self.lid .. " _SpawnCASEVAC") - + local _description = _description or "CASEVAC" local unitname = unitname or "CASEVAC" local typename = typename or "Ground Commander" - + local pos = {} pos = _Point - + local _country = 0 if _coalition == coalition.side.BLUE then _country = self.countryblue @@ -986,7 +986,7 @@ function CSAR:_SpawnCASEVAC( _Point, _coalition, _description, _nomessage, unitn end --shagrat set frequency to 0 as "flag" for no beacon self:_AddCsar(_coalition, _country, pos, typename, unitname, _description, 0, _nomessage, _description, forcedesc) - + return self end @@ -1000,10 +1000,10 @@ end -- @param #string Typename (optional) Type of plane. -- @param #boolean Forcedesc (optional) Force to use the **description passed only** for the pilot track entry. Use to have fully custom names. -- @usage If missions designers want to spawn downed pilots into the field, e.g. at mission begin, to give the helicopter guys work, they can do this like so: --- +-- -- -- Create casualty "CASEVAC" at coordinate Core.Point#COORDINATE for the blue coalition. -- my_csar:SpawnCASEVAC( coordinate, coalition.side.BLUE ) -function CSAR:SpawnCASEVAC(Point, Coalition, Description, Nomessage, Unitname, Typename, Forcedesc) +function CSAR:SpawnCASEVAC(Point, Coalition, Description, Nomessage, Unitname, Typename, Forcedesc) self:_SpawnCASEVAC(Point, Coalition, Description, Nomessage, Unitname, Typename, Forcedesc) return self end --shagrat end added CASEVAC @@ -1013,57 +1013,57 @@ end --shagrat end added CASEVAC function CSAR:_EventHandler(EventData) self:T(self.lid .. " _EventHandler") self:T({Event = EventData.id}) - + local _event = EventData -- Core.Event#EVENTDATA - - -- no Player + + -- no Player if self.enableForAI == false and _event.IniPlayerName == nil then - return self - end - - -- no event + return self + end + + -- no event if _event == nil or _event.initiator == nil then return self - - -- take off + + -- take off elseif _event.id == EVENTS.Takeoff then -- taken off self:T(self.lid .. " Event unit - Takeoff") - + local _coalition = _event.IniCoalition if _coalition ~= self.coalition then - return self --ignore! + return self --ignore! end - + if _event.IniGroupName then - self.takenOff[_event.IniUnitName] = true + self.takenOff[_event.IniUnitName] = true end - + return self - - -- player enter unit + + -- player enter unit elseif _event.id == EVENTS.PlayerEnterAircraft or _event.id == EVENTS.PlayerEnterUnit then --player entered unit self:T(self.lid .. " Event unit - Player Enter") - + local _coalition = _event.IniCoalition self:T("Coalition = "..UTILS.GetCoalitionName(_coalition)) if _coalition ~= self.coalition then - return self --ignore! + return self --ignore! end - + if _event.IniPlayerName then - self.takenOff[_event.IniPlayerName] = nil + self.takenOff[_event.IniPlayerName] = nil end - + -- jumped into flying plane? self:T("Taken Off: "..tostring(_event.IniUnit:InAir(true))) - + if _event.IniUnit:InAir(true) then self.takenOff[_event.IniPlayerName] = true end - + local _unit = _event.IniUnit local _group = _event.IniGroup - + local function IsBronco(Group) local grp = Group -- Wrapper.Group#GROUP local typename = grp:GetTypeName() @@ -1071,81 +1071,81 @@ function CSAR:_EventHandler(EventData) if typename == "Bronco-OV-10A" then return true end return false end - + if _unit:IsHelicopter() or _group:IsHelicopter() or IsBronco(_group) then self:_AddMedevacMenuItem() - end - - return self - - elseif (_event.id == EVENTS.PilotDead and self.csarOncrash == false) then - -- Pilot dead - - self:T(self.lid .. " Event unit - Pilot Dead") - - local _unit = _event.IniUnit - local _unitname = _event.IniUnitName - local _group = _event.IniGroup - - if _unit == nil then - return self -- error! - end - - local _coalition = _event.IniCoalition - if _coalition ~= self.coalition then - return self --ignore! - end - - -- Catch multiple events here? - if self.takenOff[_event.IniUnitName] == true or _group:IsAirborne() then - if self:_DoubleEjection(_unitname) then - return self - end + end - else - self:T(self.lid .. " Pilot has not taken off, ignore") - end - - return self - - elseif _event.id == EVENTS.PilotDead or _event.id == EVENTS.Ejection then - if _event.id == EVENTS.PilotDead and self.csarOncrash == false then - return self - end - self:T(self.lid .. " Event unit - Pilot Ejected") - - local _unit = _event.IniUnit - local _unitname = _event.IniUnitName - local _group = _event.IniGroup - - self:T({_unit.UnitName, _unitname, _group.GroupName}) - - if _unit == nil then - self:T("Unit NIL!") - return self -- error! - end - - --local _coalition = _unit:GetCoalition() -- nil now for some reason - local _coalition = _group:GetCoalition() - if _coalition ~= self.coalition then - self:T("Wrong coalition! Coalition = "..UTILS.GetCoalitionName(_coalition)) - return self --ignore! - end - - - self:T("Airborne: "..tostring(_group:IsAirborne())) - self:T("Taken Off: "..tostring(self.takenOff[_event.IniUnitName])) - - if not self.takenOff[_event.IniUnitName] and not _group:IsAirborne() then - self:T(self.lid .. " Pilot has not taken off, ignore") - -- return self -- give up, pilot hasnt taken off - end - + return self + + elseif (_event.id == EVENTS.PilotDead and self.csarOncrash == false) then + -- Pilot dead + + self:T(self.lid .. " Event unit - Pilot Dead") + + local _unit = _event.IniUnit + local _unitname = _event.IniUnitName + local _group = _event.IniGroup + + if _unit == nil then + return self -- error! + end + + local _coalition = _event.IniCoalition + if _coalition ~= self.coalition then + return self --ignore! + end + + -- Catch multiple events here? + if self.takenOff[_event.IniUnitName] == true or _group:IsAirborne() then if self:_DoubleEjection(_unitname) then - self:T("Double Ejection!") return self end + else + self:T(self.lid .. " Pilot has not taken off, ignore") + end + + return self + + elseif _event.id == EVENTS.PilotDead or _event.id == EVENTS.Ejection then + if _event.id == EVENTS.PilotDead and self.csarOncrash == false then + return self + end + self:T(self.lid .. " Event unit - Pilot Ejected") + + local _unit = _event.IniUnit + local _unitname = _event.IniUnitName + local _group = _event.IniGroup + + self:T({_unit.UnitName, _unitname, _group.GroupName}) + + if _unit == nil then + self:T("Unit NIL!") + return self -- error! + end + + --local _coalition = _unit:GetCoalition() -- nil now for some reason + local _coalition = _group:GetCoalition() + if _coalition ~= self.coalition then + self:T("Wrong coalition! Coalition = "..UTILS.GetCoalitionName(_coalition)) + return self --ignore! + end + + + self:T("Airborne: "..tostring(_group:IsAirborne())) + self:T("Taken Off: "..tostring(self.takenOff[_event.IniUnitName])) + + if not self.takenOff[_event.IniUnitName] and not _group:IsAirborne() then + self:T(self.lid .. " Pilot has not taken off, ignore") + -- return self -- give up, pilot hasnt taken off + end + + if self:_DoubleEjection(_unitname) then + self:T("Double Ejection!") + return self + end + local initdcscoord = nil local initcoord = nil @@ -1159,105 +1159,105 @@ function CSAR:_EventHandler(EventData) self:T({initdcscoord}) end - -- Remove downed pilot if already exists to replace with new one. - if _event.IniPlayerName then - local PilotTable = self.downedPilots --#CSAR.DownedPilot - local _foundPilot = nil - for _,_pilot in pairs(PilotTable) do - if _pilot.player == _event.IniPlayerName and _pilot.alive == true then - _foundPilot = _pilot - break - end - end - if _foundPilot then - self:T("Downed pilot already exists!") - _foundPilot.group:Destroy(false) - self:_RemoveNameFromDownedPilots(_foundPilot.name) - self:_CheckDownedPilotTable() - end + -- Remove downed pilot if already exists to replace with new one. + if _event.IniPlayerName then + local PilotTable = self.downedPilots --#CSAR.DownedPilot + local _foundPilot = nil + for _,_pilot in pairs(PilotTable) do + if _pilot.player == _event.IniPlayerName and _pilot.alive == true then + _foundPilot = _pilot + break + end end + if _foundPilot then + self:T("Downed pilot already exists!") + _foundPilot.group:Destroy(false) + self:_RemoveNameFromDownedPilots(_foundPilot.name) + self:_CheckDownedPilotTable() + end + end + + -- limit no of pilots in the field. + if self.limitmaxdownedpilots and self:_ReachedPilotLimit() then + self:T("Maxed Downed Pilot!") + return self + end + - -- limit no of pilots in the field. - if self.limitmaxdownedpilots and self:_ReachedPilotLimit() then - self:T("Maxed Downed Pilot!") - return self - end - - -- TODO: Over water check --- EVENTS.LandingAfterEjection NOT triggered by DCS, so handle csarUsePara = true case -- might create dual pilots in edge cases - + local wetfeet = false - + --local surface = _unit:GetCoordinate():GetSurfaceType() local surface = initcoord:GetSurfaceType() - + if surface == land.SurfaceType.WATER then self:T("Wet feet!") wetfeet = true - end - -- all checks passed, get going. + end + -- all checks passed, get going. if self.csarUsePara == false or (self.csarUsePara and wetfeet ) then --shagrat check parameter LandingAfterEjection, if true don't spawn a Pilot from EJECTION event, wait for the Chute to land local _freq = self:_GenerateADFFrequency() - self:_AddCsar(_coalition, _unit:GetCountry(), initcoord , _unit:GetTypeName(), _unit:GetName(), _event.IniPlayerName, _freq, false, "none") + self:_AddCsar(_coalition, _unit:GetCountry(), initcoord , _unit:GetTypeName(), _unit:GetName(), _event.IniPlayerName, _freq, false, "none") return self end - + elseif _event.id == EVENTS.Land then - self:T(self.lid .. " Landing") - - if _event.IniUnitName then - self.takenOff[_event.IniUnitName] = nil + self:T(self.lid .. " Landing") + + if _event.IniUnitName then + self.takenOff[_event.IniUnitName] = nil + end + + if self.allowFARPRescue then + + local _unit = _event.IniUnit -- Wrapper.Unit#UNIT + + if _unit == nil then + self:T(self.lid .. " Unit nil on landing") + return self -- error! end - - if self.allowFARPRescue then - - local _unit = _event.IniUnit -- Wrapper.Unit#UNIT - - if _unit == nil then - self:T(self.lid .. " Unit nil on landing") - return self -- error! - end - - --local _coalition = _event.IniCoalition - local _coalition = _event.IniGroup:GetCoalition() - if _coalition ~= self.coalition then - self:T(self.lid .. " Wrong coalition") - return self --ignore! - end - - self.takenOff[_event.IniUnitName] = nil - - local _place = _event.Place -- Wrapper.Airbase#AIRBASE - - if _place == nil then - self:T(self.lid .. " Landing Place Nil") - return self -- error! - end - - -- anyone on board? - if self.inTransitGroups[_event.IniUnitName] == nil then - -- ignore - return self - end - - if _place:GetCoalition() == self.coalition or _place:GetCoalition() == coalition.side.NEUTRAL then - self:__Landed(2,_event.IniUnitName, _place) - self:_ScheduledSARFlight(_event.IniUnitName,_event.IniGroupName,true,true) - else - self:T(string.format("Airfield %d, Unit %d", _place:GetCoalition(), _unit:GetCoalition())) - end - end - - return self + + --local _coalition = _event.IniCoalition + local _coalition = _event.IniGroup:GetCoalition() + if _coalition ~= self.coalition then + self:T(self.lid .. " Wrong coalition") + return self --ignore! end - + + self.takenOff[_event.IniUnitName] = nil + + local _place = _event.Place -- Wrapper.Airbase#AIRBASE + + if _place == nil then + self:T(self.lid .. " Landing Place Nil") + return self -- error! + end + + -- anyone on board? + if self.inTransitGroups[_event.IniUnitName] == nil then + -- ignore + return self + end + + if _place:GetCoalition() == self.coalition or _place:GetCoalition() == coalition.side.NEUTRAL then + self:__Landed(2,_event.IniUnitName, _place) + self:_ScheduledSARFlight(_event.IniUnitName,_event.IniGroupName,true,true) + else + self:T(string.format("Airfield %d, Unit %d", _place:GetCoalition(), _unit:GetCoalition())) + end + end + + return self + end + ---- shagrat on event LANDING_AFTER_EJECTION spawn pilot at parachute location if (_event.id == EVENTS.LandingAfterEjection and self.csarUsePara == true) then self:T("LANDING_AFTER_EJECTION") local _LandingPos = COORDINATE:NewFromVec3(_event.initiator:getPosition().p) local _unitname = "Aircraft" --_event.initiator:getName() or "Aircraft" --shagrat Optional use of Object name which is unfortunately 'f15_Pilot_Parachute' - local _typename = "Ejected Pilot" --_event.Initiator.getTypeName() or "Ejected Pilot" + local _typename = "Ejected Pilot" --_event.Initiator.getTypeName() or "Ejected Pilot" local _country = _event.initiator:getCountry() local _coalition = coalition.getCountryCoalition( _country ) self:T("Country = ".._country.." Coalition = ".._coalition) @@ -1265,11 +1265,11 @@ function CSAR:_EventHandler(EventData) local _freq = self:_GenerateADFFrequency() self:I({coalition=_coalition,country= _country, coord=_LandingPos, name=_unitname, player=_event.IniPlayerName, freq=_freq}) self:_AddCsar(_coalition, _country, _LandingPos, nil, _unitname, _event.IniPlayerName, _freq, false, "none")--shagrat add CSAR at Parachute location. - + Unit.destroy(_event.initiator) -- shagrat remove static Pilot model - end + end end - + return self end @@ -1287,38 +1287,38 @@ function CSAR:_InitSARForPilot(_downedGroup, _GroupName, _freq, _nomessage, _pla local _freqk = _freq / 1000 local _coordinatesText = self:_GetPositionOfWounded(_downedGroup) local _leadername = _leader:GetName() - + if not _nomessage then - if _freq ~= 0 then --shagrat - local _text = string.format("%s requests SAR at %s, beacon at %.2f KHz", _groupName, _coordinatesText, _freqk)--shagrat _groupName to prevent 'f15_Pilot_Parachute' - if self.coordtype ~= 2 then --not MGRS - self:_DisplayToAllSAR(_text,self.coalition,self.messageTime) - else - self:_DisplayToAllSAR(_text,self.coalition,self.messageTime,false,true) - local coordtext = UTILS.MGRSStringToSRSFriendly(_coordinatesText,true) - local _text = string.format("%s requests SAR at %s, beacon at %.2f kilo hertz", _groupName, coordtext, _freqk) - self:_DisplayToAllSAR(_text,self.coalition,self.messageTime,true,false) + if _freq ~= 0 then --shagrat + local _text = string.format("%s requests SAR at %s, beacon at %.2f KHz", _groupName, _coordinatesText, _freqk)--shagrat _groupName to prevent 'f15_Pilot_Parachute' + if self.coordtype ~= 2 then --not MGRS + self:_DisplayToAllSAR(_text,self.coalition,self.messageTime) + else + self:_DisplayToAllSAR(_text,self.coalition,self.messageTime,false,true) + local coordtext = UTILS.MGRSStringToSRSFriendly(_coordinatesText,true) + local _text = string.format("%s requests SAR at %s, beacon at %.2f kilo hertz", _groupName, coordtext, _freqk) + self:_DisplayToAllSAR(_text,self.coalition,self.messageTime,true,false) + end + else --shagrat CASEVAC msg + local _text = string.format("Pickup Zone at %s.", _coordinatesText ) + if self.coordtype ~= 2 then --not MGRS + self:_DisplayToAllSAR(_text,self.coalition,self.messageTime) + else + self:_DisplayToAllSAR(_text,self.coalition,self.messageTime,false,true) + local coordtext = UTILS.MGRSStringToSRSFriendly(_coordinatesText,true) + local _text = string.format("Pickup Zone at %s.", coordtext ) + self:_DisplayToAllSAR(_text,self.coalition,self.messageTime,true,false) + end end - else --shagrat CASEVAC msg - local _text = string.format("Pickup Zone at %s.", _coordinatesText ) - if self.coordtype ~= 2 then --not MGRS - self:_DisplayToAllSAR(_text,self.coalition,self.messageTime) - else - self:_DisplayToAllSAR(_text,self.coalition,self.messageTime,false,true) - local coordtext = UTILS.MGRSStringToSRSFriendly(_coordinatesText,true) - local _text = string.format("Pickup Zone at %s.", coordtext ) - self:_DisplayToAllSAR(_text,self.coalition,self.messageTime,true,false) - end - end end - + for _,_heliName in pairs(self.csarUnits) do self:_CheckWoundedGroupStatus(_heliName, _groupName) end - -- trigger FSM event + -- trigger FSM event self:__PilotDown(2,_downedGroup, _freqk, _groupName, _coordinatesText, _playername) - + return self end @@ -1336,7 +1336,7 @@ function CSAR:_CheckNameInDownedPilots(name) found = true table = _pilot break - end + end end return found, table end @@ -1366,13 +1366,13 @@ end -- @return #CSAR self function CSAR:SetCallSignOptions(ShortCallsign,Keepnumber,CallsignTranslations) if not ShortCallsign or ShortCallsign == false then - self.ShortCallsign = false + self.ShortCallsign = false else - self.ShortCallsign = true + self.ShortCallsign = true end self.Keepnumber = Keepnumber or false self.CallsignTranslations = CallsignTranslations - return self + return self end --- (Internal) Check if a name is in downed pilot table and remove it. @@ -1405,13 +1405,13 @@ function CSAR:_CheckWoundedGroupStatus(heliname,woundedgroupname) self:T("...not found in list!") return end - + local _woundedGroup = _downedpilot.group - if _woundedGroup ~= nil and _woundedGroup:IsAlive() then + if _woundedGroup ~= nil and _woundedGroup:IsAlive() then local _heliUnit = self:_GetSARHeli(_heliName) -- Wrapper.Unit#UNIT - + local _lookupKeyHeli = _heliName .. "_" .. _woundedGroupName --lookup key for message state tracking - + if _heliUnit == nil then self.heliVisibleMessage[_lookupKeyHeli] = nil self.heliCloseMessage[_lookupKeyHeli] = nil @@ -1419,15 +1419,15 @@ function CSAR:_CheckWoundedGroupStatus(heliname,woundedgroupname) self:T("...heliunit nil!") return end - + local _heliCoord = _heliUnit:GetCoordinate() local _leaderCoord = _woundedGroup:GetCoordinate() local _distance = self:_GetDistance(_heliCoord,_leaderCoord) -- autosmoke if (self.autosmoke == true) and (_distance < self.autosmokedistance) and (_distance ~= -1) then - self:_PopSmokeForGroup(_woundedGroupName, _woundedGroup) + self:_PopSmokeForGroup(_woundedGroupName, _woundedGroup) end - + if _distance < self.approachdist_near and _distance > 0 then if self:_CheckCloseWoundedGroup(_distance, _heliUnit, _heliName, _woundedGroup, _woundedGroupName) == true then -- we\'re close, reschedule @@ -1437,21 +1437,21 @@ function CSAR:_CheckWoundedGroupStatus(heliname,woundedgroupname) elseif _distance >= self.approachdist_near and _distance < self.approachdist_far then -- message once if self.heliVisibleMessage[_lookupKeyHeli] == nil then - local _pilotName = _downedpilot.desc - if self.autosmoke == true then - local dist = self.autosmokedistance / 1000 - local disttext = string.format("%.0fkm",dist) - if _SETTINGS:IsImperial() then - local dist = UTILS.MetersToNM(self.autosmokedistance) - disttext = string.format("%.0fnm",dist) - end - self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s. I hear you! Finally, that is music in my ears!\nI'll pop a smoke when you are %s away.\nLand or hover by the smoke.", self:_GetCustomCallSign(_heliName), _pilotName, disttext), self.messageTime,false,true) - else - self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s. I hear you! Finally, that is music in my ears!\nRequest a flare or smoke if you need.", self:_GetCustomCallSign(_heliName), _pilotName), self.messageTime,false,true) + local _pilotName = _downedpilot.desc + if self.autosmoke == true then + local dist = self.autosmokedistance / 1000 + local disttext = string.format("%.0fkm",dist) + if _SETTINGS:IsImperial() then + local dist = UTILS.MetersToNM(self.autosmokedistance) + disttext = string.format("%.0fnm",dist) end - --mark as shown for THIS heli and THIS group - self.heliVisibleMessage[_lookupKeyHeli] = true - end + self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s. I hear you! Finally, that is music in my ears!\nI'll pop a smoke when you are %s away.\nLand or hover by the smoke.", self:_GetCustomCallSign(_heliName), _pilotName, disttext), self.messageTime,false,true) + else + self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s. I hear you! Finally, that is music in my ears!\nRequest a flare or smoke if you need.", self:_GetCustomCallSign(_heliName), _pilotName), self.messageTime,false,true) + end + --mark as shown for THIS heli and THIS group + self.heliVisibleMessage[_lookupKeyHeli] = true + end self.heliCloseMessage[_lookupKeyHeli] = nil self.landedStatus[_lookupKeyHeli] = nil --reschedule as units aren\'t dead yet , schedule for a bit slower though as we\'re far away @@ -1459,11 +1459,11 @@ function CSAR:_CheckWoundedGroupStatus(heliname,woundedgroupname) self:__Approach(-10,heliname,woundedgroupname) end else - self:T("...Downed Pilot KIA?!") - if not _downedpilot.alive then - --self:__KIA(1,_downedpilot.name) - self:_RemoveNameFromDownedPilots(_downedpilot.name, true) - end + self:T("...Downed Pilot KIA?!") + if not _downedpilot.alive then + --self:__KIA(1,_downedpilot.name) + self:_RemoveNameFromDownedPilots(_downedpilot.name, true) + end end return self end @@ -1477,11 +1477,11 @@ function CSAR:_PopSmokeForGroup(_woundedGroupName, _woundedLeader) -- have we popped smoke already in the last 5 mins local _lastSmoke = self.smokeMarkers[_woundedGroupName] if _lastSmoke == nil or timer.getTime() > _lastSmoke then - - local _smokecolor = self.smokecolor - local _smokecoord = _woundedLeader:GetCoordinate():Translate( 6, math.random( 1, 360) ) --shagrat place smoke at a random 6 m distance, so smoke does not obscure the pilot - _smokecoord:Smoke(_smokecolor) - self.smokeMarkers[_woundedGroupName] = timer.getTime() + 300 -- next smoke time + + local _smokecolor = self.smokecolor + local _smokecoord = _woundedLeader:GetCoordinate():Translate( 6, math.random( 1, 360) ) --shagrat place smoke at a random 6 m distance, so smoke does not obscure the pilot + _smokecoord:Smoke(_smokecolor) + self.smokeMarkers[_woundedGroupName] = timer.getTime() + 300 -- next smoke time end return self end @@ -1498,43 +1498,43 @@ function CSAR:_PickupUnit(_heliUnit, _pilotName, _woundedGroup, _woundedGroupNam local _heliName = _heliUnit:GetName() local _groups = self.inTransitGroups[_heliName] local _unitsInHelicopter = self:_PilotsOnboard(_heliName) - + -- init table if there is none for this helicopter if not _groups then - self.inTransitGroups[_heliName] = {} - _groups = self.inTransitGroups[_heliName] + self.inTransitGroups[_heliName] = {} + _groups = self.inTransitGroups[_heliName] end - + -- if the heli can\'t pick them up, show a message and return local _maxUnits = self.AircraftType[_heliUnit:GetTypeName()] if _maxUnits == nil then _maxUnits = self.max_units end if _unitsInHelicopter + 1 > _maxUnits then - self:_DisplayMessageToSAR(_heliUnit, string.format("%s, %s. We\'re already crammed with %d guys! Sorry!", _pilotName, self:_GetCustomCallSign(_heliName), _unitsInHelicopter, _unitsInHelicopter), self.messageTime,false,false,true) - return self + self:_DisplayMessageToSAR(_heliUnit, string.format("%s, %s. We\'re already crammed with %d guys! Sorry!", _pilotName, self:_GetCustomCallSign(_heliName), _unitsInHelicopter, _unitsInHelicopter), self.messageTime,false,false,true) + return self end - + local found,downedgrouptable = self:_CheckNameInDownedPilots(_woundedGroupName) local grouptable = downedgrouptable --#CSAR.DownedPilot self.inTransitGroups[_heliName][_woundedGroupName] = - { + { originalUnit = grouptable.originalUnit, woundedGroup = _woundedGroupName, side = self.coalition, desc = grouptable.desc, player = grouptable.player, - } + } _woundedGroup:Destroy(false) self:_RemoveNameFromDownedPilots(_woundedGroupName,true) - + self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s I\'m in! Get to the MASH ASAP! ", self:_GetCustomCallSign(_heliName), _pilotName), self.messageTime,true,true) - + self:_UpdateUnitCargoMass(_heliName) - + self:__Boarded(5,_heliName,_woundedGroupName,grouptable.desc) - + return self end @@ -1588,136 +1588,136 @@ function CSAR:_CheckCloseWoundedGroup(_distance, _heliUnit, _heliName, _woundedG local _woundedLeader = _woundedGroup local _lookupKeyHeli = _heliUnit:GetName() .. "_" .. _woundedGroupName --lookup key for message state tracking - + local _found, _pilotable = self:_CheckNameInDownedPilots(_woundedGroupName) -- #boolean, #CSAR.DownedPilot local _pilotName = _pilotable.desc - + local _reset = true - + if (_distance < 500) then - self:T(self.lid .. "[Pickup Debug] Helo closer than 500m: ".._lookupKeyHeli) - if self.heliCloseMessage[_lookupKeyHeli] == nil then - if self.autosmoke == true then - self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s. You\'re close now! Land or hover at the smoke.", self:_GetCustomCallSign(_heliName), _pilotName), self.messageTime,false,true) - else - self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s. You\'re close now! Land in a safe place, I will go there ", self:_GetCustomCallSign(_heliName), _pilotName), self.messageTime,false,true) - end - self.heliCloseMessage[_lookupKeyHeli] = true + self:T(self.lid .. "[Pickup Debug] Helo closer than 500m: ".._lookupKeyHeli) + if self.heliCloseMessage[_lookupKeyHeli] == nil then + if self.autosmoke == true then + self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s. You\'re close now! Land or hover at the smoke.", self:_GetCustomCallSign(_heliName), _pilotName), self.messageTime,false,true) + else + self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s. You\'re close now! Land in a safe place, I will go there ", self:_GetCustomCallSign(_heliName), _pilotName), self.messageTime,false,true) end - self:T(self.lid .. "[Pickup Debug] Checking landed vs Hover for ".._lookupKeyHeli) - -- have we landed close enough? - if not _heliUnit:InAir() then - self:T(self.lid .. "[Pickup Debug] Helo landed: ".._lookupKeyHeli) - if self.pilotRuntoExtractPoint == true then - if (_distance < self.extractDistance) then - local _time = self.landedStatus[_lookupKeyHeli] - self:T(self.lid .. "[Pickup Debug] Check pilot running or arrived ".._lookupKeyHeli) - if _time == nil then - self:T(self.lid .. "[Pickup Debug] Pilot running not arrived yet ".._lookupKeyHeli) - self.landedStatus[_lookupKeyHeli] = math.floor( (_distance - self.loadDistance) / 3.6 ) - _time = self.landedStatus[_lookupKeyHeli] - _woundedGroup:OptionAlarmStateGreen() - self:_OrderGroupToMoveToPoint(_woundedGroup, _heliUnit:GetCoordinate()) - self:_DisplayMessageToSAR(_heliUnit, "Wait till " .. _pilotName .. " gets in. \nETA " .. _time .. " more seconds.", self.messageTime, false) - else - _time = self.landedStatus[_lookupKeyHeli] - 10 - self.landedStatus[_lookupKeyHeli] = _time - end - --if _time <= 0 or _distance < self.loadDistance then - self:T(self.lid .. "[Pickup Debug] Pilot close enough? ".._lookupKeyHeli) - if _distance < self.loadDistance + 5 or _distance <= 13 then - self:T(self.lid .. "[Pickup Debug] Pilot close enough - YES ".._lookupKeyHeli) - if self.pilotmustopendoors and (self:_IsLoadingDoorOpen(_heliName) == false) then - self:_DisplayMessageToSAR(_heliUnit, "Open the door to let me in!", self.messageTime, true, true) - self:T(self.lid .. "[Pickup Debug] Door closed, try again next loop ".._lookupKeyHeli) - return false - else - self:T(self.lid .. "[Pickup Debug] Pick up Pilot ".._lookupKeyHeli) - self.landedStatus[_lookupKeyHeli] = nil - self:_PickupUnit(_heliUnit, _pilotName, _woundedGroup, _woundedGroupName) - return true - end - end + self.heliCloseMessage[_lookupKeyHeli] = true + end + self:T(self.lid .. "[Pickup Debug] Checking landed vs Hover for ".._lookupKeyHeli) + -- have we landed close enough? + if not _heliUnit:InAir() then + self:T(self.lid .. "[Pickup Debug] Helo landed: ".._lookupKeyHeli) + if self.pilotRuntoExtractPoint == true then + if (_distance < self.extractDistance) then + local _time = self.landedStatus[_lookupKeyHeli] + self:T(self.lid .. "[Pickup Debug] Check pilot running or arrived ".._lookupKeyHeli) + if _time == nil then + self:T(self.lid .. "[Pickup Debug] Pilot running not arrived yet ".._lookupKeyHeli) + self.landedStatus[_lookupKeyHeli] = math.floor( (_distance - self.loadDistance) / 3.6 ) + _time = self.landedStatus[_lookupKeyHeli] + _woundedGroup:OptionAlarmStateGreen() + self:_OrderGroupToMoveToPoint(_woundedGroup, _heliUnit:GetCoordinate()) + self:_DisplayMessageToSAR(_heliUnit, "Wait till " .. _pilotName .. " gets in. \nETA " .. _time .. " more seconds.", self.messageTime, false) + else + _time = self.landedStatus[_lookupKeyHeli] - 10 + self.landedStatus[_lookupKeyHeli] = _time + end + --if _time <= 0 or _distance < self.loadDistance then + self:T(self.lid .. "[Pickup Debug] Pilot close enough? ".._lookupKeyHeli) + if _distance < self.loadDistance + 5 or _distance <= 13 then + self:T(self.lid .. "[Pickup Debug] Pilot close enough - YES ".._lookupKeyHeli) + if self.pilotmustopendoors and (self:_IsLoadingDoorOpen(_heliName) == false) then + self:_DisplayMessageToSAR(_heliUnit, "Open the door to let me in!", self.messageTime, true, true) + self:T(self.lid .. "[Pickup Debug] Door closed, try again next loop ".._lookupKeyHeli) + return false + else + self:T(self.lid .. "[Pickup Debug] Pick up Pilot ".._lookupKeyHeli) + self.landedStatus[_lookupKeyHeli] = nil + self:_PickupUnit(_heliUnit, _pilotName, _woundedGroup, _woundedGroupName) + return true end - else - self:T(self.lid .. "[Pickup Debug] Helo landed, pilot NOT set to run to helo ".._lookupKeyHeli) - if (_distance < self.loadDistance) then - self:T(self.lid .. "[Pickup Debug] Helo close enough, door check ".._lookupKeyHeli) - if self.pilotmustopendoors and (self:_IsLoadingDoorOpen(_heliName) == false) then - self:T(self.lid .. "[Pickup Debug] Door closed, try again next loop ".._lookupKeyHeli) - self:_DisplayMessageToSAR(_heliUnit, "Open the door to let me in!", self.messageTime, true, true) - return false - else - self:T(self.lid .. "[Pickup Debug] Pick up Pilot ".._lookupKeyHeli) - self:_PickupUnit(_heliUnit, _pilotName, _woundedGroup, _woundedGroupName) - return true - end end end else - self:T(self.lid .. "[Pickup Debug] Helo hovering".._lookupKeyHeli) - local _unitsInHelicopter = self:_PilotsOnboard(_heliName) - local _maxUnits = self.AircraftType[_heliUnit:GetTypeName()] - if _maxUnits == nil then - _maxUnits = self.max_units - end - self:T(self.lid .. "[Pickup Debug] Check capacity and close enough for winching ".._lookupKeyHeli) - if _heliUnit:InAir() and _unitsInHelicopter + 1 <= _maxUnits then - -- DONE - make variable - if _distance < self.rescuehoverdistance then - self:T(self.lid .. "[Pickup Debug] Helo hovering close enough ".._lookupKeyHeli) - --check height! - local leaderheight = _woundedLeader:GetHeight() - if leaderheight < 0 then leaderheight = 0 end - local _height = _heliUnit:GetHeight() - leaderheight - - -- DONE - make variable - if _height <= self.rescuehoverheight then - self:T(self.lid .. "[Pickup Debug] Helo hovering low enough ".._lookupKeyHeli) - local _time = self.hoverStatus[_lookupKeyHeli] - - if _time == nil then - self.hoverStatus[_lookupKeyHeli] = 10 - _time = 10 - else - _time = self.hoverStatus[_lookupKeyHeli] - 10 - self.hoverStatus[_lookupKeyHeli] = _time - end - self:T(self.lid .. "[Pickup Debug] Check hover timer ".._lookupKeyHeli) - if _time > 0 then - self:T(self.lid .. "[Pickup Debug] Helo hovering not long enough ".._lookupKeyHeli) - self:_DisplayMessageToSAR(_heliUnit, "Hovering above " .. _pilotName .. ". \n\nHold hover for " .. _time .. " seconds to winch them up. \n\nIf the countdown stops you\'re too far away!", self.messageTime, true) - else - self:T(self.lid .. "[Pickup Debug] Helo hovering long enough - door check ".._lookupKeyHeli) - if self.pilotmustopendoors and (self:_IsLoadingDoorOpen(_heliName) == false) then - self:_DisplayMessageToSAR(_heliUnit, "Open the door to let me in!", self.messageTime, true, true) - self:T(self.lid .. "[Pickup Debug] Door closed, try again next loop ".._lookupKeyHeli) - return false - else - self.hoverStatus[_lookupKeyHeli] = nil - self:_PickupUnit(_heliUnit, _pilotName, _woundedGroup, _woundedGroupName) - self:T(self.lid .. "[Pickup Debug] Pilot picked up ".._lookupKeyHeli) - return true - end - end - _reset = false - else - self:T(self.lid .. "[Pickup Debug] Helo hovering too high ".._lookupKeyHeli) - self:_DisplayMessageToSAR(_heliUnit, "Too high to winch " .. _pilotName .. " \nReduce height and hover for 10 seconds!", self.messageTime, true,true) - self:T(self.lid .. "[Pickup Debug] Hovering too high, try again next loop ".._lookupKeyHeli) - return false - end - end - + self:T(self.lid .. "[Pickup Debug] Helo landed, pilot NOT set to run to helo ".._lookupKeyHeli) + if (_distance < self.loadDistance) then + self:T(self.lid .. "[Pickup Debug] Helo close enough, door check ".._lookupKeyHeli) + if self.pilotmustopendoors and (self:_IsLoadingDoorOpen(_heliName) == false) then + self:T(self.lid .. "[Pickup Debug] Door closed, try again next loop ".._lookupKeyHeli) + self:_DisplayMessageToSAR(_heliUnit, "Open the door to let me in!", self.messageTime, true, true) + return false + else + self:T(self.lid .. "[Pickup Debug] Pick up Pilot ".._lookupKeyHeli) + self:_PickupUnit(_heliUnit, _pilotName, _woundedGroup, _woundedGroupName) + return true end + end end + else + self:T(self.lid .. "[Pickup Debug] Helo hovering".._lookupKeyHeli) + local _unitsInHelicopter = self:_PilotsOnboard(_heliName) + local _maxUnits = self.AircraftType[_heliUnit:GetTypeName()] + if _maxUnits == nil then + _maxUnits = self.max_units + end + self:T(self.lid .. "[Pickup Debug] Check capacity and close enough for winching ".._lookupKeyHeli) + if _heliUnit:InAir() and _unitsInHelicopter + 1 <= _maxUnits then + -- DONE - make variable + if _distance < self.rescuehoverdistance then + self:T(self.lid .. "[Pickup Debug] Helo hovering close enough ".._lookupKeyHeli) + --check height! + local leaderheight = _woundedLeader:GetHeight() + if leaderheight < 0 then leaderheight = 0 end + local _height = _heliUnit:GetHeight() - leaderheight + + -- DONE - make variable + if _height <= self.rescuehoverheight then + self:T(self.lid .. "[Pickup Debug] Helo hovering low enough ".._lookupKeyHeli) + local _time = self.hoverStatus[_lookupKeyHeli] + + if _time == nil then + self.hoverStatus[_lookupKeyHeli] = 10 + _time = 10 + else + _time = self.hoverStatus[_lookupKeyHeli] - 10 + self.hoverStatus[_lookupKeyHeli] = _time + end + self:T(self.lid .. "[Pickup Debug] Check hover timer ".._lookupKeyHeli) + if _time > 0 then + self:T(self.lid .. "[Pickup Debug] Helo hovering not long enough ".._lookupKeyHeli) + self:_DisplayMessageToSAR(_heliUnit, "Hovering above " .. _pilotName .. ". \n\nHold hover for " .. _time .. " seconds to winch them up. \n\nIf the countdown stops you\'re too far away!", self.messageTime, true) + else + self:T(self.lid .. "[Pickup Debug] Helo hovering long enough - door check ".._lookupKeyHeli) + if self.pilotmustopendoors and (self:_IsLoadingDoorOpen(_heliName) == false) then + self:_DisplayMessageToSAR(_heliUnit, "Open the door to let me in!", self.messageTime, true, true) + self:T(self.lid .. "[Pickup Debug] Door closed, try again next loop ".._lookupKeyHeli) + return false + else + self.hoverStatus[_lookupKeyHeli] = nil + self:_PickupUnit(_heliUnit, _pilotName, _woundedGroup, _woundedGroupName) + self:T(self.lid .. "[Pickup Debug] Pilot picked up ".._lookupKeyHeli) + return true + end + end + _reset = false + else + self:T(self.lid .. "[Pickup Debug] Helo hovering too high ".._lookupKeyHeli) + self:_DisplayMessageToSAR(_heliUnit, "Too high to winch " .. _pilotName .. " \nReduce height and hover for 10 seconds!", self.messageTime, true,true) + self:T(self.lid .. "[Pickup Debug] Hovering too high, try again next loop ".._lookupKeyHeli) + return false + end + end + + end + end end - + if _reset then - self.hoverStatus[_lookupKeyHeli] = nil + self.hoverStatus[_lookupKeyHeli] = nil end - + if _distance < 500 then return true else @@ -1738,14 +1738,14 @@ function CSAR:_ScheduledSARFlight(heliname,groupname, isairport, noreschedule) local _woundedGroupName = groupname if (_heliUnit == nil) then - --helicopter crashed? - self.inTransitGroups[heliname] = nil - return + --helicopter crashed? + self.inTransitGroups[heliname] = nil + return end if self.inTransitGroups[heliname] == nil or self.inTransitGroups[heliname][_woundedGroupName] == nil then - -- Groups already rescued - return + -- Groups already rescued + return end local _dist = self:_GetClosestMASH(_heliUnit) @@ -1754,9 +1754,9 @@ function CSAR:_ScheduledSARFlight(heliname,groupname, isairport, noreschedule) self:T(self.lid.."[Drop off debug] Check distance to MASH for "..heliname.." Distance can not be determined!") return end - + self:T(self.lid.."[Drop off debug] Check distance to MASH for "..heliname.." Distance km: "..math.floor(_dist/1000)) - + if ( _dist < self.FARPRescueDistance or isairport ) and _heliUnit:InAir() == false then self:T(self.lid.."[Drop off debug] Distance ok, door check") if self.pilotmustopendoors and self:_IsLoadingDoorOpen(heliname) == false then @@ -1771,8 +1771,8 @@ function CSAR:_ScheduledSARFlight(heliname,groupname, isairport, noreschedule) --queue up if not noreschedule then - self:__Returning(5,heliname,_woundedGroupName, isairport) - self:ScheduleOnce(5,self._ScheduledSARFlight,self,heliname,groupname, isairport, noreschedule) + self:__Returning(5,heliname,_woundedGroupName, isairport) + self:ScheduleOnce(5,self._ScheduledSARFlight,self,heliname,groupname, isairport, noreschedule) end return self end @@ -1784,22 +1784,22 @@ function CSAR:_RescuePilots(_heliUnit) self:T(self.lid .. " _RescuePilots") local _heliName = _heliUnit:GetName() local _rescuedGroups = self.inTransitGroups[_heliName] - + if _rescuedGroups == nil then - -- Groups already rescued - return + -- Groups already rescued + return end local PilotsSaved = self:_PilotsOnboard(_heliName) - + self.inTransitGroups[_heliName] = nil - + local _txt = string.format("%s: The %d pilot(s) have been taken to the\nmedical clinic. Good job!", self:_GetCustomCallSign(_heliName), PilotsSaved) - + self:_DisplayMessageToSAR(_heliUnit, _txt, self.messageTime) - + self:_UpdateUnitCargoMass(_heliName) - + -- trigger event self:__Rescued(-1,_heliUnit,_heliName, PilotsSaved) return self @@ -1861,9 +1861,9 @@ function CSAR:_GetPositionOfWounded(_woundedGroup,_Unit) if self.coordtype == 0 then -- Lat/Long DMTM _coordinatesText = _coordinate:ToStringLLDDM() elseif self.coordtype == 1 then -- Lat/Long DMS - _coordinatesText = _coordinate:ToStringLLDMS() + _coordinatesText = _coordinate:ToStringLLDMS() elseif self.coordtype == 2 then -- MGRS - _coordinatesText = _coordinate:ToStringMGRS() + _coordinatesText = _coordinate:ToStringMGRS() else -- Bullseye Metric --(medevac.coordtype == 4 or 3) _coordinatesText = _coordinate:ToStringBULLS(self.coalition) end @@ -1896,15 +1896,15 @@ end -- @param #string _unitName Unit to display to function CSAR:_DisplayActiveSAR(_unitName) self:T(self.lid .. " _DisplayActiveSAR") - local _msg = "Active MEDEVAC/SAR:" + local _msg = "Active MEDEVAC/SAR:" local _heli = self:_GetSARHeli(_unitName) -- Wrapper.Unit#UNIT if _heli == nil then - return + return end - + local _heliSide = self.coalition local _csarList = {} - + local _DownedPilotTable = self.downedPilots self:T({Table=_DownedPilotTable}) for _, _value in pairs(_DownedPilotTable) do @@ -1912,40 +1912,40 @@ function CSAR:_DisplayActiveSAR(_unitName) self:T(string.format("Display Active Pilot: %s", tostring(_groupName))) self:T({Table=_value}) local _woundedGroup = _value.group - if _woundedGroup and _value.alive then - local _coordinatesText = self:_GetPositionOfWounded(_woundedGroup,_heli) - local _helicoord = _heli:GetCoordinate() - local _woundcoord = _woundedGroup:GetCoordinate() - local _distance = self:_GetDistance(_helicoord, _woundcoord) - self:T({_distance = _distance}) - local distancetext = "" - local settings = _SETTINGS - if _heli:GetPlayerName() then - settings = _DATABASE:GetPlayerSettings(_heli:GetPlayerName()) or _SETTINGS - end - if settings:IsImperial() then - distancetext = string.format("%.1fnm",UTILS.MetersToNM(_distance)) - else - distancetext = string.format("%.1fkm", _distance/1000.0) - end - if _value.frequency == 0 or self.CreateRadioBeacons == false then--shagrat insert CASEVAC without Frequency - table.insert(_csarList, { dist = _distance, msg = string.format("%s at %s - %s ", _value.desc, _coordinatesText, distancetext) }) - else - table.insert(_csarList, { dist = _distance, msg = string.format("%s at %s - %.2f KHz ADF - %s ", _value.desc, _coordinatesText, _value.frequency / 1000, distancetext) }) - end + if _woundedGroup and _value.alive then + local _coordinatesText = self:_GetPositionOfWounded(_woundedGroup,_heli) + local _helicoord = _heli:GetCoordinate() + local _woundcoord = _woundedGroup:GetCoordinate() + local _distance = self:_GetDistance(_helicoord, _woundcoord) + self:T({_distance = _distance}) + local distancetext = "" + local settings = _SETTINGS + if _heli:GetPlayerName() then + settings = _DATABASE:GetPlayerSettings(_heli:GetPlayerName()) or _SETTINGS + end + if settings:IsImperial() then + distancetext = string.format("%.1fnm",UTILS.MetersToNM(_distance)) + else + distancetext = string.format("%.1fkm", _distance/1000.0) + end + if _value.frequency == 0 or self.CreateRadioBeacons == false then--shagrat insert CASEVAC without Frequency + table.insert(_csarList, { dist = _distance, msg = string.format("%s at %s - %s ", _value.desc, _coordinatesText, distancetext) }) + else + table.insert(_csarList, { dist = _distance, msg = string.format("%s at %s - %.2f KHz ADF - %s ", _value.desc, _coordinatesText, _value.frequency / 1000, distancetext) }) + end end end - + local function sortDistance(a, b) - return a.dist < b.dist + return a.dist < b.dist end - + table.sort(_csarList, sortDistance) - + for _, _line in pairs(_csarList) do - _msg = _msg .. "\n" .. _line.msg + _msg = _msg .. "\n" .. _line.msg end - + self:_DisplayMessageToSAR(_heli, _msg, self.messageTime*2, false, false, true) return self end @@ -1962,30 +1962,30 @@ function CSAR:_GetClosestDownedPilot(_heli) local _distance = 0 local _closestGroupInfo = nil local _heliCoord = _heli:GetCoordinate() or _heli:GetCoordinate() - - if _heliCoord == nil then - self:E("****Error obtaining coordinate!") - return nil - end - - local DownedPilotsTable = self.downedPilots - - for _, _groupInfo in UTILS.spairs(DownedPilotsTable) do - --for _, _groupInfo in pairs(DownedPilotsTable) do - local _woundedName = _groupInfo.name - local _tempWounded = _groupInfo.group - - -- check group exists and not moving to someone else - if _tempWounded then - local _tempCoord = _tempWounded:GetCoordinate() - _distance = self:_GetDistance(_heliCoord, _tempCoord) - if _distance ~= nil and (_shortestDistance == -1 or _distance < _shortestDistance) then - _shortestDistance = _distance - _closestGroup = _tempWounded - _closestGroupInfo = _groupInfo - end + if _heliCoord == nil then + self:E("****Error obtaining coordinate!") + return nil + end + + local DownedPilotsTable = self.downedPilots + + for _, _groupInfo in UTILS.spairs(DownedPilotsTable) do + --for _, _groupInfo in pairs(DownedPilotsTable) do + local _woundedName = _groupInfo.name + local _tempWounded = _groupInfo.group + + -- check group exists and not moving to someone else + if _tempWounded then + local _tempCoord = _tempWounded:GetCoordinate() + _distance = self:_GetDistance(_heliCoord, _tempCoord) + + if _distance ~= nil and (_shortestDistance == -1 or _distance < _shortestDistance) then + _shortestDistance = _distance + _closestGroup = _tempWounded + _closestGroupInfo = _groupInfo end + end end return { pilot = _closestGroup, distance = _shortestDistance, groupInfo = _closestGroupInfo } @@ -1998,35 +1998,35 @@ function CSAR:_SignalFlare(_unitName) self:T(self.lid .. " _SignalFlare") local _heli = self:_GetSARHeli(_unitName) if _heli == nil then - return + return end - + local _closest = self:_GetClosestDownedPilot(_heli) local smokedist = 8000 if self.approachdist_far > smokedist then smokedist = self.approachdist_far end if _closest ~= nil and _closest.pilot ~= nil and _closest.distance > 0 and _closest.distance < smokedist then - - local _clockDir = self:_GetClockDirection(_heli, _closest.pilot) - local _distance = "" - if _SETTINGS:IsImperial() then - _distance = string.format("%.1fnm",UTILS.MetersToNM(_closest.distance)) - else - _distance = string.format("%.1fkm",_closest.distance/1000) - end - local _msg = string.format("%s - Firing signal flare at your %s o\'clock. Distance %s", self:_GetCustomCallSign(_unitName), _clockDir, _distance) - self:_DisplayMessageToSAR(_heli, _msg, self.messageTime, false, true, true) - - local _coord = _closest.pilot:GetCoordinate() - _coord:FlareRed(_clockDir) + + local _clockDir = self:_GetClockDirection(_heli, _closest.pilot) + local _distance = "" + if _SETTINGS:IsImperial() then + _distance = string.format("%.1fnm",UTILS.MetersToNM(_closest.distance)) + else + _distance = string.format("%.1fkm",_closest.distance/1000) + end + local _msg = string.format("%s - Firing signal flare at your %s o\'clock. Distance %s", self:_GetCustomCallSign(_unitName), _clockDir, _distance) + self:_DisplayMessageToSAR(_heli, _msg, self.messageTime, false, true, true) + + local _coord = _closest.pilot:GetCoordinate() + _coord:FlareRed(_clockDir) else - local _distance = smokedist - local dtext = "" - if _SETTINGS:IsImperial() then - dtext = string.format("%.1fnm",UTILS.MetersToNM(smokedist)) - else - dtext = string.format("%.1fkm",smokedist/1000) - end - self:_DisplayMessageToSAR(_heli, string.format("No Pilots within %s",dtext), self.messageTime, false, false, true) + local _distance = smokedist + local dtext = "" + if _SETTINGS:IsImperial() then + dtext = string.format("%.1fnm",UTILS.MetersToNM(smokedist)) + else + dtext = string.format("%.1fkm",smokedist/1000) + end + self:_DisplayMessageToSAR(_heli, string.format("No Pilots within %s",dtext), self.messageTime, false, false, true) end return self end @@ -2034,7 +2034,7 @@ end --- (Internal) Display info to all SAR groups. -- @param #CSAR self -- @param #string _message Message to display. --- @param #number _side Coalition of message. +-- @param #number _side Coalition of message. -- @param #number _messagetime How long to show. -- @param #boolean ToSRS If true or nil, send to SRS TTS -- @param #boolean ToScreen If true or nil, send to Screen @@ -2054,7 +2054,7 @@ function CSAR:_DisplayToAllSAR(_message, _side, _messagetime,ToSRS,ToScreen) for _, _unitName in pairs(self.csarUnits) do local _unit = self:_GetSARHeli(_unitName) if _unit and not self.suppressmessages then - self:_DisplayMessageToSAR(_unit, _message, _messagetime) + self:_DisplayMessageToSAR(_unit, _message, _messagetime) end end end @@ -2068,30 +2068,30 @@ function CSAR:_ReqIRStrobe( _unitName ) self:T(self.lid .. " _ReqIRStrobe") local _heli = self:_GetSARHeli(_unitName) if _heli == nil then - return + return end local smokedist = 8000 if smokedist < self.approachdist_far then smokedist = self.approachdist_far end local _closest = self:_GetClosestDownedPilot(_heli) if _closest ~= nil and _closest.pilot ~= nil and _closest.distance > 0 and _closest.distance < smokedist then - local _clockDir = self:_GetClockDirection(_heli, _closest.pilot) - local _distance = string.format("%.1fkm",_closest.distance/1000) - if _SETTINGS:IsImperial() then - _distance = string.format("%.1fnm",UTILS.MetersToNM(_closest.distance)) - else - _distance = string.format("%.1fkm",_closest.distance/1000) - end - local _msg = string.format("%s - IR Strobe active at your %s o\'clock. Distance %s", self:_GetCustomCallSign(_unitName), _clockDir, _distance) - self:_DisplayMessageToSAR(_heli, _msg, self.messageTime, false, true, true) - _closest.pilot:NewIRMarker(true,self.IRStrobeRuntime or 300) + local _clockDir = self:_GetClockDirection(_heli, _closest.pilot) + local _distance = string.format("%.1fkm",_closest.distance/1000) + if _SETTINGS:IsImperial() then + _distance = string.format("%.1fnm",UTILS.MetersToNM(_closest.distance)) + else + _distance = string.format("%.1fkm",_closest.distance/1000) + end + local _msg = string.format("%s - IR Strobe active at your %s o\'clock. Distance %s", self:_GetCustomCallSign(_unitName), _clockDir, _distance) + self:_DisplayMessageToSAR(_heli, _msg, self.messageTime, false, true, true) + _closest.pilot:NewIRMarker(true,self.IRStrobeRuntime or 300) else - local _distance = string.format("%.1fkm",smokedist/1000) - if _SETTINGS:IsImperial() then - _distance = string.format("%.1fnm",UTILS.MetersToNM(smokedist)) - else - _distance = string.format("%.1fkm",smokedist/1000) - end - self:_DisplayMessageToSAR(_heli, string.format("No Pilots within %s",_distance), self.messageTime, false, false, true) + local _distance = string.format("%.1fkm",smokedist/1000) + if _SETTINGS:IsImperial() then + _distance = string.format("%.1fnm",UTILS.MetersToNM(smokedist)) + else + _distance = string.format("%.1fkm",smokedist/1000) + end + self:_DisplayMessageToSAR(_heli, string.format("No Pilots within %s",_distance), self.messageTime, false, false, true) end return self end @@ -2103,32 +2103,32 @@ function CSAR:_Reqsmoke( _unitName ) self:T(self.lid .. " _Reqsmoke") local _heli = self:_GetSARHeli(_unitName) if _heli == nil then - return + return end local smokedist = 8000 if smokedist < self.approachdist_far then smokedist = self.approachdist_far end local _closest = self:_GetClosestDownedPilot(_heli) if _closest ~= nil and _closest.pilot ~= nil and _closest.distance > 0 and _closest.distance < smokedist then - local _clockDir = self:_GetClockDirection(_heli, _closest.pilot) - local _distance = string.format("%.1fkm",_closest.distance/1000) - if _SETTINGS:IsImperial() then - _distance = string.format("%.1fnm",UTILS.MetersToNM(_closest.distance)) - else - _distance = string.format("%.1fkm",_closest.distance/1000) - end - local _msg = string.format("%s - Popping smoke at your %s o\'clock. Distance %s", self:_GetCustomCallSign(_unitName), _clockDir, _distance) - self:_DisplayMessageToSAR(_heli, _msg, self.messageTime, false, true, true) - local _coord = _closest.pilot:GetCoordinate() - local color = self.smokecolor - _coord:Smoke(color) + local _clockDir = self:_GetClockDirection(_heli, _closest.pilot) + local _distance = string.format("%.1fkm",_closest.distance/1000) + if _SETTINGS:IsImperial() then + _distance = string.format("%.1fnm",UTILS.MetersToNM(_closest.distance)) + else + _distance = string.format("%.1fkm",_closest.distance/1000) + end + local _msg = string.format("%s - Popping smoke at your %s o\'clock. Distance %s", self:_GetCustomCallSign(_unitName), _clockDir, _distance) + self:_DisplayMessageToSAR(_heli, _msg, self.messageTime, false, true, true) + local _coord = _closest.pilot:GetCoordinate() + local color = self.smokecolor + _coord:Smoke(color) else - local _distance = string.format("%.1fkm",smokedist/1000) - if _SETTINGS:IsImperial() then - _distance = string.format("%.1fnm",UTILS.MetersToNM(smokedist)) - else - _distance = string.format("%.1fkm",smokedist/1000) - end - self:_DisplayMessageToSAR(_heli, string.format("No Pilots within %s",_distance), self.messageTime, false, false, true) + local _distance = string.format("%.1fkm",smokedist/1000) + if _SETTINGS:IsImperial() then + _distance = string.format("%.1fnm",UTILS.MetersToNM(smokedist)) + else + _distance = string.format("%.1fkm",smokedist/1000) + end + self:_DisplayMessageToSAR(_heli, string.format("No Pilots within %s",_distance), self.messageTime, false, false, true) end return self end @@ -2150,36 +2150,36 @@ function CSAR:_GetClosestMASH(_heli) local _distance = 0 local _helicoord = _heli:GetCoordinate() local MashName = nil - + if self.allowFARPRescue then local position = _heli:GetCoordinate() local afb,distance = position:GetClosestAirbase(nil,self.coalition) _shortestDistance = distance MashName = (afb ~= nil) and afb:GetName() or "Unknown" end - + for _,_mashes in pairs(MashSets) do for _, _mashUnit in pairs(_mashes or {}) do - local _mashcoord - if _mashUnit and (not _mashUnit:IsInstanceOf("ZONE_BASE")) and _mashUnit:IsAlive() then - _mashcoord = _mashUnit:GetCoordinate() - elseif _mashUnit and _mashUnit:IsInstanceOf("ZONE_BASE") then - _mashcoord = _mashUnit:GetCoordinate() - end - _distance = self:_GetDistance(_helicoord, _mashcoord) - if _distance ~= nil and (_shortestDistance == -1 or _distance < _shortestDistance) then - _shortestDistance = _distance - MashName = _mashUnit:GetName() or "Unknown" - end + local _mashcoord + if _mashUnit and (not _mashUnit:IsInstanceOf("ZONE_BASE")) and _mashUnit:IsAlive() then + _mashcoord = _mashUnit:GetCoordinate() + elseif _mashUnit and _mashUnit:IsInstanceOf("ZONE_BASE") then + _mashcoord = _mashUnit:GetCoordinate() + end + _distance = self:_GetDistance(_helicoord, _mashcoord) + if _distance ~= nil and (_shortestDistance == -1 or _distance < _shortestDistance) then + _shortestDistance = _distance + MashName = _mashUnit:GetName() or "Unknown" + end end end - + if _shortestDistance ~= -1 then - return _shortestDistance, MashName + return _shortestDistance, MashName else - return -1 + return -1 end - + end --- (Internal) Display onboarded rescued pilots. @@ -2187,47 +2187,47 @@ end -- @param #string _unitName Name of the chopper function CSAR:_CheckOnboard(_unitName) self:T(self.lid .. " _CheckOnboard") - local _unit = self:_GetSARHeli(_unitName) - if _unit == nil then - return + local _unit = self:_GetSARHeli(_unitName) + if _unit == nil then + return + end + --list onboard pilots + local _inTransit = self.inTransitGroups[_unitName] + if _inTransit == nil then + self:_DisplayMessageToSAR(_unit, "No Rescued Pilots onboard", self.messageTime, false, false, true) + else + local _text = "Onboard - RTB to FARP/Airfield or MASH: " + for _, _onboard in pairs(self.inTransitGroups[_unitName]) do + _text = _text .. "\n" .. _onboard.desc end - --list onboard pilots - local _inTransit = self.inTransitGroups[_unitName] - if _inTransit == nil then - self:_DisplayMessageToSAR(_unit, "No Rescued Pilots onboard", self.messageTime, false, false, true) - else - local _text = "Onboard - RTB to FARP/Airfield or MASH: " - for _, _onboard in pairs(self.inTransitGroups[_unitName]) do - _text = _text .. "\n" .. _onboard.desc - end - self:_DisplayMessageToSAR(_unit, _text, self.messageTime*2, false, false, true) - end - return self + self:_DisplayMessageToSAR(_unit, _text, self.messageTime*2, false, false, true) + end + return self end --- (Internal) Populate F10 menu for CSAR players. -- @param #CSAR self function CSAR:_AddMedevacMenuItem() self:T(self.lid .. " _AddMedevacMenuItem") - + local coalition = self.coalition local allheligroupset = self.allheligroupset -- Core.Set#SET_GROUP local _allHeliGroups = allheligroupset:GetSetObjects() -- rebuild units table local _UnitList = {} - for _key, _group in pairs (_allHeliGroups) do + for _key, _group in pairs (_allHeliGroups) do local _unit = _group:GetFirstUnitAlive() -- Asume that there is only one unit in the flight for players if _unit then - --self:T("Unitname ".._unit:GetName().." IsAlive "..tostring(_unit:IsAlive()).." IsPlayer "..tostring(_unit:IsPlayer())) - if _unit:IsAlive() and _unit:IsPlayer() then + --self:T("Unitname ".._unit:GetName().." IsAlive "..tostring(_unit:IsAlive()).." IsPlayer "..tostring(_unit:IsPlayer())) + if _unit:IsAlive() and _unit:IsPlayer() then local unitName = _unit:GetName() - _UnitList[unitName] = unitName + _UnitList[unitName] = unitName end -- end isAlive end -- end if _unit end -- end for self.csarUnits = _UnitList - - -- build unit menus + + -- build unit menus for _, _unitName in pairs(self.csarUnits) do local _unit = self:_GetSARHeli(_unitName) -- Wrapper.Unit#UNIT if _unit then @@ -2250,7 +2250,7 @@ function CSAR:_AddMedevacMenuItem() end end end - end + end return self end @@ -2284,7 +2284,7 @@ end -- @param #CSAR self function CSAR:_GenerateVHFrequencies() self:T(self.lid .. " _GenerateVHFrequencies") - + local FreeVHFFrequencies = {} FreeVHFFrequencies = UTILS.GenerateVHFrequencies() self.FreeVHFFrequencies = FreeVHFFrequencies @@ -2298,8 +2298,8 @@ function CSAR:_GenerateADFFrequency() self:T(self.lid .. " _GenerateADFFrequency") -- get a free freq for a beacon if #self.FreeVHFFrequencies <= 3 then - self.FreeVHFFrequencies = self.UsedVHFFrequencies - self.UsedVHFFrequencies = {} + self.FreeVHFFrequencies = self.UsedVHFFrequencies + self.UsedVHFFrequencies = {} end local _vhf = table.remove(self.FreeVHFFrequencies, math.random(#self.FreeVHFFrequencies)) return _vhf @@ -2312,7 +2312,7 @@ end -- @return #number direction function CSAR:_GetClockDirection(_heli, _group) self:T(self.lid .. " _GetClockDirection") - + local _playerPosition = _heli:GetCoordinate() -- get position of helicopter local _targetpostions = _group:GetCoordinate() -- get position of downed pilot local _heading = _heli:GetHeading() -- heading @@ -2324,12 +2324,12 @@ function CSAR:_GetClockDirection(_heli, _group) if _heading and Angle then clock = 12 --if angle == 0 then angle = 360 end - clock = _heading-Angle + clock = _heading-Angle hours = (clock/30)*-1 clock = 12+hours clock = UTILS.Round(clock,0) if clock > 12 then clock = clock-12 end - end + end return clock end @@ -2340,62 +2340,62 @@ end -- @param #string BeaconName Beacon Name to use -- @return #CSAR self function CSAR:_AddBeaconToGroup(_group, _freq, BeaconName) - self:T(self.lid .. " _AddBeaconToGroup") - if self.CreateRadioBeacons == false then return end - local _group = _group - - if _group == nil then - --return frequency to pool of available - for _i, _current in ipairs(self.UsedVHFFrequencies) do - if _current == _freq then - table.insert(self.FreeVHFFrequencies, _freq) - table.remove(self.UsedVHFFrequencies, _i) - end - end - return - end - - if _group:IsAlive() then - local _radioUnit = _group:GetUnit(1) - if _radioUnit then - local name = _radioUnit:GetName() - local Frequency = _freq -- Freq in Hertz - --local name = _radioUnit:GetName() - local Sound = "l10n/DEFAULT/"..self.radioSound - local vec3 = _radioUnit:GetVec3() or _radioUnit:GetPositionVec3() or {x=0,y=0,z=0} - self:I(self.lid..string.format("Added Radio Beacon %d Hertz | Name %s | Position {%d,%d,%d}",Frequency,BeaconName,vec3.x,vec3.y,vec3.z)) - trigger.action.radioTransmission(Sound, vec3, 0, true, Frequency, self.ADFRadioPwr or 500,BeaconName) -- Beacon in MP only runs for exactly 30secs straight + self:T(self.lid .. " _AddBeaconToGroup") + if self.CreateRadioBeacons == false then return end + local _group = _group + + if _group == nil then + --return frequency to pool of available + for _i, _current in ipairs(self.UsedVHFFrequencies) do + if _current == _freq then + table.insert(self.FreeVHFFrequencies, _freq) + table.remove(self.UsedVHFFrequencies, _i) end end - - return self + return + end + + if _group:IsAlive() then + local _radioUnit = _group:GetUnit(1) + if _radioUnit then + local name = _radioUnit:GetName() + local Frequency = _freq -- Freq in Hertz + --local name = _radioUnit:GetName() + local Sound = "l10n/DEFAULT/"..self.radioSound + local vec3 = _radioUnit:GetVec3() or _radioUnit:GetPositionVec3() or {x=0,y=0,z=0} + self:I(self.lid..string.format("Added Radio Beacon %d Hertz | Name %s | Position {%d,%d,%d}",Frequency,BeaconName,vec3.x,vec3.y,vec3.z)) + trigger.action.radioTransmission(Sound, vec3, 0, true, Frequency, self.ADFRadioPwr or 500,BeaconName) -- Beacon in MP only runs for exactly 30secs straight + end + end + + return self end --- (Internal) Helper function to (re-)add beacon to downed pilot. -- @param #CSAR self -- @return #CSAR self function CSAR:_RefreshRadioBeacons() - self:T(self.lid .. " _RefreshRadioBeacons") - if self.CreateRadioBeacons == false then return end - if self:_CountActiveDownedPilots() > 0 then - local PilotTable = self.downedPilots - for _,_pilot in pairs (PilotTable) do - self:T({_pilot.name}) - local pilot = _pilot -- #CSAR.DownedPilot - local group = pilot.group - local frequency = pilot.frequency or 0 -- thanks to @Thrud - local bname = pilot.BeaconName or pilot.name..math.random(1,100000) - --trigger.action.stopRadioTransmission(bname) - if group and group:IsAlive() and frequency > 0 then - --self:_AddBeaconToGroup(group,frequency,bname) - else - if frequency > 0 then - trigger.action.stopRadioTransmission(bname) - end + self:T(self.lid .. " _RefreshRadioBeacons") + if self.CreateRadioBeacons == false then return end + if self:_CountActiveDownedPilots() > 0 then + local PilotTable = self.downedPilots + for _,_pilot in pairs (PilotTable) do + self:T({_pilot.name}) + local pilot = _pilot -- #CSAR.DownedPilot + local group = pilot.group + local frequency = pilot.frequency or 0 -- thanks to @Thrud + local bname = pilot.BeaconName or pilot.name..math.random(1,100000) + --trigger.action.stopRadioTransmission(bname) + if group and group:IsAlive() and frequency > 0 then + --self:_AddBeaconToGroup(group,frequency,bname) + else + if frequency > 0 then + trigger.action.stopRadioTransmission(bname) end end end - return self + end + return self end --- (Internal) Helper function to count active downed pilots. @@ -2417,45 +2417,45 @@ end -- @param #CSAR self -- @return #boolean True or false. function CSAR:_ReachedPilotLimit() - self:T(self.lid .. " _ReachedPilotLimit") - local limit = self.maxdownedpilots - local islimited = self.limitmaxdownedpilots - local count = self:_CountActiveDownedPilots() - if islimited and (count >= limit) then - if self.useFIFOLimitReplacement then - local oldIndex = -1 - local oldDownedPilot = nil - for _index, _downedpilot in pairs(self.downedPilots) do - oldIndex = _index - oldDownedPilot = _downedpilot - break - end - if oldDownedPilot then - oldDownedPilot.group:Destroy(false) - oldDownedPilot.alive = false - self:_CheckDownedPilotTable() - return false - end - end - return true - else + self:T(self.lid .. " _ReachedPilotLimit") + local limit = self.maxdownedpilots + local islimited = self.limitmaxdownedpilots + local count = self:_CountActiveDownedPilots() + if islimited and (count >= limit) then + if self.useFIFOLimitReplacement then + local oldIndex = -1 + local oldDownedPilot = nil + for _index, _downedpilot in pairs(self.downedPilots) do + oldIndex = _index + oldDownedPilot = _downedpilot + break + end + if oldDownedPilot then + oldDownedPilot.group:Destroy(false) + oldDownedPilot.alive = false + self:_CheckDownedPilotTable() return false + end end + return true + else + return false + end end - --- User - Function to add onw SET_GROUP Set-up for pilot filtering and assignment. - -- Needs to be set before starting the CSAR instance. - -- @param #CSAR self - -- @param Core.Set#SET_GROUP Set The SET_GROUP object created by the mission designer/user to represent the CSAR pilot groups. - -- @return #CSAR self - function CSAR:SetOwnSetPilotGroups(Set) - self.UserSetGroup = Set - return self - end +--- User - Function to add onw SET_GROUP Set-up for pilot filtering and assignment. +-- Needs to be set before starting the CSAR instance. +-- @param #CSAR self +-- @param Core.Set#SET_GROUP Set The SET_GROUP object created by the mission designer/user to represent the CSAR pilot groups. +-- @return #CSAR self +function CSAR:SetOwnSetPilotGroups(Set) + self.UserSetGroup = Set + return self +end - ------------------------------ - --- FSM internal Functions --- - ------------------------------ +------------------------------ +--- FSM internal Functions --- +------------------------------ --- (Internal) Function called after Start() event. -- @param #CSAR self. @@ -2473,7 +2473,7 @@ function CSAR:onafterStart(From, Event, To) self:HandleEvent(EVENTS.PlayerEnterAircraft, self._EventHandler) self:HandleEvent(EVENTS.PlayerEnterUnit, self._EventHandler) self:HandleEvent(EVENTS.PilotDead, self._EventHandler) - + if self.UserSetGroup then self.allheligroupset = self.UserSetGroup elseif self.allowbronco then @@ -2485,12 +2485,12 @@ function CSAR:onafterStart(From, Event, To) else self.allheligroupset = SET_GROUP:New():FilterCoalitions(self.coalitiontxt):FilterCategoryHelicopter():FilterStart() end - + self.mash = SET_GROUP:New():FilterCoalitions(self.coalitiontxt):FilterPrefixes(self.mashprefix):FilterStart() - + self.staticmashes = SET_STATIC:New():FilterCoalitions(self.coalitiontxt):FilterPrefixes(self.mashprefix):FilterStart() self.zonemashes = SET_ZONE:New():FilterPrefixes(self.mashprefix):FilterStart() - + --[[ if staticmashes:Count() > 0 then for _,_mash in pairs(staticmashes.Set) do @@ -2506,10 +2506,10 @@ function CSAR:onafterStart(From, Event, To) self:T("Objects in SET: "..self.mash:Count()) end --]] - + if not self.coordinate then local csarhq = self.mash:GetRandom() - if csarhq then + if csarhq then self.coordinate = csarhq:GetCoordinate() end end @@ -2535,16 +2535,16 @@ function CSAR:onafterStart(From, Event, To) self.msrs:SetLabel("CSAR") self.SRSQueue = MSRSQUEUE:New("CSAR") -- Sound.SRS#MSRSQUEUE end - + self:__Status(-10) - + if self.enableLoadSave then local interval = self.saveinterval local filename = self.filename local filepath = self.filepath self:__Save(interval,filepath,filename) end - + return self end @@ -2553,11 +2553,11 @@ end function CSAR:_CheckDownedPilotTable() local pilots = self.downedPilots local npilots = {} - + for _ind,_entry in pairs(pilots) do local _group = _entry.group if _group:IsAlive() then - npilots[_ind] = _entry + npilots[_ind] = _entry else if _entry.alive then self:__KIA(1,_entry.desc) @@ -2577,12 +2577,12 @@ function CSAR:onbeforeStatus(From, Event, To) self:T({From, Event, To}) -- housekeeping self:_AddMedevacMenuItem() - + if not self.BeaconTimer or (self.BeaconTimer and not self.BeaconTimer:IsRunning()) then self.BeaconTimer = TIMER:New(self._RefreshRadioBeacons,self) self.BeaconTimer:Start(2,self.beaconRefresher) end - + self:_CheckDownedPilotTable() for _,_sar in pairs (self.csarUnits) do local PilotTable = self.downedPilots @@ -2593,7 +2593,7 @@ function CSAR:onbeforeStatus(From, Event, To) local timestamp = entry.timestamp or 0 local now = timer.getAbsTime() if now - timestamp > 17 then -- only check if we\'re not in approach mode, which is iterations of 5 and 10. - self:_CheckWoundedGroupStatus(_sar,name) + self:_CheckWoundedGroupStatus(_sar,name) end end end @@ -2615,14 +2615,14 @@ function CSAR:onafterStatus(From, Event, To) end local PilotsInFieldN = self:_CountActiveDownedPilots() - + local PilotsBoarded = 0 for _, _unitName in pairs(self.inTransitGroups) do for _,_units in pairs(_unitName) do PilotsBoarded = PilotsBoarded + 1 end end - + if self.verbose > 0 then local text = string.format("%s Active SAR: %d | Downed Pilots in field: %d (max %d) | Pilots boarded: %d | Landings: %d | Pilots rescued: %d", self.lid,NumberOfSARPilots,PilotsInFieldN,self.maxdownedpilots,PilotsBoarded,self.rescues,self.rescuedpilots) @@ -2692,7 +2692,7 @@ function CSAR:onbeforeBoarded(From, Event, To, Heliname, Woundedgroupname) -- right subtype? if Event == subtype and not task:IsDone() then local targetzone = task.Target:GetObject() -- Core.Zone#ZONE should be a zone in this case .... - if (targetzone and targetzone.ClassName and string.match(targetzone.ClassName,"ZONE") and targetzone:IsVec2InZone(dropvec2)) + if (targetzone and targetzone.ClassName and string.match(targetzone.ClassName,"ZONE") and targetzone:IsVec2InZone(dropvec2)) or (string.find(task.CSARPilotName,Woundedgroupname)) then if task.Clients:HasUniqueID(playername) then -- success @@ -2706,7 +2706,7 @@ function CSAR:onbeforeBoarded(From, Event, To, Heliname, Woundedgroupname) return self end ---- (Internal) Function called before Returning() event. +--- (Internal) Function called before Returning() event. -- @param #CSAR self. -- @param #string From From state. -- @param #string Event Event triggered. @@ -2741,10 +2741,10 @@ function CSAR:onbeforeRescued(From, Event, To, HeliUnit, HeliName, PilotsSaved) local subtype = task:GetSubType() -- right subtype? if Event == subtype and not task:IsDone() then - if task.Clients:HasUniqueID(playername) then - -- success - task:__Success(-1) - end + if task.Clients:HasUniqueID(playername) then + -- success + task:__Success(-1) + end end end ) @@ -2791,7 +2791,7 @@ function CSAR:onbeforeSave(From, Event, To, path, filename) if not self.enableLoadSave then return self end - -- Thanks to @FunkyFranky + -- Thanks to @FunkyFranky -- Check io module is available. if not io then self:E(self.lid.."ERROR: io not desanitized. Can't save current state.") @@ -2815,7 +2815,7 @@ end -- @param #string filename (Optional) File name for saving. Default is Default is "CSAR__Persist.csv". function CSAR:onafterSave(From, Event, To, path, filename) self:T({From, Event, To, path, filename}) - -- Thanks to @FunkyFranky + -- Thanks to @FunkyFranky if not self.enableLoadSave then return self end @@ -2830,7 +2830,7 @@ function CSAR:onafterSave(From, Event, To, path, filename) if lfs then path=self.filepath or lfs.writedir() end - + -- Set file name. filename=filename or self.filename @@ -2838,9 +2838,9 @@ function CSAR:onafterSave(From, Event, To, path, filename) if path~=nil then filename=path.."\\"..filename end - + local pilots = self.downedPilots - + --local data = "LoadedData = {\n" local data = "playerName,x,y,z,coalition,country,description,typeName,unitName,freq\n" local n = 0 @@ -2858,15 +2858,15 @@ function CSAR:onafterSave(From, Event, To, path, filename) local location = group:GetVec3() local unitName = DownedPilot.originalUnit local txt = string.format("%s,%d,%d,%d,%s,%s,%s,%s,%s,%d\n",playerName,location.x,location.y,location.z,coalition,country,description,typeName,unitName,freq) - + self:I(self.lid.."Saving to CSAR File: " .. txt) - + data = data .. txt end end - + _savefile(filename, data) - + -- AutoSave if self.enableLoadSave then local interval = self.saveinterval @@ -2891,19 +2891,19 @@ function CSAR:onbeforeLoad(From, Event, To, path, filename) end --- Function that check if a file exists. local function _fileexists(name) - local f=io.open(name,"r") - if f~=nil then + local f=io.open(name,"r") + if f~=nil then io.close(f) return true else return false end end - + -- Set file name and path filename=filename or self.filename path = path or self.filepath - + -- Check io module is available. if not io then self:E(self.lid.."WARNING: io not desanitized. Cannot load file.") @@ -2933,7 +2933,7 @@ function CSAR:onbeforeLoad(From, Event, To, path, filename) else self:E(self.lid..string.format("WARNING: State file %s might not exist.", filename)) return false - --return self + --return self end end @@ -2957,11 +2957,11 @@ function CSAR:onafterLoad(From, Event, To, path, filename) f:close() return data end - + -- Set file name and path filename=filename or self.filename path = path or self.filepath - + -- Set path or default. if lfs then path=path or lfs.writedir() @@ -2976,39 +2976,39 @@ function CSAR:onafterLoad(From, Event, To, path, filename) local text=string.format("Loading CSAR state from file %s", filename) MESSAGE:New(text,10):ToAllIf(self.Debug) self:I(self.lid..text) - + local file=assert(io.open(filename, "rb")) - + local loadeddata = {} for line in file:lines() do - loadeddata[#loadeddata+1] = line + loadeddata[#loadeddata+1] = line end file:close() - + -- remove header table.remove(loadeddata, 1) - + for _id,_entry in pairs (loadeddata) do local dataset = UTILS.Split(_entry,",") -- 1=playerName,2=x,3=y,4=z,5=coalition,6=country,7=description,8=typeName,9=unitName,10=freq\n local playerName = dataset[1] - + local vec3 = {} vec3.x = tonumber(dataset[2]) vec3.y = tonumber(dataset[3]) vec3.z = tonumber(dataset[4]) local point = COORDINATE:NewFromVec3(vec3) - + local coalition = tonumber(dataset[5]) local country = tonumber(dataset[6]) local description = dataset[7] local typeName = dataset[8] local unitName = dataset[9] local freq = tonumber(dataset[10]) - - self:_AddCsar(coalition, country, point, typeName, unitName, playerName, freq, nil, description, nil) + + self:_AddCsar(coalition, country, point, typeName, unitName, playerName, freq, nil, description, nil) end - + return self end From f4cd214823f5bbf3eb423a4efa7bc2ba97d13ffd Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sun, 27 Jul 2025 19:24:43 +0200 Subject: [PATCH 133/234] #TIRESIAS - Avoid creating SET_GROUPs all the time for player objects, cached now --- Moose Development/Moose/Functional/Tiresias.lua | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/Moose Development/Moose/Functional/Tiresias.lua b/Moose Development/Moose/Functional/Tiresias.lua index 51cc395f4..8010abfcd 100644 --- a/Moose Development/Moose/Functional/Tiresias.lua +++ b/Moose Development/Moose/Functional/Tiresias.lua @@ -33,7 +33,7 @@ -- - @module Functional.Tiresias -- - @image Functional.Tiresias.jpg ---- Last Update: Dec 2023 (Optimized July 2025) +--- Last Update: July 2025 --- **TIRESIAS** class, extends Core.Base#BASE -- @type TIRESIAS @@ -55,6 +55,7 @@ -- @field #boolean SwitchAAA -- @field #string lid -- @field #table _cached_zones +-- @field #table _cached_groupsets -- @extends Core.Fsm#FSM --- @@ -104,7 +105,7 @@ TIRESIAS = { ClassName = "TIRESIAS", debug = true, - version = " 0.0.6-OPT" , + version = " 0.0.7-OPT" , Interval = 20, GroundSet = nil, VehicleSet = nil, @@ -116,6 +117,7 @@ TIRESIAS = { PlaneSwitchRange = 25, -- NM SwitchAAA = true, _cached_zones = {}, -- Cache for zone objects + _cached_groupsets = {}, -- Cache for group_set objects } --- @@ -418,6 +420,7 @@ function TIRESIAS:_SwitchOnGroups(group, radius) local group_name = group:GetName() local cache_key = group_name .. " _" .. radius local zone = self._cached_zones[cache_key] + local ground = self._cached_groupsets[cache_key] if not zone then zone = ZONE_GROUP:New(" Zone-" .. group_name, group, UTILS.NMToMeters(radius)) @@ -427,7 +430,13 @@ function TIRESIAS:_SwitchOnGroups(group, radius) zone:UpdateFromGroup(group) end - local ground = SET_GROUP:New():FilterCategoryGround():FilterZones({zone}):FilterOnce() + if not ground then + ground = SET_GROUP:New():FilterCategoryGround():FilterZones({zone}):FilterOnce() + self._cached_groupsets[cache_key] = ground + else + ground:FilterZones({zone},true):FilterOnce() + end + local count = ground:CountAlive() if self.debug then From 4b1888a34d4620655fc39deeba46ac3bc88bb7a7 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Tue, 29 Jul 2025 10:01:23 +0200 Subject: [PATCH 134/234] CSAR - Allow also the initial down message to be suppressed --- Moose Development/Moose/Ops/CSAR.lua | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Moose Development/Moose/Ops/CSAR.lua b/Moose Development/Moose/Ops/CSAR.lua index ce21f7121..56ec21ef5 100644 --- a/Moose Development/Moose/Ops/CSAR.lua +++ b/Moose Development/Moose/Ops/CSAR.lua @@ -31,7 +31,7 @@ -- @image OPS_CSAR.jpg --- --- Last Update May 2025 +-- Last Update July 2025 ------------------------------------------------------------------------- --- **CSAR** class, extends Core.Base#BASE, Core.Fsm#FSM @@ -1199,7 +1199,7 @@ function CSAR:_EventHandler(EventData) -- all checks passed, get going. if self.csarUsePara == false or (self.csarUsePara and wetfeet ) then --shagrat check parameter LandingAfterEjection, if true don't spawn a Pilot from EJECTION event, wait for the Chute to land local _freq = self:_GenerateADFFrequency() - self:_AddCsar(_coalition, _unit:GetCountry(), initcoord , _unit:GetTypeName(), _unit:GetName(), _event.IniPlayerName, _freq, false, "none") + self:_AddCsar(_coalition, _unit:GetCountry(), initcoord , _unit:GetTypeName(), _unit:GetName(), _event.IniPlayerName, _freq, self.suppressmessages, "none") return self end @@ -1264,8 +1264,8 @@ function CSAR:_EventHandler(EventData) if _coalition == self.coalition then local _freq = self:_GenerateADFFrequency() self:I({coalition=_coalition,country= _country, coord=_LandingPos, name=_unitname, player=_event.IniPlayerName, freq=_freq}) - self:_AddCsar(_coalition, _country, _LandingPos, nil, _unitname, _event.IniPlayerName, _freq, false, "none")--shagrat add CSAR at Parachute location. - + self:_AddCsar(_coalition, _country, _LandingPos, nil, _unitname, _event.IniPlayerName, _freq, self.suppressmessages, "none")--shagrat add CSAR at Parachute location. + Unit.destroy(_event.initiator) -- shagrat remove static Pilot model end end @@ -3005,8 +3005,8 @@ function CSAR:onafterLoad(From, Event, To, path, filename) local typeName = dataset[8] local unitName = dataset[9] local freq = tonumber(dataset[10]) - - self:_AddCsar(coalition, country, point, typeName, unitName, playerName, freq, nil, description, nil) + + self:_AddCsar(coalition, country, point, typeName, unitName, playerName, freq, false, description, nil) end return self From f094716b73771caf0ad6525a33e91b7176a5b79a Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Tue, 29 Jul 2025 12:04:41 +0200 Subject: [PATCH 135/234] CTLD - Added option for Vehicle Formation when going to a MOVE zone. --- Moose Development/Moose/Ops/CTLD.lua | 35 ++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/Moose Development/Moose/Ops/CTLD.lua b/Moose Development/Moose/Ops/CTLD.lua index 51896bab7..c4f907190 100644 --- a/Moose Development/Moose/Ops/CTLD.lua +++ b/Moose Development/Moose/Ops/CTLD.lua @@ -867,6 +867,7 @@ do -- my_ctld.TroopUnloadDistHoverHook = 5 -- When hovering, unload troops this far behind the Chinook -- my_ctld.showstockinmenuitems = false -- When set to true, the menu lines will also show the remaining items in stock (that is, if you set any), downside is that the menu for all will be build every 30 seconds anew. -- my_ctld.onestepmenu = false -- When set to true, the menu will create Drop and build, Get and load, Pack and remove, Pack and load, Pack. it will be a 1 step solution. +-- my_ctld.VehicleMoveFormation = AI.Task.VehicleFormation.VEE -- When a group moves to a MOVE zone, then it takes this formation. Can be a table of formations, which are then randomly chosen. Defaults to "Vee". -- -- ## 2.1 CH-47 Chinook support -- @@ -1294,6 +1295,7 @@ CTLD = { LoadedGroupsTable = {}, keeploadtable = true, allowCATransport = false, + VehicleMoveFormation = AI.Task.VehicleFormation.VEE, } ------------------------------ @@ -1414,7 +1416,7 @@ CTLD.FixedWingTypes = { --- CTLD class version. -- @field #string version -CTLD.version="1.3.36" +CTLD.version="1.3.37" --- Instantiate a new CTLD. -- @param #CTLD self @@ -1554,6 +1556,8 @@ function CTLD:New(Coalition, Prefixes, Alias) self.movetroopsdistance = 5000 self.troopdropzoneradius = 100 + self.VehicleMoveFormation = AI.Task.VehicleFormation.VEE + -- added support Hercules Mod self.enableHercules = false -- deprecated self.enableFixedWing = false @@ -4197,6 +4201,17 @@ function CTLD:_BuildObjectFromCrates(Group,Unit,Build,Repair,RepairLocation,Mult return self end +--- (Internal) Function to get a vehicle formation for a moving group +-- @param #CTLD self +-- @return #string Formation +function CTLD:_GetVehicleFormation() + local VehicleMoveFormation = self.VehicleMoveFormation or AI.Task.VehicleFormation.VEE + if type(self.VehicleMoveFormation)=="table" then + VehicleMoveFormation = self.VehicleMoveFormation[math.random(1,#self.VehicleMoveFormation)] + end + return VehicleMoveFormation +end + --- (Internal) Function to move group to WP zone. -- @param #CTLD self -- @param Wrapper.Group#GROUP Group The Group to move. @@ -4211,18 +4226,20 @@ function CTLD:_MoveGroupToZone(Group) -- yes, we can ;) local groupname = Group:GetName() local zonecoord = zone:GetRandomCoordinate(20,125) -- Core.Point#COORDINATE - local coordinate = zonecoord:GetVec2() + local formation = self:_GetVehicleFormation() + --local coordinate = zonecoord:GetVec2() Group:SetAIOn() Group:OptionAlarmStateAuto() Group:OptionDisperseOnAttack(30) - Group:OptionROEOpenFirePossible() - Group:RouteToVec2(coordinate,5) + Group:OptionROEOpenFireWeaponFree() + Group:RouteGroundTo(zonecoord,5,formation) end return self end --- (Internal) Housekeeping - Cleanup crates when build -- @param #CTLD self +-- -- @param #table Crates Table of #CTLD_CARGO objects near the unit. -- @param #CTLD.Buildable Build Table build object. -- @param #number Number Number of objects in Crates (found) to limit search. @@ -7134,6 +7151,16 @@ end local filepath = self.filepath self:__Save(interval,filepath,filename) end + + if type(self.VehicleMoveFormation) == "table" then + local Formations = {} + for _,_formation in pairs(self.VehicleMoveFormation) do + table.insert(Formations,_formation) + end + self.VehicleMoveFormation = nil + self.VehicleMoveFormation = Formations + end + return self end From 21a7023b7beb40cca9cfc72bd61d3c0497cb06f9 Mon Sep 17 00:00:00 2001 From: smiki Date: Tue, 29 Jul 2025 12:50:19 +0200 Subject: [PATCH 136/234] Removed getValueResourceByKey `UTILS.ShowPicture` and `UTILS.SetMissionBriefing` to use full file paths --- Moose Development/Moose/Utilities/Utils.lua | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Moose Development/Moose/Utilities/Utils.lua b/Moose Development/Moose/Utilities/Utils.lua index 11dcdcbb1..853575678 100644 --- a/Moose Development/Moose/Utilities/Utils.lua +++ b/Moose Development/Moose/Utilities/Utils.lua @@ -4603,11 +4603,11 @@ end -- @param #number Duration Duration in seconds, defaults to 10 -- @param #boolean ClearView If true, clears the view before showing the picture, defaults to false -- @param #number StartDelay Delay in seconds before showing the picture, defaults to 0 --- @param #number HorizontalAlign Horizontal alignment of the picture, defaults to 1 (left), can be 0 (center) or 2 (right) --- @param #number VerticalAlign Vertical alignment of the picture, defaults to 1 (top), can be 0 (center) or 2 (bottom) +-- @param #number HorizontalAlign Horizontal alignment of the picture, 0: Left, 1: Center, 2: Right +-- @param #number VerticalAlign Vertical alignment of the picture, 0: Top, 1: Center, 2: Bottom -- @param #number Size Size of the picture in percent, defaults to 100 --- @param #number SizeUnits Size units, defaults to 0 (percent), can be 1 (pixels) -function UTILS.ShowPicture(FileName, Duration, ClearView, StartDelay, HorizontalAlign, VerticalAlign, Size, SizeUnits) +-- @param #number SizeUnits Size units, 0 for % of original picture size, and 1 for % of window size +function UTILS.ShowPicture(FilePath, Duration, ClearView, StartDelay, HorizontalAlign, VerticalAlign, Size, SizeUnits) ClearView = ClearView or false StartDelay = StartDelay or 0 HorizontalAlign = HorizontalAlign or 1 @@ -4617,7 +4617,7 @@ function UTILS.ShowPicture(FileName, Duration, ClearView, StartDelay, Horizontal if ClearView then ClearView = "true" else ClearView = "false" end - net.dostring_in("mission", string.format("a_out_picture(getValueResourceByKey(\"%s\"), %d, %s, %d, \"%d\", \"%d\", %d, \"%d\")", FileName, Duration or 10, ClearView, StartDelay, HorizontalAlign, VerticalAlign, Size, SizeUnits)) + net.dostring_in("mission", string.format("a_out_picture(\"%s\", %d, %s, %d, \"%d\", \"%d\", %d, \"%d\")", FilePath, Duration or 10, ClearView, StartDelay, HorizontalAlign, VerticalAlign, Size, SizeUnits)) end --- Load a mission file. This will replace the current mission with the one given carrying along the online clients. @@ -4629,13 +4629,13 @@ end --- Set the mission briefing for a coalition. -- @param #number Coalition Briefing coalition ID, can be coalition.side.BLUE, coalition.side.RED or coalition.side.NEUTRAL -- @param #string Text Briefing text, can contain newlines, will be converted formatted properly for DCS --- @param #string Picture Picture filename, can be a file in the DEFAULT folder inside the .miz +-- @param #string Picture Picture file path, can be a file in the DEFAULT folder inside the .miz function UTILS.SetMissionBriefing(Coalition, Text, Picture) Text = Text or "" Text = Text:gsub("\n", "\\n") Picture = Picture or "" local coalName = string.lower(UTILS.GetCoalitionName(Coalition)) - net.dostring_in("mission", string.format("a_set_briefing(\"%s\", getValueResourceByKey(\"%s\"), \"%s\")", coalName, Picture, Text)) + net.dostring_in("mission", string.format("a_set_briefing(\"%s\", \"%s\", \"%s\")", coalName, Picture, Text)) end --- Show a helper gate at a DCS#Vec3 position From f735f1eb53c120ab168f359ff671f6c8ebf30019 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Tue, 29 Jul 2025 17:38:31 +0200 Subject: [PATCH 137/234] CTLD - correct ground speed for routing --- Moose Development/Moose/Ops/CTLD.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Ops/CTLD.lua b/Moose Development/Moose/Ops/CTLD.lua index c4f907190..7b46d1439 100644 --- a/Moose Development/Moose/Ops/CTLD.lua +++ b/Moose Development/Moose/Ops/CTLD.lua @@ -4231,8 +4231,8 @@ function CTLD:_MoveGroupToZone(Group) Group:SetAIOn() Group:OptionAlarmStateAuto() Group:OptionDisperseOnAttack(30) - Group:OptionROEOpenFireWeaponFree() - Group:RouteGroundTo(zonecoord,5,formation) + Group:OptionROEOpenFire() + Group:RouteGroundTo(zonecoord,25,formation) end return self end From 324f4944b4e240db631bd89413a884a89f3be4bb Mon Sep 17 00:00:00 2001 From: smiki Date: Thu, 31 Jul 2025 08:54:16 +0200 Subject: [PATCH 138/234] [ADDED] `UTILS.ShowPicture` For all, coalition, country, group and unit [ADDED] `UTILS.ShowHelperGateForUnit` --- Moose Development/Moose/Utilities/Utils.lua | 108 +++++++++++++++++++- 1 file changed, 105 insertions(+), 3 deletions(-) diff --git a/Moose Development/Moose/Utilities/Utils.lua b/Moose Development/Moose/Utilities/Utils.lua index 853575678..d5a4270f7 100644 --- a/Moose Development/Moose/Utilities/Utils.lua +++ b/Moose Development/Moose/Utilities/Utils.lua @@ -4598,7 +4598,7 @@ function UTILS.DoStringIn(State,DoString) return net.dostring_in(State,DoString) end ---- Show a picture on the screen +--- Show a picture on the screen to all -- @param #string FileName File name of the picture -- @param #number Duration Duration in seconds, defaults to 10 -- @param #boolean ClearView If true, clears the view before showing the picture, defaults to false @@ -4607,7 +4607,7 @@ end -- @param #number VerticalAlign Vertical alignment of the picture, 0: Top, 1: Center, 2: Bottom -- @param #number Size Size of the picture in percent, defaults to 100 -- @param #number SizeUnits Size units, 0 for % of original picture size, and 1 for % of window size -function UTILS.ShowPicture(FilePath, Duration, ClearView, StartDelay, HorizontalAlign, VerticalAlign, Size, SizeUnits) +function UTILS.ShowPictureToAll(FilePath, Duration, ClearView, StartDelay, HorizontalAlign, VerticalAlign, Size, SizeUnits) ClearView = ClearView or false StartDelay = StartDelay or 0 HorizontalAlign = HorizontalAlign or 1 @@ -4620,6 +4620,100 @@ function UTILS.ShowPicture(FilePath, Duration, ClearView, StartDelay, Horizontal net.dostring_in("mission", string.format("a_out_picture(\"%s\", %d, %s, %d, \"%d\", \"%d\", %d, \"%d\")", FilePath, Duration or 10, ClearView, StartDelay, HorizontalAlign, VerticalAlign, Size, SizeUnits)) end +--- Show a picture on the screen to Coalition +-- @param #number Coalition Coalition ID, can be coalition.side.BLUE, coalition.side.RED or coalition.side.NEUTRAL +-- @param #string FileName File name of the picture +-- @param #number Duration Duration in seconds, defaults to 10 +-- @param #boolean ClearView If true, clears the view before showing the picture, defaults to false +-- @param #number StartDelay Delay in seconds before showing the picture, defaults to 0 +-- @param #number HorizontalAlign Horizontal alignment of the picture, 0: Left, 1: Center, 2: Right +-- @param #number VerticalAlign Vertical alignment of the picture, 0: Top, 1: Center, 2: Bottom +-- @param #number Size Size of the picture in percent, defaults to 100 +-- @param #number SizeUnits Size units, 0 for % of original picture size, and 1 for % of window size +function UTILS.ShowPictureToCoalition(Coalition, FilePath, Duration, ClearView, StartDelay, HorizontalAlign, VerticalAlign, Size, SizeUnits) + ClearView = ClearView or false + StartDelay = StartDelay or 0 + HorizontalAlign = HorizontalAlign or 1 + VerticalAlign = VerticalAlign or 1 + Size = Size or 100 + SizeUnits = SizeUnits or 0 + + if ClearView then ClearView = "true" else ClearView = "false" end + + local coalName = string.lower(UTILS.GetCoalitionName(Coalition)) + + net.dostring_in("mission", string.format("a_out_picture_s(\"%s\", \"%s\", %d, %s, %d, \"%d\", \"%d\", %d, \"%d\")", coalName, FilePath, Duration or 10, ClearView, StartDelay, HorizontalAlign, VerticalAlign, Size, SizeUnits)) +end + +--- Show a picture on the screen to Country +-- @param #number Country Country ID, can be country.id.USA, country.id.RUSSIA, etc. +-- @param #string FileName File name of the picture +-- @param #number Duration Duration in seconds, defaults to 10 +-- @param #boolean ClearView If true, clears the view before showing the picture, defaults to false +-- @param #number StartDelay Delay in seconds before showing the picture, defaults to 0 +-- @param #number HorizontalAlign Horizontal alignment of the picture, 0: Left, 1: Center, 2: Right +-- @param #number VerticalAlign Vertical alignment of the picture, 0: Top, 1: Center, 2: Bottom +-- @param #number Size Size of the picture in percent, defaults to 100 +-- @param #number SizeUnits Size units, 0 for % of original picture size, and 1 for % of window size +function UTILS.ShowPictureToCountry(Country, FilePath, Duration, ClearView, StartDelay, HorizontalAlign, VerticalAlign, Size, SizeUnits) + ClearView = ClearView or false + StartDelay = StartDelay or 0 + HorizontalAlign = HorizontalAlign or 1 + VerticalAlign = VerticalAlign or 1 + Size = Size or 100 + SizeUnits = SizeUnits or 0 + + if ClearView then ClearView = "true" else ClearView = "false" end + + net.dostring_in("mission", string.format("a_out_picture_c(%d, \"%s\", %d, %s, %d, \"%d\", \"%d\", %d, \"%d\")", Country, FilePath, Duration or 10, ClearView, StartDelay, HorizontalAlign, VerticalAlign, Size, SizeUnits)) +end + +--- Show a picture on the screen to Group +-- @param Wrapper.Group#GROUP Group Group to show the picture to +-- @param #string FileName File name of the picture +-- @param #number Duration Duration in seconds, defaults to 10 +-- @param #boolean ClearView If true, clears the view before showing the picture, defaults to false +-- @param #number StartDelay Delay in seconds before showing the picture, defaults to 0 +-- @param #number HorizontalAlign Horizontal alignment of the picture, 0: Left, 1: Center, 2: Right +-- @param #number VerticalAlign Vertical alignment of the picture, 0: Top, 1: Center, 2: Bottom +-- @param #number Size Size of the picture in percent, defaults to 100 +-- @param #number SizeUnits Size units, 0 for % of original picture size, and 1 for % of window size +function UTILS.ShowPictureToGroup(Group, FilePath, Duration, ClearView, StartDelay, HorizontalAlign, VerticalAlign, Size, SizeUnits) + ClearView = ClearView or false + StartDelay = StartDelay or 0 + HorizontalAlign = HorizontalAlign or 1 + VerticalAlign = VerticalAlign or 1 + Size = Size or 100 + SizeUnits = SizeUnits or 0 + + if ClearView then ClearView = "true" else ClearView = "false" end + + net.dostring_in("mission", string.format("a_out_picture_g(%d, \"%s\", %d, %s, %d, \"%d\", \"%d\", %d, \"%d\")", Group:GetID(), FilePath, Duration or 10, ClearView, StartDelay, HorizontalAlign, VerticalAlign, Size, SizeUnits)) +end + +--- Show a picture on the screen to Unit +-- @param Wrapper.Unit#UNIT Unit Unit to show the picture to +-- @param #string FileName File name of the picture +-- @param #number Duration Duration in seconds, defaults to 10 +-- @param #boolean ClearView If true, clears the view before showing the picture, defaults to false +-- @param #number StartDelay Delay in seconds before showing the picture, defaults to 0 +-- @param #number HorizontalAlign Horizontal alignment of the picture, 0: Left, 1: Center, 2: Right +-- @param #number VerticalAlign Vertical alignment of the picture, 0: Top, 1: Center, 2: Bottom +-- @param #number Size Size of the picture in percent, defaults to 100 +-- @param #number SizeUnits Size units, 0 for % of original picture size, and 1 for % of window size +function UTILS.ShowPictureToGroup(Unit, FilePath, Duration, ClearView, StartDelay, HorizontalAlign, VerticalAlign, Size, SizeUnits) + ClearView = ClearView or false + StartDelay = StartDelay or 0 + HorizontalAlign = HorizontalAlign or 1 + VerticalAlign = VerticalAlign or 1 + Size = Size or 100 + SizeUnits = SizeUnits or 0 + + if ClearView then ClearView = "true" else ClearView = "false" end + + net.dostring_in("mission", string.format("a_out_picture_u(%d, \"%s\", %d, %s, %d, \"%d\", \"%d\", %d, \"%d\")", Unit:GetID(), FilePath, Duration or 10, ClearView, StartDelay, HorizontalAlign, VerticalAlign, Size, SizeUnits)) +end + --- Load a mission file. This will replace the current mission with the one given carrying along the online clients. -- @param #string FileName Mission filename function UTILS.LoadMission(FileName) @@ -4640,11 +4734,19 @@ end --- Show a helper gate at a DCS#Vec3 position -- @param DCS#Vec3 pos The position --- @param number heading Heading in degrees, can be 0..359 degrees +-- @param #number heading Heading in degrees, can be 0..359 degrees function UTILS.ShowHelperGate(pos, heading) net.dostring_in("mission",string.format("a_show_helper_gate(%s, %s, %s, %f)", pos.x, pos.y, pos.z, math.rad(heading))) end +--- Show a helper gate for a unit. +-- @param Wrapper.Unit#UNIT Unit The unit to show the gate for +-- @param #number Flag Helper gate flag +function UTILS.ShowHelperGateForUnit(Unit, Flag) + net.dostring_in("mission",string.format("a_show_route_gates_for_unit(%d, \"%d\")", Unit:GetID(), Flag)) +end + + --- Shell a zone, zone must ME created -- @param #string name The name of the ME created zone -- @param #number power Equals kg of TNT, e.g. 75 From 9b217e1c9720993474b0fceb4b0898abe0a14398 Mon Sep 17 00:00:00 2001 From: smiki Date: Thu, 31 Jul 2025 08:57:20 +0200 Subject: [PATCH 139/234] [ADDED] `UTILS.ShowPicture` For all, coalition, country, group and unit [ADDED] `UTILS.ShowHelperGateForUnit` --- Moose Development/Moose/Utilities/Utils.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/Utilities/Utils.lua b/Moose Development/Moose/Utilities/Utils.lua index d5a4270f7..afc3c3f7b 100644 --- a/Moose Development/Moose/Utilities/Utils.lua +++ b/Moose Development/Moose/Utilities/Utils.lua @@ -4701,7 +4701,7 @@ end -- @param #number VerticalAlign Vertical alignment of the picture, 0: Top, 1: Center, 2: Bottom -- @param #number Size Size of the picture in percent, defaults to 100 -- @param #number SizeUnits Size units, 0 for % of original picture size, and 1 for % of window size -function UTILS.ShowPictureToGroup(Unit, FilePath, Duration, ClearView, StartDelay, HorizontalAlign, VerticalAlign, Size, SizeUnits) +function UTILS.ShowPictureToUnit(Unit, FilePath, Duration, ClearView, StartDelay, HorizontalAlign, VerticalAlign, Size, SizeUnits) ClearView = ClearView or false StartDelay = StartDelay or 0 HorizontalAlign = HorizontalAlign or 1 From 933000ffc7ac6c996a6ff0ad0b4827a33b6dfeb3 Mon Sep 17 00:00:00 2001 From: smiki Date: Thu, 31 Jul 2025 09:06:19 +0200 Subject: [PATCH 140/234] [ADDED] `UNIT:SetCarrierIlluminationMode` --- Moose Development/Moose/Utilities/Utils.lua | 6 ++++++ Moose Development/Moose/Wrapper/Unit.lua | 7 +++++++ 2 files changed, 13 insertions(+) diff --git a/Moose Development/Moose/Utilities/Utils.lua b/Moose Development/Moose/Utilities/Utils.lua index afc3c3f7b..a9a76d535 100644 --- a/Moose Development/Moose/Utilities/Utils.lua +++ b/Moose Development/Moose/Utilities/Utils.lua @@ -4746,6 +4746,12 @@ function UTILS.ShowHelperGateForUnit(Unit, Flag) net.dostring_in("mission",string.format("a_show_route_gates_for_unit(%d, \"%d\")", Unit:GetID(), Flag)) end +--- Set the carrier illumination mode. -2: OFF, -1: AUTO, 0: NAVIGATION, 1: AC LAUNCH, 2: AC RECOVERY +-- @param #number UnitID Carrier unit ID ( UNIT:GetID() ) +-- @param #number Mode Illumination mode, can be -2: OFF, -1: AUTO, 0: NAVIGATION, 1: AC LAUNCH, 2: AC RECOVERY +function UTILS.SetCarrierIlluminationMode(UnitID, Mode) + net.dostring_in("mission",string.format("a_set_carrier_illumination_mode(%d, %d)", UnitID, Mode)) +end --- Shell a zone, zone must ME created -- @param #string name The name of the ME created zone diff --git a/Moose Development/Moose/Wrapper/Unit.lua b/Moose Development/Moose/Wrapper/Unit.lua index 20ce4837d..d005ebca2 100644 --- a/Moose Development/Moose/Wrapper/Unit.lua +++ b/Moose Development/Moose/Wrapper/Unit.lua @@ -1931,3 +1931,10 @@ end function UNIT:SetLife(Percent) net.dostring_in("mission",string.format("a_unit_set_life_percentage(%d, %f)", self:GetID(), Percent)) end + +--- Set the carrier illumination mode. -2: OFF, -1: AUTO, 0: NAVIGATION, 1: AC LAUNCH, 2: AC RECOVERY +-- @param #UNIT self +-- @param #number Mode Illumination mode, can be -2: OFF, -1: AUTO, 0: NAVIGATION, 1: AC LAUNCH, 2: AC RECOVERY +function UNIT:SetCarrierIlluminationMode(Mode) + UTILS.SetCarrierIlluminationMode(self:GetID(), Mode) +end From b318e8ae13ae180b174e5431de8084dff4daa936 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 31 Jul 2025 09:47:54 +0200 Subject: [PATCH 141/234] #AIRBOSS - Added `:SetCarrierIllumination(Mode)` --- Moose Development/Moose/Ops/Airboss.lua | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Moose Development/Moose/Ops/Airboss.lua b/Moose Development/Moose/Ops/Airboss.lua index 7f2a4b6d8..c24f6720c 100644 --- a/Moose Development/Moose/Ops/Airboss.lua +++ b/Moose Development/Moose/Ops/Airboss.lua @@ -2412,6 +2412,16 @@ end -- USER API Functions ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +--- Set the carrier illumination mode. +-- @param #AIRBOSS self +-- @param #number Mode Options are: -2: OFF, -1: AUTO, 0: NAVIGATION, 1: AC LAUNCH, 2: AC RECOVERY +-- @return #AIRBOSS self +function AIRBOSS:SetCarrierIllumination(Mode) + self.carrier:SetCarrierIlluminationMode(Mode) + return self +end + + --- Set welcome messages for players. -- @param #AIRBOSS self -- @param #boolean Switch If true, display welcome message to player. From 4e024f7173901ff2cab104f8903ca3f0496e2c04 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 31 Jul 2025 12:35:40 +0200 Subject: [PATCH 142/234] #EASYGCICAP - added FuelLow/Critical settings and stopping of Airwings if you call Stop(). --- Moose Development/Moose/Ops/EasyGCICAP.lua | 66 +++++++++++++++++++++- 1 file changed, 63 insertions(+), 3 deletions(-) diff --git a/Moose Development/Moose/Ops/EasyGCICAP.lua b/Moose Development/Moose/Ops/EasyGCICAP.lua index f8def0685..8eba99f25 100644 --- a/Moose Development/Moose/Ops/EasyGCICAP.lua +++ b/Moose Development/Moose/Ops/EasyGCICAP.lua @@ -71,6 +71,8 @@ -- @field #boolean DespawnAfterHolding -- @field #list ListOfAuftrag -- @field #string defaulttakeofftype Take off type +-- @field #number FuelLowThreshold +-- @field #number FuelCriticalThreshold -- @extends Core.Fsm#FSM --- *“Airspeed, altitude, and brains. Two are always needed to successfully complete the flight.”* -- Unknown. @@ -226,6 +228,8 @@ EASYGCICAP = { DespawnAfterHolding = true, ListOfAuftrag = {}, defaulttakeofftype = "hot", + FuelLowThreshold = 25, + FuelCriticalThreshold = 10, } --- Internal Squadron data type @@ -261,7 +265,7 @@ EASYGCICAP = { --- EASYGCICAP class version. -- @field #string version -EASYGCICAP.version="0.1.23" +EASYGCICAP.version="0.1.25" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO list @@ -315,6 +319,8 @@ function EASYGCICAP:New(Alias, AirbaseName, Coalition, EWRName) self.DespawnAfterHolding = true self.ListOfAuftrag = {} self.defaulttakeofftype = "hot" + self.FuelLowThreshold = 25 + self.FuelCriticalThreshold = 10 -- Set some string id for output to DCS.log file. self.lid=string.format("EASYGCICAP %s | ", self.alias) @@ -339,6 +345,50 @@ end -- Functions ------------------------------------------------------------------------- +--- Get a specific managed AirWing by name +-- @param #EASYGCICAP self +-- @param #string AirbaseName Airbase name of the home of this wing. +-- @return Ops.AirWing#AIRWING Airwing or nil if not found +function EASYGCICAP:GetAirwing(AirbaseName) + self:T(self.lid.."GetAirwing") + if self.wings[AirbaseName] then + return self.wings[AirbaseName][1] + end + return nil +end + +--- Get a table of all managed AirWings +-- @param #EASYGCICAP self +-- @return #table Table of Ops.AirWing#AIRWING Airwings +function EASYGCICAP:GetAirwingTable() + self:T(self.lid.."GetAirwingTable") + local Wingtable = {} + for _,_object in pairs(self.wings or {}) do + table.insert(Wingtable,_object[1]) + end + return Wingtable +end + +--- Set "fuel low" threshold for CAP and INTERCEPT flights. +-- @param #EASYGCICAP self +-- @param #number Percent RTB if fuel at this percent. Values: 1..100, defaults to 25. +-- @return #EASYGCICAP self +function EASYGCICAP:SetFuelLow(Percent) + self:T(self.lid.."SetFuelLow") + self.FuelLowThreshold = Percent or 25 + return self +end + +--- Set "fuel critical" threshold for CAP and INTERCEPT flights. +-- @param #EASYGCICAP self +-- @param #number Percent RTB if fuel at this percent. Values: 1..100, defaults to 10. +-- @return #EASYGCICAP self +function EASYGCICAP:SetFuelCritical(Percent) + self:T(self.lid.."SetFuelCritical") + self.FuelCriticalThreshold = Percent or 10 + return self +end + --- Set CAP formation. -- @param #EASYGCICAP self -- @param #number Formation Formation to fly, defaults to ENUMS.Formation.FixedWing.FingerFour.Group @@ -359,7 +409,7 @@ function EASYGCICAP:SetTankerAndAWACSInvisible(Switch) return self end ---- Count alive missions in our internal stack. +--- (internal) Count alive missions in our internal stack. -- @param #EASYGCICAP self -- @return #number count function EASYGCICAP:_CountAliveAuftrags() @@ -628,6 +678,8 @@ function EASYGCICAP:_AddAirwing(Airbasename, Alias) local engagerange = self.engagerange local GoZoneSet = self.GoZoneSet local NoGoZoneSet = self.NoGoZoneSet + local FuelLow = self.FuelLowThreshold or 25 + local FuelCritical = self.FuelCriticalThreshold or 10 function CAP_Wing:onbeforeFlightOnMission(From, Event, To, Flightgroup, Mission) local flightgroup = Flightgroup -- Ops.FlightGroup#FLIGHTGROUP @@ -639,10 +691,15 @@ function EASYGCICAP:_AddAirwing(Airbasename, Alias) flightgroup:SetDestinationbase(AIRBASE:FindByName(Airbasename)) flightgroup:GetGroup():CommandEPLRS(true,5) flightgroup:GetGroup():SetOptionRadarUsingForContinousSearch() + flightgroup:GetGroup():SetOptionLandingOverheadBreak() if Mission.type ~= AUFTRAG.Type.TANKER and Mission.type ~= AUFTRAG.Type.AWACS and Mission.type ~= AUFTRAG.Type.RECON then flightgroup:SetDetection(true) flightgroup:SetEngageDetectedOn(engagerange,{"Air"},GoZoneSet,NoGoZoneSet) flightgroup:SetOutOfAAMRTB() + flightgroup:SetFuelLowRTB(true) + flightgroup:SetFuelLowThreshold(FuelLow) + flightgroup:SetFuelCriticalRTB(true) + flightgroup:SetFuelCriticalThreshold(FuelCritical) if CapFormation then flightgroup:GetGroup():SetOption(AI.Option.Air.id.FORMATION,CapFormation) end @@ -1404,7 +1461,7 @@ function EASYGCICAP:_StartIntel() end ------------------------------------------------------------------------- --- FSM Functions +-- TODO FSM Functions ------------------------------------------------------------------------- --- (Internal) FSM Function onafterStart @@ -1535,5 +1592,8 @@ end function EASYGCICAP:onafterStop(From,Event,To) self:T({From,Event,To}) self.Intel:Stop() + for _,_wing in pairs(self.wings or {}) do + _wing:Stop() + end return self end From c3dc055fb246aa51a1441d410352777f334e7374 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Fri, 1 Aug 2025 09:23:40 +0200 Subject: [PATCH 143/234] #FLIGHTGROUP - avoid nil error on dynamic spawn clients when looking for theri original prarking space --- Moose Development/Moose/Ops/FlightGroup.lua | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Moose Development/Moose/Ops/FlightGroup.lua b/Moose Development/Moose/Ops/FlightGroup.lua index 93ab210ae..1e99bff52 100644 --- a/Moose Development/Moose/Ops/FlightGroup.lua +++ b/Moose Development/Moose/Ops/FlightGroup.lua @@ -4667,10 +4667,12 @@ function FLIGHTGROUP:GetParking(airbase) local coords={} for clientname, client in pairs(clients) do local template=_DATABASE:GetGroupTemplateFromUnitName(clientname) - local units=template.units - for i,unit in pairs(units) do - local coord=COORDINATE:New(unit.x, unit.alt, unit.y) - coords[unit.name]=coord + if template then + local units=template.units + for i,unit in pairs(units) do + local coord=COORDINATE:New(unit.x, unit.alt, unit.y) + coords[unit.name]=coord + end end end return coords From 13fa8f373e37f6445952c6da4661b58873ff06b1 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Fri, 1 Aug 2025 14:02:57 +0200 Subject: [PATCH 144/234] #MANTIS - added radar entry for Dog Ear and Nike --- Moose Development/Moose/Functional/Mantis.lua | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Functional/Mantis.lua b/Moose Development/Moose/Functional/Mantis.lua index 4b761e99f..cd3ee9cae 100644 --- a/Moose Development/Moose/Functional/Mantis.lua +++ b/Moose Development/Moose/Functional/Mantis.lua @@ -112,6 +112,7 @@ -- * SA-2, SA-3, SA-5, SA-6, SA-7, SA-8, SA-9, SA-10, SA-11, SA-13, SA-15, SA-19 -- * From IDF mod: STUNNER IDFA, TAMIR IDFA (Note all caps!) -- * From HDS (see note on HDS below): SA-2, SA-3, SA-10B, SA-10C, SA-12, SA-17, SA-20A, SA-20B, SA-23, HQ-2, SAMP/T Block 1, SAMP/T Block 1INT, SAMP/T Block2 +-- * Other Mods: Nike -- -- * From SMA: RBS98M, RBS70, RBS90, RBS90M, RBS103A, RBS103B, RBS103AM, RBS103BM, Lvkv9040M -- **NOTE** If you are using the Swedish Military Assets (SMA), please note that the **group name** for RBS-SAM types also needs to contain the keyword "SMA" @@ -275,7 +276,7 @@ MANTIS = { ClassName = "MANTIS", name = "mymantis", - version = "0.9.32", + version = "0.9.33", SAM_Templates_Prefix = "", SAM_Group = nil, EWR_Templates_Prefix = "", @@ -392,7 +393,9 @@ MANTIS.SamData = { ["SA-20B"] = { Range=200, Blindspot=4, Height=27, Type="Long" , Radar="S-300PMU2"}, ["HQ-2"] = { Range=50, Blindspot=6, Height=35, Type="Medium", Radar="HQ_2_Guideline_LN" }, ["TAMIR IDFA"] = { Range=20, Blindspot=0.6, Height=12.3, Type="Short", Radar="IRON_DOME_LN" }, - ["STUNNER IDFA"] = { Range=250, Blindspot=1, Height=45, Type="Long", Radar="DAVID_SLING_LN" }, + ["STUNNER IDFA"] = { Range=250, Blindspot=1, Height=45, Type="Long", Radar="DAVID_SLING_LN" }, + ["NIKE"] = { Range=155, Blindspot=6, Height=30, Type="Long", Radar="HIPAR" }, + ["Dog Ear"] = { Range=11, Blindspot=0, Height=9, Type="Point", Radar="Dog Ear", Point="true" }, } --- SAM data HDS From e3b587aa956720d11f83afad262cc87545a01421 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Fri, 1 Aug 2025 14:03:12 +0200 Subject: [PATCH 145/234] xx --- Moose Development/Moose/Functional/Mantis.lua | 7 +++++-- Moose Development/Moose/Ops/FlightControl.lua | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Moose Development/Moose/Functional/Mantis.lua b/Moose Development/Moose/Functional/Mantis.lua index 4b761e99f..cd3ee9cae 100644 --- a/Moose Development/Moose/Functional/Mantis.lua +++ b/Moose Development/Moose/Functional/Mantis.lua @@ -112,6 +112,7 @@ -- * SA-2, SA-3, SA-5, SA-6, SA-7, SA-8, SA-9, SA-10, SA-11, SA-13, SA-15, SA-19 -- * From IDF mod: STUNNER IDFA, TAMIR IDFA (Note all caps!) -- * From HDS (see note on HDS below): SA-2, SA-3, SA-10B, SA-10C, SA-12, SA-17, SA-20A, SA-20B, SA-23, HQ-2, SAMP/T Block 1, SAMP/T Block 1INT, SAMP/T Block2 +-- * Other Mods: Nike -- -- * From SMA: RBS98M, RBS70, RBS90, RBS90M, RBS103A, RBS103B, RBS103AM, RBS103BM, Lvkv9040M -- **NOTE** If you are using the Swedish Military Assets (SMA), please note that the **group name** for RBS-SAM types also needs to contain the keyword "SMA" @@ -275,7 +276,7 @@ MANTIS = { ClassName = "MANTIS", name = "mymantis", - version = "0.9.32", + version = "0.9.33", SAM_Templates_Prefix = "", SAM_Group = nil, EWR_Templates_Prefix = "", @@ -392,7 +393,9 @@ MANTIS.SamData = { ["SA-20B"] = { Range=200, Blindspot=4, Height=27, Type="Long" , Radar="S-300PMU2"}, ["HQ-2"] = { Range=50, Blindspot=6, Height=35, Type="Medium", Radar="HQ_2_Guideline_LN" }, ["TAMIR IDFA"] = { Range=20, Blindspot=0.6, Height=12.3, Type="Short", Radar="IRON_DOME_LN" }, - ["STUNNER IDFA"] = { Range=250, Blindspot=1, Height=45, Type="Long", Radar="DAVID_SLING_LN" }, + ["STUNNER IDFA"] = { Range=250, Blindspot=1, Height=45, Type="Long", Radar="DAVID_SLING_LN" }, + ["NIKE"] = { Range=155, Blindspot=6, Height=30, Type="Long", Radar="HIPAR" }, + ["Dog Ear"] = { Range=11, Blindspot=0, Height=9, Type="Point", Radar="Dog Ear", Point="true" }, } --- SAM data HDS diff --git a/Moose Development/Moose/Ops/FlightControl.lua b/Moose Development/Moose/Ops/FlightControl.lua index 2db7c3942..bc13affeb 100644 --- a/Moose Development/Moose/Ops/FlightControl.lua +++ b/Moose Development/Moose/Ops/FlightControl.lua @@ -2464,7 +2464,7 @@ end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- Payer Menu +-- Player Menu ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- Create player menu. From eb15fadcfeaca51d8c76064ed128b21bf292947e Mon Sep 17 00:00:00 2001 From: leka1986 Date: Sat, 2 Aug 2025 17:40:55 +0200 Subject: [PATCH 146/234] Added SetPartlyInside. if used, it the :Trigger will trigger as soon as any of the group units enteres the zone even if they are far apart. --- Moose Development/Moose/Core/Set.lua | 25 +++++++++++++++++++++++-- Moose Development/Moose/Core/Zone.lua | 20 +++++++++++++++++++- 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua index 7f863abf2..06981e95f 100644 --- a/Moose Development/Moose/Core/Set.lua +++ b/Moose Development/Moose/Core/Set.lua @@ -6691,6 +6691,8 @@ do -- SET_ZONE -- -- -- Stop watching after 1 hour -- zoneset:__TriggerStop(3600) + -- -- Call :SetPartlyInside() on any zone (or SET_ZONE) if you want GROUPs to count as inside when any of their units enters even if they are far apart. + -- -- Make sure to call :SetPartlyInside() before :Trigger()!. function SET_ZONE:Trigger(Objects) --self:I("Added Set_Zone Trigger") self:AddTransition("*","TriggerStart","TriggerRunning") @@ -6741,6 +6743,20 @@ do -- SET_ZONE -- @param Core.Zone#ZONE_BASE Zone The zone left. end + --- Toggle “partly-inside” handling for every zone in the set when those zones are used with :Trigger(). + -- * Call with no argument or **true** → enable for all. + -- * Call with **false** → disable again (handy if it was enabled before). + -- @param #SET_ZONE self + -- @return #SET_ZONE self + function SET_ZONE:SetPartlyInside(state) + for _,Zone in pairs(self.Set) do + if Zone.SetPartlyInside then + Zone:SetPartlyInside(state) + end + end + return self + end + --- (Internal) Check the assigned objects for being in/out of the zone -- @param #SET_ZONE self -- @param #boolean fromstart If true, do the init of the objects @@ -6776,8 +6792,13 @@ do -- SET_ZONE -- has not been tagged previously - wasn't in set! obj.TriggerInZone[_zone.ZoneName] = false end - -- is obj in zone? - local inzone = _zone:IsCoordinateInZone(obj:GetCoordinate()) + -- is obj in this zone? + local inzone + if _zone.PartlyInside and obj.ClassName == "GROUP" then + inzone = obj:IsAnyInZone(_zone) -- TRUE as soon as any unit is inside + else + inzone = _zone:IsCoordinateInZone(obj:GetCoordinate()) -- original centroid test + end --self:I("Object "..obj:GetName().." is in zone: "..tostring(inzone)) if inzone and not obj.TriggerInZone[_zone.ZoneName] then -- wasn't in zone before diff --git a/Moose Development/Moose/Core/Zone.lua b/Moose Development/Moose/Core/Zone.lua index 6ed990101..6b0ac3d32 100644 --- a/Moose Development/Moose/Core/Zone.lua +++ b/Moose Development/Moose/Core/Zone.lua @@ -70,6 +70,7 @@ -- @field #table Table of any trigger zone properties from the ME. The key is the Name of the property, and the value is the property's Value. -- @field #number Surface Type of surface. Only determined at the center of the zone! -- @field #number Checktime Check every Checktime seconds, used for ZONE:Trigger() +-- @field #boolean PartlyInside When called, a GROUP is considered inside as soon as any of its units enters the zone even if they are far apart. -- @extends Core.Fsm#FSM @@ -612,6 +613,8 @@ end -- -- -- Stop watching the zone after 1 hour -- triggerzone:__TriggerStop(3600) +-- -- Call :SetPartlyInside() if you use SET_GROUP to count as inside when any of their units enters even when they are far apart. +-- -- Make sure to call :SetPartlyInside() before :Trigger()! function ZONE_BASE:Trigger(Objects) --self:I("Added Zone Trigger") self:SetStartState("TriggerStopped") @@ -680,6 +683,16 @@ function ZONE_BASE:Trigger(Objects) end + --- Toggle “partly-inside” handling for this zone. To be used before :Trigger(). + -- * Default:* flag is **false** until you call the method. + -- * Call with no argument or with **true** → enable. + -- * Call with **false** → disable again (handy if it was enabled before). + -- @param #ZONE_BASE self + -- @return #ZONE_BASE self + function ZONE_BASE:SetPartlyInside(state) + self.PartlyInside = state or not ( state == false ) + return self + end --- (Internal) Check the assigned objects for being in/out of the zone -- @param #ZONE_BASE self -- @param #boolean fromstart If true, do the init of the objects @@ -718,7 +731,12 @@ function ZONE_BASE:_TriggerCheck(fromstart) obj.TriggerInZone[self.ZoneName] = false end -- is obj in zone? - local inzone = self:IsCoordinateInZone(obj:GetCoordinate()) + local inzone + if self.PartlyInside and obj.ClassName == "GROUP" then + inzone = obj:IsAnyInZone(self) -- TRUE if any unit is inside + else + inzone = self:IsCoordinateInZone(obj:GetCoordinate()) -- original barycentre test + end --self:I("Object "..obj:GetName().." is in zone: "..tostring(inzone)) if inzone and obj.TriggerInZone[self.ZoneName] then -- just count From c8d693c8e7b7bb12fac21b3b2605cd43af866ded Mon Sep 17 00:00:00 2001 From: Thomas <72444570+Applevangelist@users.noreply.github.com> Date: Mon, 4 Aug 2025 16:10:10 +0200 Subject: [PATCH 147/234] Update Airbase.lua Sinai add'l bases --- Moose Development/Moose/Wrapper/Airbase.lua | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Moose Development/Moose/Wrapper/Airbase.lua b/Moose Development/Moose/Wrapper/Airbase.lua index a24c00cbe..cf96d6064 100644 --- a/Moose Development/Moose/Wrapper/Airbase.lua +++ b/Moose Development/Moose/Wrapper/Airbase.lua @@ -736,15 +736,19 @@ AIRBASE.SouthAtlantic={ -- * AIRBASE.Sinai.Kibrit_Air_Base -- * AIRBASE.Sinai.Kom_Awshim -- * AIRBASE.Sinai.Melez +-- * AIRBASE.Sinai.Mezzeh_Air_Base -- * AIRBASE.Sinai.Nevatim -- * AIRBASE.Sinai.Ovda -- * AIRBASE.Sinai.Palmachim -- * AIRBASE.Sinai.Quwaysina +-- * AIRBASE.Sinai.Rafic_Hariri_Intl +-- * AIRBASE.Sinai.Ramat_David -- * 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.Tabuk -- * AIRBASE.Sinai.Tel_Nof -- * AIRBASE.Sinai.Wadi_Abu_Rish -- * AIRBASE.Sinai.Wadi_al_Jandali @@ -784,15 +788,19 @@ AIRBASE.Sinai = { ["Kibrit_Air_Base"] = "Kibrit Air Base", ["Kom_Awshim"] = "Kom Awshim", ["Melez"] = "Melez", + ["Mezzeh_Air_Base"] = "Mezzeh Air Base", ["Nevatim"] = "Nevatim", ["Ovda"] = "Ovda", ["Palmachim"] = "Palmachim", ["Quwaysina"] = "Quwaysina", + ["Rafic_Hariri_Intl"] = "Rafic Hariri Intl", + ["Ramat_David"] = "Ramat David", ["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", + ["Tabuk"] = "Tabuk", ["Tel_Nof"] = "Tel Nof", ["Wadi_Abu_Rish"] = "Wadi Abu Rish", ["Wadi_al_Jandali"] = "Wadi al Jandali", From 029f7a3f5c3f74617937cf8b042d4a1a436f7e14 Mon Sep 17 00:00:00 2001 From: Thomas <72444570+Applevangelist@users.noreply.github.com> Date: Wed, 6 Aug 2025 12:27:28 +0200 Subject: [PATCH 148/234] Update Scoring.lua Better check for Scenery hits where target category is usually nil --- Moose Development/Moose/Functional/Scoring.lua | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Moose Development/Moose/Functional/Scoring.lua b/Moose Development/Moose/Functional/Scoring.lua index c4a0c8e20..edab15328 100644 --- a/Moose Development/Moose/Functional/Scoring.lua +++ b/Moose Development/Moose/Functional/Scoring.lua @@ -1025,6 +1025,11 @@ function SCORING:_EventOnHit( Event ) TargetCategory = Event.TgtCategory TargetType = Event.TgtTypeName + -- Scenery hit + if (not TargetCategory) and TargetUNIT ~= nil and TargetUnit:IsInstanceOf("SCENERY") then + TargetCategory = Unit.Category.STRUCTURE + end + TargetUnitCoalition = _SCORINGCoalition[TargetCoalition] TargetUnitCategory = _SCORINGCategory[TargetCategory] TargetUnitType = TargetType From 4fa63986dc4d94f2c97ac1e13877bda28e9e28e0 Mon Sep 17 00:00:00 2001 From: Thomas <72444570+Applevangelist@users.noreply.github.com> Date: Thu, 7 Aug 2025 11:16:07 +0200 Subject: [PATCH 149/234] Update Scoring.lua Further changes --- Moose Development/Moose/Functional/Scoring.lua | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Functional/Scoring.lua b/Moose Development/Moose/Functional/Scoring.lua index edab15328..c3f4bd4b6 100644 --- a/Moose Development/Moose/Functional/Scoring.lua +++ b/Moose Development/Moose/Functional/Scoring.lua @@ -985,6 +985,7 @@ function SCORING:_EventOnHit( Event ) local TargetUnitCoalition = nil local TargetUnitCategory = nil local TargetUnitType = nil + local TargetIsScenery = false if Event.IniDCSUnit then @@ -1028,6 +1029,7 @@ function SCORING:_EventOnHit( Event ) -- Scenery hit if (not TargetCategory) and TargetUNIT ~= nil and TargetUnit:IsInstanceOf("SCENERY") then TargetCategory = Unit.Category.STRUCTURE + TargetIsScenery = true end TargetUnitCoalition = _SCORINGCoalition[TargetCoalition] @@ -1122,17 +1124,22 @@ function SCORING:_EventOnHit( Event ) MESSAGE.Type.Update ) :ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() ) :ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() ) - else + elseif TargetIsScenery ~= true then MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit enemy target " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.ScoreHit .. " times. " .. "Score: " .. PlayerHit.Score .. ". Score Total:" .. Player.Score - Player.Penalty, MESSAGE.Type.Update ) :ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() ) :ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() ) + elseif TargetIsScenery == true then + MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit scenery object." .. " Score: " .. PlayerHit.Score .. ". Score Total:" .. Player.Score - Player.Penalty, + MESSAGE.Type.Update ) + :ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() ) + :ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() ) end self:ScoreCSV( InitPlayerName, TargetPlayerName, "HIT_SCORE", 1, 1, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) end else -- A scenery object was hit. - MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit scenery object.", + MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit nothing special.", MESSAGE.Type.Update ) :ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() ) :ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() ) From 674c6eec81a5492c6d21a38be32964efc83af116 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 7 Aug 2025 11:30:39 +0200 Subject: [PATCH 150/234] More randomness in functions using random coordinates --- Moose Development/Moose/Core/Point.lua | 4 +++- Moose Development/Moose/Core/Zone.lua | 9 +++++++++ Moose Development/Moose/Shapes/Circle.lua | 12 +++++++++++- Moose Development/Moose/Shapes/Polygon.lua | 1 + Moose Development/Moose/Shapes/Triangle.lua | 5 +++++ 5 files changed, 29 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index 09af3b47e..b17e40f27 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -777,7 +777,9 @@ do -- COORDINATE -- @return DCS#Vec2 Vec2 function COORDINATE:GetRandomVec2InRadius( OuterRadius, InnerRadius ) self:F2( { OuterRadius, InnerRadius } ) - + math.random() + math.random() + math.random() local Theta = 2 * math.pi * math.random() local Radials = math.random() + math.random() if Radials > 1 then diff --git a/Moose Development/Moose/Core/Zone.lua b/Moose Development/Moose/Core/Zone.lua index 6b0ac3d32..104362abb 100644 --- a/Moose Development/Moose/Core/Zone.lua +++ b/Moose Development/Moose/Core/Zone.lua @@ -1571,6 +1571,10 @@ function ZONE_RADIUS:GetRandomVec2(inner, outer, surfacetypes) local Vec2 = self:GetVec2() local _inner = inner or 0 local _outer = outer or self:GetRadius() + + math.random() + math.random() + math.random() if surfacetypes and type(surfacetypes)~="table" then surfacetypes={surfacetypes} @@ -2936,6 +2940,11 @@ end function ZONE_POLYGON_BASE:GetRandomVec2() -- make sure we assign weights to the triangles based on their surface area, otherwise -- we'll be more likely to generate random points in smaller triangles + + math.random() + math.random() + math.random() + local weights = {} for _, triangle in pairs(self._Triangles) do weights[triangle] = triangle.SurfaceArea / self.SurfaceArea diff --git a/Moose Development/Moose/Shapes/Circle.lua b/Moose Development/Moose/Shapes/Circle.lua index 39461c522..7bdbb31c1 100644 --- a/Moose Development/Moose/Shapes/Circle.lua +++ b/Moose Development/Moose/Shapes/Circle.lua @@ -72,7 +72,7 @@ end --- Checks if a point is contained within the circle. -- @param #table point The point to check --- @return #bool True if the point is contained, false otherwise +-- @return #boolean True if the point is contained, false otherwise function CIRCLE:ContainsPoint(point) if ((point.x - self.CenterVec2.x) ^ 2 + (point.y - self.CenterVec2.y) ^ 2) ^ 0.5 <= self.Radius then return true @@ -226,6 +226,11 @@ end --- Returns a random Vec2 within the circle. -- @return #table The random Vec2 function CIRCLE:GetRandomVec2() + + math.random() + math.random() + math.random() + local angle = math.random() * 2 * math.pi local rx = math.random(0, self.Radius) * math.cos(angle) + self.CenterVec2.x @@ -237,6 +242,11 @@ end --- Returns a random Vec2 on the border of the circle. -- @return #table The random Vec2 function CIRCLE:GetRandomVec2OnBorder() + + math.random() + math.random() + math.random() + local angle = math.random() * 2 * math.pi local rx = self.Radius * math.cos(angle) + self.CenterVec2.x diff --git a/Moose Development/Moose/Shapes/Polygon.lua b/Moose Development/Moose/Shapes/Polygon.lua index d0253fa04..e126a2002 100644 --- a/Moose Development/Moose/Shapes/Polygon.lua +++ b/Moose Development/Moose/Shapes/Polygon.lua @@ -352,6 +352,7 @@ end --- Returns a random Vec2 within the polygon. The Vec2 is weighted by the areas of the triangles that make up the polygon. -- @return #table The random Vec2 function POLYGON:GetRandomVec2() + local weights = {} for _, triangle in pairs(self.Triangles) do weights[triangle] = triangle.SurfaceArea / self.SurfaceArea diff --git a/Moose Development/Moose/Shapes/Triangle.lua b/Moose Development/Moose/Shapes/Triangle.lua index 747407d2e..e9a52e866 100644 --- a/Moose Development/Moose/Shapes/Triangle.lua +++ b/Moose Development/Moose/Shapes/Triangle.lua @@ -73,6 +73,11 @@ end -- @param #table points The points of the triangle, or 3 other points if you're just using the TRIANGLE class without an object of it -- @return #table The random Vec2 function TRIANGLE:GetRandomVec2(points) + + math.random() + math.random() + math.random() + points = points or self.Points local pt = {math.random(), math.random()} table.sort(pt) From f075c02db5ced680bb23f3dc9a97f9762093bc3c Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 7 Aug 2025 18:47:49 +0200 Subject: [PATCH 151/234] #EASYGCICAP - small tweak to allow the airbase to be a carrier ship --- Moose Development/Moose/Ops/EasyGCICAP.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Moose Development/Moose/Ops/EasyGCICAP.lua b/Moose Development/Moose/Ops/EasyGCICAP.lua index 8eba99f25..92f6defe1 100644 --- a/Moose Development/Moose/Ops/EasyGCICAP.lua +++ b/Moose Development/Moose/Ops/EasyGCICAP.lua @@ -7,7 +7,7 @@ -- ------------------------------------------------------------------------- -- Date: September 2023 --- Last Update: July 2024 +-- Last Update: Aug 2025 ------------------------------------------------------------------------- -- --- **Ops** - Easy GCI & CAP Manager @@ -265,7 +265,7 @@ EASYGCICAP = { --- EASYGCICAP class version. -- @field #string version -EASYGCICAP.version="0.1.25" +EASYGCICAP.version="0.1.26" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO list @@ -633,7 +633,7 @@ function EASYGCICAP:_AddAirwing(Airbasename, Alias) local DespawnAfterHolding = self.DespawnAfterHolding -- Check STATIC name - local check = STATIC:FindByName(Airbasename,false) + local check = STATIC:FindByName(Airbasename,false) or UNIT:FindByName(Airbasename) if check == nil then MESSAGE:New(self.lid.."There's no warehouse static on the map (wrong naming?) for airbase "..tostring(Airbasename).."!",30,"CHECK"):ToAllIf(self.debug):ToLog() return @@ -967,7 +967,7 @@ end -- @param #string SquadName Squadron name - must be unique! -- @param #string AirbaseName Name of the airbase the airwing resides on, e.g. AIRBASE.Caucasus.Kutaisi -- @param #number AirFrames Number of available airframes, e.g. 20. --- @param #string Skill(optional) Skill level, e.g. AI.Skill.AVERAGE +-- @param #string Skill (optional) Skill level, e.g. AI.Skill.AVERAGE -- @param #string Modex (optional) Modex to be used,e.g. 402. -- @param #string Livery (optional) Livery name to be used. -- @return #EASYGCICAP self From 4c97d966a2038904b304dd92075b48b094269507 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sun, 10 Aug 2025 13:20:22 +0200 Subject: [PATCH 152/234] #MSRS - align google voices catalog with new voice types. --- Moose Development/Moose/Sound/SRS.lua | 260 ++++++++++++++++++++------ 1 file changed, 199 insertions(+), 61 deletions(-) diff --git a/Moose Development/Moose/Sound/SRS.lua b/Moose Development/Moose/Sound/SRS.lua index 5b9358b2f..3432e0f0c 100644 --- a/Moose Development/Moose/Sound/SRS.lua +++ b/Moose Development/Moose/Sound/SRS.lua @@ -443,28 +443,32 @@ MSRS.Voices = { ["en_AU_Standard_B"] = 'en-AU-Standard-B', -- [2] MALE ["en_AU_Standard_C"] = 'en-AU-Standard-C', -- [3] FEMALE ["en_AU_Standard_D"] = 'en-AU-Standard-D', -- [4] MALE - ["en_IN_Standard_A"] = 'en-IN-Standard-A', -- [5] FEMALE - ["en_IN_Standard_B"] = 'en-IN-Standard-B', -- [6] MALE - ["en_IN_Standard_C"] = 'en-IN-Standard-C', -- [7] MALE - ["en_IN_Standard_D"] = 'en-IN-Standard-D', -- [8] FEMALE + -- IN + ["en_IN_Standard_A"] = 'en-IN-Standard-A', -- Female + ["en_IN_Standard_B"] = 'en-IN-Standard-B', -- Male + ["en_IN_Standard_C"] = 'en-IN-Standard-C', -- Male + ["en_IN_Standard_D"] = 'en-IN-Standard-D', -- Female + ["en_IN_Standard_E"] = 'en-IN-Standard-E', -- Female + ["en_IN_Standard_F"] = 'en-IN-Standard-F', -- Male -- 2025 changes - ["en_GB_Standard_A"] = 'en-GB-Standard-N', -- [9] FEMALE - ["en_GB_Standard_B"] = 'en-GB-Standard-O', -- [10] MALE - ["en_GB_Standard_C"] = 'en-GB-Standard-N', -- [11] FEMALE - ["en_GB_Standard_D"] = 'en-GB-Standard-O', -- [12] MALE - ["en_GB_Standard_F"] = 'en-GB-Standard-N', -- [13] FEMALE - ["en_GB_Standard_O"] = 'en-GB-Standard-O', -- [12] MALE - ["en_GB_Standard_N"] = 'en-GB-Standard-N', -- [13] FEMALE - ["en_US_Standard_A"] = 'en-US-Standard-A', -- [14] MALE - ["en_US_Standard_B"] = 'en-US-Standard-B', -- [15] MALE - ["en_US_Standard_C"] = 'en-US-Standard-C', -- [16] FEMALE - ["en_US_Standard_D"] = 'en-US-Standard-D', -- [17] MALE - ["en_US_Standard_E"] = 'en-US-Standard-E', -- [18] FEMALE - ["en_US_Standard_F"] = 'en-US-Standard-F', -- [19] FEMALE - ["en_US_Standard_G"] = 'en-US-Standard-G', -- [20] FEMALE - ["en_US_Standard_H"] = 'en-US-Standard-H', -- [21] FEMALE - ["en_US_Standard_I"] = 'en-US-Standard-I', -- [22] MALE - ["en_US_Standard_J"] = 'en-US-Standard-J', -- [23] MALE + ["en_GB_Standard_A"] = 'en-GB-Standard-A', -- Female + ["en_GB_Standard_B"] = 'en-GB-Standard-B', -- Male + ["en_GB_Standard_C"] = 'en-GB-Standard-C', -- Female + ["en_GB_Standard_D"] = 'en-GB-Standard-D', -- Male + ["en_GB_Standard_F"] = 'en-GB-Standard-F', -- Female + ["en_GB_Standard_N"] = 'en-GB-Standard-N', -- Female + ["en_GB_Standard_O"] = 'en-GB-Standard-O', -- Male + -- US + ["en_US_Standard_A"] = 'en-US-Standard-A', -- Male + ["en_US_Standard_B"] = 'en-US-Standard-B', -- Male + ["en_US_Standard_C"] = 'en-US-Standard-C', -- Female + ["en_US_Standard_D"] = 'en-US-Standard-D', -- Male + ["en_US_Standard_E"] = 'en-US-Standard-E', -- Female + ["en_US_Standard_F"] = 'en-US-Standard-F', -- Female + ["en_US_Standard_G"] = 'en-US-Standard-G', -- Female + ["en_US_Standard_H"] = 'en-US-Standard-H', -- Female + ["en_US_Standard_I"] = 'en-US-Standard-I', -- Male + ["en_US_Standard_J"] = 'en-US-Standard-J', -- Male -- 2025 catalog changes ["fr_FR_Standard_A"] = "fr-FR-Standard-F", -- Female ["fr_FR_Standard_B"] = "fr-FR-Standard-G", -- Male @@ -474,14 +478,15 @@ MSRS.Voices = { ["fr_FR_Standard_G"] = "fr-FR-Standard-G", -- Male ["fr_FR_Standard_F"] = "fr-FR-Standard-F", -- Female -- 2025 catalog changes - ["de_DE_Standard_A"] = "de-DE-Standard-G", -- Female - ["de_DE_Standard_B"] = "de-DE-Standard-H", -- Male - ["de_DE_Standard_C"] = "de-DE-Standard-G", -- Female - ["de_DE_Standard_D"] = "de-DE-Standard-H", -- Male - ["de_DE_Standard_E"] = "de-DE-Standard-H", -- Male - ["de_DE_Standard_F"] = "de-DE-Standard-G", -- Female - ["de_DE_Standard_H"] = "de-DE-Standard-H", -- Male - ["de_DE_Standard_G"] = "de-DE-Standard-G", -- Female + ["de_DE_Standard_A"] = 'de-DE-Standard-A', -- Female + ["de_DE_Standard_B"] = 'de-DE-Standard-B', -- Male + ["de_DE_Standard_C"] = 'de-DE-Standard-C', -- Female + ["de_DE_Standard_D"] = 'de-DE-Standard-D', -- Male + ["de_DE_Standard_E"] = 'de-DE-Standard-E', -- Male + ["de_DE_Standard_F"] = 'de-DE-Standard-F', -- Female + ["de_DE_Standard_G"] = 'de-DE-Standard-G', -- Female + ["de_DE_Standard_H"] = 'de-DE-Standard-H', -- Male + -- ES ["es_ES_Standard_A"] = "es-ES-Standard-E", -- Female ["es_ES_Standard_B"] = "es-ES-Standard-F", -- Male ["es_ES_Standard_C"] = "es-ES-Standard-E", -- Female @@ -497,32 +502,36 @@ MSRS.Voices = { ["it_IT_Standard_F"] = "it-IT-Standard-F", -- Male }, Wavenet = { - ["en_AU_Wavenet_A"] = 'en-AU-Wavenet-A', -- [1] FEMALE - ["en_AU_Wavenet_B"] = 'en-AU-Wavenet-B', -- [2] MALE - ["en_AU_Wavenet_C"] = 'en-AU-Wavenet-C', -- [3] FEMALE - ["en_AU_Wavenet_D"] = 'en-AU-Wavenet-D', -- [4] MALE - ["en_IN_Wavenet_A"] = 'en-IN-Wavenet-A', -- [5] FEMALE - ["en_IN_Wavenet_B"] = 'en-IN-Wavenet-B', -- [6] MALE - ["en_IN_Wavenet_C"] = 'en-IN-Wavenet-C', -- [7] MALE - ["en_IN_Wavenet_D"] = 'en-IN-Wavenet-D', -- [8] FEMALE + ["en_AU_Wavenet_A"] = 'en-AU-Wavenet-A', -- Female + ["en_AU_Wavenet_B"] = 'en-AU-Wavenet-B', -- Male + ["en_AU_Wavenet_C"] = 'en-AU-Wavenet-C', -- Female + ["en_AU_Wavenet_D"] = 'en-AU-Wavenet-D', -- Male + -- IN + ["en_IN_Wavenet_A"] = 'en-IN-Wavenet-A', -- Female + ["en_IN_Wavenet_B"] = 'en-IN-Wavenet-B', -- Male + ["en_IN_Wavenet_C"] = 'en-IN-Wavenet-C', -- Male + ["en_IN_Wavenet_D"] = 'en-IN-Wavenet-D', -- Female + ["en_IN_Wavenet_E"] = 'en-IN-Wavenet-E', -- Female + ["en_IN_Wavenet_F"] = 'en-IN-Wavenet-F', -- Male -- 2025 changes - ["en_GB_Wavenet_A"] = 'en-GB-Wavenet-N', -- [9] FEMALE - ["en_GB_Wavenet_B"] = 'en-GB-Wavenet-O', -- [10] MALE - ["en_GB_Wavenet_C"] = 'en-GB-Wavenet-N', -- [11] FEMALE - ["en_GB_Wavenet_D"] = 'en-GB-Wavenet-O', -- [12] MALE - ["en_GB_Wavenet_F"] = 'en-GB-Wavenet-N', -- [13] FEMALE + ["en_GB_Wavenet_A"] = 'en-GB-Wavenet-A', -- [9] FEMALE + ["en_GB_Wavenet_B"] = 'en-GB-Wavenet-B', -- [10] MALE + ["en_GB_Wavenet_C"] = 'en-GB-Wavenet-C', -- [11] FEMALE + ["en_GB_Wavenet_D"] = 'en-GB-Wavenet-D', -- [12] MALE + ["en_GB_Wavenet_F"] = 'en-GB-Wavenet-F', -- [13] FEMALE ["en_GB_Wavenet_O"] = 'en-GB-Wavenet-O', -- [12] MALE - ["en_GB_Wavenet_N"] = 'en-GB-Wavenet-N', -- [13] FEMALE - ["en_US_Wavenet_A"] = 'en-US-Wavenet-A', -- [14] MALE - ["en_US_Wavenet_B"] = 'en-US-Wavenet-B', -- [15] MALE - ["en_US_Wavenet_C"] = 'en-US-Wavenet-C', -- [16] FEMALE - ["en_US_Wavenet_D"] = 'en-US-Wavenet-D', -- [17] MALE - ["en_US_Wavenet_E"] = 'en-US-Wavenet-E', -- [18] FEMALE - ["en_US_Wavenet_F"] = 'en-US-Wavenet-F', -- [19] FEMALE - ["en_US_Wavenet_G"] = 'en-US-Wavenet-G', -- [20] FEMALE - ["en_US_Wavenet_H"] = 'en-US-Wavenet-H', -- [21] FEMALE - ["en_US_Wavenet_I"] = 'en-US-Wavenet-I', -- [22] MALE - ["en_US_Wavenet_J"] = 'en-US-Wavenet-J', -- [23] MALE + ["en_GB_Wavenet_N"] = 'en-GB-Wavenet-N', -- [13] FEMALE + -- US + ["en_US_Wavenet_A"] = 'en-US-Wavenet-A', -- Male + ["en_US_Wavenet_B"] = 'en-US-Wavenet-B', -- Male + ["en_US_Wavenet_C"] = 'en-US-Wavenet-C', -- Female + ["en_US_Wavenet_D"] = 'en-US-Wavenet-D', -- Male + ["en_US_Wavenet_E"] = 'en-US-Wavenet-E', -- Female + ["en_US_Wavenet_F"] = 'en-US-Wavenet-F', -- Female + ["en_US_Wavenet_G"] = 'en-US-Wavenet-G', -- Female + ["en_US_Wavenet_H"] = 'en-US-Wavenet-H', -- Female + ["en_US_Wavenet_I"] = 'en-US-Wavenet-I', -- Male + ["en_US_Wavenet_J"] = 'en-US-Wavenet-J', -- Male -- 2025 catalog changes ["fr_FR_Wavenet_A"] = "fr-FR-Wavenet-F", -- Female ["fr_FR_Wavenet_B"] = "fr-FR-Wavenet-G", -- Male @@ -532,14 +541,15 @@ MSRS.Voices = { ["fr_FR_Wavenet_G"] = "fr-FR-Wavenet-G", -- Male ["fr_FR_Wavenet_F"] = "fr-FR-Wavenet-F", -- Female -- 2025 catalog changes - ["de_DE_Wavenet_A"] = "de-DE-Wavenet-G", -- Female - ["de_DE_Wavenet_B"] = "de-DE-Wavenet-H", -- Male - ["de_DE_Wavenet_C"] = "de-DE-Wavenet-G", -- Female - ["de_DE_Wavenet_D"] = "de-DE-Wavenet-H", -- Male - ["de_DE_Wavenet_E"] = "de-DE-Wavenet-H", -- Male - ["de_DE_Wavenet_F"] = "de-DE-Wavenet-G", -- Female - ["de_DE_Wavenet_H"] = "de-DE-Wavenet-H", -- Male - ["de_DE_Wavenet_G"] = "de-DE-Wavenet-G", -- Female + ["de_DE_Wavenet_A"] = 'de-DE-Wavenet-A', -- Female + ["de_DE_Wavenet_B"] = 'de-DE-Wavenet-B', -- Male + ["de_DE_Wavenet_C"] = 'de-DE-Wavenet-C', -- Female + ["de_DE_Wavenet_D"] = 'de-DE-Wavenet-D', -- Male + ["de_DE_Wavenet_E"] = 'de-DE-Wavenet-E', -- Male + ["de_DE_Wavenet_F"] = 'de-DE-Wavenet-F', -- Female + ["de_DE_Wavenet_G"] = 'de-DE-Wavenet-G', -- Female + ["de_DE_Wavenet_H"] = 'de-DE-Wavenet-H', -- Male + -- ES ["es_ES_Wavenet_B"] = "es-ES-Wavenet-E", -- Male ["es_ES_Wavenet_C"] = "es-ES-Wavenet-F", -- Female ["es_ES_Wavenet_D"] = "es-ES-Wavenet-E", -- Female @@ -553,6 +563,134 @@ MSRS.Voices = { ["it_IT_Wavenet_E"] = "it-IT-Wavenet-E", -- Female ["it_IT_Wavenet_F"] = "it-IT-Wavenet-F", -- Male } , + Chirp3HD = { + ["en_GB_Chirp3_HD_Aoede"] = 'en-GB-Chirp3-HD-Aoede', -- Female + ["en_GB_Chirp3_HD_Charon"] = 'en-GB-Chirp3-HD-Charon', -- Male + ["en_GB_Chirp3_HD_Fenrir"] = 'en-GB-Chirp3-HD-Fenrir', -- Male + ["en_GB_Chirp3_HD_Kore"] = 'en-GB-Chirp3-HD-Kore', -- Female + ["en_GB_Chirp3_HD_Leda"] = 'en-GB-Chirp3-HD-Leda', -- Female + ["en_GB_Chirp3_HD_Orus"] = 'en-GB-Chirp3-HD-Orus', -- Male + ["en_GB_Chirp3_HD_Puck"] = 'en-GB-Chirp3-HD-Puck', -- Male + ["en_GB_Chirp3_HD_Zephyr"] = 'en-GB-Chirp3-HD-Zephyr', -- Female + --["de_DE_Chirp3_HD_Aoede"] = 'de-DE-Chirp3-HD-Aoede', -- Female (Datenfehler im Original) + ["en_US_Chirp3_HD_Charon"] = 'en-US-Chirp3-HD-Charon', -- Male + ["en_US_Chirp3_HD_Fenrir"] = 'en-US-Chirp3-HD-Fenrir', -- Male + ["en_US_Chirp3_HD_Kore"] = 'en-US-Chirp3-HD-Kore', -- Female + ["en_US_Chirp3_HD_Leda"] = 'en-US-Chirp3-HD-Leda', -- Female + ["en_US_Chirp3_HD_Orus"] = 'en-US-Chirp3-HD-Orus', -- Male + ["en_US_Chirp3_HD_Puck"] = 'en-US-Chirp3-HD-Puck', -- Male + --["de_DE_Chirp3_HD_Zephyr"] = 'de-DE-Chirp3-HD-Zephyr', -- Female (Datenfehler im Original) + -- DE + ["de_DE_Chirp3_HD_Aoede"] = 'de-DE-Chirp3-HD-Aoede', -- Female + ["de_DE_Chirp3_HD_Charon"] = 'de-DE-Chirp3-HD-Charon', -- Male + ["de_DE_Chirp3_HD_Fenrir"] = 'de-DE-Chirp3-HD-Fenrir', -- Male + ["de_DE_Chirp3_HD_Kore"] = 'de-DE-Chirp3-HD-Kore', -- Female + ["de_DE_Chirp3_HD_Leda"] = 'de-DE-Chirp3-HD-Leda', -- Female + ["de_DE_Chirp3_HD_Orus"] = 'de-DE-Chirp3-HD-Orus', -- Male + ["de_DE_Chirp3_HD_Puck"] = 'de-DE-Chirp3-HD-Puck', -- Male + ["de_DE_Chirp3_HD_Zephyr"] = 'de-DE-Chirp3-HD-Zephyr', -- Female + -- AU + ["en_AU_Chirp3_HD_Aoede"] = 'en-AU-Chirp3-HD-Aoede', -- Female + ["en_AU_Chirp3_HD_Charon"] = 'en-AU-Chirp3-HD-Charon', -- Male + ["en_AU_Chirp3_HD_Fenrir"] = 'en-AU-Chirp3-HD-Fenrir', -- Male + ["en_AU_Chirp3_HD_Kore"] = 'en-AU-Chirp3-HD-Kore', -- Female + ["en_AU_Chirp3_HD_Leda"] = 'en-AU-Chirp3-HD-Leda', -- Female + ["en_AU_Chirp3_HD_Orus"] = 'en-AU-Chirp3-HD-Orus', -- Male + ["en_AU_Chirp3_HD_Puck"] = 'en-AU-Chirp3-HD-Puck', -- Male + ["en_AU_Chirp3_HD_Zephyr"] = 'en-AU-Chirp3-HD-Zephyr', -- Female + -- IN + ["en_IN_Chirp3_HD_Aoede"] = 'en-IN-Chirp3-HD-Aoede', -- Female + ["en_IN_Chirp3_HD_Charon"] = 'en-IN-Chirp3-HD-Charon', -- Male + ["en_IN_Chirp3_HD_Fenrir"] = 'en-IN-Chirp3-HD-Fenrir', -- Male + ["en_IN_Chirp3_HD_Kore"] = 'en-IN-Chirp3-HD-Kore', -- Female + ["en_IN_Chirp3_HD_Leda"] = 'en-IN-Chirp3-HD-Leda', -- Female + ["en_IN_Chirp3_HD_Orus"] = 'en-IN-Chirp3-HD-Orus', -- Male + }, + ChirpHD = { + ["en_US_Chirp_HD_D"] = 'en-US-Chirp-HD-D', -- Male + ["en_US_Chirp_HD_F"] = 'en-US-Chirp-HD-F', -- Female + ["en_US_Chirp_HD_O"] = 'en-US-Chirp-HD-O', -- Female + -- DE + ["de_DE_Chirp_HD_D"] = 'de-DE-Chirp-HD-D', -- Male + ["de_DE_Chirp_HD_F"] = 'de-DE-Chirp-HD-F', -- Female + ["de_DE_Chirp_HD_O"] = 'de-DE-Chirp-HD-O', -- Female + -- AU + ["en_AU_Chirp_HD_D"] = 'en-AU-Chirp-HD-D', -- Male + ["en_AU_Chirp_HD_F"] = 'en-AU-Chirp-HD-F', -- Female + ["en_AU_Chirp_HD_O"] = 'en-AU-Chirp-HD-O', -- Female + -- IN + ["en_IN_Chirp_HD_D"] = 'en-IN-Chirp-HD-D', -- Male + ["en_IN_Chirp_HD_F"] = 'en-IN-Chirp-HD-F', -- Female + ["en_IN_Chirp_HD_O"] = 'en-IN-Chirp-HD-O', -- Female + }, + }, + Neural2 = { + ["en_GB_Neural2_A"] = 'en-GB-Neural2-A', -- Female + ["en_GB_Neural2_B"] = 'en-GB-Neural2-B', -- Male + ["en_GB_Neural2_C"] = 'en-GB-Neural2-C', -- Female + ["en_GB_Neural2_D"] = 'en-GB-Neural2-D', -- Male + ["en_GB_Neural2_F"] = 'en-GB-Neural2-F', -- Female + ["en_GB_Neural2_N"] = 'en-GB-Neural2-N', -- Female + ["en_GB_Neural2_O"] = 'en-GB-Neural2-O', -- Male + -- US + ["en_US_Neural2_A"] = 'en-US-Neural2-A', -- Male + ["en_US_Neural2_C"] = 'en-US-Neural2-C', -- Female + ["en_US_Neural2_D"] = 'en-US-Neural2-D', -- Male + ["en_US_Neural2_E"] = 'en-US-Neural2-E', -- Female + ["en_US_Neural2_F"] = 'en-US-Neural2-F', -- Female + ["en_US_Neural2_G"] = 'en-US-Neural2-G', -- Female + ["en_US_Neural2_H"] = 'en-US-Neural2-H', -- Female + ["en_US_Neural2_I"] = 'en-US-Neural2-I', -- Male + ["en_US_Neural2_J"] = 'en-US-Neural2-J', -- Male + -- DE + ["de_DE_Neural2_G"] = 'de-DE-Neural2-G', -- Female + ["de_DE_Neural2_H"] = 'de-DE-Neural2-H', -- Male + -- AU + ["en_AU_Neural2_A"] = 'en-AU-Neural2-A', -- Female + ["en_AU_Neural2_B"] = 'en-AU-Neural2-B', -- Male + ["en_AU_Neural2_C"] = 'en-AU-Neural2-C', -- Female + ["en_AU_Neural2_D"] = 'en-AU-Neural2-D', -- Male + -- IN + ["en_IN_Neural2_A"] = 'en-IN-Neural2-A', -- Female + ["en_IN_Neural2_B"] = 'en-IN-Neural2-B', -- Male + ["en_IN_Neural2_C"] = 'en-IN-Neural2-C', -- Male + ["en_IN_Neural2_D"] = 'en-IN-Neural2-D', -- Female + }, + News = { + ["en_GB_News_G"] = 'en-GB-News-G', -- Female + ["en_GB_News_H"] = 'en-GB-News-H', -- Female + ["en_GB_News_I"] = 'en-GB-News-I', -- Female + ["en_GB_News_J"] = 'en-GB-News-J', -- Male + ["en_GB_News_K"] = 'en-GB-News-K', -- Male + ["en_GB_News_L"] = 'en-GB-News-L', -- Male + ["en_GB_News_M"] = 'en-GB-News-M', -- Male + -- US + ["en_US_News_K"] = 'en-US-News-K', -- Female + ["en_US_News_L"] = 'en-US-News-L', -- Female + ["en_US_News_N"] = 'en-US-News-N', -- Male + -- AU + ["en_AU_News_E"] = 'en-AU-News-E', -- Female + ["en_AU_News_F"] = 'en-AU-News-F', -- Female + ["en_AU_News_G"] = 'en-AU-News-G', -- Male + }, + Casual = { + ["en_US_Casual_K"] = 'en-US-Casual-K', -- Male + }, + Polyglot = { + ["en_US_Polyglot_1"] = 'en-US-Polyglot-1', -- Male + ["de_DE_Polyglot_1"] = 'de-DE-Polyglot-1', -- Male + ["en_AU_Polyglot_1"] = 'en-AU-Polyglot-1', -- Male + }, + Studio = { + -- Englisch (UK) - Studio + ["en_GB_Studio_B"] = 'en-GB-Studio-B', -- Male + ["en_GB_Studio_C"] = 'en-GB-Studio-C', -- Female + -- Englisch (USA) - Studio + ["en_US_Studio_O"] = 'en-US-Studio-O', -- Female + ["en_US_Studio_Q"] = 'en-US-Studio-Q', -- Male + -- DE + ["de_DE_Studio_B"] = 'de-DE-Studio-B', -- Male + ["de_DE_Studio_C"] = 'de-DE-Studio-C', -- Female }, } From 03c3a20b1b3f55e0273d60b7b97e3d8327e240d1 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sun, 10 Aug 2025 13:33:16 +0200 Subject: [PATCH 153/234] #AIRWING, #EASYGCICAP - allow moving zones as patrol points for CAP/TANKER/AWACS/RECON --- Moose Development/Moose/Ops/AirWing.lua | 58 ++++++++++++++-------- Moose Development/Moose/Ops/Auftrag.lua | 2 +- Moose Development/Moose/Ops/EasyGCICAP.lua | 39 ++++++++++++--- Moose Development/Moose/Ops/OpsGroup.lua | 2 +- 4 files changed, 72 insertions(+), 29 deletions(-) diff --git a/Moose Development/Moose/Ops/AirWing.lua b/Moose Development/Moose/Ops/AirWing.lua index 4447ed86b..a4b1b58e5 100644 --- a/Moose Development/Moose/Ops/AirWing.lua +++ b/Moose Development/Moose/Ops/AirWing.lua @@ -159,6 +159,8 @@ AIRWING = { -- @field #number refuelsystem Refueling system type: `0=Unit.RefuelingSystem.BOOM_AND_RECEPTACLE`, `1=Unit.RefuelingSystem.PROBE_AND_DROGUE`. -- @field #number noccupied Number of flights on this patrol point. -- @field Wrapper.Marker#MARKER marker F10 marker. +-- @field #boolean IsZonePoint flag for using a (moving) zone as point for patrol etc. +-- @field Core.Zone#ZONE_BASE patrolzone in case Patrol coordinate was handed as zone, store here. --- Patrol zone. -- @type AIRWING.PatrolZone @@ -187,13 +189,14 @@ AIRWING = { --- AIRWING class version. -- @field #string version -AIRWING.version="0.9.6" +AIRWING.version="0.9.7" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- ToDo list ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO: Check that airbase has enough parking spots if a request is BIG. +-- DONE: Allow (moving) zones as base for patrol points. -- DONE: Spawn in air ==> Needs WAREHOUSE update. -- DONE: Spawn hot. -- DONE: Make special request to transfer squadrons to anther airwing (or warehouse). @@ -807,13 +810,22 @@ function AIRWING:_PatrolPointMarkerText(point) end --- Update marker of the patrol point. +-- @param #AIRWING self -- @param #AIRWING.PatrolData point Patrol point table. function AIRWING:UpdatePatrolPointMarker(point) - if self.markpoints then -- sometimes there's a direct call from #OPSGROUP + + if self and self.markpoints then -- sometimes there's a direct call from #OPSGROUP local text=string.format("%s Occupied=%d\nheading=%03d, leg=%d NM, alt=%d ft, speed=%d kts", point.type, point.noccupied, point.heading, point.leg, point.altitude, point.speed) - - point.marker:UpdateText(text, 1) + + if point.IsZonePoint and point.IsZonePoint == true and point.patrolzone then + -- update position + local Coordinate = point.patrolzone:GetCoordinate() + point.marker:UpdateCoordinate(Coordinate) + point.marker:UpdateText(text, 1.5) + else + point.marker:UpdateText(text, 1) + end end end @@ -821,7 +833,7 @@ end --- Create a new generic patrol point. -- @param #AIRWING self -- @param #string Type Patrol point type, e.g. "CAP" or "AWACS". Default "Unknown". --- @param Core.Point#COORDINATE Coordinate Coordinate of the patrol point. Default 10-15 NM away from the location of the airwing. +-- @param Core.Point#COORDINATE Coordinate Coordinate of the patrol point. Default 10-15 NM away from the location of the airwing. Can be handed as a Core.Zone#ZONE object (e.g. in case you want the point to align with a moving zone). -- @param #number Altitude Orbit altitude in feet. Default random between Angels 10 and 20. -- @param #number Heading Heading in degrees. Default random (0, 360] degrees. -- @param #number LegLength Length of race-track orbit in NM. Default 15 NM. @@ -830,14 +842,16 @@ end -- @return #AIRWING.PatrolData Patrol point table. function AIRWING:NewPatrolPoint(Type, Coordinate, Altitude, Speed, Heading, LegLength, RefuelSystem) - -- Check if a zone was passed instead of a coordinate. - if Coordinate and Coordinate:IsInstanceOf("ZONE_BASE") then - Coordinate=Coordinate:GetCoordinate() - end - local patrolpoint={} --#AIRWING.PatrolData patrolpoint.type=Type or "Unknown" patrolpoint.coord=Coordinate or self:GetCoordinate():Translate(UTILS.NMToMeters(math.random(10, 15)), math.random(360)) + if Coordinate:IsInstanceOf("ZONE_BASE") then + patrolpoint.IsZonePoint = true + patrolpoint.patrolzone = Coordinate + patrolpoint.coord = patrolpoint.patrolzone:GetCoordinate() + else + patrolpoint.IsZonePoint = false + end patrolpoint.heading=Heading or math.random(360) patrolpoint.leg=LegLength or 15 patrolpoint.altitude=Altitude or math.random(10,20)*1000 @@ -847,7 +861,7 @@ function AIRWING:NewPatrolPoint(Type, Coordinate, Altitude, Speed, Heading, LegL if self.markpoints then patrolpoint.marker=MARKER:New(Coordinate, "New Patrol Point"):ToAll() - AIRWING.UpdatePatrolPointMarker(patrolpoint) + self:UpdatePatrolPointMarker(patrolpoint) end return patrolpoint @@ -855,7 +869,7 @@ end --- Add a patrol Point for CAP missions. -- @param #AIRWING self --- @param Core.Point#COORDINATE Coordinate Coordinate of the patrol point. +-- @param Core.Point#COORDINATE Coordinate Coordinate of the patrol point. Can be handed as a Core.Zone#ZONE object (e.g. in case you want the point to align with a moving zone). -- @param #number Altitude Orbit altitude in feet. -- @param #number Speed Orbit speed in knots. -- @param #number Heading Heading in degrees. @@ -872,7 +886,7 @@ end --- Add a patrol Point for RECON missions. -- @param #AIRWING self --- @param Core.Point#COORDINATE Coordinate Coordinate of the patrol point. +-- @param Core.Point#COORDINATE Coordinate Coordinate of the patrol point. Can be handed as a Core.Zone#ZONE object (e.g. in case you want the point to align with a moving zone). -- @param #number Altitude Orbit altitude in feet. -- @param #number Speed Orbit speed in knots. -- @param #number Heading Heading in degrees. @@ -889,7 +903,7 @@ end --- Add a patrol Point for TANKER missions. -- @param #AIRWING self --- @param Core.Point#COORDINATE Coordinate Coordinate of the patrol point. +-- @param Core.Point#COORDINATE Coordinate Coordinate of the patrol point. Can be handed as a Core.Zone#ZONE object (e.g. in case you want the point to align with a moving zone). -- @param #number Altitude Orbit altitude in feet. -- @param #number Speed Orbit speed in knots. -- @param #number Heading Heading in degrees. @@ -907,7 +921,7 @@ end --- Add a patrol Point for AWACS missions. -- @param #AIRWING self --- @param Core.Point#COORDINATE Coordinate Coordinate of the patrol point. +-- @param Core.Point#COORDINATE Coordinate Coordinate of the patrol point. Can be handed as a Core.Zone#ZONE object (e.g. in case you want the point to align with a moving zone). -- @param #number Altitude Orbit altitude in feet. -- @param #number Speed Orbit speed in knots. -- @param #number Heading Heading in degrees. @@ -1176,6 +1190,10 @@ function AIRWING:_GetPatrolData(PatrolPoints, RefuelSystem) for _,_patrolpoint in pairs(PatrolPoints) do local patrolpoint=_patrolpoint --#AIRWING.PatrolData + if patrolpoint.IsZonePoint and patrolpoint.IsZonePoint == true and patrolpoint.patrolzone then + -- update + patrolpoint.coord = patrolpoint.patrolzone:GetCoordinate() + end if (RefuelSystem and patrolpoint.refuelsystem and RefuelSystem==patrolpoint.refuelsystem) or RefuelSystem==nil or patrolpoint.refuelsystem==nil then return patrolpoint end @@ -1235,7 +1253,7 @@ function AIRWING:CheckCAP() patrol.noccupied=patrol.noccupied+1 - if self.markpoints then AIRWING.UpdatePatrolPointMarker(patrol) end + if self.markpoints then self:UpdatePatrolPointMarker(patrol) end self:AddMission(missionCAP) @@ -1287,7 +1305,7 @@ function AIRWING:CheckRECON() patrol.noccupied=patrol.noccupied+1 - if self.markpoints then AIRWING.UpdatePatrolPointMarker(patrol) end + if self.markpoints then self:UpdatePatrolPointMarker(patrol) end self:AddMission(missionRECON) @@ -1332,7 +1350,7 @@ function AIRWING:CheckTANKER() patrol.noccupied=patrol.noccupied+1 - if self.markpoints then AIRWING.UpdatePatrolPointMarker(patrol) end + if self.markpoints then self:UpdatePatrolPointMarker(patrol) end self:AddMission(mission) @@ -1351,7 +1369,7 @@ function AIRWING:CheckTANKER() patrol.noccupied=patrol.noccupied+1 - if self.markpoints then AIRWING.UpdatePatrolPointMarker(patrol) end + if self.markpoints then self:UpdatePatrolPointMarker(patrol) end self:AddMission(mission) @@ -1389,7 +1407,7 @@ function AIRWING:CheckAWACS() patrol.noccupied=patrol.noccupied+1 - if self.markpoints then AIRWING.UpdatePatrolPointMarker(patrol) end + if self.markpoints then self:UpdatePatrolPointMarker(patrol) end self:AddMission(mission) diff --git a/Moose Development/Moose/Ops/Auftrag.lua b/Moose Development/Moose/Ops/Auftrag.lua index f0c2a1eaf..b4e6128a1 100644 --- a/Moose Development/Moose/Ops/Auftrag.lua +++ b/Moose Development/Moose/Ops/Auftrag.lua @@ -1727,7 +1727,7 @@ function AUFTRAG:NewSEADInZone(TargetZone, Altitude, TargetTypes, Duration) local mission=AUFTRAG:New(AUFTRAG.Type.SEAD) - mission:_TargetFromObject(TargetZone) + --mission:_TargetFromObject(TargetZone) -- DCS Task options: mission.engageWeaponType=ENUMS.WeaponFlag.Auto diff --git a/Moose Development/Moose/Ops/EasyGCICAP.lua b/Moose Development/Moose/Ops/EasyGCICAP.lua index 92f6defe1..93ec9b202 100644 --- a/Moose Development/Moose/Ops/EasyGCICAP.lua +++ b/Moose Development/Moose/Ops/EasyGCICAP.lua @@ -1,10 +1,15 @@ ------------------------------------------------------------------------- -- Easy CAP/GCI Class, based on OPS classes ------------------------------------------------------------------------- --- Documentation +-- +-- ## Documentation: -- -- https://flightcontrol-master.github.io/MOOSE_DOCS_DEVELOP/Documentation/Ops.EasyGCICAP.html -- +-- ## Example Missions: +-- +-- Demo missions can be found on [github](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/Ops/EasyGCICAP). +-- ------------------------------------------------------------------------- -- Date: September 2023 -- Last Update: Aug 2025 @@ -73,6 +78,7 @@ -- @field #string defaulttakeofftype Take off type -- @field #number FuelLowThreshold -- @field #number FuelCriticalThreshold +-- @field #boolean showpatrolpointmarks -- @extends Core.Fsm#FSM --- *“Airspeed, altitude, and brains. Two are always needed to successfully complete the flight.”* -- Unknown. @@ -230,6 +236,7 @@ EASYGCICAP = { defaulttakeofftype = "hot", FuelLowThreshold = 25, FuelCriticalThreshold = 10, + showpatrolpointmarks = false, } --- Internal Squadron data type @@ -265,7 +272,7 @@ EASYGCICAP = { --- EASYGCICAP class version. -- @field #string version -EASYGCICAP.version="0.1.26" +EASYGCICAP.version="0.1.27" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO list @@ -321,6 +328,7 @@ function EASYGCICAP:New(Alias, AirbaseName, Coalition, EWRName) self.defaulttakeofftype = "hot" self.FuelLowThreshold = 25 self.FuelCriticalThreshold = 10 + self.showpatrolpointmarks = false -- Set some string id for output to DCS.log file. self.lid=string.format("EASYGCICAP %s | ", self.alias) @@ -379,6 +387,19 @@ function EASYGCICAP:SetFuelLow(Percent) return self end +--- Set markers on the map for Patrol Points. +-- @param #EASYGCICAP self +-- @param #boolean onoff Set to true to switch markers on. +-- @return #EASYGCICAP self +function EASYGCICAP:ShowPatrolPointMarkers(onoff) + if onoff then + self.showpatrolpointmarks = true + else + self.showpatrolpointmarks = false + end + return self +end + --- Set "fuel critical" threshold for CAP and INTERCEPT flights. -- @param #EASYGCICAP self -- @param #number Percent RTB if fuel at this percent. Values: 1..100, defaults to 10. @@ -648,6 +669,10 @@ function EASYGCICAP:_AddAirwing(Airbasename, Alias) CAP_Wing:SetRespawnAfterDestroyed() CAP_Wing:SetNumberCAP(self.capgrouping) CAP_Wing:SetCapCloseRaceTrack(true) + + if self.showpatrolpointmarks then + CAP_Wing:ShowPatrolPointMarkers(true) + end if self.capOptionVaryStartTime then CAP_Wing:SetCapStartTimeVariation(self.capOptionVaryStartTime,self.capOptionVaryEndTime) @@ -738,14 +763,14 @@ end --- Add a CAP patrol point to a Wing -- @param #EASYGCICAP self -- @param #string AirbaseName Name of the Wing's airbase --- @param Core.Point#COORDINATE Coordinate. +-- @param Core.Point#COORDINATE Coordinate. Can be handed as a Core.Zone#ZONE object (e.g. in case you want the point to align with a moving zone). -- @param #number Altitude Defaults to 25000 feet ASL. -- @param #number Speed Defaults to 300 knots TAS. -- @param #number Heading Defaults to 90 degrees (East). -- @param #number LegLength Defaults to 15 NM. -- @return #EASYGCICAP self function EASYGCICAP:AddPatrolPointCAP(AirbaseName,Coordinate,Altitude,Speed,Heading,LegLength) - self:T(self.lid.."AddPatrolPointCAP "..Coordinate:ToStringLLDDM()) + self:T(self.lid.."AddPatrolPointCAP")--..Coordinate:ToStringLLDDM()) local EntryCAP = {} -- #EASYGCICAP.CapPoint EntryCAP.AirbaseName = AirbaseName EntryCAP.Coordinate = Coordinate @@ -763,7 +788,7 @@ end --- Add a RECON patrol point to a Wing -- @param #EASYGCICAP self -- @param #string AirbaseName Name of the Wing's airbase --- @param Core.Point#COORDINATE Coordinate. +-- @param Core.Point#COORDINATE Coordinate. Can be handed as a Core.Zone#ZONE object (e.g. in case you want the point to align with a moving zone). -- @param #number Altitude Defaults to 25000 feet. -- @param #number Speed Defaults to 300 knots. -- @param #number Heading Defaults to 90 degrees (East). @@ -788,7 +813,7 @@ end --- Add a TANKER patrol point to a Wing -- @param #EASYGCICAP self -- @param #string AirbaseName Name of the Wing's airbase --- @param Core.Point#COORDINATE Coordinate. +-- @param Core.Point#COORDINATE Coordinate. Can be handed as a Core.Zone#ZONE object (e.g. in case you want the point to align with a moving zone). -- @param #number Altitude Defaults to 25000 feet. -- @param #number Speed Defaults to 300 knots. -- @param #number Heading Defaults to 90 degrees (East). @@ -813,7 +838,7 @@ end --- Add an AWACS patrol point to a Wing -- @param #EASYGCICAP self -- @param #string AirbaseName Name of the Wing's airbase --- @param Core.Point#COORDINATE Coordinate. +-- @param Core.Point#COORDINATE Coordinate. Can be handed as a Core.Zone#ZONE object (e.g. in case you want the point to align with a moving zone). -- @param #number Altitude Defaults to 25000 feet. -- @param #number Speed Defaults to 300 knots. -- @param #number Heading Defaults to 90 degrees (East). diff --git a/Moose Development/Moose/Ops/OpsGroup.lua b/Moose Development/Moose/Ops/OpsGroup.lua index 0a62c204e..40dccb84e 100644 --- a/Moose Development/Moose/Ops/OpsGroup.lua +++ b/Moose Development/Moose/Ops/OpsGroup.lua @@ -5730,7 +5730,7 @@ function OPSGROUP:onafterMissionDone(From, Event, To, Mission) -- Decrease patrol data. if Mission.patroldata then Mission.patroldata.noccupied=Mission.patroldata.noccupied-1 - AIRWING.UpdatePatrolPointMarker(Mission.patroldata) + AIRWING.UpdatePatrolPointMarker(self,Mission.patroldata) end -- Switch auto engage detected off. This IGNORES that engage detected had been activated for the group! From 8cac4dbf9e5ea138c73185c9be3eb471e8722fcb Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sun, 10 Aug 2025 13:35:24 +0200 Subject: [PATCH 154/234] #TIRESIAS - allow documents to build --- Moose Development/Moose/Functional/Tiresias.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Functional/Tiresias.lua b/Moose Development/Moose/Functional/Tiresias.lua index 8010abfcd..b0ed49798 100644 --- a/Moose Development/Moose/Functional/Tiresias.lua +++ b/Moose Development/Moose/Functional/Tiresias.lua @@ -30,8 +30,8 @@ ---- #-- Author : **applevangelist ** (Optimized by AI) --- --- - @module Functional.Tiresias --- - @image Functional.Tiresias.jpg +-- @module Functional.Tiresias +-- @image Functional.Tiresias.jpg --- Last Update: July 2025 From b32a8a28993483a2b60c755144d4c7faa16236ff Mon Sep 17 00:00:00 2001 From: Thomas <72444570+Applevangelist@users.noreply.github.com> Date: Mon, 11 Aug 2025 12:57:37 +0200 Subject: [PATCH 155/234] #EasyGCICAP Adjustments for CAP ZONE using Added missing computations for coordinate when the zone is moving --- Moose Development/Moose/Ops/EasyGCICAP.lua | 36 ++++++++++++++++------ 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/Moose Development/Moose/Ops/EasyGCICAP.lua b/Moose Development/Moose/Ops/EasyGCICAP.lua index 93ec9b202..f0700332d 100644 --- a/Moose Development/Moose/Ops/EasyGCICAP.lua +++ b/Moose Development/Moose/Ops/EasyGCICAP.lua @@ -269,6 +269,7 @@ EASYGCICAP = { -- @field #number Speed -- @field #number Heading -- @field #number LegLength +-- @field Core.Zone#ZONE_BASE Zone --- EASYGCICAP class version. -- @field #string version @@ -771,16 +772,22 @@ end -- @return #EASYGCICAP self function EASYGCICAP:AddPatrolPointCAP(AirbaseName,Coordinate,Altitude,Speed,Heading,LegLength) self:T(self.lid.."AddPatrolPointCAP")--..Coordinate:ToStringLLDDM()) - local EntryCAP = {} -- #EASYGCICAP.CapPoint + local coordinate = Coordinate + local EntryCAP = {} -- #EASYGCICAP.CapPoint + if Coordinate:IsInstanceOf("ZONE_BASE") then + -- adjust coordinate and get the coordinate from the zone + coordinate = Coordinate:GetCoordinate() + EntryCAP.Zone = Coordinate + end EntryCAP.AirbaseName = AirbaseName - EntryCAP.Coordinate = Coordinate + EntryCAP.Coordinate = coordinate EntryCAP.Altitude = Altitude or 25000 EntryCAP.Speed = Speed or 300 EntryCAP.Heading = Heading or 90 EntryCAP.LegLength = LegLength or 15 self.ManagedCP[#self.ManagedCP+1] = EntryCAP if self.debug then - local mark = MARKER:New(Coordinate,self.lid.."Patrol Point"):ToAll() + local mark = MARKER:New(coordinate,self.lid.."Patrol Point"):ToAll() end return self end @@ -926,7 +933,12 @@ function EASYGCICAP:_SetCAPPatrolPoints() local Speed = data.Speed local Heading = data.Heading local LegLength = data.LegLength - Wing:AddPatrolPointCAP(Coordinate,Altitude,Speed,Heading,LegLength) + local Zone = _data.Zone + if Zone then + Wing:AddPatrolPointCAP(Zone,Altitude,Speed,Heading,LegLength) + else + Wing:AddPatrolPointCAP(Coordinate,Altitude,Speed,Heading,LegLength) + end end return self @@ -1281,19 +1293,19 @@ end -- @return #boolean assigned -- @return #number leftover function EASYGCICAP:_TryAssignIntercept(ReadyFlightGroups,InterceptAuftrag,Group,WingSize) - self:I("_TryAssignIntercept for size "..WingSize or 1) + self:T("_TryAssignIntercept for size "..WingSize or 1) local assigned = false local wingsize = WingSize or 1 local mindist = 0 local disttable = {} if Group and Group:IsAlive() then local gcoord = Group:GetCoordinate() or COORDINATE:New(0,0,0) - self:I(self.lid..string.format("Assignment for %s",Group:GetName())) + self:T(self.lid..string.format("Assignment for %s",Group:GetName())) for _name,_FG in pairs(ReadyFlightGroups or {}) do local FG = _FG -- Ops.FlightGroup#FLIGHTGROUP local fcoord = FG:GetCoordinate() local dist = math.floor(UTILS.Round(fcoord:Get2DDistance(gcoord)/1000,1)) - self:I(self.lid..string.format("FG %s Distance %dkm",_name,dist)) + self:T(self.lid..string.format("FG %s Distance %dkm",_name,dist)) disttable[#disttable+1] = { FG=FG, dist=dist} if dist>mindist then mindist=dist end end @@ -1310,7 +1322,7 @@ function EASYGCICAP:_TryAssignIntercept(ReadyFlightGroups,InterceptAuftrag,Group local cm = FG:GetMissionCurrent() if cm then cm:Cancel() end wingsize = wingsize - 1 - self:I(self.lid..string.format("Assigned to FG %s Distance %dkm",FG:GetName(),_entry.dist)) + self:T(self.lid..string.format("Assigned to FG %s Distance %dkm",FG:GetName(),_entry.dist)) if wingsize == 0 then assigned = true break @@ -1340,7 +1352,7 @@ function EASYGCICAP:_AssignIntercept(Cluster) local conflictzoneset = self.ConflictZoneSet local ReadyFlightGroups = self.ReadyFlightGroups - -- Aircraft? + -- Aircraft? if Cluster.ctype ~= INTEL.Ctype.AIRCRAFT then return end -- Threatlevel 0..10 local contact = self.Intel:GetHighestThreatContact(Cluster) @@ -1385,6 +1397,10 @@ function EASYGCICAP:_AssignIntercept(Cluster) local data = _data -- #EASYGCICAP.CapPoint local name = data.AirbaseName local zonecoord = data.Coordinate + if data.Zone then + -- refresh coordinate in case we have a (moving) zone + zonecoord = data.Zone:GetCoordinate() + end local airwing = wings[name][1] local coa = AIRBASE:FindByName(name):GetCoalition() local samecoalitionab = coa == self.coalition and true or false @@ -1582,7 +1598,7 @@ function EASYGCICAP:onafterStatus(From,Event,To) local engage = FG:IsEngaging() local hasmissiles = FG:IsOutOfMissiles() == nil and true or false local ready = hasmissiles and FG:IsFuelGood() and FG:IsAirborne() - --self:I(string.format("Flightgroup %s Engaging = %s Ready = %s",tostring(name),tostring(engage),tostring(ready))) + --self:T(string.format("Flightgroup %s Engaging = %s Ready = %s",tostring(name),tostring(engage),tostring(ready))) if ready then self.ReadyFlightGroups[name] = FG end From 35f15435a3a77e39d9e26a3f1f157f8681c6005d Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 14 Aug 2025 09:12:58 +0200 Subject: [PATCH 156/234] #MANTIS - Added Pantsir S1, TOR M2, IRIS-T SLM to main man SAM data (from CH mod) --- Moose Development/Moose/Functional/Mantis.lua | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/Moose Development/Moose/Functional/Mantis.lua b/Moose Development/Moose/Functional/Mantis.lua index cd3ee9cae..67816cf04 100644 --- a/Moose Development/Moose/Functional/Mantis.lua +++ b/Moose Development/Moose/Functional/Mantis.lua @@ -108,6 +108,10 @@ -- * Patriot -- * Rapier -- * Roland +-- * IRIS-T SLM +-- * Pantsir S1 +-- * TOR M2 +-- * C-RAM -- * Silkworm (though strictly speaking this is a surface to ship missile) -- * SA-2, SA-3, SA-5, SA-6, SA-7, SA-8, SA-9, SA-10, SA-11, SA-13, SA-15, SA-19 -- * From IDF mod: STUNNER IDFA, TAMIR IDFA (Note all caps!) @@ -276,7 +280,7 @@ MANTIS = { ClassName = "MANTIS", name = "mymantis", - version = "0.9.33", + version = "0.9.34", SAM_Templates_Prefix = "", SAM_Group = nil, EWR_Templates_Prefix = "", @@ -385,7 +389,7 @@ MANTIS.SamData = { ["Chaparral"] = { Range=8, Blindspot=0, Height=3, Type="Short", Radar="Chaparral" }, ["Linebacker"] = { Range=4, Blindspot=0, Height=3, Type="Point", Radar="Linebacker", Point="true" }, ["Silkworm"] = { Range=90, Blindspot=1, Height=0.2, Type="Long", Radar="Silkworm" }, - ["HEMTT_C-RAM_Phalanx"] = { Range=2, Blindspot=0, Height=2, Type="Point", Radar="HEMTT_C-RAM_Phalanx", Point="true" }, + ["C-RAM"] = { Range=2, Blindspot=0, Height=2, Type="Point", Radar="HEMTT_C-RAM_Phalanx", Point="true" }, -- units from HDS Mod, multi launcher options is tricky ["SA-10B"] = { Range=75, Blindspot=0, Height=18, Type="Medium" , Radar="SA-10B"}, ["SA-17"] = { Range=50, Blindspot=3, Height=50, Type="Medium", Radar="SA-17" }, @@ -396,6 +400,10 @@ MANTIS.SamData = { ["STUNNER IDFA"] = { Range=250, Blindspot=1, Height=45, Type="Long", Radar="DAVID_SLING_LN" }, ["NIKE"] = { Range=155, Blindspot=6, Height=30, Type="Long", Radar="HIPAR" }, ["Dog Ear"] = { Range=11, Blindspot=0, Height=9, Type="Point", Radar="Dog Ear", Point="true" }, + -- CH Added to DCS core 2.9.19.x + ["Pantsir S1"] = { Range=20, Blindspot=1.2, Height=15, Type="Short", Radar="PantsirS1" }, + ["Tor M2"] = { Range=12, Blindspot=1, Height=10, Type="Short", Radar="TorM2" }, + ["IRIS-T SLM"] = { Range=40, Blindspot=0.5, Height=20, Type="Medium", Radar="CH_IRIST_SLM" }, } --- SAM data HDS @@ -1288,7 +1296,7 @@ do end end -- rejectzones - if #self.RejectZones > 0 and inzone then -- maybe in accept zone, but check the overlaps + if #self.RejectZones > 0 then for _,_zone in pairs(self.RejectZones) do local zone = _zone -- Core.Zone#ZONE if zone:IsCoordinateInZone(coord) then @@ -1299,7 +1307,7 @@ do end end -- conflictzones - if #self.ConflictZones > 0 and not inzone then -- if not already accepted, might be in conflict zones + if #self.ConflictZones > 0 then for _,_zone in pairs(self.ConflictZones) do local zone = _zone -- Core.Zone#ZONE if zone:IsCoordinateInZone(coord) then From 4a04d7cce7b178ff4ea48cb480d705a331e2030e Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 14 Aug 2025 17:15:43 +0200 Subject: [PATCH 157/234] xx --- Moose Development/Moose/Functional/Mantis.lua | 32 +++++++++++-------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/Moose Development/Moose/Functional/Mantis.lua b/Moose Development/Moose/Functional/Mantis.lua index 67816cf04..9714fbe80 100644 --- a/Moose Development/Moose/Functional/Mantis.lua +++ b/Moose Development/Moose/Functional/Mantis.lua @@ -22,7 +22,7 @@ -- @module Functional.Mantis -- @image Functional.Mantis.jpg -- --- Last Update: July 2025 +-- Last Update: August 2025 ------------------------------------------------------------------------- --- **MANTIS** class, extends Core.Base#BASE @@ -308,7 +308,7 @@ MANTIS = { adv_state = 0, AWACS_Prefix = "", advAwacs = false, - verbose = false, + verbose = true, awacsrange = 250000, Shorad = nil, ShoradLink = false, @@ -401,8 +401,8 @@ MANTIS.SamData = { ["NIKE"] = { Range=155, Blindspot=6, Height=30, Type="Long", Radar="HIPAR" }, ["Dog Ear"] = { Range=11, Blindspot=0, Height=9, Type="Point", Radar="Dog Ear", Point="true" }, -- CH Added to DCS core 2.9.19.x - ["Pantsir S1"] = { Range=20, Blindspot=1.2, Height=15, Type="Short", Radar="PantsirS1" }, - ["Tor M2"] = { Range=12, Blindspot=1, Height=10, Type="Short", Radar="TorM2" }, + ["Pantsir S1"] = { Range=20, Blindspot=1.2, Height=15, Type="Point", Radar="PantsirS1" , Point="true" }, + ["Tor M2"] = { Range=12, Blindspot=1, Height=10, Type="Point", Radar="TorM2", Point="true" }, ["IRIS-T SLM"] = { Range=40, Blindspot=0.5, Height=20, Type="Medium", Radar="CH_IRIST_SLM" }, } @@ -469,15 +469,15 @@ MANTIS.SamDataCH = { -- https://www.currenthill.com/ -- group name MUST contain CHM to ID launcher type correctly! ["2S38 CHM"] = { Range=6, Blindspot=0.1, Height=4.5, Type="Short", Radar="2S38" }, - ["PantsirS1 CHM"] = { Range=20, Blindspot=1.2, Height=15, Type="Short", Radar="PantsirS1" }, + ["PantsirS1 CHM"] = { Range=20, Blindspot=1.2, Height=15, Type="Point", Radar="PantsirS1", Point="true" }, ["PantsirS2 CHM"] = { Range=30, Blindspot=1.2, Height=18, Type="Medium", Radar="PantsirS2" }, ["PGL-625 CHM"] = { Range=10, Blindspot=1, Height=5, Type="Short", Radar="PGL_625" }, ["HQ-17A CHM"] = { Range=15, Blindspot=1.5, Height=10, Type="Short", Radar="HQ17A" }, ["M903PAC2 CHM"] = { Range=120, Blindspot=3, Height=24.5, Type="Long", Radar="MIM104_M903_PAC2" }, ["M903PAC3 CHM"] = { Range=160, Blindspot=1, Height=40, Type="Long", Radar="MIM104_M903_PAC3" }, - ["TorM2 CHM"] = { Range=12, Blindspot=1, Height=10, Type="Short", Radar="TorM2" }, - ["TorM2K CHM"] = { Range=12, Blindspot=1, Height=10, Type="Short", Radar="TorM2K" }, - ["TorM2M CHM"] = { Range=16, Blindspot=1, Height=10, Type="Short", Radar="TorM2M" }, + ["TorM2 CHM"] = { Range=12, Blindspot=1, Height=10, Type="Point", Radar="TorM2", Point="true" }, + ["TorM2K CHM"] = { Range=12, Blindspot=1, Height=10, Type="Point", Radar="TorM2K", Point="true" }, + ["TorM2M CHM"] = { Range=16, Blindspot=1, Height=10, Type="Point", Radar="TorM2M", Point="true" }, ["NASAMS3-AMRAAMER CHM"] = { Range=50, Blindspot=2, Height=35.7, Type="Medium", Radar="CH_NASAMS3_LN_AMRAAM_ER" }, ["NASAMS3-AIM9X2 CHM"] = { Range=20, Blindspot=0.2, Height=18, Type="Short", Radar="CH_NASAMS3_LN_AIM9X2" }, ["C-RAM CHM"] = { Range=2, Blindspot=0, Height=2, Type="Point", Radar="CH_Centurion_C_RAM", Point="true" }, @@ -583,7 +583,7 @@ do self.advanced = false self.adv_ratio = 100 self.adv_state = 0 - self.verbose = false + self.verbose = true self.Adv_EWR_Group = nil self.AWACS_Prefix = awacs or nil self.awacsrange = 250000 --DONE: 250km, User Function to change @@ -893,7 +893,11 @@ do self.AcceptZones = AcceptZones or {} self.RejectZones = RejectZones or {} self.ConflictZones = ConflictZones or {} - if #self.AcceptZones > 0 or #self.RejectZones > 0 or #self.ConflictZones > 0 then + self.AcceptZonesNo = UTILS.TableLength(self.AcceptZones) + self.RejectZonesNo = UTILS.TableLength(self.RejectZones) + self.ConflictZonesNo = UTILS.TableLength(self.ConflictZones) + self:T(string.format("AcceptZonesNo = %d | RejectZonesNo = %d | ConflictZonesNo = %d",self.AcceptZonesNo,self.RejectZonesNo,self.ConflictZonesNo)) + if self.AcceptZonesNo > 0 or self.RejectZonesNo > 0 or self.ConflictZonesNo > 0 then self.usezones = true end return self @@ -1285,7 +1289,8 @@ do self:T(self.lid.."_CheckCoordinateInZones") local inzone = false -- acceptzones - if #self.AcceptZones > 0 then + self:T(string.format("AcceptZonesNo = %d | RejectZonesNo = %d | ConflictZonesNo = %d",self.AcceptZonesNo,self.RejectZonesNo,self.ConflictZonesNo)) + if self.AcceptZonesNo > 0 then for _,_zone in pairs(self.AcceptZones) do local zone = _zone -- Core.Zone#ZONE if zone:IsCoordinateInZone(coord) then @@ -1296,7 +1301,7 @@ do end end -- rejectzones - if #self.RejectZones > 0 then + if self.RejectZonesNo > 0 then for _,_zone in pairs(self.RejectZones) do local zone = _zone -- Core.Zone#ZONE if zone:IsCoordinateInZone(coord) then @@ -1307,7 +1312,7 @@ do end end -- conflictzones - if #self.ConflictZones > 0 then + if self.ConflictZonesNo > 0 then for _,_zone in pairs(self.ConflictZones) do local zone = _zone -- Core.Zone#ZONE if zone:IsCoordinateInZone(coord) then @@ -1373,6 +1378,7 @@ do end -- check accept/reject zones local zonecheck = true + self:T("self.usezones = "..tostring(self.usezones)) if self.usezones then -- DONE zonecheck = self:_CheckCoordinateInZones(coord) From b9cf1e46afcee679aa09b480d3451864da72a5e3 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 14 Aug 2025 17:17:34 +0200 Subject: [PATCH 158/234] xx --- Moose Development/Moose/Functional/Mantis.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Functional/Mantis.lua b/Moose Development/Moose/Functional/Mantis.lua index 9714fbe80..2e1ff3b18 100644 --- a/Moose Development/Moose/Functional/Mantis.lua +++ b/Moose Development/Moose/Functional/Mantis.lua @@ -308,7 +308,7 @@ MANTIS = { adv_state = 0, AWACS_Prefix = "", advAwacs = false, - verbose = true, + verbose = false, awacsrange = 250000, Shorad = nil, ShoradLink = false, @@ -583,7 +583,7 @@ do self.advanced = false self.adv_ratio = 100 self.adv_state = 0 - self.verbose = true + self.verbose = false self.Adv_EWR_Group = nil self.AWACS_Prefix = awacs or nil self.awacsrange = 250000 --DONE: 250km, User Function to change From 1b169f007c317a2250a62681de846a61bcddc4e7 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Fri, 15 Aug 2025 14:26:41 +0200 Subject: [PATCH 159/234] xx --- Moose Development/Moose/Ops/AirWing.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/Ops/AirWing.lua b/Moose Development/Moose/Ops/AirWing.lua index a4b1b58e5..1e11793e3 100644 --- a/Moose Development/Moose/Ops/AirWing.lua +++ b/Moose Development/Moose/Ops/AirWing.lua @@ -845,7 +845,7 @@ function AIRWING:NewPatrolPoint(Type, Coordinate, Altitude, Speed, Heading, LegL local patrolpoint={} --#AIRWING.PatrolData patrolpoint.type=Type or "Unknown" patrolpoint.coord=Coordinate or self:GetCoordinate():Translate(UTILS.NMToMeters(math.random(10, 15)), math.random(360)) - if Coordinate:IsInstanceOf("ZONE_BASE") then + if Coordinate and Coordinate:IsInstanceOf("ZONE_BASE") then patrolpoint.IsZonePoint = true patrolpoint.patrolzone = Coordinate patrolpoint.coord = patrolpoint.patrolzone:GetCoordinate() From 67cb84455029531efe460e3b2e664c23ae07befb Mon Sep 17 00:00:00 2001 From: smiki Date: Sun, 24 Aug 2025 15:07:27 +0200 Subject: [PATCH 160/234] Validate and Reposition Ground Units algorithm [ADDED] UTILS.ValidateAndRepositionGroundUnits [ADDED] SPAWN:InitValidateAndRepositionGroundUnits [ADDED] CTLD.validateAndRepositionUnits --- Moose Development/Moose/Core/Spawn.lua | 24 +++- Moose Development/Moose/Ops/CTLD.lua | 8 +- Moose Development/Moose/Utilities/Utils.lua | 121 ++++++++++++++++++++ 3 files changed, 151 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Core/Spawn.lua b/Moose Development/Moose/Core/Spawn.lua index c81aea59d..6e95e285b 100644 --- a/Moose Development/Moose/Core/Spawn.lua +++ b/Moose Development/Moose/Core/Spawn.lua @@ -1049,6 +1049,22 @@ function SPAWN:InitSetUnitAbsolutePositions(Positions) return self end + +--- Uses Disposition and other fallback logic to find better ground positions for ground units. +--- NOTE: This is not a spawn randomizer. +--- It will try to find clear ground locations avoiding trees, water, roads, runways, map scenery, statics and other units in the area. +--- Maintains the original layout and unit positions as close as possible by searching for the next closest valid position to each unit. +-- @param #boolean OnOff Enable/disable the feature. +-- @param #number MaxRadius (Optional) Max radius to search for valid ground locations in meters. Default is double the max radius of the units. +-- @param #number Spacing (Optional) Minimum spacing between units in meters. Default is 5% of the search radius or 5 meters, whichever is larger. +-- @return #SPAWN +function SPAWN:InitValidateAndRepositionGroundUnits(OnOff, MaxRadius, Spacing) + self.SpawnValidateAndRepositionGroundUnits = OnOff + self.SpawnValidateAndRepositionGroundUnitsRadius = MaxRadius + self.SpawnValidateAndRepositionGroundUnitsSpacing = Spacing + return self +end + --- This method is rather complicated to understand. But I'll try to explain. -- This method becomes useful when you need to spawn groups with random templates of groups defined within the mission editor, -- but they will all follow the same Template route and have the same prefix name. @@ -1829,7 +1845,13 @@ function SPAWN:SpawnWithIndex( SpawnIndex, NoBirth ) if self.SpawnHiddenOnMap then SpawnTemplate.hidden=self.SpawnHiddenOnMap end - + + if self.SpawnValidateAndRepositionGroundUnits then + local units = SpawnTemplate.units + local gPos = { x = SpawnTemplate.x, y = SpawnTemplate.y } + UTILS.ValidateAndRepositionGroundUnits(gPos, units, self.SpawnValidateAndRepositionGroundUnitsRadius, self.SpawnValidateAndRepositionGroundUnitsSpacing) + end + -- Set country, coalition and category. SpawnTemplate.CategoryID = self.SpawnInitCategory or SpawnTemplate.CategoryID SpawnTemplate.CountryID = self.SpawnInitCountry or SpawnTemplate.CountryID diff --git a/Moose Development/Moose/Ops/CTLD.lua b/Moose Development/Moose/Ops/CTLD.lua index 7b46d1439..40f2dc8e3 100644 --- a/Moose Development/Moose/Ops/CTLD.lua +++ b/Moose Development/Moose/Ops/CTLD.lua @@ -1564,7 +1564,9 @@ function CTLD:New(Coalition, Prefixes, Alias) self.FixedMinAngels = 165 -- for troop/cargo drop via chute self.FixedMaxAngels = 2000 -- for troop/cargo drop via chute self.FixedMaxSpeed = 77 -- 280 kph or 150kn eq 77 mps - + + self.validateAndRepositionUnits = false -- 280 kph or 150kn eq 77 mps + -- message suppression self.suppressmessages = false @@ -3735,6 +3737,7 @@ function CTLD:_UnloadTroops(Group, Unit) self.DroppedTroops[self.TroopCounter] = SPAWN:NewWithAlias(_template,alias) :InitDelayOff() :InitSetUnitAbsolutePositions(Positions) + :InitValidateAndRepositionGroundUnits(self.validateAndRepositionUnits) :OnSpawnGroup(function(grp) grp.spawntime = timer.getTime() end) :SpawnFromVec2(randomcoord:GetVec2()) self:__TroopsDeployed(1, Group, Unit, self.DroppedTroops[self.TroopCounter],type) @@ -4181,11 +4184,13 @@ function CTLD:_BuildObjectFromCrates(Group,Unit,Build,Repair,RepairLocation,Mult self.DroppedTroops[self.TroopCounter] = SPAWN:NewWithAlias(_template,alias) --:InitRandomizeUnits(true,20,2) :InitDelayOff() + :InitValidateAndRepositionGroundUnits(self.validateAndRepositionUnits) :OnSpawnGroup(function(grp) grp.spawntime = timer.getTime() end) :SpawnFromVec2(randomcoord) else -- don't random position of e.g. SAM units build as FOB self.DroppedTroops[self.TroopCounter] = SPAWN:NewWithAlias(_template,alias) :InitDelayOff() + :InitValidateAndRepositionGroundUnits(self.validateAndRepositionUnits) :OnSpawnGroup(function(grp) grp.spawntime = timer.getTime() end) :SpawnFromVec2(randomcoord) end @@ -5211,6 +5216,7 @@ function CTLD:_UnloadSingleTroopByID(Group, Unit, chunkID) self.DroppedTroops[self.TroopCounter] = SPAWN:NewWithAlias(_template, alias) :InitDelayOff() :InitSetUnitAbsolutePositions(Positions) + :InitValidateAndRepositionGroundUnits(self.validateAndRepositionUnits) :OnSpawnGroup(function(grp) grp.spawntime = timer.getTime() end) :SpawnFromVec2(randomcoord:GetVec2()) self:__TroopsDeployed(1, Group, Unit, self.DroppedTroops[self.TroopCounter], cType) diff --git a/Moose Development/Moose/Utilities/Utils.lua b/Moose Development/Moose/Utilities/Utils.lua index a9a76d535..c7543b3a2 100644 --- a/Moose Development/Moose/Utilities/Utils.lua +++ b/Moose Development/Moose/Utilities/Utils.lua @@ -4871,3 +4871,124 @@ function UTILS.FindNearestPointOnCircle(Vec1,Radius,Vec2) return {x=qx, y=qy} end + +--- This function uses Disposition and other fallback logic to find better ground positions for a group of ground units. +--- NOTE: This is not a spawn randomizer. +--- It will try to find clear ground locations avoiding trees, water, roads, runways, map scenery, statics and other units in the area and modifies the provided positions table. +--- Maintains the original layout and unit positions as close as possible by searching for the next closest valid position to each unit. +-- @param table Positions A table of DCS#Vec2 or DCS#Vec3, can be a units table from the group template. +-- @param DCS#Vec2 Anchor (Optional) DCS#Vec2 or DCS#Vec3 as anchor point to calculate offset of the units. +-- @param #number MaxRadius (Optional) Max radius to search for valid ground locations in meters. Default is double the max radius of the units. +-- @param #number Spacing (Optional) Minimum spacing between units in meters. Default is 5% of the search radius or 5 meters, whichever is larger. +function UTILS.ValidateAndRepositionGroundUnits(Anchor, Positions, MaxRadius, Spacing) + local units = Positions + Anchor = Anchor or UTILS.GetCenterPoint(units) + local gPos = { x = Anchor.x, y = Anchor.z or Anchor.y } + local maxRadius = 0 + local unitCount = 0 + for _, unit in pairs(units) do + local pos = { x = unit.x, y = unit.z or unit.y } + local dist = UTILS.VecDist2D(pos, gPos) + if dist > maxRadius then + maxRadius = dist + end + unitCount = unitCount + 1 + end + maxRadius = MaxRadius or math.max(maxRadius * 2, 10) + local spacing = Spacing or math.max(maxRadius * 0.05, 5) + if unitCount > 0 and maxRadius > 5 then + local spots = UTILS.GetSimpleZones(UTILS.Vec2toVec3(gPos), maxRadius, spacing, 1000) + if spots and #spots > 0 then + local validSpots = {} + for _, spot in pairs(spots) do -- Disposition sometimes returns points on roads, hence this filter. + if land.getSurfaceType(spot) == land.SurfaceType.LAND then + table.insert(validSpots, spot) + end + end + spots = validSpots + end + + local step = spacing + for _, unit in pairs(units) do + local pos = { x = unit.x, y = unit.z or unit.y } + local isOnLand = land.getSurfaceType(pos) == land.SurfaceType.LAND + local isValid = false + if spots and #spots > 0 then + local si = 1 + local sid = 0 + local closestDist = 100000000 + local closestSpot + for _, spot in pairs(spots) do + local dist = UTILS.VecDist2D(pos, spot) + if dist < closestDist then + local skip = false + for _, unit2 in pairs(units) do + local pos2 = { x = unit2.x, y = unit2.z or unit2.y } + local dist2 = UTILS.VecDist2D(spot, pos2) + if dist2 < spacing and isOnLand then + skip = true + break + end + end + if not skip then + closestDist = dist + closestSpot = spot + sid = si + end + end + si = si + 1 + end + if closestSpot then + if closestDist >= spacing then + pos = closestSpot + end + isValid = true + table.remove(spots, sid) + end + end + + -- Failsafe calculation + if not isValid and not isOnLand then + + local h = UTILS.HdgTo(pos, gPos) + local retries = 0 + while not isValid and retries < 500 do + + local dist = UTILS.VecDist2D(pos, gPos) + pos = UTILS.Vec2Translate(pos, step, h) + + local skip = false + for _, unit2 in pairs(units) do + if unit ~= unit2 then + local pos2 = { x = unit2.x, y = unit2.z or unit2.y } + local dist2 = UTILS.VecDist2D(pos, pos2) + if dist2 < 12 then + isValid = false + skip = true + break + end + end + end + + if not skip and dist > step and land.getSurfaceType(pos) == land.SurfaceType.LAND then + isValid = true + break + elseif dist <= step then + break + end + + retries = retries + 1 + end + end + + if isValid then + unit.x = pos.x + if unit.z then + unit.z = pos.y + else + unit.y = pos.y + end + end + end + end +end From 78b3efcf0095044067eda0838604f5a929d0a9d9 Mon Sep 17 00:00:00 2001 From: smiki Date: Sun, 24 Aug 2025 15:10:47 +0200 Subject: [PATCH 161/234] Validate and Reposition Ground Units algorithm [ADDED] UTILS.ValidateAndRepositionGroundUnits [ADDED] SPAWN:InitValidateAndRepositionGroundUnits [ADDED] CTLD.validateAndRepositionUnits --- Moose Development/Moose/Ops/CTLD.lua | 3 ++- Moose Development/Moose/Utilities/Utils.lua | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Ops/CTLD.lua b/Moose Development/Moose/Ops/CTLD.lua index 40f2dc8e3..6b1bb8d60 100644 --- a/Moose Development/Moose/Ops/CTLD.lua +++ b/Moose Development/Moose/Ops/CTLD.lua @@ -868,7 +868,8 @@ do -- my_ctld.showstockinmenuitems = false -- When set to true, the menu lines will also show the remaining items in stock (that is, if you set any), downside is that the menu for all will be build every 30 seconds anew. -- my_ctld.onestepmenu = false -- When set to true, the menu will create Drop and build, Get and load, Pack and remove, Pack and load, Pack. it will be a 1 step solution. -- my_ctld.VehicleMoveFormation = AI.Task.VehicleFormation.VEE -- When a group moves to a MOVE zone, then it takes this formation. Can be a table of formations, which are then randomly chosen. Defaults to "Vee". --- +-- my_ctld.validateAndRepositionUnits = false -- Uses Disposition and other logic to find better ground positions for ground units avoiding trees, water, roads, runways, map scenery, statics and other units in the area. (Default is false) +-- -- ## 2.1 CH-47 Chinook support -- -- The Chinook comes with the option to use the ground crew menu to load and unload cargo into the Helicopter itself for better immersion. As well, it can sling-load cargo from ground. The cargo you can actually **create** diff --git a/Moose Development/Moose/Utilities/Utils.lua b/Moose Development/Moose/Utilities/Utils.lua index c7543b3a2..bdbff6b38 100644 --- a/Moose Development/Moose/Utilities/Utils.lua +++ b/Moose Development/Moose/Utilities/Utils.lua @@ -4872,7 +4872,7 @@ function UTILS.FindNearestPointOnCircle(Vec1,Radius,Vec2) return {x=qx, y=qy} end ---- This function uses Disposition and other fallback logic to find better ground positions for a group of ground units. +--- This function uses Disposition and other fallback logic to find better ground positions for ground units. --- NOTE: This is not a spawn randomizer. --- It will try to find clear ground locations avoiding trees, water, roads, runways, map scenery, statics and other units in the area and modifies the provided positions table. --- Maintains the original layout and unit positions as close as possible by searching for the next closest valid position to each unit. From 8169235d2fb944028f5c8ae7d04094f24b520bb3 Mon Sep 17 00:00:00 2001 From: smiki Date: Sun, 24 Aug 2025 16:27:55 +0200 Subject: [PATCH 162/234] [FIXED] Maintain valid unit positions --- Moose Development/Moose/Utilities/Utils.lua | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/Moose Development/Moose/Utilities/Utils.lua b/Moose Development/Moose/Utilities/Utils.lua index bdbff6b38..989e9ef07 100644 --- a/Moose Development/Moose/Utilities/Utils.lua +++ b/Moose Development/Moose/Utilities/Utils.lua @@ -4921,20 +4921,9 @@ function UTILS.ValidateAndRepositionGroundUnits(Anchor, Positions, MaxRadius, Sp for _, spot in pairs(spots) do local dist = UTILS.VecDist2D(pos, spot) if dist < closestDist then - local skip = false - for _, unit2 in pairs(units) do - local pos2 = { x = unit2.x, y = unit2.z or unit2.y } - local dist2 = UTILS.VecDist2D(spot, pos2) - if dist2 < spacing and isOnLand then - skip = true - break - end - end - if not skip then - closestDist = dist - closestSpot = spot - sid = si - end + closestDist = dist + closestSpot = spot + sid = si end si = si + 1 end From facac821305d6d406b48431f098f68cd56ea030b Mon Sep 17 00:00:00 2001 From: smiki Date: Sun, 24 Aug 2025 16:44:41 +0200 Subject: [PATCH 163/234] [ADDED] WAREHOUSE:SetValidateAndRepositionGroundUnits to use for Brigades --- Moose Development/Moose/Functional/Warehouse.lua | 14 ++++++++++++++ Moose Development/Moose/Utilities/Utils.lua | 4 ++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Functional/Warehouse.lua b/Moose Development/Moose/Functional/Warehouse.lua index 2486e74b6..19654ad5e 100644 --- a/Moose Development/Moose/Functional/Warehouse.lua +++ b/Moose Development/Moose/Functional/Warehouse.lua @@ -4247,6 +4247,16 @@ function WAREHOUSE:_AssetItemInfo(asset) self:T3({Template=asset.template}) end +--- This function uses Disposition and other fallback logic to find better ground positions for ground units. +--- NOTE: This is not a spawn randomizer. +--- It will try to find clear ground locations avoiding trees, water, roads, runways, map scenery, statics and other units in the area and modifies the provided positions table. +--- Maintains the original layout and unit positions as close as possible by searching for the next closest valid position to each unit. +--- Uses UTILS.ValidateAndRepositionGroundUnits. +-- @param #boolean Enabled Enable/disable the feature. +function WAREHOUSE:SetValidateAndRepositionGroundUnits(Enabled) + self.ValidateAndRepositionGroundUnits = Enabled +end + --- On after "NewAsset" event. A new asset has been added to the warehouse stock. -- @param #WAREHOUSE self -- @param #string From From state. @@ -5965,6 +5975,10 @@ function WAREHOUSE:_SpawnAssetGroundNaval(alias, asset, request, spawnzone, late template.y = coord.z template.alt = coord.y + if self.ValidateAndRepositionGroundUnits then + UTILS.ValidateAndRepositionGroundUnits(template.units) + end + -- Spawn group. local group=_DATABASE:Spawn(template) --Wrapper.Group#GROUP diff --git a/Moose Development/Moose/Utilities/Utils.lua b/Moose Development/Moose/Utilities/Utils.lua index 989e9ef07..cd94f71b2 100644 --- a/Moose Development/Moose/Utilities/Utils.lua +++ b/Moose Development/Moose/Utilities/Utils.lua @@ -4876,11 +4876,11 @@ end --- NOTE: This is not a spawn randomizer. --- It will try to find clear ground locations avoiding trees, water, roads, runways, map scenery, statics and other units in the area and modifies the provided positions table. --- Maintains the original layout and unit positions as close as possible by searching for the next closest valid position to each unit. --- @param table Positions A table of DCS#Vec2 or DCS#Vec3, can be a units table from the group template. +-- @param #table Positions A table of DCS#Vec2 or DCS#Vec3, can be a units table from the group template. -- @param DCS#Vec2 Anchor (Optional) DCS#Vec2 or DCS#Vec3 as anchor point to calculate offset of the units. -- @param #number MaxRadius (Optional) Max radius to search for valid ground locations in meters. Default is double the max radius of the units. -- @param #number Spacing (Optional) Minimum spacing between units in meters. Default is 5% of the search radius or 5 meters, whichever is larger. -function UTILS.ValidateAndRepositionGroundUnits(Anchor, Positions, MaxRadius, Spacing) +function UTILS.ValidateAndRepositionGroundUnits(Positions, Anchor, MaxRadius, Spacing) local units = Positions Anchor = Anchor or UTILS.GetCenterPoint(units) local gPos = { x = Anchor.x, y = Anchor.z or Anchor.y } From 9adf342dd84e9bcabc3890350cf2d1f90b255c9b Mon Sep 17 00:00:00 2001 From: smiki Date: Sun, 24 Aug 2025 16:45:54 +0200 Subject: [PATCH 164/234] [ADDED] WAREHOUSE:SetValidateAndRepositionGroundUnits to use for Brigades --- Moose Development/Moose/Functional/Warehouse.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Functional/Warehouse.lua b/Moose Development/Moose/Functional/Warehouse.lua index 19654ad5e..807f57f98 100644 --- a/Moose Development/Moose/Functional/Warehouse.lua +++ b/Moose Development/Moose/Functional/Warehouse.lua @@ -5975,9 +5975,9 @@ function WAREHOUSE:_SpawnAssetGroundNaval(alias, asset, request, spawnzone, late template.y = coord.z template.alt = coord.y - if self.ValidateAndRepositionGroundUnits then + if self.ValidateAndRepositionGroundUnits then UTILS.ValidateAndRepositionGroundUnits(template.units) - end + end -- Spawn group. local group=_DATABASE:Spawn(template) --Wrapper.Group#GROUP From 2c12cfe4fd018da77bee56c5932420ec7b77b4a7 Mon Sep 17 00:00:00 2001 From: smiki Date: Sun, 24 Aug 2025 17:06:45 +0200 Subject: [PATCH 165/234] [ADDED] WAREHOUSE:SetValidateAndRepositionGroundUnits to use for Brigades --- Moose Development/Moose/Core/Spawn.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/Core/Spawn.lua b/Moose Development/Moose/Core/Spawn.lua index 6e95e285b..0d58567a4 100644 --- a/Moose Development/Moose/Core/Spawn.lua +++ b/Moose Development/Moose/Core/Spawn.lua @@ -1849,7 +1849,7 @@ function SPAWN:SpawnWithIndex( SpawnIndex, NoBirth ) if self.SpawnValidateAndRepositionGroundUnits then local units = SpawnTemplate.units local gPos = { x = SpawnTemplate.x, y = SpawnTemplate.y } - UTILS.ValidateAndRepositionGroundUnits(gPos, units, self.SpawnValidateAndRepositionGroundUnitsRadius, self.SpawnValidateAndRepositionGroundUnitsSpacing) + UTILS.ValidateAndRepositionGroundUnits(units, gPos, self.SpawnValidateAndRepositionGroundUnitsRadius, self.SpawnValidateAndRepositionGroundUnitsSpacing) end -- Set country, coalition and category. From cc7685161461e3e4430a83633e904897c72d4f30 Mon Sep 17 00:00:00 2001 From: smiki Date: Mon, 25 Aug 2025 23:08:25 +0200 Subject: [PATCH 166/234] [ADDED] `ValidateAndRepositionGroundUnits` to UNIT and GROUP respawns --- Moose Development/Moose/Wrapper/Group.lua | 14 ++++++++++++++ Moose Development/Moose/Wrapper/Unit.lua | 14 ++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index 89ff5f7c3..dc6cf3af1 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -2231,6 +2231,10 @@ function GROUP:Respawn( Template, Reset ) --UTILS.PrintTableToLog(Template) + if self.ValidateAndRepositionGroundUnits then + UTILS.ValidateAndRepositionGroundUnits(Template.units) + end + -- Spawn new group. self:ScheduleOnce(0.1,_DATABASE.Spawn,_DATABASE,Template) --_DATABASE:Spawn(Template) @@ -3192,3 +3196,13 @@ function GROUP:IsAAA() end return isAAA end + +--- This function uses Disposition and other fallback logic to find better ground positions for ground units. +--- NOTE: This is not a spawn randomizer. +--- It will try to find clear ground locations avoiding trees, water, roads, runways, map scenery, statics and other units in the area and modifies the provided positions table. +--- Maintains the original layout and unit positions as close as possible by searching for the next closest valid position to each unit. +--- Uses UTILS.ValidateAndRepositionGroundUnits. +-- @param #boolean Enabled Enable/disable the feature. +function GROUP:SetValidateAndRepositionGroundUnits(Enabled) + self.ValidateAndRepositionGroundUnits = Enabled +end diff --git a/Moose Development/Moose/Wrapper/Unit.lua b/Moose Development/Moose/Wrapper/Unit.lua index d005ebca2..9fd6963a1 100644 --- a/Moose Development/Moose/Wrapper/Unit.lua +++ b/Moose Development/Moose/Wrapper/Unit.lua @@ -377,6 +377,10 @@ function UNIT:ReSpawnAt(Coordinate, Heading) --self:T( SpawnGroupTemplate ) + if self.ValidateAndRepositionGroundUnits then + UTILS.ValidateAndRepositionGroundUnits(SpawnGroupTemplate.units) + end + _DATABASE:Spawn(SpawnGroupTemplate) end @@ -1938,3 +1942,13 @@ end function UNIT:SetCarrierIlluminationMode(Mode) UTILS.SetCarrierIlluminationMode(self:GetID(), Mode) end + +--- This function uses Disposition and other fallback logic to find better ground positions for ground units. +--- NOTE: This is not a spawn randomizer. +--- It will try to find clear ground locations avoiding trees, water, roads, runways, map scenery, statics and other units in the area and modifies the provided positions table. +--- Maintains the original layout and unit positions as close as possible by searching for the next closest valid position to each unit. +--- Uses UTILS.ValidateAndRepositionGroundUnits. +-- @param #boolean Enabled Enable/disable the feature. +function UNIT:SetValidateAndRepositionGroundUnits(Enabled) + self.ValidateAndRepositionGroundUnits = Enabled +end From b6d725920a5dfb1c2a55fc3f13128dcd10bdd390 Mon Sep 17 00:00:00 2001 From: smiki Date: Mon, 25 Aug 2025 23:22:00 +0200 Subject: [PATCH 167/234] [ADDED] `ValidateAndRepositionGroundUnits` to OPSGROUP --- Moose Development/Moose/Ops/Legion.lua | 1 + Moose Development/Moose/Ops/OpsGroup.lua | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/Moose Development/Moose/Ops/Legion.lua b/Moose Development/Moose/Ops/Legion.lua index b3c00592f..71b1c0f55 100644 --- a/Moose Development/Moose/Ops/Legion.lua +++ b/Moose Development/Moose/Ops/Legion.lua @@ -1823,6 +1823,7 @@ function LEGION:_CreateFlightGroup(asset) --- opsgroup=ARMYGROUP:New(asset.spawngroupname) + opsgroup:SetValidateAndRepositionGroundUnits(self.ValidateAndRepositionGroundUnits) elseif self:IsFleet() then diff --git a/Moose Development/Moose/Ops/OpsGroup.lua b/Moose Development/Moose/Ops/OpsGroup.lua index 40dccb84e..02ea215f4 100644 --- a/Moose Development/Moose/Ops/OpsGroup.lua +++ b/Moose Development/Moose/Ops/OpsGroup.lua @@ -7847,6 +7847,10 @@ function OPSGROUP:_Spawn(Delay, Template) -- Debug output. self:T2({Template=Template}) + if self:IsArmygroup() and self.ValidateAndRepositionGroundUnits then + UTILS.ValidateAndRepositionGroundUnits(Template.units) + end + -- Spawn new group. self.group=_DATABASE:Spawn(Template) --local countryID=self.group:GetCountry() @@ -13955,6 +13959,15 @@ function OPSGROUP:_GetDetectedTarget() return targetgroup, targetdist end +--- This function uses Disposition and other fallback logic to find better ground positions for ground units. +--- NOTE: This is not a spawn randomizer. +--- It will try to find clear ground locations avoiding trees, water, roads, runways, map scenery, statics and other units in the area and modifies the provided positions table. +--- Maintains the original layout and unit positions as close as possible by searching for the next closest valid position to each unit. +--- Uses UTILS.ValidateAndRepositionGroundUnits. +-- @param #boolean Enabled Enable/disable the feature. +function OPSGROUP:SetValidateAndRepositionGroundUnits(Enabled) + self.ValidateAndRepositionGroundUnits = Enabled +end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- From 2479147fd9948ef8bea9dd6e13edd4449261aa75 Mon Sep 17 00:00:00 2001 From: smiki Date: Tue, 26 Aug 2025 13:15:12 +0200 Subject: [PATCH 168/234] [ADDED] `ValidateAndRepositionGroundUnits` to OPSGROUP --- Moose Development/Moose/Ops/OpsGroup.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/Moose Development/Moose/Ops/OpsGroup.lua b/Moose Development/Moose/Ops/OpsGroup.lua index 02ea215f4..f23053a18 100644 --- a/Moose Development/Moose/Ops/OpsGroup.lua +++ b/Moose Development/Moose/Ops/OpsGroup.lua @@ -7853,6 +7853,7 @@ function OPSGROUP:_Spawn(Delay, Template) -- Spawn new group. self.group=_DATABASE:Spawn(Template) + self.group:SetValidateAndRepositionGroundUnits(self.ValidateAndRepositionGroundUnits) --local countryID=self.group:GetCountry() --local categoryID=self.group:GetCategory() --local dcsgroup=coalition.addGroup(countryID, categoryID, Template) From db053398d233f37e221bc20bc5d136871e60073c Mon Sep 17 00:00:00 2001 From: TeTeT Nimitz Date: Wed, 27 Aug 2025 13:12:50 +0200 Subject: [PATCH 169/234] Add support for Vietnam War Vessels carriers to Airboss: - CVA-31 Bon Homme Richard - Generic Essex with SCB-125 upgrade (angled Deck) - CVAN-65 Enterprise 1966 - CVN-65 Enterprise modern --- Moose Development/Moose/Ops/Airboss.lua | 65 +++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/Moose Development/Moose/Ops/Airboss.lua b/Moose Development/Moose/Ops/Airboss.lua index c24f6720c..89f6f5b37 100644 --- a/Moose Development/Moose/Ops/Airboss.lua +++ b/Moose Development/Moose/Ops/Airboss.lua @@ -1317,6 +1317,10 @@ AIRBOSS.AircraftCarrier={ -- @field #string FORRESTAL USS Forrestal (CV-59) [Heatblur Carrier Module] -- @field #string VINSON USS Carl Vinson (CVN-70) [Deprecated!] -- @field #string ESSEX Essex class carrier (e.g. USS Yorktown (CV-10)) [Magnitude 3 Carrier Module] +-- @field #string BONHOMMERICHARD USS Bon Homme Richard carrier [VWV Mod] +-- @field #string ESSEXSCB125 Generic Essex class carrier with angled deck (SCB-125 upgrade) [VWV Mod] +-- @field #string ENTERPRISE66 USS Enterprise in the 1966 configuration [VWV Mod] +-- @field #string ENTERPRISEMODERN USS Enterprise in a modern configuration [Derived VWV Mod] -- @field #string HERMES HMS Hermes (R12) [V/STOL Carrier] -- @field #string INVINCIBLE HMS Invincible (R05) [V/STOL Carrier] -- @field #string TARAWA USS Tarawa (LHA-1) [V/STOL Carrier] @@ -1331,8 +1335,12 @@ AIRBOSS.CarrierType = { TRUMAN = "CVN_75", STENNIS = "Stennis", FORRESTAL = "Forrestal", + ENTERPRISE66 = "USS Enterprise 1966", + ENTERPRISEMODERN = "cvn-65", VINSON = "VINSON", ESSEX = "Essex", + BONHOMMERICHARD = "USS Bon Homme Richard", + ESSEXSCB125 = "essex_scb125", HERMES = "HERMES81", INVINCIBLE = "hms_invincible", TARAWA = "LHA_Tarawa", @@ -2019,11 +2027,19 @@ function AIRBOSS:New( carriername, alias ) self:_InitNimitz() elseif self.carriertype == AIRBOSS.CarrierType.FORRESTAL then self:_InitForrestal() + elseif self.carriertype == AIRBOSS.CarrierType.ENTERPRISE66 then + self:_InitEnterprise() + elseif self.carriertype == AIRBOSS.CarrierType.ENTERPRISEMODERN then + self:_InitEnterprise() elseif self.carriertype == AIRBOSS.CarrierType.VINSON then -- Carl Vinson is legacy now. self:_InitStennis() elseif self.carriertype == AIRBOSS.CarrierType.ESSEX then self:_InitEssex() + elseif self.carriertype == AIRBOSS.CarrierType.BONHOMMERICHARD then + self:_InitBonHommeRichard() + elseif self.carriertype == AIRBOSS.CarrierType.ESSEXSCB125 then + self:_InitEssexSCB125() elseif self.carriertype == AIRBOSS.CarrierType.HERMES then -- Hermes parameters. self:_InitHermes() @@ -4653,6 +4669,26 @@ function AIRBOSS:_InitForrestal() end +--- Init parameters for Enterprise carrier. +-- @param #AIRBOSS self +function AIRBOSS:_InitEnterprise() + -- Using Forrestal as template + self:_InitForrestal() + + self.carrierparam.sterndist = -164.30 + self.carrierparam.deckheight = 19.52 + + self.carrierparam.totlength = 335 + self.carrierparam.rwylength = 223 + + -- Wires. + self.carrierparam.wire1 = 57.7 + self.carrierparam.wire2 = 69.6 + self.carrierparam.wire3 = 79.5 + self.carrierparam.wire4 = 90.0 + +end + --- Init parameters for Essec class carriers. -- @param #AIRBOSS self function AIRBOSS:_InitEssex() @@ -4698,6 +4734,35 @@ function AIRBOSS:_InitEssex() end +--- Init parameters for CVA-31 Bon Homme Richard carriers. +-- @param #AIRBOSS self +function AIRBOSS:_InitBonHommeRichard() + -- Init Essex as default + self:_InitEssex() + + self.carrierparam.deckheight = 16.95 + + -- Landing runway. + -- from BHR EssexRunwayAndRoutes.lua + self.carrierparam.rwyangle = -11.4 + self.carrierparam.rwylength = 97 + self.carrierparam.rwywidth = 20 + + -- Wires. + self.carrierparam.wire1 = 40.4 -- Distance from stern to first wire. Original from Frank - 42 + self.carrierparam.wire2 = 45 + self.carrierparam.wire3 = 51 + self.carrierparam.wire4 = 58.1 +end + +--- Init parameters for Generic Essex SC125 class carriers. +-- @param #AIRBOSS self +function AIRBOSS:_InitEssexSCB125() + -- Init Bon Homme Richard as default + self:_InitBonHommeRichard() + +end + --- Init parameters for R12 HMS Hermes carrier. -- @param #AIRBOSS self function AIRBOSS:_InitHermes() From e590701c01e331d9d972434a304bc59a5ab5be5b Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 28 Aug 2025 11:13:50 +0200 Subject: [PATCH 170/234] xx --- Moose Development/Moose/Ops/Auftrag.lua | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/Moose Development/Moose/Ops/Auftrag.lua b/Moose Development/Moose/Ops/Auftrag.lua index b4e6128a1..41bac80e0 100644 --- a/Moose Development/Moose/Ops/Auftrag.lua +++ b/Moose Development/Moose/Ops/Auftrag.lua @@ -1321,13 +1321,19 @@ end -- @param #number Altitude Orbit altitude in feet. Default is y component of `Coordinate`. -- @param #number Speed Orbit indicated airspeed in knots at the set altitude ASL. Default 350 KIAS. -- @param #number Heading Heading of race-track pattern in degrees. Default 270 (East to West). --- @param #number Leg Length of race-track in NM. Default 10 NM. +-- @param #number Leg Length of race-track in NM. Default 10 NM. Set to 0 for a simple circular orbit. -- @param #number RefuelSystem Refueling system (0=boom, 1=probe). This info is *only* for AIRWINGs so they launch the right tanker type. -- @return #AUFTRAG self function AUFTRAG:NewTANKER(Coordinate, Altitude, Speed, Heading, Leg, RefuelSystem) - + + local mission + if Leg == 0 then + mission=AUFTRAG:NewORBIT_CIRCLE(Coordinate,Altitude,Speed) + else + mission=AUFTRAG:NewORBIT_RACETRACK(Coordinate,Altitude,Speed,Heading,Leg) + end -- Create ORBIT first. - local mission=AUFTRAG:NewORBIT_RACETRACK(Coordinate, Altitude, Speed, Heading, Leg) + --local mission=AUFTRAG:NewORBIT_RACETRACK(Coordinate, Altitude, Speed, Heading, Leg) -- Mission type TANKER. mission.type=AUFTRAG.Type.TANKER From efb1d79e7739c15898d4ce4bf7cd6088b85540e3 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 28 Aug 2025 13:17:57 +0200 Subject: [PATCH 171/234] #COHORT - Fix Callsign Setting --- Moose Development/Moose/Ops/Cohort.lua | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/Moose Development/Moose/Ops/Cohort.lua b/Moose Development/Moose/Ops/Cohort.lua index 26f54e66d..c18d838d6 100644 --- a/Moose Development/Moose/Ops/Cohort.lua +++ b/Moose Development/Moose/Ops/Cohort.lua @@ -88,7 +88,7 @@ COHORT = { --- COHORT class version. -- @field #string version -COHORT.version="0.3.6" +COHORT.version="0.3.7" --- Global variable to store the unique(!) cohort names _COHORTNAMES={} @@ -100,6 +100,7 @@ _COHORTNAMES={} -- DONE: Create FLOTILLA class. -- DONE: Added check for properties. -- DONE: Make general so that PLATOON and SQUADRON can inherit this class. +-- DONE: Better setting of call signs. ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- Constructor @@ -515,10 +516,12 @@ end -- @param #COHORT self -- @param #number Callsign Callsign from CALLSIGN.Aircraft, e.g. "Chevy" for CALLSIGN.Aircraft.CHEVY. -- @param #number Index Callsign index, Chevy-**1**. +-- @param #string CallsignString (optional) Set this for tasks like TANKER, AWACS or KIOWA and the like, which have special names. E.g. "Darkstar" or "Roughneck". -- @return #COHORT self -function COHORT:SetCallsign(Callsign, Index) +function COHORT:SetCallsign(Callsign, Index, CallsignString) self.callsignName=Callsign self.callsignIndex=Index + self.callsignClearName=CallsignString self.callsign={} self.callsign.NumberSquad=Callsign self.callsign.NumberGroup=Index @@ -679,7 +682,16 @@ end function COHORT:GetCallsign(Asset) if self.callsignName then - + --[[ + ["callsign"] = + { + [2] = 1, + ["name"] = "Darkstar11", + [3] = 1, + [1] = 5, + [4] = "Darkstar11", + }, -- end of ["callsign"] + ]] Asset.callsign={} for i=1,Asset.nunits do @@ -695,12 +707,16 @@ function COHORT:GetCallsign(Asset) else self.callsigncounter=self.callsigncounter+1 end + callsign["name"] = self.callsignClearName or UTILS.GetCallsignName(self.callsignName) or "None" + callsign["name"] = string.format("%s%d%d",callsign["name"],callsign[2],callsign[3]) + callsign[4] = callsign["name"] Asset.callsign[i]=callsign self:T3({callsign=callsign}) - --TODO: there is also a table entry .name, which is a string. + --DONE: there is also a table entry .name, which is a string. + --UTILS.PrintTableToLog(callsign) end From e003b91bbe0b3edf22da430b577d5950f71dc852 Mon Sep 17 00:00:00 2001 From: smiki Date: Thu, 28 Aug 2025 19:36:22 +0200 Subject: [PATCH 172/234] [ADDED] `SPAWNSTATIC:InitValidateAndRepositionStatic(OnOff, MaxRadius)` --- Moose Development/Moose/Core/Spawn.lua | 1 + Moose Development/Moose/Core/SpawnStatic.lua | 22 +++++++++ Moose Development/Moose/Utilities/Utils.lua | 48 ++++++++++++++++++++ Moose Development/Moose/Wrapper/Group.lua | 1 + Moose Development/Moose/Wrapper/Unit.lua | 1 + 5 files changed, 73 insertions(+) diff --git a/Moose Development/Moose/Core/Spawn.lua b/Moose Development/Moose/Core/Spawn.lua index 0d58567a4..f58937439 100644 --- a/Moose Development/Moose/Core/Spawn.lua +++ b/Moose Development/Moose/Core/Spawn.lua @@ -1054,6 +1054,7 @@ end --- NOTE: This is not a spawn randomizer. --- It will try to find clear ground locations avoiding trees, water, roads, runways, map scenery, statics and other units in the area. --- Maintains the original layout and unit positions as close as possible by searching for the next closest valid position to each unit. +-- @param #SPAWN self -- @param #boolean OnOff Enable/disable the feature. -- @param #number MaxRadius (Optional) Max radius to search for valid ground locations in meters. Default is double the max radius of the units. -- @param #number Spacing (Optional) Minimum spacing between units in meters. Default is 5% of the search radius or 5 meters, whichever is larger. diff --git a/Moose Development/Moose/Core/SpawnStatic.lua b/Moose Development/Moose/Core/SpawnStatic.lua index 344d1a5d7..c67d6ed7c 100644 --- a/Moose Development/Moose/Core/SpawnStatic.lua +++ b/Moose Development/Moose/Core/SpawnStatic.lua @@ -378,6 +378,20 @@ function SPAWNSTATIC:InitLinkToUnit(Unit, OffsetX, OffsetY, OffsetAngle) return self end +--- Uses Disposition and other fallback logic to find a better and valid ground spawn position. +--- NOTE: This is not a spawn randomizer. +--- It will try to a find clear ground location avoiding trees, water, roads, runways, map scenery, other statics and other units in the area. +--- Uses the initial position if it's a valid location. +-- @param #SPAWNSTATIC self +-- @param #boolean OnOff Enable/disable the feature. +-- @param #number MaxRadius (Optional) Max radius to search for a valid ground location in meters. Default is 10 times the max radius of the static. +-- @return #SPAWNSTATIC self +function SPAWNSTATIC:InitValidateAndRepositionStatic(OnOff, MaxRadius) + self.SpawnValidateAndRepositionStatic = OnOff + self.ValidateAndRepositionStaticMaxRadius = MaxRadius + return self +end + --- Allows to place a CallFunction hook when a new static spawns. -- The provided method will be called when a new group is spawned, including its given parameters. -- The first parameter of the SpawnFunction is the @{Wrapper.Static#STATIC} that was spawned. @@ -544,6 +558,14 @@ function SPAWNSTATIC:_SpawnStatic(Template, CountryID) -- Add static to the game. local Static=nil --DCS#StaticObject + if self.ValidateAndRepositionStatic then + local validPos = UTILS.ValidateAndRepositionStatic(CountryID, Template.category, Template.type, Template, Template.shape_name, self.ValidateAndRepositionStaticMaxRadius) + if validPos then + Template.x = validPos.x + Template.y = validPos.y + end + end + if self.InitFarp then local TemplateGroup={} diff --git a/Moose Development/Moose/Utilities/Utils.lua b/Moose Development/Moose/Utilities/Utils.lua index cd94f71b2..1a2809b24 100644 --- a/Moose Development/Moose/Utilities/Utils.lua +++ b/Moose Development/Moose/Utilities/Utils.lua @@ -4981,3 +4981,51 @@ function UTILS.ValidateAndRepositionGroundUnits(Positions, Anchor, MaxRadius, Sp end end end + +--- This function uses Disposition and other fallback logic to find better ground positions for ground units. +--- NOTE: This is not a spawn randomizer. +--- It will try to find clear ground locations avoiding trees, water, roads, runways, map scenery, statics and other units in the area and modifies the provided positions table. +--- Maintains the original layout and unit positions as close as possible by searching for the next closest valid position to each unit. +-- @param #table Positions A table of DCS#Vec2 or DCS#Vec3, can be a units table from the group template. +-- @param DCS#Vec2 Position DCS#Vec2 or DCS#Vec3 initial spawn location. +-- @param #number MaxRadius (Optional) Max radius to search for valid ground locations in meters. Default is double the max radius of the static. +-- @return DCS#Vec2 Initial Position if it's valid, else a valid spawn position. nil if no valid position found. +function UTILS.ValidateAndRepositionStatic(Country, Category, Type, Position, ShapeName, MaxRadius) + local coord = COORDINATE:NewFromVec2(Position) + local st = SPAWNSTATIC:NewFromType(Type, Category, Country) + if ShapeName then + st:InitShape(ShapeName) + end + local sName = "s-"..timer.getTime().."-"..math.random(1,10000) + local tempStatic = st:SpawnFromCoordinate(coord, 0, sName) + if tempStatic then + local sRadius = tempStatic:GetBoundingRadius(2) or 3 + tempStatic:Destroy() + sRadius = sRadius * 0.5 + MaxRadius = MaxRadius or math.max(sRadius * 10, 100) + local positions = UTILS.GetSimpleZones(coord:GetVec3(), MaxRadius, sRadius, 20) + if positions and #positions > 0 then + local closestSpot + local closestDist = math.huge + for _, spot in pairs(positions) do -- Disposition sometimes returns points on roads, hence this filter. + if land.getSurfaceType(spot) == land.SurfaceType.LAND then + local dist = UTILS.VecDist2D(Position, spot) + if dist < closestDist then + closestDist = dist + closestSpot = spot + end + end + end + + if closestSpot then + if closestDist >= sRadius then + return closestSpot + else + return Position + end + end + end + end + + return nil +end diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index dc6cf3af1..77380fb7b 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -3202,6 +3202,7 @@ end --- It will try to find clear ground locations avoiding trees, water, roads, runways, map scenery, statics and other units in the area and modifies the provided positions table. --- Maintains the original layout and unit positions as close as possible by searching for the next closest valid position to each unit. --- Uses UTILS.ValidateAndRepositionGroundUnits. +-- @param #UNIT self -- @param #boolean Enabled Enable/disable the feature. function GROUP:SetValidateAndRepositionGroundUnits(Enabled) self.ValidateAndRepositionGroundUnits = Enabled diff --git a/Moose Development/Moose/Wrapper/Unit.lua b/Moose Development/Moose/Wrapper/Unit.lua index 9fd6963a1..9d2ab5cfd 100644 --- a/Moose Development/Moose/Wrapper/Unit.lua +++ b/Moose Development/Moose/Wrapper/Unit.lua @@ -1948,6 +1948,7 @@ end --- It will try to find clear ground locations avoiding trees, water, roads, runways, map scenery, statics and other units in the area and modifies the provided positions table. --- Maintains the original layout and unit positions as close as possible by searching for the next closest valid position to each unit. --- Uses UTILS.ValidateAndRepositionGroundUnits. +-- @param #UNIT self -- @param #boolean Enabled Enable/disable the feature. function UNIT:SetValidateAndRepositionGroundUnits(Enabled) self.ValidateAndRepositionGroundUnits = Enabled From 323f09b06c85df89956b7d3766c0bf5213619ed1 Mon Sep 17 00:00:00 2001 From: smiki Date: Thu, 28 Aug 2025 19:38:05 +0200 Subject: [PATCH 173/234] [ADDED] `SPAWNSTATIC:InitValidateAndRepositionStatic(OnOff, MaxRadius)` --- Moose Development/Moose/Core/SpawnStatic.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/Core/SpawnStatic.lua b/Moose Development/Moose/Core/SpawnStatic.lua index c67d6ed7c..332e7e464 100644 --- a/Moose Development/Moose/Core/SpawnStatic.lua +++ b/Moose Development/Moose/Core/SpawnStatic.lua @@ -387,7 +387,7 @@ end -- @param #number MaxRadius (Optional) Max radius to search for a valid ground location in meters. Default is 10 times the max radius of the static. -- @return #SPAWNSTATIC self function SPAWNSTATIC:InitValidateAndRepositionStatic(OnOff, MaxRadius) - self.SpawnValidateAndRepositionStatic = OnOff + self.ValidateAndRepositionStatic = OnOff self.ValidateAndRepositionStaticMaxRadius = MaxRadius return self end From 42ecdd3b1468d43e08be6c53acebc672d9b8a6ea Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sun, 31 Aug 2025 13:24:31 +0200 Subject: [PATCH 174/234] #AIRBASE - Add Sinai Damascus Intl Airbase in the enumerator --- Moose Development/Moose/Wrapper/Airbase.lua | 100 ++++++++++---------- 1 file changed, 51 insertions(+), 49 deletions(-) diff --git a/Moose Development/Moose/Wrapper/Airbase.lua b/Moose Development/Moose/Wrapper/Airbase.lua index cf96d6064..58b1fea1e 100644 --- a/Moose Development/Moose/Wrapper/Airbase.lua +++ b/Moose Development/Moose/Wrapper/Airbase.lua @@ -703,55 +703,56 @@ AIRBASE.SouthAtlantic={ --- Airbases of the Sinai map: -- --- * 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.Borg_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.Mezzeh_Air_Base --- * AIRBASE.Sinai.Nevatim --- * AIRBASE.Sinai.Ovda --- * AIRBASE.Sinai.Palmachim --- * AIRBASE.Sinai.Quwaysina --- * AIRBASE.Sinai.Rafic_Hariri_Intl --- * AIRBASE.Sinai.Ramat_David --- * 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.Tabuk --- * AIRBASE.Sinai.Tel_Nof --- * AIRBASE.Sinai.Wadi_Abu_Rish --- * AIRBASE.Sinai.Wadi_al_Jandali +-- * AIRBASE.SinaiMap.Abu_Rudeis +-- * AIRBASE.SinaiMap.Abu_Suwayr +-- * AIRBASE.SinaiMap.Al_Bahr_al_Ahmar +-- * AIRBASE.SinaiMap.Al_Ismailiyah +-- * AIRBASE.SinaiMap.Al_Khatatbah +-- * AIRBASE.SinaiMap.Al_Mansurah +-- * AIRBASE.SinaiMap.Al_Rahmaniyah_Air_Base +-- * AIRBASE.SinaiMap.As_Salihiyah +-- * AIRBASE.SinaiMap.AzZaqaziq +-- * AIRBASE.SinaiMap.Baluza +-- * AIRBASE.SinaiMap.Ben_Gurion +-- * AIRBASE.SinaiMap.Beni_Suef +-- * AIRBASE.SinaiMap.Bilbeis_Air_Base +-- * AIRBASE.SinaiMap.Bir_Hasanah +-- * AIRBASE.SinaiMap.Birma_Air_Base +-- * AIRBASE.SinaiMap.Borg_El_Arab_International_Airport +-- * AIRBASE.SinaiMap.Cairo_International_Airport +-- * AIRBASE.SinaiMap.Cairo_West +-- * AIRBASE.SinaiMap.Damascus_Intl +-- * AIRBASE.SinaiMap.Difarsuwar_Airfield +-- * AIRBASE.SinaiMap.El_Arish +-- * AIRBASE.SinaiMap.El_Gora +-- * AIRBASE.SinaiMap.El_Minya +-- * AIRBASE.SinaiMap.Fayed +-- * AIRBASE.SinaiMap.Gebel_El_Basur_Air_Base +-- * AIRBASE.SinaiMap.Hatzerim +-- * AIRBASE.SinaiMap.Hatzor +-- * AIRBASE.SinaiMap.Hurghada_International_Airport +-- * AIRBASE.SinaiMap.Inshas_Airbase +-- * AIRBASE.SinaiMap.Jiyanklis_Air_Base +-- * AIRBASE.SinaiMap.Kedem +-- * AIRBASE.SinaiMap.Kibrit_Air_Base +-- * AIRBASE.SinaiMap.Kom_Awshim +-- * AIRBASE.SinaiMap.Melez +-- * AIRBASE.SinaiMap.Mezzeh_Air_Base +-- * AIRBASE.SinaiMap.Nevatim +-- * AIRBASE.SinaiMap.Ovda +-- * AIRBASE.SinaiMap.Palmachim +-- * AIRBASE.SinaiMap.Quwaysina +-- * AIRBASE.SinaiMap.Rafic_Hariri_Intl +-- * AIRBASE.SinaiMap.Ramat_David +-- * AIRBASE.SinaiMap.Ramon_Airbase +-- * AIRBASE.SinaiMap.Ramon_International_Airport +-- * AIRBASE.SinaiMap.Sde_Dov +-- * AIRBASE.SinaiMap.Sharm_El_Sheikh_International_Airport +-- * AIRBASE.SinaiMap.St_Catherine +-- * AIRBASE.SinaiMap.Tabuk +-- * AIRBASE.SinaiMap.Tel_Nof +-- * AIRBASE.SinaiMap.Wadi_Abu_Rish +-- * AIRBASE.SinaiMap.Wadi_al_Jandali -- -- @field Sinai AIRBASE.Sinai = { @@ -773,6 +774,7 @@ AIRBASE.Sinai = { ["Borg_El_Arab_International_Airport"] = "Borg El Arab International Airport", ["Cairo_International_Airport"] = "Cairo International Airport", ["Cairo_West"] = "Cairo West", + ["Damascus_Intl"] = "Damascus Intl", ["Difarsuwar_Airfield"] = "Difarsuwar Airfield", ["El_Arish"] = "El Arish", ["El_Gora"] = "El Gora", From 6c1907f7e0f14497e08c2ca08281de5119b655f4 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sun, 31 Aug 2025 13:27:24 +0200 Subject: [PATCH 175/234] GROUO correction in class self line 3205 --- Moose Development/Moose/Wrapper/Group.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index 77380fb7b..6ff787553 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -3202,7 +3202,7 @@ end --- It will try to find clear ground locations avoiding trees, water, roads, runways, map scenery, statics and other units in the area and modifies the provided positions table. --- Maintains the original layout and unit positions as close as possible by searching for the next closest valid position to each unit. --- Uses UTILS.ValidateAndRepositionGroundUnits. --- @param #UNIT self +-- @param #GROUP self -- @param #boolean Enabled Enable/disable the feature. function GROUP:SetValidateAndRepositionGroundUnits(Enabled) self.ValidateAndRepositionGroundUnits = Enabled From 873879ff794237212fe6f76f723a8d47506a00a3 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sun, 31 Aug 2025 18:22:17 +0200 Subject: [PATCH 176/234] #AIRBOSS - Slight tweak to EnableSRS() when no parameters are handed in. --- Moose Development/Moose/Ops/Airboss.lua | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/Moose Development/Moose/Ops/Airboss.lua b/Moose Development/Moose/Ops/Airboss.lua index 89f6f5b37..70535cd0e 100644 --- a/Moose Development/Moose/Ops/Airboss.lua +++ b/Moose Development/Moose/Ops/Airboss.lua @@ -39,6 +39,8 @@ -- * [USS America](https://en.wikipedia.org/wiki/USS_America_\(LHA-6\)) (LHA-6) -- * [Juan Carlos I](https://en.wikipedia.org/wiki/Spanish_amphibious_assault_ship_Juan_Carlos_I) (L61) -- * [HMAS Canberra](https://en.wikipedia.org/wiki/HMAS_Canberra_\(L02\)) (L02) +-- * BONHOMMERICHARD [VWV Mod] +-- * ENTERPRISE66 [VWV Mod] -- -- **Supported Aircraft:** -- @@ -1764,7 +1766,7 @@ AIRBOSS.MenuF10Root = nil --- Airboss class version. -- @field #string version -AIRBOSS.version = "1.4.1" +AIRBOSS.version = "1.4.2" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO list ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -3126,8 +3128,8 @@ function AIRBOSS:EnableSRS(PathToSRS,Port,Culture,Gender,Voice,GoogleCreds,Volum self.SRS:SetCulture(Culture or "en-US") --self.SRS:SetFrequencies(Frequencies) self.SRS:SetGender(Gender or "male") - self.SRS:SetPath(PathToSRS) - self.SRS:SetPort(Port or 5002) + --self.SRS:SetPath(PathToSRS) + self.SRS:SetPort(Port or MSRS.port or 5002) self.SRS:SetLabel(self.AirbossRadio.alias or "AIRBOSS") self.SRS:SetCoordinate(self.carrier:GetCoordinate()) self.SRS:SetVolume(Volume or 1) @@ -3138,7 +3140,10 @@ function AIRBOSS:EnableSRS(PathToSRS,Port,Culture,Gender,Voice,GoogleCreds,Volum if Voice then self.SRS:SetVoice(Voice) end - self.SRS:SetVolume(Volume or 1.0) + if (not Voice) and self.SRS and self.SRS:GetProvider() == MSRS.Provider.GOOGLE then + self.SRS.voice = MSRS.poptions["gcloud"].voice or MSRS.Voices.Google.Standard.en_US_Standard_B + end + --self.SRS:SetVolume(Volume or 1.0) -- SRSQUEUE self.SRSQ = MSRSQUEUE:New("AIRBOSS") self.SRSQ:SetTransmitOnlyWithPlayers(true) From 44f3c776eb0bad395b2520a89b2630a8345ef74b Mon Sep 17 00:00:00 2001 From: smiki Date: Mon, 1 Sep 2025 09:30:05 +0200 Subject: [PATCH 177/234] [FIXED] `UTILS.HdgTo to accept both Vec2 or Vec3` --- Moose Development/Moose/Utilities/Utils.lua | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Moose Development/Moose/Utilities/Utils.lua b/Moose Development/Moose/Utilities/Utils.lua index 1a2809b24..e4d85fbff 100644 --- a/Moose Development/Moose/Utilities/Utils.lua +++ b/Moose Development/Moose/Utilities/Utils.lua @@ -1586,12 +1586,12 @@ function UTILS.HdgDiff(h1, h2) return math.abs(delta) end ---- Returns the heading from one vec3 to another vec3. --- @param DCS#Vec3 a From vec3. --- @param DCS#Vec3 b To vec3. +--- Returns the heading from one vec2/vec3 to another vec2/vec3. +-- @param DCS#Vec3 a From Vec2 or Vec3. +-- @param DCS#Vec3 b To Vec2 or Vec3. -- @return #number Heading in degrees. function UTILS.HdgTo(a, b) - local dz=b.z-a.z + local dz=(b.z or b.y) - (a.z or a.y) local dx=b.x-a.x local heading=math.deg(math.atan2(dz, dx)) if heading < 0 then @@ -4982,7 +4982,7 @@ function UTILS.ValidateAndRepositionGroundUnits(Positions, Anchor, MaxRadius, Sp end end ---- This function uses Disposition and other fallback logic to find better ground positions for ground units. +--- This function uses Disposition and other fallback logic to find better ground positions for statics. --- NOTE: This is not a spawn randomizer. --- It will try to find clear ground locations avoiding trees, water, roads, runways, map scenery, statics and other units in the area and modifies the provided positions table. --- Maintains the original layout and unit positions as close as possible by searching for the next closest valid position to each unit. From 7df90b2d302887cb052840688587b9d98ca5ff38 Mon Sep 17 00:00:00 2001 From: smiki Date: Wed, 3 Sep 2025 09:12:20 +0200 Subject: [PATCH 178/234] [ADDED] `GROUP:GetBoundingBox()` since `POSITIONABLE:GetBoundingBox()` is only for units --- Moose Development/Moose/Wrapper/Group.lua | 46 +++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index 6ff787553..cdc76a54d 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -3207,3 +3207,49 @@ end function GROUP:SetValidateAndRepositionGroundUnits(Enabled) self.ValidateAndRepositionGroundUnits = Enabled end + + +--- Get the bounding box of the group combining UNIT:GetBoundingBox() units. +-- @param #GROUP self +-- @return DCS#Box3 The bounding box of the GROUP. +-- @return #nil The GROUP does not have any alive units. +function GROUP:GetBoundingBox() + local bbox = { min = { x = math.huge, y = math.huge, z = math.huge }, + max = { x = -math.huge, y = -math.huge, z = -math.huge } + } + + local Units = self:GetUnits() or {} + if #Units == 0 then + return nil + end + + for _, unit in pairs(Units) do + if unit and unit:IsAlive() then + local ubox = unit:GetBoundingBox() + + if ubox then + if ubox.min.x < bbox.min.x then + bbox.min.x = ubox.min.x + end + if ubox.min.y < bbox.min.y then + bbox.min.y = ubox.min.y + end + if ubox.min.z < bbox.min.z then + bbox.min.z = ubox.min.z + end + + if ubox.max.x > bbox.max.x then + bbox.max.x = ubox.max.x + end + if ubox.max.y > bbox.max.y then + bbox.max.y = ubox.max.y + end + if ubox.max.z > bbox.max.z then + bbox.max.z = ubox.max.z + end + end + end + end + + return bbox +end From 03275938e787eb0b9cdf08402cab1d67c716c8ed Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sun, 7 Sep 2025 18:58:41 +0200 Subject: [PATCH 179/234] #CLIENTMENU - add missing func from documentation --- Moose Development/Moose/Core/ClientMenu.lua | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Core/ClientMenu.lua b/Moose Development/Moose/Core/ClientMenu.lua index 5e7219add..fea72914d 100644 --- a/Moose Development/Moose/Core/ClientMenu.lua +++ b/Moose Development/Moose/Core/ClientMenu.lua @@ -20,7 +20,7 @@ -- -- @module Core.ClientMenu -- @image Core_Menu.JPG --- last change: Jan 2025 +-- last change: Sept 2025 -- TODO ---------------------------------------------------------------------------------------------------------------- @@ -417,7 +417,7 @@ end CLIENTMENUMANAGER = { ClassName = "CLIENTMENUMANAGER", lid = "", - version = "0.1.6", + version = "0.1.7", name = nil, clientset = nil, menutree = {}, @@ -806,6 +806,16 @@ function CLIENTMENUMANAGER:ResetMenuComplete() return self end +--- Remove the entry and all entries below the given entry from the client's F10 menus. +-- @param #CLIENTMENUMANAGER self +-- @param #CLIENTMENU Entry The entry to remove +-- @param Wrapper.Client#CLIENT Client (optional) If given, make this change only for this client. +-- @return #CLIENTMENUMANAGER self +function CLIENTMENUMANAGER:DeleteEntry(Entry,Client) + self:T(self.lid.."DeleteEntry") + return self:DeleteF10Entry(Entry,Client) +end + --- Remove the entry and all entries below the given entry from the client's F10 menus. -- @param #CLIENTMENUMANAGER self -- @param #CLIENTMENU Entry The entry to remove From 09e5fca1a57c91b93cb8987f7d07a93bcddb4734 Mon Sep 17 00:00:00 2001 From: smiki Date: Thu, 11 Sep 2025 00:38:20 +0200 Subject: [PATCH 180/234] [FIXED] CTLD. Injected spawns not using `InitValidateAndRepositionGroundUnits` --- Moose Development/Moose/Ops/CTLD.lua | 3 +++ Moose Development/Moose/Wrapper/Group.lua | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/Moose Development/Moose/Ops/CTLD.lua b/Moose Development/Moose/Ops/CTLD.lua index 6b1bb8d60..556b03038 100644 --- a/Moose Development/Moose/Ops/CTLD.lua +++ b/Moose Development/Moose/Ops/CTLD.lua @@ -6930,6 +6930,7 @@ end local alias = string.format("%s-%d", _template, math.random(1,100000)) self.DroppedTroops[self.TroopCounter] = SPAWN:NewWithAlias(_template,alias) :InitRandomizeUnits(randompositions,20,2) + :InitValidateAndRepositionGroundUnits(self.validateAndRepositionUnits) :InitDelayOff() :OnSpawnGroup(function(grp,TimeStamp) grp.spawntime = TimeStamp or timer.getTime() end,TimeStamp) :SpawnFromVec2(randomcoord) @@ -7083,12 +7084,14 @@ end if canmove then self.DroppedTroops[self.TroopCounter] = SPAWN:NewWithAlias(_template,alias) :InitRandomizeUnits(true,20,2) + :InitValidateAndRepositionGroundUnits(self.validateAndRepositionUnits) :InitDelayOff() :OnSpawnGroup(function(grp,TimeStamp) grp.spawntime = TimeStamp or timer.getTime() end,TimeStamp) :SpawnFromVec2(randomcoord) else -- don't random position of e.g. SAM units build as FOB self.DroppedTroops[self.TroopCounter] = SPAWN:NewWithAlias(_template,alias) :InitDelayOff() + :InitValidateAndRepositionGroundUnits(self.validateAndRepositionUnits) :OnSpawnGroup(function(grp,TimeStamp) grp.spawntime = TimeStamp or timer.getTime() end,TimeStamp) :SpawnFromVec2(randomcoord) end diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index cdc76a54d..1c38db672 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -231,6 +231,7 @@ GROUP.Attribute = { GROUND_AAA="Ground_AAA", GROUND_SAM="Ground_SAM", GROUND_SHORAD="Ground_SHORAD", + GROUND_BALLISTICMISSILE="Ground_BallisticMissile", GROUND_OTHER="Ground_OtherGround", NAVAL_AIRCRAFTCARRIER="Naval_AircraftCarrier", NAVAL_WARSHIP="Naval_WarShip", @@ -2643,6 +2644,8 @@ function GROUP:GetAttribute() local artillery=self:HasAttribute("Artillery") local tank=self:HasAttribute("Old Tanks") or self:HasAttribute("Modern Tanks") or self:HasAttribute("Tanks") local aaa=self:HasAttribute("AAA") and (not self:HasAttribute("SAM elements")) + local ballisticMissile=artillery and self:HasAttribute("SS_missile") + local shorad=self:HasAttribute("SR SAM") local ewr=self:HasAttribute("EWR") local ifv=self:HasAttribute("IFV") local sam=self:HasAttribute("SAM elements") or self:HasAttribute("Optical Tracker") @@ -2684,6 +2687,8 @@ function GROUP:GetAttribute() attribute=GROUP.Attribute.GROUND_SAM elseif aaa then attribute=GROUP.Attribute.GROUND_AAA + elseif artillery and ballisticMissile then + attribute=GROUP.Attribute.GROUND_BALLISTICMISSILE elseif artillery then attribute=GROUP.Attribute.GROUND_ARTILLERY elseif tank then From 3f8954d21da7a050ea33fb29d81b44f1640fb359 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Mon, 15 Sep 2025 09:28:35 +0200 Subject: [PATCH 181/234] #EASYGCICAP - Fixed - for Tanker Squadrons the TACAN channel could not be nil. --- Moose Development/Moose/Ops/EasyGCICAP.lua | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Ops/EasyGCICAP.lua b/Moose Development/Moose/Ops/EasyGCICAP.lua index f0700332d..5c789141f 100644 --- a/Moose Development/Moose/Ops/EasyGCICAP.lua +++ b/Moose Development/Moose/Ops/EasyGCICAP.lua @@ -273,7 +273,7 @@ EASYGCICAP = { --- EASYGCICAP class version. -- @field #string version -EASYGCICAP.version="0.1.27" +EASYGCICAP.version="0.1.28" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO list @@ -1209,7 +1209,9 @@ function EASYGCICAP:_AddTankerSquadron(TemplateName, SquadName, AirbaseName, Air Squadron_One:SetSkill(Skill or AI.Skill.AVERAGE) Squadron_One:SetMissionRange(self.missionrange) Squadron_One:SetRadio(Frequency,Modulation) - Squadron_One:AddTacanChannel(TACAN,TACAN) + if TACAN then + Squadron_One:AddTacanChannel(TACAN,TACAN) + end local wing = self.wings[AirbaseName][1] -- Ops.Airwing#AIRWING From f73dc6c3be6e77b6fc5497e531dd9adbe3905836 Mon Sep 17 00:00:00 2001 From: smiki Date: Tue, 16 Sep 2025 15:14:28 +0200 Subject: [PATCH 182/234] [Added] `PLAYERTASKCONTROLLER:CanJoinTask` Override function in order to implement custom logic if a player can join a task or not. --- Moose Development/Moose/Ops/PlayerTask.lua | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Moose Development/Moose/Ops/PlayerTask.lua b/Moose Development/Moose/Ops/PlayerTask.lua index 7ce6d57c2..77516f752 100644 --- a/Moose Development/Moose/Ops/PlayerTask.lua +++ b/Moose Development/Moose/Ops/PlayerTask.lua @@ -3530,6 +3530,16 @@ function PLAYERTASKCONTROLLER:AddPlayerTaskToQueue(PlayerTask,Silent,TaskFilter) return self end +--- [User] Override this function in order to implement custom logic if a player can join a task or not. +-- @param #PLAYERTASKCONTROLLER self +-- @param Ops.PlayerTask#PLAYERTASK Task +-- @param Wrapper.Group#GROUP Group +-- @param Wrapper.Client#CLIENT Client +-- @return #boolean Outcome True if player can join the task, false if not +function PLAYERTASKCONTROLLER:CanJoinTask(Task, Group, Client) + return true +end + --- [Internal] Join a player to a task -- @param #PLAYERTASKCONTROLLER self -- @param Ops.PlayerTask#PLAYERTASK Task @@ -3540,6 +3550,11 @@ end function PLAYERTASKCONTROLLER:_JoinTask(Task, Force, Group, Client) self:T({Force, Group, Client}) self:T(self.lid.."_JoinTask") + + if not self:CanJoinTask(Task, Group, Client) then + return self + end + local force = false if type(Force) == "boolean" then force = Force From 5414adc8d850b96da29f7fd00f9fd7ee177b8174 Mon Sep 17 00:00:00 2001 From: smiki Date: Wed, 17 Sep 2025 09:26:34 +0200 Subject: [PATCH 183/234] [Added] `PLAYERTASK:CanJoinTask` Override function in order to implement custom logic if a player can join a task or not. --- Moose Development/Moose/Ops/PlayerTask.lua | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Moose Development/Moose/Ops/PlayerTask.lua b/Moose Development/Moose/Ops/PlayerTask.lua index 77516f752..9a7679936 100644 --- a/Moose Development/Moose/Ops/PlayerTask.lua +++ b/Moose Development/Moose/Ops/PlayerTask.lua @@ -387,6 +387,14 @@ function PLAYERTASK:_CheckCaptureOpsZoneSuccess(OpsZone, CaptureSquadGroupNamePr return OpsZone:GetOwner() == Coalition and isClientInZone and isCaptureGroupInZone end +--- [User] Override this function in order to implement custom logic if a player can join a task or not. +-- @param #PLAYERTASK self +-- @param Wrapper.Group#GROUP Group +-- @param Wrapper.Client#CLIENT Client +-- @return #boolean Outcome True if player can join the task, false if not +function PLAYERTASK:CanJoinTask(Group, Client) + return true +end --- [Internal] Add a PLAYERTASKCONTROLLER for this task -- @param #PLAYERTASK self @@ -3555,6 +3563,10 @@ function PLAYERTASKCONTROLLER:_JoinTask(Task, Force, Group, Client) return self end + if not Task:CanJoinTask(Group, Client) then + return self + end + local force = false if type(Force) == "boolean" then force = Force From 04fcb985fe27bb9f5a065f7588aef8b5b9671e99 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Wed, 17 Sep 2025 12:04:34 +0200 Subject: [PATCH 184/234] #PLAYERTASK - Ensure call task failed on the controller --- Moose Development/Moose/Ops/PlayerTask.lua | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Ops/PlayerTask.lua b/Moose Development/Moose/Ops/PlayerTask.lua index 7ce6d57c2..95a98fcfd 100644 --- a/Moose Development/Moose/Ops/PlayerTask.lua +++ b/Moose Development/Moose/Ops/PlayerTask.lua @@ -98,7 +98,7 @@ PLAYERTASK = { --- PLAYERTASK class version. -- @field #string version -PLAYERTASK.version="0.1.27" +PLAYERTASK.version="0.1.28" --- Generic task condition. -- @type PLAYERTASK.Condition @@ -1227,7 +1227,10 @@ function PLAYERTASK:onafterFailed(From, Event, To) self.TargetMarker:Remove() end self.FinalState = "Failed" - self:__Done(-1) + if self.TaskController then + self.TaskController:__TaskFailed(-1,self) + end + self:__Done(-1.5) end if self.TaskController.Scoring then local clients,count = self:GetClientObjects() From 65d1c4187eff15d34465f37647c3e5dce5b0dbb5 Mon Sep 17 00:00:00 2001 From: smiki Date: Wed, 17 Sep 2025 20:19:17 +0200 Subject: [PATCH 185/234] [Fixed] attempt to index field 'Place' (a nil value) in LandingAfterEjection --- Moose Development/Moose/Core/Event.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Moose Development/Moose/Core/Event.lua b/Moose Development/Moose/Core/Event.lua index c5893325b..7cdec63ac 100644 --- a/Moose Development/Moose/Core/Event.lua +++ b/Moose Development/Moose/Core/Event.lua @@ -1508,7 +1508,9 @@ function EVENT:onEvent( Event ) else if Event.place:isExist() and Object.getCategory(Event.place) ~= Object.Category.SCENERY then Event.Place=AIRBASE:Find(Event.place) - Event.PlaceName=Event.Place:GetName() + if Event.Place then + Event.PlaceName=Event.Place:GetName() + end end end end From b320ba597a09bc40062f48c3c7dc11f5c6bede3b Mon Sep 17 00:00:00 2001 From: m1nd Date: Thu, 18 Sep 2025 00:32:48 +0200 Subject: [PATCH 186/234] fix: Add conditional checks for AWACS markers based on `AllowMarkers` property --- Moose Development/Moose/Ops/Awacs.lua | 64 ++++++++++++++++++++------- 1 file changed, 48 insertions(+), 16 deletions(-) diff --git a/Moose Development/Moose/Ops/Awacs.lua b/Moose Development/Moose/Ops/Awacs.lua index c4d4632fa..a2dff4db3 100644 --- a/Moose Development/Moose/Ops/Awacs.lua +++ b/Moose Development/Moose/Ops/Awacs.lua @@ -2021,7 +2021,9 @@ function AWACS:SetAdditionalZone(Zone, Draw) self.BorderZone = Zone if self.debug then Zone:DrawZone(self.coalition,{1,0.64,0},1,{1,0.64,0},0.2,1,true) - MARKER:New(Zone:GetCoordinate(),"Defensive Zone"):ToCoalition(self.coalition) + if self.AllowMarkers then + MARKER:New(Zone:GetCoordinate(),"Defensive Zone"):ToCoalition(self.coalition) + end elseif Draw then Zone:DrawZone(self.coalition,{1,0.64,0},1,{1,0.64,0},0.2,1,true) end @@ -2041,7 +2043,9 @@ function AWACS:SetRejectionZone(Zone,Draw) --MARKER:New(Zone:GetCoordinate(),"Rejection Zone"):ToAll() elseif self.debug then Zone:DrawZone(self.coalition,{1,0.64,0},1,{1,0.64,0},0.2,1,true) - MARKER:New(Zone:GetCoordinate(),"Rejection Zone"):ToCoalition(self.coalition) + if self.AllowMarkers then + MARKER:New(Zone:GetCoordinate(),"Rejection Zone"):ToCoalition(self.coalition) + end end return self end @@ -4094,10 +4098,14 @@ function AWACS:_CreateAnchorStackFromMarker(Name,Coord) if self.debug then AnchorStackOne.StationZone:DrawZone(self.coalition,{0,0,1},1,{0,0,1},0.2,5,true) local stationtag = string.format("Station: %s\nCoordinate: %s",newname,self.StationZone:GetCoordinate():ToStringLLDDM()) - AnchorStackOne.AnchorMarker=MARKER:New(AnchorStackOne.StationZone:GetCoordinate(),stationtag):ToCoalition(self.coalition) + if self.AllowMarkers then + AnchorStackOne.AnchorMarker=MARKER:New(AnchorStackOne.StationZone:GetCoordinate(),stationtag):ToCoalition(self.coalition) + end else local stationtag = string.format("Station: %s\nCoordinate: %s",newname,self.StationZone:GetCoordinate():ToStringLLDDM()) - AnchorStackOne.AnchorMarker=MARKER:New(AnchorStackOne.StationZone:GetCoordinate(),stationtag):ToCoalition(self.coalition) + if self.AllowMarkers then + AnchorStackOne.AnchorMarker=MARKER:New(AnchorStackOne.StationZone:GetCoordinate(),stationtag):ToCoalition(self.coalition) + end end self.AnchorStacks:Push(AnchorStackOne,newname) @@ -4140,10 +4148,14 @@ function AWACS:_CreateAnchorStack() --self.AnchorStacks:Flush() AnchorStackOne.StationZone:DrawZone(self.coalition,{0,0,1},1,{0,0,1},0.2,5,true) local stationtag = string.format("Station: %s\nCoordinate: %s",newname,self.StationZone:GetCoordinate():ToStringLLDDM()) - AnchorStackOne.AnchorMarker=MARKER:New(AnchorStackOne.StationZone:GetCoordinate(),stationtag):ToCoalition(self.coalition) + if self.AllowMarkers then + AnchorStackOne.AnchorMarker=MARKER:New(AnchorStackOne.StationZone:GetCoordinate(),stationtag):ToCoalition(self.coalition) + end else local stationtag = string.format("Station: %s\nCoordinate: %s",newname,self.StationZone:GetCoordinate():ToStringLLDDM()) - AnchorStackOne.AnchorMarker=MARKER:New(AnchorStackOne.StationZone:GetCoordinate(),stationtag):ToCoalition(self.coalition) + if self.AllowMarkers then + AnchorStackOne.AnchorMarker=MARKER:New(AnchorStackOne.StationZone:GetCoordinate(),stationtag):ToCoalition(self.coalition) + end end self.AnchorStacks:Push(AnchorStackOne,newname) else @@ -4167,10 +4179,14 @@ function AWACS:_CreateAnchorStack() if self.debug then AnchorStackOne.StationZone:DrawZone(self.coalition,{0,0,1},1,{0,0,1},0.2,5,true) local stationtag = string.format("Station: %s\nCoordinate: %s",newname,self.StationZone:GetCoordinate():ToStringLLDDM()) - AnchorStackOne.AnchorMarker=MARKER:New(AnchorStackOne.StationZone:GetCoordinate(),stationtag):ToCoalition(self.coalition) + if self.AllowMarkers then + AnchorStackOne.AnchorMarker=MARKER:New(AnchorStackOne.StationZone:GetCoordinate(),stationtag):ToCoalition(self.coalition) + end else local stationtag = string.format("Station: %s\nCoordinate: %s",newname,self.StationZone:GetCoordinate():ToStringLLDDM()) - AnchorStackOne.AnchorMarker=MARKER:New(AnchorStackOne.StationZone:GetCoordinate(),stationtag):ToCoalition(self.coalition) + if self.AllowMarkers then + AnchorStackOne.AnchorMarker=MARKER:New(AnchorStackOne.StationZone:GetCoordinate(),stationtag):ToCoalition(self.coalition) + end end self.AnchorStacks:Push(AnchorStackOne,newname) end @@ -5102,10 +5118,14 @@ function AWACS:AddCAPAirWing(AirWing,Zone) if self.debug then AnchorStackOne.StationZone:DrawZone(self.coalition,{0,0,1},1,{0,0,1},0.2,5,true) local stationtag = string.format("Station: %s\nCoordinate: %s",newname,self.StationZone:GetCoordinate():ToStringLLDDM()) - AnchorStackOne.AnchorMarker=MARKER:New(AnchorStackOne.StationZone:GetCoordinate(),stationtag):ToCoalition(self.coalition) + if self.AllowMarkers then + AnchorStackOne.AnchorMarker=MARKER:New(AnchorStackOne.StationZone:GetCoordinate(),stationtag):ToCoalition(self.coalition) + end else local stationtag = string.format("Station: %s\nCoordinate: %s",newname,self.StationZone:GetCoordinate():ToStringLLDDM()) - AnchorStackOne.AnchorMarker=MARKER:New(AnchorStackOne.StationZone:GetCoordinate(),stationtag):ToCoalition(self.coalition) + if self.AllowMarkers then + AnchorStackOne.AnchorMarker=MARKER:New(AnchorStackOne.StationZone:GetCoordinate(),stationtag):ToCoalition(self.coalition) + end end self.AnchorStacks:Push(AnchorStackOne,newname) AirWing.HasOwnStation = true @@ -5948,23 +5968,35 @@ function AWACS:onafterStart(From, Event, To) self.OpsZone:DrawZone(self.coalition,{1,0,0},1,{1,0,0},0.2,5,true) local AOCoordString = self.AOCoordinate:ToStringLLDDM() local Rocktag = string.format("FEZ: %s\nBulls Coordinate: %s",self.AOName,AOCoordString) - MARKER:New(self.AOCoordinate,Rocktag):ToCoalition(self.coalition) + if self.AllowMarkers then + MARKER:New(self.AOCoordinate,Rocktag):ToCoalition(self.coalition) + end self.StationZone:DrawZone(self.coalition,{0,0,1},1,{0,0,1},0.2,5,true) local stationtag = string.format("Station: %s\nCoordinate: %s",self.StationZoneName,self.StationZone:GetCoordinate():ToStringLLDDM()) if not self.GCI then - MARKER:New(self.StationZone:GetCoordinate(),stationtag):ToCoalition(self.coalition) + if self.AllowMarkers then + MARKER:New(self.StationZone:GetCoordinate(),stationtag):ToCoalition(self.coalition) + end self.OrbitZone:DrawZone(self.coalition,{0,1,0},1,{0,1,0},0.2,5,true) - MARKER:New(self.OrbitZone:GetCoordinate(),"AIC Orbit Zone"):ToCoalition(self.coalition) + if self.AllowMarkers then + MARKER:New(self.OrbitZone:GetCoordinate(),"AIC Orbit Zone"):ToCoalition(self.coalition) + end end else local AOCoordString = self.AOCoordinate:ToStringLLDDM() local Rocktag = string.format("FEZ: %s\nBulls Coordinate: %s",self.AOName,AOCoordString) - MARKER:New(self.AOCoordinate,Rocktag):ToCoalition(self.coalition) + if self.AllowMarkers then + MARKER:New(self.AOCoordinate,Rocktag):ToCoalition(self.coalition) + end if not self.GCI then - MARKER:New(self.OrbitZone:GetCoordinate(),"AIC Orbit Zone"):ToCoalition(self.coalition) + if self.AllowMarkers then + MARKER:New(self.OrbitZone:GetCoordinate(),"AIC Orbit Zone"):ToCoalition(self.coalition) + end end local stationtag = string.format("Station: %s\nCoordinate: %s",self.StationZoneName,self.StationZone:GetCoordinate():ToStringLLDDM()) - MARKER:New(self.StationZone:GetCoordinate(),stationtag):ToCoalition(self.coalition) + if self.AllowMarkers then + MARKER:New(self.StationZone:GetCoordinate(),stationtag):ToCoalition(self.coalition) + end end if not self.GCI then From c5b0be5d21944fa5f9f2da18a013cdca1e19dd91 Mon Sep 17 00:00:00 2001 From: Thomas <72444570+Applevangelist@users.noreply.github.com> Date: Mon, 22 Sep 2025 11:08:15 +0200 Subject: [PATCH 187/234] Update Airbase.lua Iraq Airbases --- Moose Development/Moose/Wrapper/Airbase.lua | 51 +++++++++++++-------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/Moose Development/Moose/Wrapper/Airbase.lua b/Moose Development/Moose/Wrapper/Airbase.lua index 58b1fea1e..23874b387 100644 --- a/Moose Development/Moose/Wrapper/Airbase.lua +++ b/Moose Development/Moose/Wrapper/Airbase.lua @@ -933,37 +933,52 @@ AIRBASE.Afghanistan = { --- 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_Kut_Airbase +-- * AIRBASE.Iraq.Al_Sahra_Airport -- * AIRBASE.Iraq.Al_Salam_Airbase --- * AIRBASE.Iraq.Balad_Airbase --- * AIRBASE.Iraq.Kirkuk_International_Airport --- * AIRBASE.Iraq.Bashur_Airport +-- * AIRBASE.Iraq.Al_Taji_Airport -- * AIRBASE.Iraq.Al_Taquddum_Airport --- * AIRBASE.Iraq.Qayyarah_Airfield_West +-- * AIRBASE.Iraq.Baghdad_International_Airport +-- * AIRBASE.Iraq.Balad_Airbase +-- * AIRBASE.Iraq.Bashur_Airport +-- * AIRBASE.Iraq.Erbil_International_Airport +-- * AIRBASE.Iraq.Sulaimaniyah_International_Airport +-- * AIRBASE.Iraq.H2_Airbase +-- * AIRBASE.Iraq.H3_Main_Airbase +-- * AIRBASE.Iraq.H3_Northwest_Airbase +-- * AIRBASE.Iraq.H3_Southwest_Airbase -- * AIRBASE.Iraq.K1_Base +-- * AIRBASE.Iraq.Kirkuk_International_Airport +-- * AIRBASE.Iraq.Mosul_International_Airport +-- * AIRBASE.Iraq.Qayyarah_Airfield_West +-- * AIRBASE.Iraq.Sulaimaniyah_International_Airport -- -- @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_Kut_Airport"] = "Al-Kut Airport", + ["Al_Sahra_Airport"] = "Al-Sahra Airport", ["Al_Salam_Airbase"] = "Al-Salam Airbase", - ["Balad_Airbase"] = "Balad Airbase", - ["Kirkuk_International_Airport"] = "Kirkuk International Airport", - ["Bashur_Airport"] = "Bashur Airport", + ["Al_Taji_Airport"] = "Al-Taji Airport", ["Al_Taquddum_Airport"] = "Al-Taquddum Airport", - ["Qayyarah_Airfield_West"] = "Qayyarah Airfield West", + ["Baghdad_International_Airport"] = "Baghdad International Airport", + ["Balad_Airbase"] = "Balad Airbase", + ["Bashur_Airport"] = "Bashur Airport", + ["Erbil_International_Airport"] = "Erbil International Airport", + ["H2_Airbase"] = "H-2 Airbase", + ["H3_Main_Airbase"] = "H-3 Main Airbase", + ["H3_Northwest_Airbase"] = "H-3 Northwest Airbase", + ["H3_Southwest_Airbase"] = "H-3 Southwest Airbase", ["K1_Base"] = "K1 Base", + ["Kirkuk_International_Airport"] = "Kirkuk International Airport", + ["Mosul_International_Airport"] = "Mosul International Airport", + ["Qayyarah_Airfield_West"] = "Qayyarah Airfield West", + ["Sulaimaniyah_International_Airport"] = "Sulaimaniyah International Airport", } + --- Airbases of the Germany Cold War map -- * AIRBASE.GermanyCW.Airracing_Frankfurt -- * AIRBASE.GermanyCW.Airracing_Frankfurt From c2f0ce0fa2de38b0abfaa37ed73327da9307105e Mon Sep 17 00:00:00 2001 From: Thomas <72444570+Applevangelist@users.noreply.github.com> Date: Mon, 22 Sep 2025 11:13:44 +0200 Subject: [PATCH 188/234] Update Airbase.lua --- Moose Development/Moose/Wrapper/Airbase.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/Moose Development/Moose/Wrapper/Airbase.lua b/Moose Development/Moose/Wrapper/Airbase.lua index 23874b387..7b56f195b 100644 --- a/Moose Development/Moose/Wrapper/Airbase.lua +++ b/Moose Development/Moose/Wrapper/Airbase.lua @@ -956,7 +956,6 @@ AIRBASE.Afghanistan = { -- -- @field Iraq AIRBASE.Iraq = { -{ ["Al_Asad_Airbase"] = "Al-Asad Airbase", ["Al_Kut_Airport"] = "Al-Kut Airport", ["Al_Sahra_Airport"] = "Al-Sahra Airport", From 6fdf3957bdb88a7477410f6e63d9c9a1b621a720 Mon Sep 17 00:00:00 2001 From: Thomas <72444570+Applevangelist@users.noreply.github.com> Date: Tue, 23 Sep 2025 15:19:10 +0200 Subject: [PATCH 189/234] Fix for #Storage.lua some missing string concats --- Moose Development/Moose/Wrapper/Storage.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Moose Development/Moose/Wrapper/Storage.lua b/Moose Development/Moose/Wrapper/Storage.lua index 4b445613c..4e6fbad2b 100644 --- a/Moose Development/Moose/Wrapper/Storage.lua +++ b/Moose Development/Moose/Wrapper/Storage.lua @@ -753,7 +753,7 @@ function STORAGE:LoadFromFile(Path,Filename) end end else - self:E("File for Liquids could not be found: "..tostring(Path).."\\"..tostring(Filename"_Liquids.csv")) + self:E("File for Liquids could not be found: "..tostring(Path).."\\"..tostring(Filename).."_Liquids.csv")) end end @@ -773,7 +773,7 @@ function STORAGE:LoadFromFile(Path,Filename) end end else - self:E("File for Aircraft could not be found: "..tostring(Path).."\\"..tostring(Filename"_Aircraft.csv")) + self:E("File for Aircraft could not be found: "..tostring(Path).."\\"..tostring(Filename).."_Aircraft.csv")) end end @@ -805,7 +805,7 @@ function STORAGE:LoadFromFile(Path,Filename) end end else - self:E("File for Weapons could not be found: "..tostring(Path).."\\"..tostring(Filename"_Weapons.csv")) + self:E("File for Weapons could not be found: "..tostring(Path).."\\"..tostring(Filename).."_Weapons.csv")) end end From 3beb98a5e9dbae24d9439e80c24e34c1e0bae0eb Mon Sep 17 00:00:00 2001 From: Thomas <72444570+Applevangelist@users.noreply.github.com> Date: Tue, 23 Sep 2025 15:26:38 +0200 Subject: [PATCH 190/234] Update Storage.lua --- Moose Development/Moose/Wrapper/Storage.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Moose Development/Moose/Wrapper/Storage.lua b/Moose Development/Moose/Wrapper/Storage.lua index 4e6fbad2b..5b5c23b3d 100644 --- a/Moose Development/Moose/Wrapper/Storage.lua +++ b/Moose Development/Moose/Wrapper/Storage.lua @@ -753,7 +753,7 @@ function STORAGE:LoadFromFile(Path,Filename) end end else - self:E("File for Liquids could not be found: "..tostring(Path).."\\"..tostring(Filename).."_Liquids.csv")) + self:E("File for Liquids could not be found: "..tostring(Path).."\\"..tostring(Filename).."_Liquids.csv") end end @@ -773,7 +773,7 @@ function STORAGE:LoadFromFile(Path,Filename) end end else - self:E("File for Aircraft could not be found: "..tostring(Path).."\\"..tostring(Filename).."_Aircraft.csv")) + self:E("File for Aircraft could not be found: "..tostring(Path).."\\"..tostring(Filename).."_Aircraft.csv") end end @@ -805,7 +805,7 @@ function STORAGE:LoadFromFile(Path,Filename) end end else - self:E("File for Weapons could not be found: "..tostring(Path).."\\"..tostring(Filename).."_Weapons.csv")) + self:E("File for Weapons could not be found: "..tostring(Path).."\\"..tostring(Filename).."_Weapons.csv") end end From ec0ff7afcd687e49d8ad2b17fd2e93342b727cd9 Mon Sep 17 00:00:00 2001 From: smiki Date: Wed, 24 Sep 2025 15:14:21 +0200 Subject: [PATCH 191/234] [Fixed] Zone Scans returns objects outside the zone --- Moose Development/Moose/Core/Zone.lua | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/Moose Development/Moose/Core/Zone.lua b/Moose Development/Moose/Core/Zone.lua index 104362abb..c2deb6823 100644 --- a/Moose Development/Moose/Core/Zone.lua +++ b/Moose Development/Moose/Core/Zone.lua @@ -1180,15 +1180,13 @@ function ZONE_RADIUS:Scan( ObjectCategories, UnitCategories ) local function EvaluateZone( ZoneObject ) --if ZoneObject:isExist() then --FF: isExist always returns false for SCENERY objects since DCS 2.2 and still in DCS 2.5 - if ZoneObject then + if ZoneObject and self:IsVec3InZone(ZoneObject:getPoint()) then -- Get object category. local ObjectCategory = Object.getCategory(ZoneObject) if ( ObjectCategory == Object.Category.UNIT and ZoneObject:isExist() and ZoneObject:isActive() ) or (ObjectCategory == Object.Category.STATIC and ZoneObject:isExist()) then - local CoalitionDCSUnit = ZoneObject:getCoalition() - local Include = false if not UnitCategories then -- Anything found is included. @@ -3308,14 +3306,12 @@ function ZONE_POLYGON:Scan( ObjectCategories, UnitCategories ) local function EvaluateZone( ZoneObject ) - if ZoneObject then + if ZoneObject and self:IsVec3InZone(ZoneObject:getPoint()) then local ObjectCategory = Object.getCategory(ZoneObject) if ( ObjectCategory == Object.Category.UNIT and ZoneObject:isExist() and ZoneObject:isActive() ) or (ObjectCategory == Object.Category.STATIC and ZoneObject:isExist()) then - local CoalitionDCSUnit = ZoneObject:getCoalition() - local Include = false if not UnitCategories then -- Anything found is included. @@ -3347,7 +3343,7 @@ function ZONE_POLYGON:Scan( ObjectCategories, UnitCategories ) end -- trying with box search - if ObjectCategory == Object.Category.SCENERY and self:IsVec3InZone(ZoneObject:getPoint()) then + if ObjectCategory == Object.Category.SCENERY then local SceneryType = ZoneObject:getTypeName() local SceneryName = ZoneObject:getName() self.ScanData.Scenery[SceneryType] = self.ScanData.Scenery[SceneryType] or {} From 8fb4d4c7c634d8602bdd14e4b9cb8804333b6b56 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 25 Sep 2025 12:13:29 +0200 Subject: [PATCH 192/234] #CTLD - add CratesPickedUp at one more point --- Moose Development/Moose/Ops/CTLD.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Moose Development/Moose/Ops/CTLD.lua b/Moose Development/Moose/Ops/CTLD.lua index 556b03038..9dff3ecec 100644 --- a/Moose Development/Moose/Ops/CTLD.lua +++ b/Moose Development/Moose/Ops/CTLD.lua @@ -1417,7 +1417,7 @@ CTLD.FixedWingTypes = { --- CTLD class version. -- @field #string version -CTLD.version="1.3.37" +CTLD.version="1.3.38" --- Instantiate a new CTLD. -- @param #CTLD self @@ -3328,6 +3328,7 @@ function CTLD:_LoadCratesNearby(Group, Unit) self:_RefreshLoadCratesMenu(Group, Unit) -- clean up real world crates self:_CleanupTrackedCrates(crateidsloaded) + self:__CratesPickedUp(1, Group, Unit, loaded.Cargo) end end return self From 47ddc642394164c0b5df0998840d34a7ba01b471 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 25 Sep 2025 15:17:03 +0200 Subject: [PATCH 193/234] #EASYGCICAP added `EASYGCICAP:SetCAPEngageTargetTypes(types)` --- Moose Development/Moose/Ops/EasyGCICAP.lua | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Ops/EasyGCICAP.lua b/Moose Development/Moose/Ops/EasyGCICAP.lua index 5c789141f..8a902cad5 100644 --- a/Moose Development/Moose/Ops/EasyGCICAP.lua +++ b/Moose Development/Moose/Ops/EasyGCICAP.lua @@ -79,6 +79,7 @@ -- @field #number FuelLowThreshold -- @field #number FuelCriticalThreshold -- @field #boolean showpatrolpointmarks +-- @field #table EngageTargetTypes -- @extends Core.Fsm#FSM --- *“Airspeed, altitude, and brains. Two are always needed to successfully complete the flight.”* -- Unknown. @@ -237,6 +238,7 @@ EASYGCICAP = { FuelLowThreshold = 25, FuelCriticalThreshold = 10, showpatrolpointmarks = false, + EngageTargetTypes = {"Air"}, } --- Internal Squadron data type @@ -273,7 +275,7 @@ EASYGCICAP = { --- EASYGCICAP class version. -- @field #string version -EASYGCICAP.version="0.1.28" +EASYGCICAP.version="0.1.30" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO list @@ -330,6 +332,7 @@ function EASYGCICAP:New(Alias, AirbaseName, Coalition, EWRName) self.FuelLowThreshold = 25 self.FuelCriticalThreshold = 10 self.showpatrolpointmarks = false + self.EngageTargetTypes = {"Air"} -- Set some string id for output to DCS.log file. self.lid=string.format("EASYGCICAP %s | ", self.alias) @@ -608,6 +611,17 @@ function EASYGCICAP:SetCapStartTimeVariation(Start, End) return self end + +--- Set which target types CAP flights will prefer to engage, defaults to {"Air"} +-- @param #EASYGCICAP self +-- @param #table types Table of comma separated #string entries, defaults to {"Air"} (everything that flies and is not a weapon). Useful other options are e.g. {"Bombers"}, {"Fighters"}, +-- or {"Helicopters"} or combinations like {"Bombers", "Fighters", "UAVs"}. See [Hoggit Wiki](https://wiki.hoggitworld.com/view/DCS_enum_attributes). +-- @return #EASYGCICAP self +function EASYGCICAP:SetCAPEngageTargetTypes(types) + self.EngageTargetTypes = types or {"Air"} + return self +end + --- Add an AirWing to the manager -- @param #EASYGCICAP self -- @param #string Airbasename @@ -706,6 +720,7 @@ function EASYGCICAP:_AddAirwing(Airbasename, Alias) local NoGoZoneSet = self.NoGoZoneSet local FuelLow = self.FuelLowThreshold or 25 local FuelCritical = self.FuelCriticalThreshold or 10 + local EngageTypes = self.EngageTargetTypes or {"Air"} function CAP_Wing:onbeforeFlightOnMission(From, Event, To, Flightgroup, Mission) local flightgroup = Flightgroup -- Ops.FlightGroup#FLIGHTGROUP @@ -720,7 +735,7 @@ function EASYGCICAP:_AddAirwing(Airbasename, Alias) flightgroup:GetGroup():SetOptionLandingOverheadBreak() if Mission.type ~= AUFTRAG.Type.TANKER and Mission.type ~= AUFTRAG.Type.AWACS and Mission.type ~= AUFTRAG.Type.RECON then flightgroup:SetDetection(true) - flightgroup:SetEngageDetectedOn(engagerange,{"Air"},GoZoneSet,NoGoZoneSet) + flightgroup:SetEngageDetectedOn(engagerange,EngageTypes,GoZoneSet,NoGoZoneSet) flightgroup:SetOutOfAAMRTB() flightgroup:SetFuelLowRTB(true) flightgroup:SetFuelLowThreshold(FuelLow) From aec69884dc2ca86b306ef4e14fd9fe649e90ccdf Mon Sep 17 00:00:00 2001 From: smiki Date: Fri, 26 Sep 2025 15:13:03 +0200 Subject: [PATCH 194/234] [ADDED] CTLD. UH-60L DAP default unit capability --- Moose Development/Moose/Ops/CTLD.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/Moose Development/Moose/Ops/CTLD.lua b/Moose Development/Moose/Ops/CTLD.lua index 9dff3ecec..0c354709c 100644 --- a/Moose Development/Moose/Ops/CTLD.lua +++ b/Moose Development/Moose/Ops/CTLD.lua @@ -1396,6 +1396,7 @@ CTLD.UnitTypeCapabilities = { ["Hercules"] = {type="Hercules", crates=true, troops=true, cratelimit = 7, trooplimit = 64, length = 25, cargoweightlimit = 19000}, -- 19t cargo, 64 paratroopers. --Actually it's longer, but the center coord is off-center of the model. ["UH-60L"] = {type="UH-60L", crates=true, troops=true, cratelimit = 2, trooplimit = 20, length = 16, cargoweightlimit = 3500}, -- 4t cargo, 20 (unsec) seats + ["UH-60L_DAP"] = {type="UH-60L_DAP", crates=false, troops=true, cratelimit = 0, trooplimit = 2, length = 16, cargoweightlimit = 500}, -- UH-60L DAP is an attack helo but can do limited CSAR and CTLD ["MH-60R"] = {type="MH-60R", crates=true, troops=true, cratelimit = 2, trooplimit = 20, length = 16, cargoweightlimit = 3500}, -- 4t cargo, 20 (unsec) seats ["SH-60B"] = {type="SH-60B", crates=true, troops=true, cratelimit = 2, trooplimit = 20, length = 16, cargoweightlimit = 3500}, -- 4t cargo, 20 (unsec) seats ["AH-64D_BLK_II"] = {type="AH-64D_BLK_II", crates=false, troops=true, cratelimit = 0, trooplimit = 2, length = 17, cargoweightlimit = 200}, -- 2 ppl **outside** the helo From 362652ac6cdf9afef3e0ec80c73b67a0c04ba822 Mon Sep 17 00:00:00 2001 From: smiki Date: Fri, 26 Sep 2025 15:14:12 +0200 Subject: [PATCH 195/234] [ADDED] CSAR. UH-60L DAP aircraft type --- Moose Development/Moose/Ops/CSAR.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/Moose Development/Moose/Ops/CSAR.lua b/Moose Development/Moose/Ops/CSAR.lua index 56ec21ef5..d9d743d95 100644 --- a/Moose Development/Moose/Ops/CSAR.lua +++ b/Moose Development/Moose/Ops/CSAR.lua @@ -305,6 +305,7 @@ CSAR.AircraftType["Mi-24P"] = 8 CSAR.AircraftType["Mi-24V"] = 8 CSAR.AircraftType["Bell-47"] = 2 CSAR.AircraftType["UH-60L"] = 10 +CSAR.AircraftType["UH-60L_DAP"] = 2 CSAR.AircraftType["AH-64D_BLK_II"] = 2 CSAR.AircraftType["Bronco-OV-10A"] = 2 CSAR.AircraftType["MH-60R"] = 10 From b51e758516150d45a841a4d51d7373fb3e61f681 Mon Sep 17 00:00:00 2001 From: smiki Date: Tue, 30 Sep 2025 21:17:29 +0200 Subject: [PATCH 196/234] [ADDED] SET_OPSGROUP:CountAlive --- Moose Development/Moose/Core/Set.lua | 22 +++++++++++++++++++ .../Moose/Wrapper/Positionable.lua | 18 ++++++++------- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua index 06981e95f..5ee275fd5 100644 --- a/Moose Development/Moose/Core/Set.lua +++ b/Moose Development/Moose/Core/Set.lua @@ -7865,6 +7865,28 @@ do -- SET_OPSGROUP return self end + --- Iterate the SET_OPSGROUP and count how many GROUPs and UNITs are alive. + -- @param #SET_GROUP self + -- @return #number The number of GROUPs alive. + -- @return #number The number of UNITs alive. + function SET_OPSGROUP:CountAlive() + local CountG = 0 + local CountU = 0 + + local Set = self:GetSet() + + for GroupID, GroupData in pairs( Set ) do -- For each GROUP in SET_GROUP + if GroupData and GroupData:IsAlive() then + CountG = CountG + 1 + -- Count Units. + CountU = CountU + GroupData:GetGroup():CountAliveUnits() + end + + end + + return CountG, CountU + end + --- Finds an OPSGROUP based on the group name. -- @param #SET_OPSGROUP self -- @param #string GroupName Name of the group. diff --git a/Moose Development/Moose/Wrapper/Positionable.lua b/Moose Development/Moose/Wrapper/Positionable.lua index 65b145384..038eefe56 100644 --- a/Moose Development/Moose/Wrapper/Positionable.lua +++ b/Moose Development/Moose/Wrapper/Positionable.lua @@ -361,15 +361,17 @@ function POSITIONABLE:GetCoord() -- Get the current position. local PositionableVec3 = self:GetVec3() - if self.coordinate then - -- Update COORDINATE from 3D vector. - self.coordinate:UpdateFromVec3( PositionableVec3 ) - else - -- New COORDINATE. - self.coordinate = COORDINATE:NewFromVec3( PositionableVec3 ) - end + if PositionableVec3 then + if self.coordinate then + -- Update COORDINATE from 3D vector. + self.coordinate:UpdateFromVec3( PositionableVec3 ) + else + -- New COORDINATE. + self.coordinate = COORDINATE:NewFromVec3( PositionableVec3 ) + end - return self.coordinate + return self.coordinate + end end -- Error message. From 43b4a6834b021d999845a094f4ca2c9d9c6bb97f Mon Sep 17 00:00:00 2001 From: smiki Date: Wed, 1 Oct 2025 14:50:04 +0200 Subject: [PATCH 197/234] [FIXED] ZONE_POLYGON from RECT ME drawing rotation not taken into account. --- Moose Development/Moose/Core/Database.lua | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/Moose Development/Moose/Core/Database.lua b/Moose Development/Moose/Core/Database.lua index a8c814260..20d6c94ce 100644 --- a/Moose Development/Moose/Core/Database.lua +++ b/Moose Development/Moose/Core/Database.lua @@ -577,13 +577,22 @@ do -- Zones and Pathlines -- For a rectangular polygon drawing, we have the width (y) and height (x). local w=objectData.width local h=objectData.height + local rotation = UTILS.ToRadian(objectData.angle or 0) - -- Create points from center using with and height (width for y and height for x is a bit confusing, but this is how ED implemented it). - local points={} - points[1]={x=vec2.x-h/2, y=vec2.y+w/2} --Upper left - points[2]={x=vec2.x+h/2, y=vec2.y+w/2} --Upper right - points[3]={x=vec2.x+h/2, y=vec2.y-w/2} --Lower right - points[4]={x=vec2.x-h/2, y=vec2.y-w/2} --Lower left + local dx = vec2.x + math.abs(w) + local dy = vec2.y + math.abs(h) + + local sinRot = math.sin(-rotation) + local cosRot = math.cos(-rotation) + dx = (dx / 2) + dy = (dy / 2) + + local points = { + { x = -dx * cosRot - (-dy * sinRot) + vec2.x, y = -dx * sinRot + (-dy * cosRot) + vec2.y }, + { x = dx * cosRot - (-dy * sinRot) + vec2.x, y = dx * sinRot + (-dy * cosRot) + vec2.y }, + { x = dx * cosRot - (dy * sinRot) + vec2.x, y = dx * sinRot + (dy * cosRot) + vec2.y }, + { x = -dx * cosRot - (dy * sinRot) + vec2.x, y = -dx * sinRot + (dy * cosRot) + vec2.y }, + } --local coord=COORDINATE:NewFromVec2(vec2):MarkToAll("MapX, MapY") From f39236c8fd8954f71b9a4921d4b398f6436db5c9 Mon Sep 17 00:00:00 2001 From: smiki Date: Wed, 1 Oct 2025 14:59:59 +0200 Subject: [PATCH 198/234] [FIXED] ZONE_POLYGON from RECT ME drawing rotation not taken into account. --- Moose Development/Moose/Core/Database.lua | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Moose Development/Moose/Core/Database.lua b/Moose Development/Moose/Core/Database.lua index 20d6c94ce..e74461eca 100644 --- a/Moose Development/Moose/Core/Database.lua +++ b/Moose Development/Moose/Core/Database.lua @@ -579,13 +579,10 @@ do -- Zones and Pathlines local h=objectData.height local rotation = UTILS.ToRadian(objectData.angle or 0) - local dx = vec2.x + math.abs(w) - local dy = vec2.y + math.abs(h) - local sinRot = math.sin(-rotation) local cosRot = math.cos(-rotation) - dx = (dx / 2) - dy = (dy / 2) + local dx = w / 2 + local dy = h / 2 local points = { { x = -dx * cosRot - (-dy * sinRot) + vec2.x, y = -dx * sinRot + (-dy * cosRot) + vec2.y }, From aace98545aed59648b89197ae553efeafbe1dce0 Mon Sep 17 00:00:00 2001 From: smiki Date: Wed, 1 Oct 2025 15:07:18 +0200 Subject: [PATCH 199/234] [FIXED] ZONE_POLYGON from RECT ME drawing rotation not taken into account. --- Moose Development/Moose/Core/Database.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Core/Database.lua b/Moose Development/Moose/Core/Database.lua index e74461eca..b66ee1787 100644 --- a/Moose Development/Moose/Core/Database.lua +++ b/Moose Development/Moose/Core/Database.lua @@ -581,8 +581,8 @@ do -- Zones and Pathlines local sinRot = math.sin(-rotation) local cosRot = math.cos(-rotation) - local dx = w / 2 - local dy = h / 2 + local dx = h / 2 + local dy = w / 2 local points = { { x = -dx * cosRot - (-dy * sinRot) + vec2.x, y = -dx * sinRot + (-dy * cosRot) + vec2.y }, From 935b52c48984a21b8683ccd8b5475032ee08dd31 Mon Sep 17 00:00:00 2001 From: smiki Date: Wed, 1 Oct 2025 15:11:44 +0200 Subject: [PATCH 200/234] [FIXED] ZONE_POLYGON from RECT ME drawing rotation not taken into account. --- Moose Development/Moose/Core/Database.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Core/Database.lua b/Moose Development/Moose/Core/Database.lua index b66ee1787..e1a1e732d 100644 --- a/Moose Development/Moose/Core/Database.lua +++ b/Moose Development/Moose/Core/Database.lua @@ -579,8 +579,8 @@ do -- Zones and Pathlines local h=objectData.height local rotation = UTILS.ToRadian(objectData.angle or 0) - local sinRot = math.sin(-rotation) - local cosRot = math.cos(-rotation) + local sinRot = math.sin(rotation) + local cosRot = math.cos(rotation) local dx = h / 2 local dy = w / 2 From 5ae6495e6949b2a202f0dde1f7b716203d4cb5d1 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sun, 5 Oct 2025 13:51:55 +0200 Subject: [PATCH 201/234] #CSAR Added functionality to determine if a landing took place at a helo base (named "H ..." in newer maps). --- Moose Development/Moose/Ops/CSAR.lua | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/Moose Development/Moose/Ops/CSAR.lua b/Moose Development/Moose/Ops/CSAR.lua index d9d743d95..9ba328b5c 100644 --- a/Moose Development/Moose/Ops/CSAR.lua +++ b/Moose Development/Moose/Ops/CSAR.lua @@ -31,7 +31,7 @@ -- @image OPS_CSAR.jpg --- --- Last Update July 2025 +-- Last Update Oct 2025 ------------------------------------------------------------------------- --- **CSAR** class, extends Core.Base#BASE, Core.Fsm#FSM @@ -315,7 +315,7 @@ CSAR.AircraftType["CH-47Fbl1"] = 31 --- CSAR class version. -- @field #string version -CSAR.version="1.0.33" +CSAR.version="1.0.34" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- ToDo list @@ -1244,7 +1244,10 @@ function CSAR:_EventHandler(EventData) if _place:GetCoalition() == self.coalition or _place:GetCoalition() == coalition.side.NEUTRAL then self:__Landed(2,_event.IniUnitName, _place) - self:_ScheduledSARFlight(_event.IniUnitName,_event.IniGroupName,true,true) + local IsHeloBase = false + local ABName = _place:GetName() + if ABName and string.find(ABName,"^H") then IsHeloBase = true end -- if name starts with an H it's an (possibly elevated) helo base on current maps + self:_ScheduledSARFlight(_event.IniUnitName,_event.IniGroupName,true,true,IsHeloBase) else self:T(string.format("Airfield %d, Unit %d", _place:GetCoalition(), _unit:GetCoalition())) end @@ -1731,8 +1734,9 @@ end -- @param #string heliname Heli name -- @param #string groupname Group name -- @param #boolean isairport If true, EVENT.Landing took place at an airport or FARP --- @param #boolean noreschedule If true, do not try to reschedule this is distances are not ok (coming from landing event) -function CSAR:_ScheduledSARFlight(heliname,groupname, isairport, noreschedule) +-- @param #boolean noreschedule If true, do not try to reschedule this if distances are not ok (coming from landing event) +-- @param #boolean IsHeloBase If true, landing took place at a Helo Base (name "H ..." on current maps) +function CSAR:_ScheduledSARFlight(heliname,groupname, isairport, noreschedule, IsHeloBase) self:T(self.lid .. " _ScheduledSARFlight") self:T({heliname,groupname}) local _heliUnit = self:_GetSARHeli(heliname) @@ -1758,7 +1762,7 @@ function CSAR:_ScheduledSARFlight(heliname,groupname, isairport, noreschedule) self:T(self.lid.."[Drop off debug] Check distance to MASH for "..heliname.." Distance km: "..math.floor(_dist/1000)) - if ( _dist < self.FARPRescueDistance or isairport ) and _heliUnit:InAir() == false then + if ( _dist < self.FARPRescueDistance or isairport ) and ((_heliUnit:InAir() == false) or (IsHeloBase == true)) then self:T(self.lid.."[Drop off debug] Distance ok, door check") if self.pilotmustopendoors and self:_IsLoadingDoorOpen(heliname) == false then self:_DisplayMessageToSAR(_heliUnit, "Open the door to let me out!", self.messageTime, true, true) @@ -1773,7 +1777,7 @@ function CSAR:_ScheduledSARFlight(heliname,groupname, isairport, noreschedule) --queue up if not noreschedule then self:__Returning(5,heliname,_woundedGroupName, isairport) - self:ScheduleOnce(5,self._ScheduledSARFlight,self,heliname,groupname, isairport, noreschedule) + self:ScheduleOnce(5,self._ScheduledSARFlight,self,heliname,groupname, isairport, noreschedule, IsHeloBase) end return self end From db138be5f3da8aa05384e142a22e8f2dd63003f4 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sun, 5 Oct 2025 13:52:22 +0200 Subject: [PATCH 202/234] #SCoRING - suppress autocreation of CSV files better --- Moose Development/Moose/Functional/Scoring.lua | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Functional/Scoring.lua b/Moose Development/Moose/Functional/Scoring.lua index c3f4bd4b6..2c49243f8 100644 --- a/Moose Development/Moose/Functional/Scoring.lua +++ b/Moose Development/Moose/Functional/Scoring.lua @@ -321,7 +321,9 @@ function SCORING:New( GameName, SavePath, AutoSave ) -- Create the CSV file. self.AutoSavePath = SavePath self.AutoSave = AutoSave or true - self:OpenCSV( GameName ) + if self.AutoSave == true then + self:OpenCSV( GameName ) + end return self @@ -1935,7 +1937,7 @@ function SCORING:ScoreCSV( PlayerName, TargetPlayerName, ScoreType, ScoreTimes, TargetUnitType = TargetUnitType or "" TargetUnitName = TargetUnitName or "" - if lfs and io and os and self.AutoSave then + if lfs and io and os and self.AutoSave == true and self.CSVFile ~= nil then self.CSVFile:write( '"' .. self.GameName .. '"' .. ',' .. '"' .. self.RunTime .. '"' .. ',' .. From 6e45ee558e6882ceaf331b26f73b82888a851441 Mon Sep 17 00:00:00 2001 From: smiki Date: Sun, 5 Oct 2025 16:57:33 +0200 Subject: [PATCH 203/234] [FIXED] SPAWNSTATIC not registering script spawned static templates therefore ReSpawn is not working. --- Moose Development/Moose/Core/SpawnStatic.lua | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/Moose Development/Moose/Core/SpawnStatic.lua b/Moose Development/Moose/Core/SpawnStatic.lua index 332e7e464..06a9179e1 100644 --- a/Moose Development/Moose/Core/SpawnStatic.lua +++ b/Moose Development/Moose/Core/SpawnStatic.lua @@ -633,16 +633,15 @@ function SPAWNSTATIC:_SpawnStatic(Template, CountryID) if self.StaticCopyFrom ~= nil then mystatic.StaticCopyFrom = self.StaticCopyFrom - if not _DATABASE.Templates.Statics[Template.name] then - local TemplateGroup={} - TemplateGroup.units={} - TemplateGroup.units[1]=Template - TemplateGroup.x=Template.x - TemplateGroup.y=Template.y - TemplateGroup.name=Template.name - _DATABASE:_RegisterStaticTemplate( TemplateGroup, self.CoalitionID, self.CategoryID, CountryID ) - end end + + local TemplateGroup={} + TemplateGroup.units={} + TemplateGroup.units[1]=Template + TemplateGroup.x=Template.x + TemplateGroup.y=Template.y + TemplateGroup.name=Template.name + _DATABASE:_RegisterStaticTemplate( TemplateGroup, self.CoalitionID, self.CategoryID, CountryID ) return mystatic end From fd4ea81e46cf8b63fb7f6d9d7eb1e802762b72bc Mon Sep 17 00:00:00 2001 From: frankiep95 <38260710+frankiep95@users.noreply.github.com> Date: Sun, 5 Oct 2025 12:50:56 -0400 Subject: [PATCH 204/234] minor fixes to grading, and BRC callout --- Moose Development/Moose/Ops/Airboss.lua | 47 ++++++++++++++++--------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/Moose Development/Moose/Ops/Airboss.lua b/Moose Development/Moose/Ops/Airboss.lua index fcf723279..f50802de2 100644 --- a/Moose Development/Moose/Ops/Airboss.lua +++ b/Moose Development/Moose/Ops/Airboss.lua @@ -21,7 +21,7 @@ -- * Multiple carrier support due to object oriented approach. -- * Unlimited number of players. -- * Persistence of player results (optional). LSO grading data is saved to csv file. --- * Trap sheet (optional). +-- * Trap sheet (optional). -- * Finite State Machine (FSM) implementation. -- -- **Supported Carriers:** @@ -6870,6 +6870,9 @@ function AIRBOSS:_AddMarshalGroup( flight, stack ) -- Convert to clock string. local Ccharlie = UTILS.SecondsToClock( flight.Tcharlie ) + -- Make sure brc is never above 360 + brc = brc % 360 + -- Combined marshal call. self:_MarshalCallArrived( flight.onboard, flight.case, brc, alt, Ccharlie, P ) @@ -8062,7 +8065,7 @@ end --- Check current player status. -- @param #AIRBOSS self function AIRBOSS:_CheckPlayerStatus() - + local tomcat = playerData.actype == AIRBOSS.AircraftCarrier.F14A or playerData.actype == AIRBOSS.AircraftCarrier.F14B -- Loop over all players. for _playerName, _playerData in pairs( self.players ) do local playerData = _playerData -- #AIRBOSS.PlayerData @@ -8087,9 +8090,13 @@ function AIRBOSS:_CheckPlayerStatus() playerData.wrappedUpAtWakeFull = true-- VNAO Edit - Added elseif math.abs(playerData.unit:GetRoll()) >45 then-- VNAO Edit - Added playerData.wrappedUpAtWakeUnderline = true -- VNAO Edit - Added - elseif math.abs(playerData.unit:GetRoll()) <20 and math.abs(playerData.unit:GetRoll()) >=10 then -- VNAO Edit - Added a new AA comment based on discussion with Lipps today, and going to replace the AA at the X with the original LUL comments + elseif math.abs(playerData.unit:GetRoll()) <20 and math.abs(playerData.unit:GetRoll()) >=10 and not tomcat then -- VNAO Edit - Added a new AA comment based on discussion with Lipps today, and going to replace the AA at the X with the original LUL comments playerData.AAatWakeLittle = true -- VNAO Edit - Added - elseif math.abs(playerData.unit:GetRoll()) <10 and math.abs(playerData.unit:GetRoll()) >=2 then -- VNAO Edit - Added a new AA comment based on discussion with Lipps today, and going to replace the AA at the X with the original LUL comments + elseif math.abs(playerData.unit:GetRoll()) <10 and math.abs(playerData.unit:GetRoll()) >=2 and not tomcat then -- VNAO Edit - Added a new AA comment based on discussion with Lipps today, and going to replace the AA at the X with the original LUL comments + playerData.AAatWakeFull = true -- VNAO Edit - Added + elseif math.abs(playerData.unit:GetRoll()) <12 and math.abs(playerData.unit:GetRoll()) >=5 and tomcat then -- VNAO Edit - Added a new AA comment based on discussion with Lipps today, and going to replace the AA at the X with the original LUL comments + playerData.AAatWakeLittle = true -- VNAO Edit - Added + elseif math.abs(playerData.unit:GetRoll()) <5 and math.abs(playerData.unit:GetRoll()) >=2 and tomcat then -- VNAO Edit - Added a new AA comment based on discussion with Lipps today, and going to replace the AA at the X with the original LUL comments playerData.AAatWakeFull = true -- VNAO Edit - Added elseif math.abs(playerData.unit:GetRoll()) <2 then -- VNAO Edit - Added a new AA comment based on discussion with Lipps today, and going to replace the AA at the X with the original LUL comments playerData.AAatWakeUnderline = true -- VNAO Edit - Added @@ -8335,7 +8342,7 @@ end function AIRBOSS:_SetTimeInGroove( playerData ) -- Set time in the groove - if playerData.TIG0 then + if playerData.TIG0 > 2 then --circuit added to prevent negative groove time playerData.Tgroove = timer.getTime() - playerData.TIG0 - 1.5 -- VNAO Edit - Subtracting an extra 1.5 else playerData.Tgroove = 999 @@ -12671,7 +12678,7 @@ function AIRBOSS:_LSOgrade( playerData ) local TIG = "" -- Analyse flight data and convert to LSO text. if playerData.Tgroove and playerData.Tgroove <= 360 and playerData.case < 3 then --Circuit Added - TIG = self:_EvalGrooveTime( playerData ) --Circuit Added + TIG = self:_EvalGrooveTime( playerData ) or "N/A" --Circuit Added end --Circuit Added local GXX, nXX = self:_Flightdata2Text( playerData, AIRBOSS.GroovePos.XX ) local GIM, nIM = self:_Flightdata2Text( playerData, AIRBOSS.GroovePos.IM ) @@ -12865,16 +12872,21 @@ function AIRBOSS:_LSOgrade( playerData ) end - -- VNAO EDIT: Subtract 1pt from overall grade if it is a 1 wire. If it's already a 1pt pass, ignore. - if playerData.wire == 1 and points > 1 then -- VNAO EDIT: added - if points == 4 then -- VNAO EDIT: added - points = 3 -- VNAO EDIT: added - grade = "(OK)" -- VNAO EDIT: added - elseif points == 3 then -- VNAO EDIT: added - points = 2 -- VNAO EDIT: added - grade = "--" -- VNAO EDIT: added - end -- VNAO EDIT: added - end -- VNAO EDIT: added + -- -- VNAO EDIT: Subtract 1pt from overall grade if it is a 1 wire. If it's already a 1pt pass, ignore. + -- if playerData.wire == 1 and points > 1 then -- VNAO EDIT: added + -- if points == 4 then -- VNAO EDIT: added + -- points = 3 -- VNAO EDIT: added + -- grade = "(OK)" -- VNAO EDIT: added + -- elseif points == 3 then -- VNAO EDIT: added + -- points = 2 -- VNAO EDIT: added + -- grade = "--" -- VNAO EDIT: added + -- end -- VNAO EDIT: added + -- end -- VNAO EDIT: added + + -- Circuit edit only take points awary from a 1 wire if there are more than 4 other deviations + if playerData.wire == 1 and points >= 3 and N > 4 then + points = points -1 + end env.info("Returning: " .. grade .. " " .. points .. " " .. G) @@ -12950,6 +12962,7 @@ function AIRBOSS:_Flightdata2Text( playerData, groovestep ) -- Speed via AoA. Depends on aircraft type. local S = nil + local A = nil --circuit moved this line to be seen outside of this scope if step~=AIRBOSS.PatternStep.GROOVE_IW then -- VNAO Edit - Added To avoid getting an AOA or GS grade in the wires... let's just check left or right in the wires if AIRBOSS.PatternStep.GROOVE_AR and playerData.waveoff == true and playerData.owo == true then -- VNAO Edit - Added -- env.info('Adam MOOSE Edit -AR and waved off so do not add AOA or GS errors to comments ') -- VNAO Edit - Added @@ -12970,7 +12983,7 @@ function AIRBOSS:_Flightdata2Text( playerData, groovestep ) end -- Glideslope/altitude. Good [-0.3, 0.4] asymmetric! - local A = nil + if GSE > self.gle.HIGH then A = underline( "H" ) elseif GSE > self.gle.High then From 5404f9ef199b0c2f6df28399650074ba8a340d77 Mon Sep 17 00:00:00 2001 From: frankiep95 <38260710+frankiep95@users.noreply.github.com> Date: Sun, 5 Oct 2025 13:31:18 -0400 Subject: [PATCH 205/234] Minor Fixes to grading fixed high low comments and BRC comment --- Moose Development/Moose/Ops/Airboss.lua | 122 +++--------------------- 1 file changed, 11 insertions(+), 111 deletions(-) diff --git a/Moose Development/Moose/Ops/Airboss.lua b/Moose Development/Moose/Ops/Airboss.lua index d602c9018..6a6819600 100644 --- a/Moose Development/Moose/Ops/Airboss.lua +++ b/Moose Development/Moose/Ops/Airboss.lua @@ -8145,8 +8145,7 @@ end --- Check current player status. -- @param #AIRBOSS self function AIRBOSS:_CheckPlayerStatus() - local tomcat = playerData.actype == AIRBOSS.AircraftCarrier.F14A or playerData.actype == AIRBOSS.AircraftCarrier.F14B - -- Loop over all players. + -- Loop over all players. for _playerName, _playerData in pairs( self.players ) do local playerData = _playerData -- #AIRBOSS.PlayerData @@ -8170,13 +8169,9 @@ function AIRBOSS:_CheckPlayerStatus() playerData.wrappedUpAtWakeFull = true-- VNAO Edit - Added elseif math.abs(playerData.unit:GetRoll()) >45 then-- VNAO Edit - Added playerData.wrappedUpAtWakeUnderline = true -- VNAO Edit - Added - elseif math.abs(playerData.unit:GetRoll()) <20 and math.abs(playerData.unit:GetRoll()) >=10 and not tomcat then -- VNAO Edit - Added a new AA comment based on discussion with Lipps today, and going to replace the AA at the X with the original LUL comments + elseif math.abs(playerData.unit:GetRoll()) <20 and math.abs(playerData.unit:GetRoll()) >=10 then -- VNAO Edit - Added a new AA comment based on discussion with Lipps today, and going to replace the AA at the X with the original LUL comments playerData.AAatWakeLittle = true -- VNAO Edit - Added - elseif math.abs(playerData.unit:GetRoll()) <10 and math.abs(playerData.unit:GetRoll()) >=2 and not tomcat then -- VNAO Edit - Added a new AA comment based on discussion with Lipps today, and going to replace the AA at the X with the original LUL comments - playerData.AAatWakeFull = true -- VNAO Edit - Added - elseif math.abs(playerData.unit:GetRoll()) <12 and math.abs(playerData.unit:GetRoll()) >=5 and tomcat then -- VNAO Edit - Added a new AA comment based on discussion with Lipps today, and going to replace the AA at the X with the original LUL comments - playerData.AAatWakeLittle = true -- VNAO Edit - Added - elseif math.abs(playerData.unit:GetRoll()) <5 and math.abs(playerData.unit:GetRoll()) >=2 and tomcat then -- VNAO Edit - Added a new AA comment based on discussion with Lipps today, and going to replace the AA at the X with the original LUL comments + elseif math.abs(playerData.unit:GetRoll()) <10 and math.abs(playerData.unit:GetRoll()) >=2 then -- VNAO Edit - Added a new AA comment based on discussion with Lipps today, and going to replace the AA at the X with the original LUL comments playerData.AAatWakeFull = true -- VNAO Edit - Added elseif math.abs(playerData.unit:GetRoll()) <2 then -- VNAO Edit - Added a new AA comment based on discussion with Lipps today, and going to replace the AA at the X with the original LUL comments playerData.AAatWakeUnderline = true -- VNAO Edit - Added @@ -9651,7 +9646,7 @@ end --- Break entry for case I/II recoveries. -- @param #AIRBOSS self -- @param #AIRBOSS.PlayerData playerData Player data table. -function AIRBOSS:_BreakEntry( playerData ) --Adam Edits begin 7/24/23 +function AIRBOSS:_BreakEntry( playerData ) -- Get distances between carrier and player unit (parallel and perpendicular to direction of movement of carrier) local X, Z = self:_GetDistances( playerData.unit ) @@ -9662,111 +9657,16 @@ function AIRBOSS:_BreakEntry( playerData ) --Adam Edits begin 7/24/23 return end - local stern = self:_GetSternCoord() - local coord = playerData.unit:GetCoordinate() - local dist = coord:Get2DDistance( stern ) - - --adam edits - local playerCallsign = playerData.unit:GetCallsign() - --trigger.action.outText(' Hornet is hook down on pre-break entry for testing hook argument ', 5) - --trigger.action.outText(' Hornet callsign is '..playerCallsign, 5) - local playerName = playerData.name - local unit = playerData.unit - - --local playerName = unit:GetName() - --trigger.action.outText(' Hornet name is '..playerName, 5) - local unitClient = Unit.getByName(unit:GetName()) - local hookArgument = unitClient:getDrawArgumentValue(25) - local hookArgument_Tomcat = unitClient:getDrawArgumentValue(1305) - local speedMPS = playerData.unit:GetVelocityMPS() - local speedKTS = UTILS.MpsToKnots( speedMPS ) - local player_alt = playerData.unit:GetAltitude() - - player_alt_feet = player_alt * 3.28 - player_alt_feet = player_alt_feet/10 - player_alt_feet = math.floor(player_alt_feet)*10 - - local player_velocity_round = speedKTS * 1.00 - player_velocity_round = player_velocity_round/10 - player_velocity_round = math.floor(player_velocity_round)*10 - - local player_alt_feet = player_alt * 3.28 - player_alt_feet = player_alt_feet/10 - player_alt_feet = math.floor(player_alt_feet)*10 - - local Play_SH_Sound = USERSOUND:New( "Airboss Soundfiles/GreatBallsOfFire.ogg" ) - local Play_666SH_Sound = USERSOUND:New( "Airboss Soundfiles/Runninwiththedevil.ogg" ) - local playerType = playerData.actype - - - - if dist <1000 and clientSHBFlag == false then - - if speedKTS > 450 and speedKTS < 590 then - if player_alt_feet < 1500 then - if hookArgument > 0 or hookArgument_Tomcat > 0 then - --trigger.action.outText(' 1 - Hornet is hook down so SHB!!!! Hook argument is: '..hookArgument, 5) - playerData.shb = true - trigger.action.outText(playerName..' performing a Sierra Hotel Break in a '..playerType, 10) - local sh_message_to_discord = ('**'..playerName..' is performing a Sierra Hotel Break in a '..playerType..' at '..player_velocity_round..' knots and '..player_alt_feet..' feet!**') - HypeMan.sendBotMessage(sh_message_to_discord) - Play_SH_Sound:ToAll() - clientSHBFlag = true - else - --trigger.action.outText(' Hornet is hook up on initial and just fast so no SHB. Hook argument is: '..hookArgument, 5) - playerData.shb = false - end - -- Next step: Early Break. - else - end - elseif speedKTS > 589 then - if player_alt_feet < 625 and player_alt_feet >575 then --SHB 666 - if hookArgument > 0 or hookArgument_Tomcat > 0 then - --trigger.action.outText(' 1 - Hornet is hook down so SHB!!!! Hook argument is: '..hookArgument, 5) - playerData.shb = true - trigger.action.outText(playerName..' performing a 666 Sierra Hotel Break in a '..playerType, 10) - local sh_message_to_discord = ('**'..playerName..' is performing a 666 Sierra Hotel Break in a '..playerType..' at '..player_velocity_round..' knots and '..player_alt_feet..' feet!**') - HypeMan.sendBotMessage(sh_message_to_discord) - Play_666SH_Sound:ToAll() - clientSHBFlag = true - else - --trigger.action.outText(' Hornet is hook up on initial and just fast so no SHB. Hook argument is: '..hookArgument, 5) - playerData.shb = false - end - else - if hookArgument > 0 or hookArgument_Tomcat > 0 then - --trigger.action.outText(' 1 - Hornet is hook down so SHB!!!! Hook argument is: '..hookArgument, 5) - playerData.shb = true - trigger.action.outText(playerName..' performing a Sierra Hotel Break in a '..playerType, 10) - local sh_message_to_discord = ('**'..playerName..' is performing a Sierra Hotel Break in a '..playerType..' at '..player_velocity_round..' knots and '..player_alt_feet..' feet!**') - HypeMan.sendBotMessage(sh_message_to_discord) - Play_SH_Sound:ToAll() - clientSHBFlag = true - else - --trigger.action.outText(' Hornet is hook up on initial and just fast so no SHB. Hook argument is: '..hookArgument, 5) - playerData.shb = false - end - end - else - --trigger.action.outText(' Hornet is less than 400 kts so not SHB.... ', 5) - end - else - --trigger.action.outText(' ******TEST OF of Break Entry and distance to CVN is: '..dist, 5) - - end - - -- Check if we are in front of the boat (diffX > 0). if self:_CheckLimits( X, Z, self.BreakEntry ) then - --trigger.action.outText(' 2 - Hornet is hook down on break entry for testing hook argument ', 5) -- Hint for player about altitude, AoA etc. self:_PlayerHint( playerData ) + -- Next step: Early Break. self:_SetPlayerStep( playerData, AIRBOSS.PatternStep.EARLYBREAK ) - clientSHBFlag = false end -end--Adam Edits end 7/24/23 +end --- Break. -- @param #AIRBOSS self @@ -10368,19 +10268,19 @@ function AIRBOSS:_Groove( playerData ) if rho >= RAR and rho <= RIM then if gd.LUE > 0.22 and lineupError < -0.22 then env.info " Drift Right across centre ==> DR-" - gd.Drift = " DR" + gd.Drift = "DR" self:T( self.lid .. string.format( "Got Drift Right across centre step %s, d=%.3f: Max LUE=%.3f, lower LUE=%.3f", gs, d, gd.LUE, lineupError ) ) elseif gd.LUE < -0.22 and lineupError > 0.22 then env.info " Drift Left ==> DL-" - gd.Drift = " DL" + gd.Drift = "DL" self:T( self.lid .. string.format( "Got Drift Left across centre at step %s, d=%.3f: Min LUE=%.3f, lower LUE=%.3f", gs, d, gd.LUE, lineupError ) ) elseif gd.LUE > 0.13 and lineupError < -0.14 then env.info " Little Drift Right across centre ==> (DR-)" - gd.Drift = " (DR)" + gd.Drift = "(DR)" self:T( self.lid .. string.format( "Got Little Drift Right across centre at step %s, d=%.3f: Max LUE=%.3f, lower LUE=%.3f", gs, d, gd.LUE, lineupError ) ) elseif gd.LUE < -0.13 and lineupError > 0.14 then env.info " Little Drift Left across centre ==> (DL-)" - gd.Drift = " (DL)" + gd.Drift = "(DL)" self:E( self.lid .. string.format( "Got Little Drift Left across centre at step %s, d=%.3f: Min LUE=%.3f, lower LUE=%.3f", gs, d, gd.LUE, lineupError ) ) end end @@ -12758,7 +12658,7 @@ function AIRBOSS:_LSOgrade( playerData ) local TIG = "" -- Analyse flight data and convert to LSO text. if playerData.Tgroove and playerData.Tgroove <= 360 and playerData.case < 3 then --Circuit Added - TIG = self:_EvalGrooveTime( playerData ) or "N/A" --Circuit Added + TIG = self:_EvalGrooveTime( playerData ) or "N/A" --Circuit Added end --Circuit Added local GXX, nXX = self:_Flightdata2Text( playerData, AIRBOSS.GroovePos.XX ) local GIM, nIM = self:_Flightdata2Text( playerData, AIRBOSS.GroovePos.IM ) From 0f42218681801e9ec4e7665c290db9d32cd11023 Mon Sep 17 00:00:00 2001 From: nasgroup94 Date: Mon, 6 Oct 2025 18:08:23 -0400 Subject: [PATCH 206/234] minor edits --- Moose Development/Moose/Ops/Airboss.lua | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Moose Development/Moose/Ops/Airboss.lua b/Moose Development/Moose/Ops/Airboss.lua index 6a6819600..246e960d1 100644 --- a/Moose Development/Moose/Ops/Airboss.lua +++ b/Moose Development/Moose/Ops/Airboss.lua @@ -7606,7 +7606,7 @@ function AIRBOSS:_InitPlayer( playerData, step ) playerData.landed = false playerData.Tlso = timer.getTime() playerData.Tgroove = nil - playerData.TIG0 = nil + playerData.TIG0 = 0 --changed to prevent errors in script when player is not in correct spot playerData.wire = nil playerData.flag = -100 playerData.debriefschedulerID = nil @@ -8417,7 +8417,7 @@ end function AIRBOSS:_SetTimeInGroove( playerData ) -- Set time in the groove - if playerData.TIG0 > 2 then --circuit added to prevent negative groove time + if playerData.TIG0 then playerData.Tgroove = timer.getTime() - playerData.TIG0 - 1.5 -- VNAO Edit - Subtracting an extra 1.5 else playerData.Tgroove = 999 @@ -11958,10 +11958,12 @@ function AIRBOSS:GetHeading( magnetic ) hdg = hdg - self.magvar end - -- Adjust negative values. - if hdg < 0 then - hdg = hdg + 360 - end + -- -- Adjust negative values. + -- if hdg < 0 then + -- hdg = hdg + 360 + -- end + + hdg = hdg % 360 -- using this to replace the above function to prevent negative values and BRC higher than 360 return hdg end From 8cb91477cfb4dfad01f6e1634f54f7f57f50d864 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Tue, 7 Oct 2025 11:41:00 +0200 Subject: [PATCH 207/234] #AWACS - added function to set own BullsEye coordinate if necessary --- Moose Development/Moose/Ops/Awacs.lua | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Moose Development/Moose/Ops/Awacs.lua b/Moose Development/Moose/Ops/Awacs.lua index a2dff4db3..062f32d7b 100644 --- a/Moose Development/Moose/Ops/Awacs.lua +++ b/Moose Development/Moose/Ops/Awacs.lua @@ -509,7 +509,7 @@ do -- @field #AWACS AWACS = { ClassName = "AWACS", -- #string - version = "0.2.72", -- #string + version = "0.2.73", -- #string lid = "", -- #string coalition = coalition.side.BLUE, -- #number coalitiontxt = "blue", -- #string @@ -1596,6 +1596,16 @@ function AWACS:SetLocale(Locale) return self end +--- [User] Set own coordinate for BullsEye. +-- @param #AWACS self +-- @param Core.Point#COORDINATE +-- @return #AWACS self +function AWACS:SetBullsCoordinate(Coordinate) + self:T(self.lid.."SetBullsCoordinate") + self.AOCoordinate = Coordinate + return self +end + --- [User] Set the max mission range flights can be away from their home base. -- @param #AWACS self -- @param #number NM Distance in nautical miles From a85b6c960c1ccbf4b5e1e0fc5a95654c24175eaa Mon Sep 17 00:00:00 2001 From: smiki Date: Tue, 7 Oct 2025 15:41:54 +0200 Subject: [PATCH 208/234] [FIXED] Incorrect Airbase center position [ADDED] UH-60L weapons --- Moose Development/Moose/Utilities/Enums.lua | 10 ++++++++++ Moose Development/Moose/Wrapper/Airbase.lua | 11 +++++++++++ 2 files changed, 21 insertions(+) diff --git a/Moose Development/Moose/Utilities/Enums.lua b/Moose Development/Moose/Utilities/Enums.lua index d4bbf158d..14b7370a2 100644 --- a/Moose Development/Moose/Utilities/Enums.lua +++ b/Moose Development/Moose/Utilities/Enums.lua @@ -606,6 +606,7 @@ ENUMS.Storage = { OH58 = {}, -- Kiowa specifics UH1H = {}, -- Huey specifics AH64D = {}, -- Huey specifics + UH60L = {}, -- Huey specifics } } @@ -1315,6 +1316,15 @@ ENUMS.Storage.weapons.UH1H.M134_MiniGun_Right_Door = {4,15,46,175} ENUMS.Storage.weapons.UH1H.M60_MG_Right_Door = {4,15,46,177} ENUMS.Storage.weapons.UH1H.M134_MiniGun_Left_Door = {4,15,46,174} ENUMS.Storage.weapons.UH1H.M60_MG_Left_Door = {4,15,46,176} +-- UH-60L +ENUMS.Storage.weapons.UH60L.M151_HYDRA = {4, 7, 33, 147} -- 2.75" Hydra, UnGd Rkts M151, HE +ENUMS.Storage.weapons.UH60L.M156_HYDRA = {4, 7, 33, 148} -- 2.75" Hydra, UnGd Rkts M156, Wht Phos +ENUMS.Storage.weapons.UH60L.M229_HYDRA = {4, 7, 33, 148} -- 2.75" Hydra, UnGd Rkts M229, HE +ENUMS.Storage.weapons.UH60L.M257_HYDRA = {4, 7, 33, 151} -- 2.75" Hydra, UnGd Rkts M257, Para Illum +ENUMS.Storage.weapons.UH60L.M259_HYDRA = {4, 7, 33, 151} -- 2.75" Hydra, UnGd Rkts M259, Smoke Marker +ENUMS.Storage.weapons.UH60L.M274_HYDRA = {4, 7, 33, 150} -- 2.75" Hydra, UnGd Rkts M274, Practice Smk + + -- Kiowa ENUMS.Storage.weapons.OH58.FIM92 = {4,4,7,449} ENUMS.Storage.weapons.OH58.MG_M3P100 = {4,15,46,2611} diff --git a/Moose Development/Moose/Wrapper/Airbase.lua b/Moose Development/Moose/Wrapper/Airbase.lua index 7b56f195b..b2cc7a670 100644 --- a/Moose Development/Moose/Wrapper/Airbase.lua +++ b/Moose Development/Moose/Wrapper/Airbase.lua @@ -1574,6 +1574,17 @@ end return self end + +--- Get the true airbase center as seen in the ME. The position returned by the dcs object is is wrong and often at the start of the runway. +-- @return DCS#Vec2 The center of the true center of the airbase if it contains runways, otherwise the default DCS object position. +function AIRBASE:GetVec2() + local runways = self:GetRunways() + if runways and #runways > 0 then + return runways[1].center:GetVec2() + end + return self:GetCoordinate():GetVec2() +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() From 5183fcc31670911994cee675f900bb981f8c0e6b Mon Sep 17 00:00:00 2001 From: Thomas <72444570+Applevangelist@users.noreply.github.com> Date: Tue, 7 Oct 2025 15:51:22 +0200 Subject: [PATCH 209/234] Update Enums.lua --- Moose Development/Moose/Utilities/Enums.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/Utilities/Enums.lua b/Moose Development/Moose/Utilities/Enums.lua index 14b7370a2..bc1a0b2c8 100644 --- a/Moose Development/Moose/Utilities/Enums.lua +++ b/Moose Development/Moose/Utilities/Enums.lua @@ -606,7 +606,7 @@ ENUMS.Storage = { OH58 = {}, -- Kiowa specifics UH1H = {}, -- Huey specifics AH64D = {}, -- Huey specifics - UH60L = {}, -- Huey specifics + UH60L = {}, -- Blackhawk specifics } } From 146f869aaa9c04d2bb9f4c4b864d6f3734ab8101 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Tue, 7 Oct 2025 17:48:06 +0200 Subject: [PATCH 210/234] #RAT - reduce log noise --- Moose Development/Moose/Functional/RAT.lua | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Moose Development/Moose/Functional/RAT.lua b/Moose Development/Moose/Functional/RAT.lua index c1cf49111..8793c5a64 100644 --- a/Moose Development/Moose/Functional/RAT.lua +++ b/Moose Development/Moose/Functional/RAT.lua @@ -5492,7 +5492,7 @@ function RAT:_ATCInit(airports_map) if not RAT.ATC.init then local text text="Starting RAT ATC.\nSimultanious = "..RAT.ATC.Nclearance.."\n".."Delay = "..RAT.ATC.delay - BASE:T(RAT.id..text) + BASE:T2(RAT.id..text) RAT.ATC.init=true for _,ap in pairs(airports_map) do local name=ap:GetName() @@ -5515,7 +5515,7 @@ end -- @param #string name Group name of the flight. -- @param #string dest Name of the destination airport. function RAT:_ATCAddFlight(name, dest) - BASE:T(string.format("%sATC %s: Adding flight %s with destination %s.", RAT.id, dest, name, dest)) + BASE:T2(string.format("%sATC %s: Adding flight %s with destination %s.", RAT.id, dest, name, dest)) RAT.ATC.flight[name]={} RAT.ATC.flight[name].destination=dest RAT.ATC.flight[name].Tarrive=-1 @@ -5540,7 +5540,7 @@ end -- @param #string name Group name of the flight. -- @param #number time Time the fight first registered. function RAT:_ATCRegisterFlight(name, time) - BASE:T(RAT.id.."Flight ".. name.." registered at ATC for landing clearance.") + BASE:T2(RAT.id.."Flight ".. name.." registered at ATC for landing clearance.") RAT.ATC.flight[name].Tarrive=time RAT.ATC.flight[name].holding=0 end @@ -5571,7 +5571,7 @@ function RAT:_ATCStatus() -- Aircraft is holding. local text=string.format("ATC %s: Flight %s is holding for %i:%02d. %s.", dest, name, hold/60, hold%60, busy) - BASE:T(RAT.id..text) + BASE:T2(RAT.id..text) elseif hold==RAT.ATC.onfinal then @@ -5579,7 +5579,7 @@ function RAT:_ATCStatus() local Tfinal=Tnow-RAT.ATC.flight[name].Tonfinal local text=string.format("ATC %s: Flight %s is on final. Waiting %i:%02d for landing event.", dest, name, Tfinal/60, Tfinal%60) - BASE:T(RAT.id..text) + BASE:T2(RAT.id..text) elseif hold==RAT.ATC.unregistered then @@ -5629,12 +5629,12 @@ function RAT:_ATCCheck() -- Debug message. local text=string.format("ATC %s: Flight %s runway is busy. You are #%d of %d in landing queue. Your holding time is %i:%02d.", name, flight,qID, nqueue, RAT.ATC.flight[flight].holding/60, RAT.ATC.flight[flight].holding%60) - BASE:T(RAT.id..text) + BASE:T2(RAT.id..text) else local text=string.format("ATC %s: Flight %s was cleared for landing. Your holding time was %i:%02d.", name, flight, RAT.ATC.flight[flight].holding/60, RAT.ATC.flight[flight].holding%60) - BASE:T(RAT.id..text) + BASE:T2(RAT.id..text) -- Clear flight for landing. RAT:_ATCClearForLanding(name, flight) @@ -5677,7 +5677,7 @@ function RAT:_ATCClearForLanding(airport, flight) flight = string.match(flight,"^(.+)#") end local text2=string.format("ATC %s: Flight %s you are cleared for landing.", airport, flight) - BASE:T( RAT.id..text1) + BASE:T2( RAT.id..text1) MESSAGE:New(text2, 10):ToAllIf(RAT.ATC.messages) end @@ -5722,9 +5722,9 @@ function RAT:_ATCFlightLanded(name) name = string.match(name,"^(.+)#") end local text4=string.format("ATC %s: Flight %s landed. Welcome to %s.", dest, name, dest) - BASE:T(RAT.id..text1) - BASE:T(RAT.id..text2) - BASE:T(RAT.id..text3) + BASE:T2(RAT.id..text1) + BASE:T2(RAT.id..text2) + BASE:T2(RAT.id..text3) MESSAGE:New(text4, 10):ToAllIf(RAT.ATC.messages) end From 91e26adc6a5d60c45bdd86cf88e1d3009622cd05 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Tue, 7 Oct 2025 17:49:45 +0200 Subject: [PATCH 211/234] #AUFTRAG - Added functions to check repeatability #OPS - less noise in log #LEGION - Added mission housekeeping --- Moose Development/Moose/Ops/Auftrag.lua | 17 +++++++++++++++++ Moose Development/Moose/Ops/FlightGroup.lua | 2 +- Moose Development/Moose/Ops/Legion.lua | 11 ++++++++++- Moose Development/Moose/Ops/OpsGroup.lua | 4 ++-- 4 files changed, 30 insertions(+), 4 deletions(-) diff --git a/Moose Development/Moose/Ops/Auftrag.lua b/Moose Development/Moose/Ops/Auftrag.lua index 41bac80e0..f14440690 100644 --- a/Moose Development/Moose/Ops/Auftrag.lua +++ b/Moose Development/Moose/Ops/Auftrag.lua @@ -4016,6 +4016,23 @@ function AUFTRAG:IsOver() return over end +--- Check if mission is repeatable. +-- @param #AUFTRAG self +-- @return #boolean If true, mission is repeatable. +function AUFTRAG:IsRepeatable() + local repeatmeS=self.repeatedSuccess 1800 then + mission = nil + end end -- Check that runway is operational and that carrier is not recovering. @@ -761,7 +770,7 @@ function LEGION:CheckMissionQueue() -- Reduce number of reinforcements. if reinforce then mission.reinforce=mission.reinforce-#assets - self:I(self.lid..string.format("Reinforced with N=%d Nreinforce=%d", #assets, mission.reinforce)) + self:T(self.lid..string.format("Reinforced with N=%d Nreinforce=%d", #assets, mission.reinforce)) end return true diff --git a/Moose Development/Moose/Ops/OpsGroup.lua b/Moose Development/Moose/Ops/OpsGroup.lua index f23053a18..4a49abaef 100644 --- a/Moose Development/Moose/Ops/OpsGroup.lua +++ b/Moose Development/Moose/Ops/OpsGroup.lua @@ -7534,7 +7534,7 @@ end function OPSGROUP:onafterElementDead(From, Event, To, Element) -- Debug info. - self:I(self.lid..string.format("Element dead %s at t=%.3f", Element.name, timer.getTime())) + self:T(self.lid..string.format("Element dead %s at t=%.3f", Element.name, timer.getTime())) -- Set element status. self:_UpdateStatus(Element, OPSGROUP.ElementStatus.DEAD) @@ -8090,7 +8090,7 @@ function OPSGROUP:onafterStop(From, Event, To) _DATABASE.FLIGHTGROUPS[self.groupname]=nil -- Debug output. - self:I(self.lid.."STOPPED! Unhandled events, cleared scheduler and removed from _DATABASE") + self:T(self.lid.."STOPPED! Unhandled events, cleared scheduler and removed from _DATABASE") end --- On after "OutOfAmmo" event. From 1e60a0a32a7e84d1532a6aa340f8d3e2fe94e599 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Tue, 7 Oct 2025 18:06:20 +0200 Subject: [PATCH 212/234] #RAT 3.0.0 --- Moose Development/Moose/Functional/RAT.lua | 2722 ++++++++++---------- 1 file changed, 1420 insertions(+), 1302 deletions(-) diff --git a/Moose Development/Moose/Functional/RAT.lua b/Moose Development/Moose/Functional/RAT.lua index 8793c5a64..560410ae2 100644 --- a/Moose Development/Moose/Functional/RAT.lua +++ b/Moose Development/Moose/Functional/RAT.lua @@ -1,4 +1,4 @@ ---- **Functional** - Create random airtraffic in your missions. +--- **Functional** - Create random air traffic in your missions. -- -- === -- @@ -43,8 +43,6 @@ -- -- ### Author: **funkyfranky** -- --- ### Contributions: FlightControl --- -- === -- @module Functional.RAT -- @image RAT.JPG @@ -53,6 +51,7 @@ --- RAT class -- @type RAT -- @field #string ClassName Name of the Class. +-- @field #string lid Log identifier. -- @field #boolean Debug Turn debug messages on or off. -- @field Wrapper.Group#GROUP templategroup Group serving as template for the RAT aircraft. -- @field #string alias Alias for spawned group. @@ -147,6 +146,7 @@ -- @field #boolean parkingverysafe If true, parking spots are considered as non-free until a possible aircraft has left and taken off. Default false. -- @field #boolean despawnair If true, aircraft are despawned when they reach their destination zone. Default. -- @field #boolean eplrs If true, turn on EPLSR datalink for the RAT group. +-- @field #number NspawnMax Max number of spawns. -- @extends Core.Spawn#SPAWN --- Implements an easy to use way to randomly fill your map with AI aircraft. @@ -179,8 +179,8 @@ -- * Climb rate is set to a moderate value of ~1500 ft/min. -- * The standard descent rate follows the 3:1 rule, i.e. 1000 ft decent per 3 miles of travel. Hence, angle of descent is ~3.6 degrees. -- * A holding point is randomly selected at a distance between 5 and 10 km away from destination airport. --- * The altitude of theholding point is ~1200 m AGL. Holding patterns might or might not happen with variable duration. --- * If an aircraft is spawned in air, the procedure omitts taxi and take-off and starts with the climb/cruising part. +-- * The altitude of the holding point is ~1200 m AGL. Holding patterns might or might not happen with variable duration. +-- * If an aircraft is spawned in air, the procedure omits taxi and take-off and starts with the climb/cruising part. -- * All values are randomized for each spawned aircraft. -- -- ## Mission Editor Setup @@ -196,13 +196,13 @@ -- Voilà, your already done! -- -- Optionally, you can set a specific livery for the aircraft or give it some weapons. --- However, the aircraft will by default not engage any enemies. Think of them as beeing on a peaceful or ferry mission. +-- However, the aircraft will by default not engage any enemies. Think of them as being on a peaceful or ferry mission. -- -- ## Basic Lua Script -- -- ![Process](..\Presentations\RAT\RAT_Basic_Lua_Script.png) -- --- The basic Lua script for one template group consits of two simple lines as shown in the picture above. +-- The basic Lua script for one template group consists of two simple lines as shown in the picture above. -- -- * **Line 2** creates a new RAT object "yak". The only required parameter for the constructor @{#RAT.New}() is the name of the group as defined in the mission editor. In this example it is "RAT_YAK". -- * **Line 5** trigger the command to spawn the aircraft. The (optional) parameter for the @{#RAT.Spawn}() function is the number of aircraft to be spawned of this object. @@ -216,9 +216,9 @@ -- ## Parking Problems -- -- One big issue in DCS is that not all aircraft can be spawned on every airport or airbase. In particular, bigger aircraft might not have a valid parking spot at smaller airports and --- airstripes. This can lead to multiple problems in DCS. +-- airstrips. This can lead to multiple problems in DCS. -- --- * Landing: When an aircraft tries to land at an airport where it does not have a valid parking spot, it is immidiately despawned the moment its wheels touch the runway, i.e. +-- * Landing: When an aircraft tries to land at an airport where it does not have a valid parking spot, it is immediately despawned the moment its wheels touch the runway, i.e. -- when a landing event is triggered. This leads to the loss of the RAT aircraft. On possible way to circumvent the this problem is to let another RAT aircraft spawn at landing -- and not when it shuts down its engines. See the @{#RAT.RespawnAfterLanding}() function. -- * Spawning: When a big aircraft is dynamically spawned on a small airbase a few things can go wrong. For example, it could be spawned at a parking spot with a shelter. @@ -246,9 +246,9 @@ -- c17:Spawn(5) -- -- This would randomly spawn five C-17s but only on airports which have big open air parking spots. Note that also only destination airports are allowed --- which do have this type of parking spot. This should ensure that the aircraft is able to land at the destination without beeing despawned immidiately. +-- which do have this type of parking spot. This should ensure that the aircraft is able to land at the destination without being despawned immediately. -- --- Also, the aircraft are spawned only on the requested parking spot types and not on any other type. If no parking spot of this type is availabe at the +-- Also, the aircraft are spawned only on the requested parking spot types and not on any other type. If no parking spot of this type is available at the -- moment of spawning, the group is automatically spawned in air above the selected airport. -- -- ## Examples @@ -274,7 +274,7 @@ -- -- It is also possible to make aircraft "commute" between two airports, i.e. flying from airport A to B and then back from B to A, etc. -- This can be done by the @{#RAT.Commute}() function. Note that if no departure or destination airports are specified, the first departure and destination are chosen randomly. --- Then the aircraft will fly back and forth between those two airports indefinetly. +-- Then the aircraft will fly back and forth between those two airports indefinitely. -- -- -- ### Spawn in Air @@ -302,7 +302,7 @@ -- * @{#RAT.SetTakeoff}("cold"), which means that all aircraft are spawned with their engines off, -- * @{#RAT.SetTakeoff}("hot"), which means that all aircraft are spawned with their engines on, -- * @{#RAT.SetTakeoff}("runway"), which means that all aircraft are spawned already at the runway ready to takeoff. --- Note that in this case the default spawn intervall is set to 180 seconds in order to avoid aircraft jamms on the runway. Generally, this takeoff at runways should be used with care and problems are to be expected. +-- Note that in this case the default spawn intervall is set to 180 seconds in order to avoid aircraft jams on the runway. Generally, this takeoff at runways should be used with care and problems are to be expected. -- -- -- The options @{#RAT.SetMinDistance}() and @{#RAT.SetMaxDistance}() can be used to restrict the range from departure to destination. For example @@ -325,7 +325,7 @@ -- -- * @{#RAT.SetFLcruise}(300) will cause most planes fly around FL300. -- * @{#RAT.SetFLmin}(100) restricts the cruising alt such that no plane will fly below FL100. Note that this automatically changes the minimum distance from departure to destination. --- That means that only destinations are possible for which the aircraft has had enought time to reach that flight level and descent again. +-- That means that only destinations are possible for which the aircraft has had enough time to reach that flight level and descent again. -- * @{#RAT.SetFLmax}(200) will restrict the cruise alt to maximum FL200, i.e. no aircraft will travel above this height. -- -- @@ -432,7 +432,7 @@ RAT={ ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- Categories of the RAT class. --- @list cat +-- @type RAT.cat -- @field #string plane Plane. -- @field #string heli Heli. RAT.cat={ @@ -441,7 +441,7 @@ RAT.cat={ } --- RAT waypoint type. --- @list wp +-- @type RAT.wp RAT.wp={ coldorhot=0, air=1, @@ -457,7 +457,7 @@ RAT.wp={ } --- RAT aircraft status. --- @list status +-- @type RAT.status RAT.status={ -- Waypoint states. Departure="At departure point", @@ -483,8 +483,30 @@ RAT.status={ EventCrash="Crashed", } +--- Datastructure of a spawned RAT group. +-- @type RAT.RatCraft +-- @field #number index Spawn index. +-- @field Wrapper.Group#Group group The aircraft group. +-- @field Ops.FlightGroup#FLIGHTGROUP flightgroup The flight group. +-- @field Wrapper.Airbase#AIRBASE destination Destination of this group. Can also be a ZONE. +-- @field Wrapper.Airbase#AIRBASE departure Departure place of this group. Can also be a ZONE. +-- @field #table waypoints Waypoints. +-- @field #boolean airborne Whether this group is airborne. +-- @field #number nunits Number of units. +-- @field Core.Point#COORDINATE Pnow Current position. +-- @field #number Distance Distance travelled in meters. +-- @field #number takeoff Takeoff type. +-- @field #number landing Laning type. +-- @field #table wpdesc Waypoint descriptins. +-- @field #table wpstatus Waypoint status. +-- @field #boolean active Whether the group is active or uncontrolled. +-- @field #string status Status of the group. +-- @field #string livery Livery of the group. +-- @field #boolean despawnme Despawn group if `true` in the next status update. +-- @field #number nrespawn Number of respawns. + --- RAT friendly coalitions. --- @list coal +-- @type RAT.coal RAT.coal={ same="same", sameonly="sameonly", @@ -492,7 +514,7 @@ RAT.coal={ } --- RAT unit conversions. --- @list unit +-- @type RAT.unit RAT.unit={ ft2meter=0.305, kmh2ms=0.278, @@ -502,7 +524,7 @@ RAT.unit={ } --- RAT rules of engagement. --- @list ROE +-- @type RAT.ROE RAT.ROE={ weaponhold="hold", weaponfree="free", @@ -510,7 +532,7 @@ RAT.ROE={ } --- RAT reaction to threat. --- @list ROT +-- @type RAT.ROT RAT.ROT={ evade="evade", passive="passive", @@ -518,7 +540,16 @@ RAT.ROT={ } --- RAT ATC. --- @list ATC +-- @type RAT.ATC +-- @field #boolean init True if ATC was initialized. +-- @field #table flight List of flights. +-- @field #table airport List of airports. +-- @field #number unregistered Enumerator for unregistered flights unregistered=-1. +-- @field #number Nclearance Number of flights that get landing clearance simultaniously. Default 2. +-- @field #number delay Delay between landing flights in seconds. Default 240 sec. +-- @field #boolean messages If `true`, ATC sends messages. +-- @field #number T0 Time stamp [sec, timer.getTime()] when ATC was initialized. +-- @field #number onfinal Enumerator onfinal=100. RAT.ATC={ init=false, flight={}, @@ -545,13 +576,18 @@ RAT.id="RAT | " --- RAT version. -- @list version RAT.version={ - version = "2.3.9", + version = "3.0.0", print = true, } ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --TODO list: +--TODO: Add unlimited fuel option (and disable range check). This also needs to be added to FLIGHTGROUP +--TODO: +--TODO: Add max number of spawns +--TODO: Add Stop function +--TODO: Integrate FLIGHTGROUP --DONE: Add scheduled spawn. --DONE: Add possibility to spawn in air. --DONE: Add departure zones for air start. @@ -597,19 +633,21 @@ RAT.version={ -- @usage yak1:RAT("RAT_YAK") will create a RAT object called "yak1". The template group in the mission editor must have the name "RAT_YAK". -- @usage yak2:RAT("RAT_YAK", "Yak2") will create a RAT object "yak2". The template group in the mission editor must have the name "RAT_YAK" but the group will be called "Yak2" in e.g. the F10 menu. function RAT:New(groupname, alias) - BASE:F({groupname=groupname, alias=alias}) -- Inherit SPAWN class. self=BASE:Inherit(self, SPAWN:NewWithAlias(groupname, alias)) -- #RAT - + + -- Log id. + self.lid=string.format("RAT %s | ", alias or groupname) + -- Version info. if RAT.version.print then - env.info(RAT.id.."Version "..RAT.version.version) + env.info(self.lid.."Version "..RAT.version.version) RAT.version.print=false - end + end -- Welcome message. - self:F(RAT.id..string.format("Creating new RAT object from template: %s.", groupname)) + self:F(self.lid..string.format("Creating new RAT object from template: %s.", groupname)) -- Set alias. alias=alias or groupname @@ -622,7 +660,7 @@ function RAT:New(groupname, alias) -- Check the group actually exists. if DCSgroup==nil then - self:E(RAT.id..string.format("ERROR: Group with name %s does not exist in the mission editor!", groupname)) + self:E(self.lid..string.format("ERROR: Group with name %s does not exist in the mission editor!", groupname)) return nil end @@ -644,6 +682,51 @@ function RAT:New(groupname, alias) return self end +--- Stop RAT spawning by unhandling events, stoping schedulers etc. +-- @param #RAT self +-- @param #number delay Delay before stop in seconds. +function RAT:Stop(delay) + self:T3(self.lid..string.format("Stopping RAT! Delay %s sec!", tostring(delay))) + + if delay and delay>0 then + self:T2(self.lid..string.format("Stopping RAT in %d sec!", delay)) + self:ScheduleOnce(delay, RAT.Stop, self) + else + + self:T(self.lid.."Stopping RAT: Clearing schedulers and unhandling events!") + + if self.sid_Activate then + self.Scheduler:ScheduleStop(self.sid_Activate) + end + + if self.sid_Spawn then + self.Scheduler:ScheduleStop(self.sid_Spawn) + end + + if self.sid_Status then + self.Scheduler:ScheduleStop(self.sid_Status) + end + + + if self.Scheduler then + self.Scheduler:Clear() + end + + self.norespawn=true + + -- Un-Handle events. + self:UnHandleEvent(EVENTS.Birth) + self:UnHandleEvent(EVENTS.EngineStartup) + self:UnHandleEvent(EVENTS.Takeoff) + self:UnHandleEvent(EVENTS.Land) + self:UnHandleEvent(EVENTS.EngineShutdown) + self:UnHandleEvent(EVENTS.Dead) + self:UnHandleEvent(EVENTS.Crash) + self:UnHandleEvent(EVENTS.Hit) + + end +end + ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- Spawn function ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -668,7 +751,7 @@ function RAT:Spawn(naircraft) -- Init RAT ATC if not already done. if self.ATCswitch and not RAT.ATC.init then - self:_ATCInit(self.airports_map) + RAT._ATCInit(self.airports_map) end -- Create F10 main menu if it does not exists yet. @@ -679,10 +762,10 @@ function RAT:Spawn(naircraft) -- Set the coalition table based on choice of self.coalition and self.friendly. self:_SetCoalitionTable() - -- Get all airports of this map beloning to friendly coalition(s). + -- Get all airports of this map belonging to friendly coalition(s). self:_GetAirportsOfCoalition() - -- Set submenuname if it has not been set by user. + -- Set sub-menu name if it has not been set by user. if not self.SubMenuName then self.SubMenuName=self.alias end @@ -799,7 +882,7 @@ function RAT:Spawn(naircraft) end end text=text..string.format("******************************************************\n") - self:T(RAT.id..text) + self:T(self.lid..text) -- Create submenus. if self.f10menu then @@ -820,7 +903,8 @@ function RAT:Spawn(naircraft) local Tstop=Tstart+dt*(self.ngroups-1) -- Status check and report scheduler. - SCHEDULER:New(nil, self.Status, {self}, Tstart+1, self.statusinterval) + self.sid_Status=self:ScheduleRepeat(Tstart+1, self.statusinterval, nil, nil, RAT.Status, self) + -- Handle events. self:HandleEvent(EVENTS.Birth, self._OnBirth) @@ -838,11 +922,11 @@ function RAT:Spawn(naircraft) end -- Start scheduled spawning. - SCHEDULER:New(nil, self._SpawnWithRoute, {self}, Tstart, dt, 0.0, Tstop) + self.sid_Spawn=self:ScheduleRepeat(Tstart, dt, 0.0, Tstop, RAT._SpawnWithRoute, self) -- Start scheduled activation of uncontrolled groups. if self.uncontrolled and self.activate_uncontrolled then - SCHEDULER:New(nil, self._ActivateUncontrolled, {self}, self.activate_delay, self.activate_delta, self.activate_frand) + self.sid_Activate=self:ScheduleRepeat(self.activate_delay, self.activate_delta, self.activate_frand, nil, RAT._ActivateUncontrolled, self) end return true @@ -873,13 +957,13 @@ function RAT:_CheckConsistency() -- Only zones but not takeoff air == > Enable takeoff air. if self.Ndeparture_Zones>0 and self.takeoff~=RAT.wp.air then self.takeoff=RAT.wp.air - self:E(RAT.id..string.format("ERROR: At least one zone defined as departure and takeoff is NOT set to air. Enabling air start for RAT group %s!", self.alias)) + self:E(self.lid..string.format("WARNING: At least one zone defined as departure and takeoff is NOT set to air. Enabling air start for RAT group %s!", self.alias)) end -- No airport and no zone specified. if self.Ndeparture_Airports==0 and self.Ndeparture_Zone==0 then self.random_departure=true local text=string.format("No airports or zones found given in SetDeparture(). Enabling random departure airports for RAT group %s!", self.alias) - self:E(RAT.id.."ERROR: "..text) + self:E(self.lid.."ERROR: "..text) MESSAGE:New(text, 30):ToAll() end end @@ -901,20 +985,20 @@ function RAT:_CheckConsistency() if self.Ndestination_Zones>0 and self.landing~=RAT.wp.air and not self.returnzone then self.landing=RAT.wp.air self.destinationzone=true - self:E(RAT.id.."ERROR: At least one zone defined as destination and landing is NOT set to air. Enabling destination zone!") + self:E(self.lid.."WARNING: At least one zone defined as destination and landing is NOT set to air. Enabling destination zone!") end -- No specified airport and no zone found at all. if self.Ndestination_Airports==0 and self.Ndestination_Zones==0 then self.random_destination=true local text="No airports or zones found given in SetDestination(). Enabling random destination airports!" - self:E(RAT.id.."ERROR: "..text) + self:E(self.lid.."ERROR: "..text) MESSAGE:New(text, 30):ToAll() end end -- Destination zone and return zone should not be used together. if self.destinationzone and self.returnzone then - self:E(RAT.id.."ERROR: Destination zone _and_ return to zone not possible! Disabling return to zone.") + self:E(self.lid.."ERROR: Destination zone _and_ return to zone not possible! Disabling return to zone.") self.returnzone=false end -- If returning to a zone, we set the landing type to "air" if takeoff is in air. @@ -1195,7 +1279,7 @@ function RAT:SetDeparture(departurenames) names={departurenames} else -- error message - self:E(RAT.id.."ERROR: Input parameter must be a string or a table in SetDeparture()!") + self:E(self.lid.."ERROR: Input parameter must be a string or a table in SetDeparture()!") end -- Put names into arrays. @@ -1208,7 +1292,7 @@ function RAT:SetDeparture(departurenames) -- If it is not an airport, we assume it is a zone. table.insert(self.departure_ports, name) else - self:E(RAT.id.."ERROR: No departure airport or zone found with name "..name) + self:E(self.lid.."ERROR: No departure airport or zone found with name "..name) end end @@ -1218,9 +1302,9 @@ end --- Set name of destination airports or zones for the AI aircraft. -- @param #RAT self --- @param #string destinationnames Name of the destination airport or table of destination airports. +-- @param #string destinationnames Name of the destination airport or #table of destination airports. -- @return #RAT RAT self object. --- @usage RAT:SetDestination("Krymsk") makes all aircraft of this RAT oject fly to Krymsk airport. +-- @usage RAT:SetDestination("Krymsk") makes all aircraft of this RAT object fly to Krymsk airport. function RAT:SetDestination(destinationnames) self:F2(destinationnames) @@ -1235,7 +1319,7 @@ function RAT:SetDestination(destinationnames) names={destinationnames} else -- Error message. - self:E(RAT.id.."ERROR: Input parameter must be a string or a table in SetDestination()!") + self:E(self.lid.."ERROR: Input parameter must be a string or a table in SetDestination()!") end -- Put names into arrays. @@ -1248,7 +1332,7 @@ function RAT:SetDestination(destinationnames) -- If it is not an airport, we assume it is a zone. table.insert(self.destination_ports, name) else - self:E(RAT.id.."ERROR: No destination airport or zone found with name "..name) + self:E(self.lid.."ERROR: No destination airport or zone found with name "..name) end end @@ -1439,16 +1523,23 @@ function RAT:SetSpawnInterval(interval) return self end +--- Set max number of groups that will be spawned. When this limit is reached, no more RAT groups are spawned. +-- @param #RAT self +-- @param #number Nmax Max number of groups. Default `nil`=unlimited. +-- @return #RAT RAT self object. +function RAT:SetSpawnLimit(Nmax) + self.NspawnMax=Nmax + return self +end + --- Make aircraft respawn the moment they land rather than at engine shut down. -- @param #RAT self --- @param #number delay (Optional) Delay in seconds until respawn happens after landing. Default is 180 seconds. Minimum is 1.0 seconds. +-- @param #number delay (Optional) Delay in seconds until respawn happens after landing. Default is 1 second. Minimum is 1 second. -- @return #RAT RAT self object. function RAT:RespawnAfterLanding(delay) self:F2(delay) - delay = delay or 180 self.respawn_at_landing=true - delay=math.max(1.0, delay) - self.respawn_delay=delay + self:SetRespawnDelay(delay) return self end @@ -1473,7 +1564,7 @@ function RAT:NoRespawn() return self end ---- Number of tries to respawn an aircraft in case it has accitentally been spawned on runway. +--- Number of tries to respawn an aircraft in case it has accidentally been spawned on runway. -- @param #RAT self -- @param #number n Number of retries. Default is 3. -- @return #RAT RAT self object. @@ -1484,7 +1575,8 @@ function RAT:SetMaxRespawnTriedWhenSpawnedOnRunway(n) return self end ---- Aircraft will be respawned directly after take-off. +--- A new aircraft is spawned directly after the last one took off. This creates a lot of outbound traffic. Aircraft are not respawned after they reached their destination. +-- Therefore, this option is not to be used with the "commute" or "continue journey" options. -- @param #RAT self -- @return #RAT RAT self object. function RAT:RespawnAfterTakeoff() @@ -1529,7 +1621,7 @@ function RAT:RespawnInAirNotAllowed() return self end ---- Check if aircraft have accidentally been spawned on the runway. If so they will be removed immediatly. +--- Check if aircraft have accidentally been spawned on the runway. If so they will be removed immediately. -- @param #RAT self -- @param #boolean switch If true, check is performed. If false, this check is omitted. -- @param #number radius Distance in meters until a unit is considered to have spawned accidentally on the runway. Default is 75 m. @@ -1559,15 +1651,6 @@ function RAT:CheckOnTop(switch, radius) return self end ---- Put parking spot coordinates in a data base for future use of aircraft. (Obsolete! API function will be removed soon.) --- @param #RAT self --- @param #boolean switch If true, parking spots are memorized. This is also the default setting. --- @return #RAT RAT self object. -function RAT:ParkingSpotDB(switch) - self:E("RAT ParkingSpotDB function is obsolete and will be removed soon!") - return self -end - --- Enable Radio. Overrules the ME setting. -- @param #RAT self -- @return #RAT RAT self object. @@ -1670,7 +1753,7 @@ function RAT:Uncontrolled() return self end ---- Activate uncontrolled aircraft. +--- Define how aircraft that are spawned in uncontrolled state are activate. -- @param #RAT self -- @param #number maxactivated Maximal numnber of activated aircraft. Absolute maximum will be the number of spawned groups. Default is 1. -- @param #number delay Time delay in seconds before (first) aircraft is activated. Default is 1 second. @@ -2016,7 +2099,7 @@ function RAT:_InitAircraft(DCSgroup) self.category=RAT.cat.heli else self.category="other" - self:E(RAT.id.."ERROR: Group of RAT is neither airplane nor helicopter!") + self:E(self.lid.."ERROR: Group of RAT is neither airplane nor helicopter!") end -- Get type of aircraft. @@ -2057,6 +2140,7 @@ function RAT:_InitAircraft(DCSgroup) self.aircraft.height=6.97 -- <- These lines added self.aircraft.width=21.44 -- <- These lines added end + self.aircraft.box=math.max(self.aircraft.length,self.aircraft.width) -- info message @@ -2076,7 +2160,7 @@ function RAT:_InitAircraft(DCSgroup) text=text..string.format("Eff range = %6.1f km (with 95 percent initial fuel amount)\n", self.aircraft.Reff/1000) text=text..string.format("Ceiling = %6.1f km = FL%3.0f\n", self.aircraft.ceiling/1000, self.aircraft.ceiling/RAT.unit.FL2m) text=text..string.format("******************************************************\n") - self:T(RAT.id..text) + self:T(self.lid..text) end @@ -2099,7 +2183,15 @@ end -- @param #table parkingdata Explicitly specify the parking spots when spawning at an airport. -- @return #number Spawn index. function RAT:_SpawnWithRoute(_departure, _destination, _takeoff, _landing, _livery, _waypoint, _lastpos, _nrespawn, parkingdata) - self:F({rat=RAT.id, departure=_departure, destination=_destination, takeoff=_takeoff, landing=_landing, livery=_livery, waypoint=_waypoint, lastpos=_lastpos, nrespawn=_nrespawn}) + self:F({rat=self.lid, departure=_departure, destination=_destination, takeoff=_takeoff, landing=_landing, livery=_livery, waypoint=_waypoint, lastpos=_lastpos, nrespawn=_nrespawn}) + + -- Check if max spawn limit exists and is reached. SpawnIndex counting starts at 0, hence greater equal and not greater. + if self.NspawnMax and self.SpawnIndex>=self.NspawnMax then + self:T(self.lid..string.format("Max limit of spawns reached %d >= %d! Will not spawn any more groups", self.NspawnMax, self.SpawnIndex)) + return + else + self:T2(self.lid..string.format("Spawning with spawn index=%d", self.SpawnIndex)) + end -- Set takeoff type. local takeoff=self.takeoff @@ -2126,7 +2218,7 @@ function RAT:_SpawnWithRoute(_departure, _destination, _takeoff, _landing, _live end -- Set flight plan. - local departure, destination, waypoints, WPholding, WPfinal = self:_SetRoute(takeoff, landing, _departure, _destination, _waypoint) + local departure, destination, waypoints, wpdesc, wpstatus = self:_SetRoute(takeoff, landing, _departure, _destination, _waypoint) -- Return nil if we could not find a departure destination or waypoints if not (departure and destination and waypoints) then @@ -2142,108 +2234,136 @@ function RAT:_SpawnWithRoute(_departure, _destination, _takeoff, _landing, _live -- Choose random livery. livery=self.livery[math.random(#self.livery)] local text=string.format("Chosen livery for group %s: %s", self:_AnticipatedGroupName(), livery) - self:T(RAT.id..text) + self:T(self.lid..text) else livery=nil end + + -- We set the aircraft to uncontrolled if the departure airbase has a FLIGHTCONTROL. + local uncontrolled=self.uncontrolled + local isFlightcontrol=self:_IsFlightControlAirbase(departure) + if takeoff~=RAT.wp.air and departure and isFlightcontrol then + takeoff=RAT.wp.cold + uncontrolled=true + end -- Modify the spawn template to follow the flight plan. - local successful=self:_ModifySpawnTemplate(waypoints, livery, _lastpos, departure, takeoff, parkingdata) + local successful=self:_ModifySpawnTemplate(waypoints, livery, _lastpos, departure, takeoff, parkingdata, uncontrolled) if not successful then return nil end -- Actually spawn the group. local group=self:SpawnWithIndex(self.SpawnIndex) -- Wrapper.Group#GROUP - + + -- Group name. + local groupname=group:GetName() + + -- Create a flightgroup object. + local flightgroup=FLIGHTGROUP:New(group) + + -- Setting holding time to nil so that flight never gets landing clearance. This is done by the RAT ATC (FC sets holdtime to nil in FLIGHTGROUP). + if self.ATCswitch then + flightgroup.holdtime=nil + end + + -- No automatic despawning if group gets stuck. + flightgroup.stuckDespawn=false + + -- Increase counter of alive groups (also uncontrolled ones). self.alive=self.alive+1 - self:T(RAT.id..string.format("Alive groups counter now = %d.",self.alive)) + self:T(self.lid..string.format("Alive groups counter now = %d.",self.alive)) -- ATC is monitoring this flight (if it is supposed to land). if self.ATCswitch and landing==RAT.wp.landing then + + -- Get destination airbase name. For returnzone, this is the departure airbase. + local airbasename=destination:GetName() if self.returnzone then - self:_ATCAddFlight(group:GetName(), departure:GetName()) - else - self:_ATCAddFlight(group:GetName(), destination:GetName()) + airbasename=departure:GetName() + end + + -- Add flight (if there is no FC at the airbase) + if not self:_IsFlightControlAirbase(airbasename) then + self:_ATCAddFlight(groupname, airbasename) end end -- Place markers of waypoints on F10 map. if self.placemarkers then - self:_PlaceMarkers(waypoints, self.SpawnIndex) + self:_PlaceMarkers(waypoints, wpdesc, self.SpawnIndex) + end + + -- Set group ready for takeoff at the FLIGHTCONTROL (if we do not do via a scheduler). + if isFlightcontrol and not self.activate_uncontrolled then + local N=math.random(120) + self:T(self.lid..string.format("Flight will be ready for takeoff in %d seconds", N)) + flightgroup:SetReadyForTakeoff(true, N) end -- Set group to be invisible. if self.invisible then - self:_CommandInvisible(group, true) + flightgroup:SetDefaultInvisible(true) + flightgroup:SwitchInvisible(true) end -- Set group to be immortal. if self.immortal then - self:_CommandImmortal(group, true) + flightgroup:SetDefaultImmortal(true) + flightgroup:SwitchImmortal(true) end -- Set group to be immortal. if self.eplrs then - group:CommandEPLRS(true, 1) + flightgroup:SetDefaultEPLRS(true) + flightgroup:SwitchEPLRS(true) end -- Set ROE, default is "weapon hold". - self:_SetROE(group, self.roe) + self:_SetROE(flightgroup, self.roe) -- Set ROT, default is "no reaction". - self:_SetROT(group, self.rot) - + self:_SetROT(flightgroup, self.rot) + -- Init ratcraft array. - self.ratcraft[self.SpawnIndex]={} - self.ratcraft[self.SpawnIndex]["group"]=group - self.ratcraft[self.SpawnIndex]["destination"]=destination - self.ratcraft[self.SpawnIndex]["departure"]=departure - self.ratcraft[self.SpawnIndex]["waypoints"]=waypoints - self.ratcraft[self.SpawnIndex]["airborne"]=group:InAir() - self.ratcraft[self.SpawnIndex]["nunits"]=group:GetInitialSize() - -- Time and position on ground. For check if aircraft is stuck somewhere. - if group:InAir() then - self.ratcraft[self.SpawnIndex]["Tground"]=nil - self.ratcraft[self.SpawnIndex]["Pground"]=nil - self.ratcraft[self.SpawnIndex]["Uground"]=nil - self.ratcraft[self.SpawnIndex]["Tlastcheck"]=nil - else - self.ratcraft[self.SpawnIndex]["Tground"]=timer.getTime() - self.ratcraft[self.SpawnIndex]["Pground"]=group:GetCoordinate() - self.ratcraft[self.SpawnIndex]["Uground"]={} - for _,_unit in pairs(group:GetUnits()) do - local _unitname=_unit:GetName() - self.ratcraft[self.SpawnIndex]["Uground"][_unitname]=_unit:GetCoordinate() - end - self.ratcraft[self.SpawnIndex]["Tlastcheck"]=timer.getTime() - end + local ratcraft={} --#RAT.RatCraft + ratcraft.index=self.SpawnIndex + ratcraft.group=group + ratcraft.flightgroup=flightgroup + ratcraft.destination=destination + ratcraft.departure=departure + ratcraft.waypoints=waypoints + ratcraft.airborne=group:InAir() + ratcraft.nunits=group:GetInitialSize() + -- Initial and current position. For calculating the travelled distance. - self.ratcraft[self.SpawnIndex]["P0"]=group:GetCoordinate() - self.ratcraft[self.SpawnIndex]["Pnow"]=group:GetCoordinate() - self.ratcraft[self.SpawnIndex]["Distance"]=0 + ratcraft.Pnow=group:GetCoordinate() + ratcraft.Distance=0 -- Each aircraft gets its own takeoff type. - self.ratcraft[self.SpawnIndex].takeoff=takeoff - self.ratcraft[self.SpawnIndex].landing=landing - self.ratcraft[self.SpawnIndex].wpholding=WPholding - self.ratcraft[self.SpawnIndex].wpfinal=WPfinal + ratcraft.takeoff=takeoff + ratcraft.landing=landing + ratcraft.wpdesc=wpdesc + ratcraft.wpstatus=wpstatus -- Aircraft is active or spawned in uncontrolled state. - self.ratcraft[self.SpawnIndex].active=not self.uncontrolled + ratcraft.active=not uncontrolled -- Set status to spawned. This will be overwritten in birth event. - self.ratcraft[self.SpawnIndex]["status"]=RAT.status.Spawned + ratcraft.status=RAT.status.Spawned -- Livery - self.ratcraft[self.SpawnIndex].livery=livery + ratcraft.livery=livery -- If this switch is set to true, the aircraft will be despawned the next time the status function is called. - self.ratcraft[self.SpawnIndex].despawnme=false + ratcraft.despawnme=false -- Number of preformed spawn attempts for this group. - self.ratcraft[self.SpawnIndex].nrespawn=nrespawn + ratcraft.nrespawn=nrespawn + + -- Add ratcaft to table. + self.ratcraft[self.SpawnIndex]=ratcraft -- Create submenu for this group. if self.f10menu then @@ -2252,23 +2372,154 @@ function RAT:_SpawnWithRoute(_departure, _destination, _takeoff, _landing, _live self.Menu[self.SubMenuName].groups[self.SpawnIndex]=MENU_MISSION:New(name, self.Menu[self.SubMenuName].groups) -- F10/RAT//Group X/Set ROE self.Menu[self.SubMenuName].groups[self.SpawnIndex]["roe"]=MENU_MISSION:New("Set ROE", self.Menu[self.SubMenuName].groups[self.SpawnIndex]) - MENU_MISSION_COMMAND:New("Weapons hold", self.Menu[self.SubMenuName].groups[self.SpawnIndex]["roe"], self._SetROE, self, group, RAT.ROE.weaponhold) - MENU_MISSION_COMMAND:New("Weapons free", self.Menu[self.SubMenuName].groups[self.SpawnIndex]["roe"], self._SetROE, self, group, RAT.ROE.weaponfree) - MENU_MISSION_COMMAND:New("Return fire", self.Menu[self.SubMenuName].groups[self.SpawnIndex]["roe"], self._SetROE, self, group, RAT.ROE.returnfire) + MENU_MISSION_COMMAND:New("Weapons hold", self.Menu[self.SubMenuName].groups[self.SpawnIndex]["roe"], self._SetROE, self, flightgroup, RAT.ROE.weaponhold) + MENU_MISSION_COMMAND:New("Weapons free", self.Menu[self.SubMenuName].groups[self.SpawnIndex]["roe"], self._SetROE, self, flightgroup, RAT.ROE.weaponfree) + MENU_MISSION_COMMAND:New("Return fire", self.Menu[self.SubMenuName].groups[self.SpawnIndex]["roe"], self._SetROE, self, flightgroup, RAT.ROE.returnfire) -- F10/RAT//Group X/Set ROT self.Menu[self.SubMenuName].groups[self.SpawnIndex]["rot"]=MENU_MISSION:New("Set ROT", self.Menu[self.SubMenuName].groups[self.SpawnIndex]) - MENU_MISSION_COMMAND:New("No reaction", self.Menu[self.SubMenuName].groups[self.SpawnIndex]["rot"], self._SetROT, self, group, RAT.ROT.noreaction) - MENU_MISSION_COMMAND:New("Passive defense", self.Menu[self.SubMenuName].groups[self.SpawnIndex]["rot"], self._SetROT, self, group, RAT.ROT.passive) - MENU_MISSION_COMMAND:New("Evade on fire", self.Menu[self.SubMenuName].groups[self.SpawnIndex]["rot"], self._SetROT, self, group, RAT.ROT.evade) + MENU_MISSION_COMMAND:New("No reaction", self.Menu[self.SubMenuName].groups[self.SpawnIndex]["rot"], self._SetROT, self, flightgroup, RAT.ROT.noreaction) + MENU_MISSION_COMMAND:New("Passive defense", self.Menu[self.SubMenuName].groups[self.SpawnIndex]["rot"], self._SetROT, self, flightgroup, RAT.ROT.passive) + MENU_MISSION_COMMAND:New("Evade on fire", self.Menu[self.SubMenuName].groups[self.SpawnIndex]["rot"], self._SetROT, self, flightgroup, RAT.ROT.evade) -- F10/RAT//Group X/ MENU_MISSION_COMMAND:New("Despawn group", self.Menu[self.SubMenuName].groups[self.SpawnIndex], self._Despawn, self, group) MENU_MISSION_COMMAND:New("Place markers", self.Menu[self.SubMenuName].groups[self.SpawnIndex], self._PlaceMarkers, self, waypoints, self.SpawnIndex) MENU_MISSION_COMMAND:New("Status report", self.Menu[self.SubMenuName].groups[self.SpawnIndex], self.Status, self, true, self.SpawnIndex) end + --- Function called when passing a waypoint. + function flightgroup.OnAfterPassingWaypoint(Flightgroup, From, Event, To, Waypoint) + local waypoint=Waypoint --Ops.OpsGroup#OPSGROUP.Waypoint + local flightgroup=Flightgroup --Ops.FlightGroup#FLIGHTGROUP + + local wpid=waypoint.uid + + local ratcraft=self:_GetRatcraftFromGroup(flightgroup.group) + + local wpdescription=tostring(ratcraft.wpdesc[wpid]) + local wpstatus=ratcraft.wpstatus[wpid] + + -- Debug info. + self:T(self.lid..string.format("RAT passed waypoint %s [uid=%d]: %s [status=%s]", waypoint.name, wpid, wpdescription, wpstatus)) + + -- Set status + self:_SetStatus(group, wpstatus) + + if waypoint.uid==3 then + --flightgroup:SelfDestruction(Delay,ExplosionPower,ElementName) + end + + end + + --- Function called when passing the FINAL waypoint + function flightgroup.OnAfterPassedFinalWaypoint(flightgroup, From, Event, To) + + self:T(self.lid..string.format("RAT passed FINAL waypoint")) + + local ratcraft=self:_GetRatcraftFromGroup(flightgroup.group) + + -- Info message. + local text=string.format("Flight %s arrived at final destination %s.", group:GetName(), destination:GetName()) + MESSAGE:New(text, 10):ToAllIf(self.reportstatus) + self:T(self.lid..text) + + if landing==RAT.wp.air then + -- Final waypoint is air ==> Despawn flight + + -- Info message. + local text=string.format("Activating despawn switch for flight %s! Group will be detroyed soon.", group:GetName()) + MESSAGE:New(text, 10):ToAllIf(self.Debug) + self:T(self.lid..text) + + -- Enable despawn switch. Next time the status function is called, the aircraft will be despawned. + ratcraft.despawnme=true + end + + end + + --- Function called when flight is RTB. + function flightgroup.OnAfterRTB(flightgroup, From, Event, To, airbase, SpeedTo, SpeedHold, SpeedLand) + self:T(self.lid..string.format("RAT group is RTB")) + end + + --- Function called when flight is holding. + function flightgroup.OnAfterHolding(Flightgroup, From, Event, To) + local flightgroup=Flightgroup --Ops.FlightGroup#FLIGHTGROUP + + local ratcraft=self:_GetRatcraftFromGroup(flightgroup.group) + + local destinationname=ratcraft.destination:GetName() + + -- Aircraft arrived at holding point + local text=string.format("Flight %s to %s ATC: Holding and awaiting landing clearance.", groupname, destinationname) + self:T(self.lid..text) + MESSAGE:New(text, 10):ToAllIf(self.reportstatus) + + -- Get FLIGHTCONTROL if there is any. + local fc=_DATABASE:GetFlightControl(destinationname) + + -- Register aircraft at RAT ATC (but only if there is no FLIGHTCONTROL) + if self.ATCswitch and not fc then + self:T(self.lid..string.format("RAT group is HOLDING ==> ATCRegisterFlight")) + + -- Create F10 menu + if self.f10menu then + MENU_MISSION_COMMAND:New("Clear for landing", self.Menu[self.SubMenuName].groups[self.SpawnIndex], flightgroup.ClearToLand, flightgroup) + end + + -- Register at ATC + RAT._ATCRegisterFlight(groupname, timer.getTime()) + end + end + + --- Function called when the group landed at an airbase. + function flightgroup.OnAfterLanded(Flightgroup, From, Event, To, Airport) + self:T(self.lid..string.format("RAT group landed at airbase")) + end + + --- Function called when the group arrived at their parking positions. + function flightgroup.OnAfterArrived(Flightgroup, From, Event, To) + self:T(self.lid..string.format("RAT group arrived")) + end + + --- Function called when a group got stuck. + function flightgroup.OnAfterStuck(Flightgroup, From, Event, To, Stucktime) + local flightgroup=Flightgroup --Ops.FlightGroup#FLIGHTGROUP + self:T(self.lid..string.format("Group %s got stuck for %d seconds", flightgroup:GetName(), Stucktime)) + if Stucktime>10*60 then + self:_Respawn(flightgroup.group) + end + + end + + return self.SpawnIndex end +--- Check if a given airbase has a FLIGHTCONTROL. +-- @param #RAT self +-- @param Wrapper.Airbase#AIRBASE airbase The airbase. +-- @return #boolean `true` if the airbase has a FLIGHTCONTROL. +function RAT:_IsFlightControlAirbase(airbase) + + if type(airbase)=="table" then + airbase=airbase:GetName() + end + + if airbase then + + local fc=_DATABASE:GetFlightControl(airbase) + + if fc then + self:T(self.lid..string.format("Airbase %s has a FLIGHTCONTROL running", airbase)) + return true + else + return false + end + + end + + return nil +end --- Clear flight for landing. Sets tigger value to 1. -- @param #RAT self @@ -2276,195 +2527,265 @@ end function RAT:ClearForLanding(name) trigger.action.setUserFlag(name, 1) local flagvalue=trigger.misc.getUserFlag(name) - self:T(RAT.id.."ATC: User flag value (landing) for "..name.." set to "..flagvalue) + self:T(self.lid.."ATC: User flag value (landing) for "..name.." set to "..flagvalue) end ---- Respawn a group. +--- Despawn the original group and re-spawn a new one. -- @param #RAT self --- @param #number index Spawn index. +-- @param Wrapper.Group#GROUP group The group that should be respawned. -- @param Core.Point#COORDINATE lastpos Last known position of the group. --- @param #number delay Delay before respawn -function RAT:_Respawn(index, lastpos, delay) - - -- Get the spawn index from group - --local index=self:GetSpawnIndexFromGroup(group) - - -- Get departure and destination from previous journey. - local departure=self.ratcraft[index].departure - local destination=self.ratcraft[index].destination - local takeoff=self.ratcraft[index].takeoff - local landing=self.ratcraft[index].landing - local livery=self.ratcraft[index].livery - local lastwp=self.ratcraft[index].waypoints[#self.ratcraft[index].waypoints] - --local lastpos=group:GetCoordinate() - - local _departure=nil - local _destination=nil - local _takeoff=nil - local _landing=nil - local _livery=nil - local _lastwp=nil - local _lastpos=nil - - if self.continuejourney then - - -- We continue our journey from the old departure airport. - _departure=destination:GetName() - - -- Use the same livery for next aircraft. - _livery=livery - - -- Last known position of the aircraft, which should be the sparking spot location. - -- Note: we have to check that it was supposed to land and not respawned directly after landing or after takeoff. - -- TODO: Need to think if continuejourney with respawn_after_takeoff actually makes sense. - if landing==RAT.wp.landing and lastpos and not (self.respawn_at_landing or self.respawn_after_takeoff) then - -- Check that we have an airport or FARP but not a ship (which would be categroy 1). - if destination:GetCategory()==4 then - _lastpos=lastpos - end - end - - if self.destinationzone then - - -- Case: X --> Zone --> Zone --> Zone - _takeoff=RAT.wp.air - _landing=RAT.wp.air - - elseif self.returnzone then - - -- Case: X --> Zone --> X, X --> Zone --> X - -- We flew to a zone and back. Takeoff type does not change. - _takeoff=self.takeoff - - -- If we took of in air we also want to land "in air". - if self.takeoff==RAT.wp.air then - _landing=RAT.wp.air - else - _landing=RAT.wp.landing - end - - -- Departure stays the same. (The destination is the zone here.) - _departure=departure:GetName() +-- @param #number delay Delay before despawn in seconds. +function RAT:_Respawn(group, lastpos, delay) + if delay and delay>0 then + + self:ScheduleOnce(delay, RAT._Respawn, self, group, lastpos, 0) + + else + if group then + self:T(self.lid..string.format("Respawning ratcraft from group %s", group:GetName())) else - - -- Default case. Takeoff and landing type does not change. - _takeoff=self.takeoff - _landing=self.landing - + self:E(self.lid..string.format("ERROR: group is nil in _Respawn!")) + return nil end + + -- Get ratcraft from group. + local ratcraft=self:_GetRatcraftFromGroup(group) - elseif self.commute then - - -- We commute between departure and destination. - - if self.starshape==true then - if destination:GetName()==self.homebase then - -- We are at our home base ==> destination is again randomly selected. - _departure=self.homebase - _destination=nil -- destination will be set anew - else - -- We are not a our home base ==> we fly back to our home base. - _departure=destination:GetName() - _destination=self.homebase - end - else - -- Simply switch departure and destination. - _departure=destination:GetName() - _destination=departure:GetName() - end - - -- Use the same livery for next aircraft. - _livery=livery - - -- Last known position of the aircraft, which should be the sparking spot location. - -- Note: we have to check that it was supposed to land and not respawned directly after landing or after takeoff. - -- TODO: Need to think if commute with respawn_after_takeoff actually makes sense. - if landing==RAT.wp.landing and lastpos and not (self.respawn_at_landing or self.respawn_after_takeoff) then - -- Check that we have landed on an airport or FARP but not a ship (which would be categroy 1). - if destination:GetCategory()==4 then - _lastpos=lastpos - end - end - - -- Handle takeoff type. - if self.destinationzone then - -- self.takeoff is either RAT.wp.air or RAT.wp.cold - -- self.landing is RAT.wp.Air - - if self.takeoff==RAT.wp.air then - - -- Case: Zone <--> Zone (both have takeoff air) - _takeoff=RAT.wp.air -- = self.takeoff (because we just checked) - _landing=RAT.wp.air -- = self.landing (because destinationzone) - - else - - -- Case: Airport <--> Zone - if takeoff==RAT.wp.air then - -- Last takeoff was air so we are at the airport now, takeoff is from ground. - _takeoff=self.takeoff -- must be either hot/cold/runway/hotcold - _landing=RAT.wp.air -- must be air = self.landing (because destinationzone) + -- Get last known position. + lastpos=lastpos or group:GetCoordinate() + + -- Get departure and destination from previous journey. + local departure=ratcraft.departure + local destination=ratcraft.destination --Wrapper.Airbase#AIRBASE + local takeoff=ratcraft.takeoff + local landing=ratcraft.landing + local livery=ratcraft.livery + local lastwp=ratcraft.waypoints[#ratcraft.waypoints] + local flightgroup=ratcraft.flightgroup + + + -- In case we stay at the same airport, we save the parking data to respawn at the same spot. + local parkingdata=nil + if self.continuejourney or self.commute then + for _,_element in pairs(flightgroup.elements) do + local element=_element --Ops.OpsGroup#OPSGROUP.Element + + if element.parking then + -- Init table. + if parkingdata==nil then + parkingdata={} + end + + self:T(self.lid..string.format("Element %s was parking at spot id=%d", element.name, element.parking.TerminalID)) + table.insert(parkingdata, UTILS.DeepCopy(element.parking)) + else + self:E(self.lid..string.format("WARNING: Element %s did NOT have a not parking spot!", tostring(element.name))) + end + end + end + + -- Despawn old group. + self:_Despawn(ratcraft.group) + + local _departure=nil + local _destination=nil --Wrapper.Airbase#AIRBASE + local _takeoff=nil + local _landing=nil + local _livery=nil + local _lastwp=nil + local _lastpos=nil + + if self.continuejourney then + + --- + -- Continue Journey + --- + + -- We continue our journey from the old departure airport. + _departure=destination:GetName() + + -- Use the same livery for next aircraft. + _livery=livery + + -- Last known position of the aircraft, which should be the sparking spot location. + -- Note: we have to check that it was supposed to land and not respawned directly after landing or after takeoff. + -- DONE: Need to think if continuejourney with respawn_after_takeoff actually makes sense? + -- No, does not make sense. Disable it in consistency check. + if landing==RAT.wp.landing and not (self.respawn_at_landing or self.respawn_after_takeoff) then + -- Check that we have an airport or FARP but not a ship (which would be categroy 1). + if destination:GetCategory()==4 then + _lastpos=lastpos + end + end + + if self.destinationzone then + + -- Case: X --> Zone --> Zone --> Zone + _takeoff=RAT.wp.air + _landing=RAT.wp.air + + elseif self.returnzone then + + -- Case: X --> Zone --> X, X --> Zone --> X + -- We flew to a zone and back. Takeoff type does not change. + _takeoff=self.takeoff + + -- If we took of in air we also want to land "in air". + if self.takeoff==RAT.wp.air then + _landing=RAT.wp.air else - -- Last takeoff was on ground so we are at a zone now ==> takeoff in air, landing at airport. - _takeoff=RAT.wp.air _landing=RAT.wp.landing end - + + -- Departure stays the same. (The destination is the zone here.) + _departure=departure:GetName() + + else + + -- Default case. Takeoff and landing type does not change. + _takeoff=self.takeoff + _landing=self.landing + end - - elseif self.returnzone then - - -- We flew to a zone and back. No need to swap departure and destination. - _departure=departure:GetName() - _destination=destination:GetName() - - -- Takeoff and landing should also not change. - _takeoff=self.takeoff - _landing=self.landing - + + elseif self.commute then + + --- + -- Commute + --- + + -- We commute between departure and destination. + + if self.starshape==true then + if destination:GetName()==self.homebase then + -- We are at our home base ==> destination is again randomly selected. + _departure=self.homebase + _destination=nil -- destination will be set anew + else + -- We are not a our home base ==> we fly back to our home base. + _departure=destination:GetName() + _destination=self.homebase + end + else + -- Simply switch departure and destination. + _departure=destination:GetName() + _destination=departure:GetName() + end + + -- Use the same livery for next aircraft. + _livery=livery + + -- Last known position of the aircraft, which should be the sparking spot location. + -- Note: we have to check that it was supposed to land and not respawned directly after landing or after takeoff. + -- TODO: Need to think if commute with respawn_after_takeoff actually makes sense. + if landing==RAT.wp.landing and lastpos and not (self.respawn_at_landing or self.respawn_after_takeoff) then + -- Check that we have landed on an airport or FARP but not a ship (which would be categroy 1). + if destination:GetCategory()==4 then + _lastpos=lastpos + end + end + + -- Handle takeoff type. + if self.destinationzone then + -- self.takeoff is either RAT.wp.air or RAT.wp.cold + -- self.landing is RAT.wp.Air + + if self.takeoff==RAT.wp.air then + + -- Case: Zone <--> Zone (both have takeoff air) + _takeoff=RAT.wp.air -- = self.takeoff (because we just checked) + _landing=RAT.wp.air -- = self.landing (because destinationzone) + + else + + -- Case: Airport <--> Zone + if takeoff==RAT.wp.air then + -- Last takeoff was air so we are at the airport now, takeoff is from ground. + _takeoff=self.takeoff -- must be either hot/cold/runway/hotcold + _landing=RAT.wp.air -- must be air = self.landing (because destinationzone) + else + -- Last takeoff was on ground so we are at a zone now ==> takeoff in air, landing at airport. + _takeoff=RAT.wp.air + _landing=RAT.wp.landing + end + + end + + elseif self.returnzone then + + -- We flew to a zone and back. No need to swap departure and destination. + _departure=departure:GetName() + _destination=destination:GetName() + + -- Takeoff and landing should also not change. + _takeoff=self.takeoff + _landing=self.landing + + end + end - + + -- Take the last waypoint as initial waypoint for next plane. + if _takeoff==RAT.wp.air and (self.continuejourney or self.commute) then + _lastwp=lastwp + end + + -- Debug + self:T2({departure=_departure, destination=_destination, takeoff=_takeoff, landing=_landing, livery=_livery, lastwp=_lastwp}) + + -- We should give it at least 3 sec since this seems to be the time until free parking spots after despawn are available again (Sirri Island test). + local respawndelay=self.respawn_delay or 1 + + -- Spawn new group. + self:T(self.lid..string.format("%s delayed respawn in %.1f seconds.", self.alias, respawndelay)) + self:ScheduleOnce(respawndelay, RAT._SpawnWithRoute, self,_departure,_destination,_takeoff,_landing,_livery, nil,_lastpos, nil, parkingdata) + end - -- Take the last waypoint as initial waypoint for next plane. - if _takeoff==RAT.wp.air and (self.continuejourney or self.commute) then - _lastwp=lastwp - end - - -- Debug - self:T2({departure=_departure, destination=_destination, takeoff=_takeoff, landing=_landing, livery=_livery, lastwp=_lastwp}) - - -- We should give it at least 3 sec since this seems to be the time until free parking spots after despawn are available again (Sirri Island test). - local respawndelay - if delay then - respawndelay=delay - elseif self.respawn_delay then - respawndelay=self.respawn_delay+3 -- despawn happens after self.respawndelay. We add another 3 sec for free parking. - else - respawndelay=3 - end - - -- Spawn new group. - local arg={} - arg.self=self - arg.departure=_departure - arg.destination=_destination - arg.takeoff=_takeoff - arg.landing=_landing - arg.livery=_livery - arg.lastwp=_lastwp - arg.lastpos=_lastpos - self:T(RAT.id..string.format("%s delayed respawn in %.1f seconds.", self.alias, respawndelay)) - SCHEDULER:New(nil, self._SpawnWithRouteTimer, {arg}, respawndelay) - end ---- Delayed spawn function called by scheduler. +--- Despawn group. The `FLIGHTGROUP` is despawned and stopped. The ratcraft is removed from the self.ratcraft table. Menues are removed. -- @param #RAT self --- @param #table arg Parameters: arg.self, arg.departure, arg.destination, arg.takeoff, arg.landing, arg.livery, arg.lastwp, arg.lastpos -function RAT._SpawnWithRouteTimer(arg) - RAT._SpawnWithRoute(arg.self, arg.departure, arg.destination, arg.takeoff, arg.landing, arg.livery, arg.lastwp, arg.lastpos) +-- @param Wrapper.Group#GROUP group Group to be despawned. +-- @param #number delay Delay in seconds before the despawn happens. Default is immidiately. +function RAT:_Despawn(group, delay) + + if delay and delay>0 then + -- Delayed call. + self:ScheduleOnce(delay, RAT._Despawn, self, group, 0) + else + + if group then + + -- Get spawnindex of group. + local index=self:GetSpawnIndexFromGroup(group) + + if index then + + -- Debug info. + self:T(self.lid..string.format("Despawning group %s (index=%d)", group:GetName(), index)) + + -- Get ratcraft. + local ratcraft=self.ratcraft[index] --#RAT.RatCraft + + -- Despawn flightgroup and stop. + ratcraft.flightgroup:Despawn() + ratcraft.flightgroup:__Stop(0.1) + + -- Nil ratcraft in table. + self.ratcraft[index].group=nil + self.ratcraft[index]["status"]="Dead" + self.ratcraft[index]=nil + + -- Remove submenu for this group. + if self.f10menu and self.SubMenuName ~= nil then + self.Menu[self.SubMenuName]["groups"][index]:Remove() + end + + end + end + end end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -2479,7 +2800,8 @@ end -- @return Wrapper.Airbase#AIRBASE Departure airbase. -- @return Wrapper.Airbase#AIRBASE Destination airbase. -- @return #table Table of flight plan waypoints. --- @return #nil If no valid departure or destination airport could be found. +-- @return #table Table of waypoint descriptions. +-- @return #table Table of waypoint status. function RAT:_SetRoute(takeoff, landing, _departure, _destination, _waypoint) -- Max cruise speed. @@ -2525,7 +2847,7 @@ function RAT:_SetRoute(takeoff, landing, _departure, _destination, _waypoint) -- DEPARTURE AIRPORT -- Departure airport or zone. - local departure=nil + local departure=nil --Wrapper.Airbase#AIRBASE if _departure then if self:_AirportExists(_departure) then -- Check if new departure is an airport. @@ -2539,7 +2861,7 @@ function RAT:_SetRoute(takeoff, landing, _departure, _destination, _waypoint) departure=ZONE:FindByName(_departure) else local text=string.format("ERROR! Specified departure airport %s does not exist for %s.", _departure, self.alias) - self:E(RAT.id..text) + self:E(self.lid..text) end else @@ -2552,12 +2874,12 @@ function RAT:_SetRoute(takeoff, landing, _departure, _destination, _waypoint) -- Return nil if no departure could be found. if not departure then local text=string.format("ERROR! No valid departure airport could be found for %s.", self.alias) - self:E(RAT.id..text) + self:E(self.lid..text) return nil end -- Coordinates of departure point. - local Pdeparture + local Pdeparture --Core.Point#COORDINATE if takeoff==RAT.wp.air then if _waypoint then -- Use coordinates of previous flight (commute or journey). @@ -2619,11 +2941,11 @@ function RAT:_SetRoute(takeoff, landing, _departure, _destination, _waypoint) mindist=math.max(self.mindist, mindist) local text=string.format("Adjusting min distance to %d km (for given min FL%03d)", mindist/1000, self.FLminuser/RAT.unit.FL2m) - self:T(RAT.id..text) + self:T(self.lid..text) end -- DESTINATION AIRPORT - local destination=nil + local destination=nil --Wrapper.Airbase#AIRBASE if _destination then if self:_AirportExists(_destination) then @@ -2637,7 +2959,7 @@ function RAT:_SetRoute(takeoff, landing, _departure, _destination, _waypoint) destination=ZONE:FindByName(_destination) else local text=string.format("ERROR: Specified destination airport/zone %s does not exist for %s!", _destination, self.alias) - self:E(RAT.id.."ERROR: "..text) + self:E(self.lid.."ERROR: "..text) end else @@ -2666,7 +2988,7 @@ function RAT:_SetRoute(takeoff, landing, _departure, _destination, _waypoint) if not destination then local text=string.format("No valid destination airport could be found for %s!", self.alias) MESSAGE:New(text, 60):ToAll() - self:E(RAT.id.."ERROR: "..text) + self:E(self.lid.."ERROR: "..text) return nil end @@ -2674,7 +2996,7 @@ function RAT:_SetRoute(takeoff, landing, _departure, _destination, _waypoint) if destination:GetName()==departure:GetName() then local text=string.format("%s: Destination and departure are identical. Airport/zone %s.", self.alias, destination:GetName()) MESSAGE:New(text, 30):ToAll() - self:E(RAT.id.."ERROR: "..text) + self:E(self.lid.."ERROR: "..text) end -- Get a random point inside zone return zone. @@ -2691,7 +3013,7 @@ function RAT:_SetRoute(takeoff, landing, _departure, _destination, _waypoint) end -- Get destination coordinate. Either in a zone or exactly at the airport. - local Pdestination + local Pdestination --Core.Point#COORDINATE if landing==RAT.wp.air then local vec2=destination:GetRandomVec2() Pdestination=COORDINATE:NewFromVec2(vec2) @@ -2936,7 +3258,7 @@ function RAT:_SetRoute(takeoff, landing, _departure, _destination, _waypoint) text=text..string.format("h_descent_max = %6.1f m\n", h_descent_max) end text=text..string.format("******************************************************\n") - self:T2(RAT.id..text) + self:T2(self.lid..text) -- Ensure that cruise distance is positve. Can be slightly negative in special cases. And we don't want to turn back. if d_cruise<0 then @@ -2946,14 +3268,16 @@ function RAT:_SetRoute(takeoff, landing, _departure, _destination, _waypoint) -- Waypoints and coordinates local wp={} local c={} + local waypointdescriptions={} + local waypointstatus={} local wpholding=nil local wpfinal=nil -- Departure/Take-off c[#c+1]=Pdeparture wp[#wp+1]=self:_Waypoint(#wp+1, "Departure", takeoff, c[#wp+1], VxClimb, H_departure, departure) - self.waypointdescriptions[#wp]="Departure" - self.waypointstatus[#wp]=RAT.status.Departure + waypointdescriptions[#wp]="Departure" + waypointstatus[#wp]=RAT.status.Departure -- Climb if takeoff==RAT.wp.air then @@ -2967,8 +3291,8 @@ function RAT:_SetRoute(takeoff, landing, _departure, _destination, _waypoint) c[#c+1]=c[#c]:Translate(d_climb, heading) wp[#wp+1]=self:_Waypoint(#wp+1, "Begin of Cruise", RAT.wp.cruise, c[#wp+1], VxCruise, FLcruise) - self.waypointdescriptions[#wp]="Begin of Cruise" - self.waypointstatus[#wp]=RAT.status.Cruise + waypointdescriptions[#wp]="Begin of Cruise" + waypointstatus[#wp]=RAT.status.Cruise end else @@ -2978,12 +3302,12 @@ function RAT:_SetRoute(takeoff, landing, _departure, _destination, _waypoint) c[#c+1]=c[#c]:Translate(d_climb/2, heading) wp[#wp+1]=self:_Waypoint(#wp+1, "Climb", RAT.wp.climb, c[#wp+1], VxClimb, H_departure+(FLcruise-H_departure)/2) - self.waypointdescriptions[#wp]="Climb" - self.waypointstatus[#wp]=RAT.status.Climb + waypointdescriptions[#wp]="Climb" + waypointstatus[#wp]=RAT.status.Climb wp[#wp+1]=self:_Waypoint(#wp+1, "Begin of Cruise", RAT.wp.cruise, c[#wp+1], VxCruise, FLcruise) - self.waypointdescriptions[#wp]="Begin of Cruise" - self.waypointstatus[#wp]=RAT.status.Cruise + waypointdescriptions[#wp]="Begin of Cruise" + waypointstatus[#wp]=RAT.status.Cruise end @@ -2993,8 +3317,8 @@ function RAT:_SetRoute(takeoff, landing, _departure, _destination, _waypoint) if self.returnzone then c[#c+1]=Preturn wp[#wp+1]=self:_Waypoint(#wp+1, "Return Zone", RAT.wp.cruise, c[#wp+1], VxCruise, FLcruise) - self.waypointdescriptions[#wp]="Return Zone" - self.waypointstatus[#wp]=RAT.status.Uturn + waypointdescriptions[#wp]="Return Zone" + waypointstatus[#wp]=RAT.status.Uturn end if landing==RAT.wp.air then @@ -3002,23 +3326,23 @@ function RAT:_SetRoute(takeoff, landing, _departure, _destination, _waypoint) -- Next waypoint is already the final destination. c[#c+1]=Pdestination wp[#wp+1]=self:_Waypoint(#wp+1, "Final Destination", RAT.wp.finalwp, c[#wp+1], VxCruise, FLcruise) - self.waypointdescriptions[#wp]="Final Destination" - self.waypointstatus[#wp]=RAT.status.Destination + waypointdescriptions[#wp]="Final Destination" + waypointstatus[#wp]=RAT.status.Destination elseif self.returnzone then -- The little bit back to end of cruise. c[#c+1]=c[#c]:Translate(d_cruise/2, heading-180) wp[#wp+1]=self:_Waypoint(#wp+1, "End of Cruise", RAT.wp.cruise, c[#wp+1], VxCruise, FLcruise) - self.waypointdescriptions[#wp]="End of Cruise" - self.waypointstatus[#wp]=RAT.status.Descent + waypointdescriptions[#wp]="End of Cruise" + waypointstatus[#wp]=RAT.status.Descent else c[#c+1]=c[#c]:Translate(d_cruise, heading) wp[#wp+1]=self:_Waypoint(#wp+1, "End of Cruise", RAT.wp.cruise, c[#wp+1], VxCruise, FLcruise) - self.waypointdescriptions[#wp]="End of Cruise" - self.waypointstatus[#wp]=RAT.status.Descent + waypointdescriptions[#wp]="End of Cruise" + waypointstatus[#wp]=RAT.status.Descent end @@ -3027,31 +3351,31 @@ function RAT:_SetRoute(takeoff, landing, _departure, _destination, _waypoint) if self.returnzone then c[#c+1]=c[#c]:Translate(d_descent/2, heading-180) wp[#wp+1]=self:_Waypoint(#wp+1, "Descent", RAT.wp.descent, c[#wp+1], VxDescent, FLcruise-(FLcruise-(h_holding+H_holding))/2) - self.waypointdescriptions[#wp]="Descent" - self.waypointstatus[#wp]=RAT.status.DescentHolding + waypointdescriptions[#wp]="Descent" + waypointstatus[#wp]=RAT.status.DescentHolding else c[#c+1]=c[#c]:Translate(d_descent/2, heading) wp[#wp+1]=self:_Waypoint(#wp+1, "Descent", RAT.wp.descent, c[#wp+1], VxDescent, FLcruise-(FLcruise-(h_holding+H_holding))/2) - self.waypointdescriptions[#wp]="Descent" - self.waypointstatus[#wp]=RAT.status.DescentHolding + waypointdescriptions[#wp]="Descent" + waypointstatus[#wp]=RAT.status.DescentHolding end end -- Holding and final destination. if landing==RAT.wp.landing then - -- Holding point - c[#c+1]=Pholding - wp[#wp+1]=self:_Waypoint(#wp+1, "Holding Point", RAT.wp.holding, c[#wp+1], VxHolding, H_holding+h_holding) - self.waypointdescriptions[#wp]="Holding Point" - self.waypointstatus[#wp]=RAT.status.Holding - wpholding=#wp + -- Holding point (removed the holding point because FLIGHTGROUP sends group to holding point with RTB command after the last waypoint) +-- c[#c+1]=Pholding +-- wp[#wp+1]=self:_Waypoint(#wp+1, "Holding Point", RAT.wp.holding, c[#wp+1], VxHolding, H_holding+h_holding) +-- waypointdescriptions[#wp]="Holding Point" +-- waypointstatus[#wp]=RAT.status.Holding +-- wpholding=#wp - -- Final destination. + -- Final destination (leave this in because FLIGHTGROUP needs to know that we want to land and removes the landing waypoint automatically) c[#c+1]=Pdestination wp[#wp+1]=self:_Waypoint(#wp+1, "Final Destination", landing, c[#wp+1], VxFinal, H_destination, destination) - self.waypointdescriptions[#wp]="Final Destination" - self.waypointstatus[#wp]=RAT.status.Destination + waypointdescriptions[#wp]="Final Destination" + waypointstatus[#wp]=RAT.status.Destination end @@ -3065,14 +3389,14 @@ function RAT:_SetRoute(takeoff, landing, _departure, _destination, _waypoint) end -- Some info on the route. - self:_Routeinfo(waypoints, "Waypoint info in set_route:") + self:_Routeinfo(waypoints, "Waypoint info in set_route:", waypointdescriptions) -- Return departure, destination and waypoints. if self.returnzone then -- We return the actual zone here because returning the departure leads to problems with commute. - return departure, destination_returnzone, waypoints, wpholding, wpfinal + return departure, destination_returnzone, waypoints, waypointdescriptions, waypointstatus else - return departure, destination, waypoints, wpholding, wpfinal + return departure, destination, waypoints, waypointdescriptions, waypointstatus end end @@ -3143,10 +3467,10 @@ function RAT:_PickDeparture(takeoff) if takeoff==RAT.wp.air then dep=ZONE:FindByName(name) else - self:E(RAT.id..string.format("ERROR! Takeoff is not in air. Cannot use %s as departure.", name)) + self:E(self.lid..string.format("ERROR! Takeoff is not in air. Cannot use %s as departure.", name)) end else - self:E(RAT.id..string.format("ERROR: No airport or zone found with name %s.", name)) + self:E(self.lid..string.format("ERROR: No airport or zone found with name %s.", name)) end -- Add to departures table. @@ -3159,7 +3483,7 @@ function RAT:_PickDeparture(takeoff) end -- Info message. - self:T(RAT.id..string.format("Number of possible departures for %s= %d", self.alias, #departures)) + self:T(self.lid..string.format("Number of possible departures for %s= %d", self.alias, #departures)) -- Select departure airport or zone. local departure=departures[math.random(#departures)] @@ -3172,9 +3496,9 @@ function RAT:_PickDeparture(takeoff) text=string.format("%s: Chosen departure airport: %s (ID %d)", self.alias, departure:GetName(), departure:GetID()) end --MESSAGE:New(text, 30):ToAllIf(self.Debug) - self:T(RAT.id..text) + self:T(self.lid..text) else - self:E(RAT.id..string.format("ERROR! No departure airport or zone found for %s.", self.alias)) + self:E(self.lid..string.format("ERROR! No departure airport or zone found for %s.", self.alias)) departure=nil end @@ -3255,10 +3579,10 @@ function RAT:_PickDestination(departure, q, minrange, maxrange, random, landing) if landing==RAT.wp.air then dest=ZONE:FindByName(name) else - self:E(RAT.id..string.format("ERROR! Landing is not in air. Cannot use zone %s as destination!", name)) + self:E(self.lid..string.format("ERROR! Landing is not in air. Cannot use zone %s as destination!", name)) end else - self:E(RAT.id..string.format("ERROR! No airport or zone found with name %s", name)) + self:E(self.lid..string.format("ERROR! No airport or zone found with name %s", name)) end if dest then @@ -3270,7 +3594,7 @@ function RAT:_PickDestination(departure, q, minrange, maxrange, random, landing) table.insert(destinations, dest) else local text=string.format("Destination %s is ouside range. Distance = %5.1f km, min = %5.1f km, max = %5.1f km.", name, distance, minrange, maxrange) - self:T(RAT.id..text) + self:T(self.lid..text) end end @@ -3279,7 +3603,7 @@ function RAT:_PickDestination(departure, q, minrange, maxrange, random, landing) end -- Info message. - self:T(RAT.id..string.format("Number of possible destinations = %s.", #destinations)) + self:T(self.lid..string.format("Number of possible destinations = %s.", #destinations)) if #destinations > 0 then --- Compare distance of destination airports. @@ -3311,11 +3635,11 @@ function RAT:_PickDestination(departure, q, minrange, maxrange, random, landing) else text=string.format("%s Chosen destination airport: %s (ID %d).", self.alias, destination:GetName(), destination:GetID()) end - self:T(RAT.id..text) + self:T(self.lid..text) --MESSAGE:New(text, 30):ToAllIf(self.Debug) else - self:E(RAT.id.."ERROR! No destination airport or zone found.") + self:E(self.lid.."ERROR! No destination airport or zone found.") destination=nil end @@ -3403,11 +3727,11 @@ function RAT:_GetAirportsOfMap() table.insert(self.airports_map, _myab) local text="MOOSE: Airport ID = ".._myab:GetID().." and Name = ".._myab:GetName()..", Category = ".._myab:GetCategory()..", TypeName = ".._myab:GetTypeName() - self:T(RAT.id..text) + self:T(self.lid..text) else - self:E(RAT.id..string.format("WARNING: Airbase %s does not exsist as MOOSE object!", tostring(_name))) + self:E(self.lid..string.format("WARNING: Airbase %s does not exsist as MOOSE object!", tostring(_name))) end end @@ -3423,22 +3747,12 @@ function RAT:_GetAirportsOfCoalition() local airport=_airport --Wrapper.Airbase#AIRBASE local category=airport:GetAirbaseCategory() if airport:GetCoalition()==coalition then - -- Planes cannot land on FARPs. - --local condition1=self.category==RAT.cat.plane and airport:GetTypeName()=="FARP" - local condition1=self.category==RAT.cat.plane and category==Airbase.Category.HELIPAD - -- Planes cannot land on ships. - --local condition2=self.category==RAT.cat.plane and airport:GetCategory()==1 - local condition2=self.category==RAT.cat.plane and category==Airbase.Category.SHIP - -- Check that airport has the requested terminal types. - -- NOT good here because we would also not allow any airport zones! - --[[ - local nspots=1 - if self.termtype then - nspots=airport:GetParkingSpotsNumber(self.termtype) - end - local condition3 = nspots==0 - ]] + -- Planes cannot land on FARPs. + local condition1=self.category==RAT.cat.plane and category==Airbase.Category.HELIPAD + + -- Planes cannot land on ships. + local condition2=self.category==RAT.cat.plane and category==Airbase.Category.SHIP if not (condition1 or condition2) then table.insert(self.airports, airport) @@ -3450,7 +3764,7 @@ function RAT:_GetAirportsOfCoalition() if #self.airports==0 then local text=string.format("No possible departure/destination airports found for RAT %s.", tostring(self.alias)) MESSAGE:New(text, 10):ToAll() - self:E(RAT.id..text) + self:E(self.lid..text) end end @@ -3462,13 +3776,7 @@ end -- @param #number forID (Optional) Send message only for this ID. function RAT:Status(message, forID) - -- Optional arguments. - if message==nil then - message=false - end - if forID==nil then - forID=false - end + self:T(self.lid.."Checking status") -- Current time. local Tnow=timer.getTime() @@ -3477,117 +3785,49 @@ function RAT:Status(message, forID) local nalive=0 -- Loop over all ratcraft. - for spawnindex,ratcraft in ipairs(self.ratcraft) do + for spawnindex,_ratcraft in pairs(self.ratcraft) do + local ratcraft=_ratcraft --#RAT.RatCraft + + self:T(self.lid..string.format("Ratcraft Index=%s", tostring(spawnindex))) -- Get group. local group=ratcraft.group --Wrapper.Group#GROUP - if group and group:IsAlive() and (group:GetCoordinate() or group:GetVec3()) then + if group and group:IsAlive() then nalive=nalive+1 + + self:T(self.lid..string.format("Ratcraft Index=%s is ALIVE", tostring(spawnindex))) -- Gather some information. local prefix=self:_GetPrefixFromGroup(group) local life=self:_GetLife(group) local fuel=group:GetFuel()*100.0 local airborne=group:InAir() - local coords=group:GetCoordinate() or group:GetVec3() - local alt=1000 - if coords then - alt=coords.y or 1000 - end - --local vel=group:GetVelocityKMH() + local coords=group:GetCoordinate() + local alt=coords~=nil and coords.y or 1000 local departure=ratcraft.departure:GetName() local destination=ratcraft.destination:GetName() local type=self.aircraft.type local status=ratcraft.status local active=ratcraft.active - local Nunits=ratcraft.nunits -- group:GetSize() + local Nunits=ratcraft.nunits local N0units=group:GetInitialSize() - -- Monitor time and distance on ground. - local Tg=0 - local Dg=0 - local dTlast=0 - local stationary=false --lets assume, we did move - if airborne then - -- Aircraft is airborne. - ratcraft["Tground"]=nil - ratcraft["Pground"]=nil - ratcraft["Uground"]=nil - ratcraft["Tlastcheck"]=nil - else - --Aircraft is on ground. - if ratcraft["Tground"] then - -- Aircraft was already on ground. Calculate total time on ground. - Tg=Tnow-ratcraft["Tground"] - - -- Distance on ground since last check. - Dg=coords:Get2DDistance(ratcraft["Pground"]) - - -- Time interval since last check. - dTlast=Tnow-ratcraft["Tlastcheck"] - - -- If more than Tinactive seconds passed since last check ==> check how much we moved meanwhile. - if dTlast > self.Tinactive then - - --[[ - if Dg<50 and active and status~=RAT.status.EventBirth then - stationary=true - end - ]] - - -- Loop over all units. - for _,_unit in pairs(group:GetUnits()) do - - if _unit and _unit:IsAlive() then - - -- Unit name, coord and distance since last check. - local unitname=_unit:GetName() - local unitcoord=_unit:GetCoordinate() - local Ug=unitcoord:Get2DDistance(ratcraft.Uground[unitname]) - - -- Debug info - self:T2(RAT.id..string.format("Unit %s travelled distance on ground %.1f m since %d seconds.", unitname, Ug, dTlast)) - - -- If aircraft did not move more than 50 m since last check, we call it stationary and despawn it. - -- Aircraft which are spawned uncontrolled or starting their engines are not counted. - if Ug<50 and active and status~=RAT.status.EventBirth then - stationary=true - end - - -- Update coords. - ratcraft["Uground"][unitname]=unitcoord - end - end - - -- Set the current time to know when the next check is necessary. - ratcraft["Tlastcheck"]=Tnow - ratcraft["Pground"]=coords - end - - else - -- First time we see that the aircraft is on ground. Initialize the times and position. - ratcraft["Tground"]=Tnow - ratcraft["Tlastcheck"]=Tnow - ratcraft["Pground"]=coords - ratcraft["Uground"]={} - for _,_unit in pairs(group:GetUnits()) do - local unitname=_unit:GetName() - ratcraft.Uground[unitname]=_unit:GetCoordinate() - end - end + -- Monitor travelled distance since last check. + local Dtravel=0 + if coords and ratcraft.Pnow then + local Dtravel=coords:Get2DDistance(ratcraft.Pnow) + ratcraft.Pnow=coords end - -- Monitor travelled distance since last check. - local Pn=coords - local Dtravel=Pn:Get2DDistance(ratcraft["Pnow"]) - ratcraft["Pnow"]=Pn - -- Add up the travelled distance. - ratcraft["Distance"]=ratcraft["Distance"]+Dtravel + ratcraft.Distance=ratcraft.Distance+Dtravel -- Distance remaining to destination. - local Ddestination=Pn:Get2DDistance(ratcraft.destination:GetCoordinate()) + local Ddestination=-1 + if ratcraft.Pnow then + Ddestination=ratcraft.Pnow:Get2DDistance(ratcraft.destination:GetCoordinate()) + end -- Status report. if (forID and spawnindex==forID) or (not forID) then @@ -3610,76 +3850,78 @@ function RAT:Status(message, forID) else text=text.." [on ground]\n" end - text=text..string.format("Fuel = %3.0f %%\n", fuel) - text=text..string.format("Life = %3.0f %%\n", life) - text=text..string.format("FL%03d = %i m ASL\n", alt/RAT.unit.FL2m, alt) - --text=text..string.format("Speed = %i km/h\n", vel) - text=text..string.format("Distance travelled = %6.1f km\n", ratcraft["Distance"]/1000) - text=text..string.format("Distance to destination = %6.1f km", Ddestination/1000) - if not airborne then - text=text..string.format("\nTime on ground = %6.0f seconds\n", Tg) - text=text..string.format("Position change = %8.1f m since %3.0f seconds.", Dg, dTlast) - end - self:T(RAT.id..text) + text=text..string.format("Fuel = %3.0f %%\n", fuel) + text=text..string.format("Life = %3.0f %%\n", life) + text=text..string.format("FL%03d = %i m ASL\n", alt/RAT.unit.FL2m, alt) + text=text..string.format("Distance travelled = %6.1f km\n", ratcraft["Distance"]/1000) + text=text..string.format("Distance to dest = %6.1f km", Ddestination/1000) + self:T(self.lid..text) if message then MESSAGE:New(text, 20):ToAll() end end - -- Despawn groups if they are on ground and don't move or are damaged. - if not airborne then - - -- Despawn unit if it did not move more then 50 m in the last 180 seconds. - if stationary then - local text=string.format("Group %s is despawned after being %d seconds inaktive on ground.", self.alias, dTlast) - self:T(RAT.id..text) - self:_Despawn(group) - end - - -- Despawn group if life is < 10% and distance travelled < 100 m. - if life<10 and Dtravel<100 then - local text=string.format("Damaged group %s is despawned. Life = %3.0f", self.alias, life) - self:T(RAT.id..text) - self:_Despawn(group) - end - - end - -- Despawn groups after they have reached their destination zones. if ratcraft.despawnme then - local text=string.format("Flight %s will be despawned NOW!", self.alias) - self:T(RAT.id..text) - - -- Respawn group - if (not self.norespawn) and (not self.respawn_after_takeoff) then - local idx=self:GetSpawnIndexFromGroup(group) - local coord=group:GetCoordinate() - self:_Respawn(idx, coord, 0) - end - - -- Despawn old group. - if self.despawnair then - self:_Despawn(group, 0) + if self.norespawn or self.respawn_after_takeoff then + + -- Despawn old group. + if self.despawnair then + self:T(self.lid..string.format("[STATUS despawnme] Flight %s will be despawned NOW and NO new group is created!", self.alias)) + self:_Despawn(group) + end + + else + + -- Despawn old group and respawn a new one. + self:T(self.lid..string.format("[STATUS despawnme] Flight %s will be despawned NOW and a new group is respawned!", self.alias)) + self:_Respawn(group) + end end else -- Group does not exist. - local text=string.format("Group does not exist in loop ratcraft status.") - self:T2(RAT.id..text) + local text=string.format("Group does not exist in loop ratcraft status for spawn index=%d", spawnindex) + self:T2(self.lid..text) + self:T2(ratcraft) end end -- Alive groups. local text=string.format("Alive groups of %s: %d, nalive=%d/%d", self.alias, self.alive, nalive, self.ngroups) - self:T(RAT.id..text) + self:T(self.lid..text) MESSAGE:New(text, 20):ToAllIf(message and not forID) end +--- Remove ratcraft from self.ratcraft table. +-- @param #RAT self +-- @param #RAT.RatCraft ratcraft The ratcraft to be removed. +-- @return #RAT self +function RAT:_RemoveRatcraft(ratcraft) + + self.ratcraft[ratcraft.index]=nil + + return self +end + +--- Get ratcraft from group. +-- @param #RAT self +-- @param Wrapper.Group#Group group The group object. +-- @return #RAT.RatCraft The ratcraft object. +function RAT:_GetRatcraftFromGroup(group) + + local index=self:GetSpawnIndexFromGroup(group) + + local ratcraft=self.ratcraft[index] + + return ratcraft +end + --- Get (relative) life of first unit of a group. -- @param #RAT self -- @param Wrapper.Group#GROUP group Group of unit. @@ -3691,10 +3933,10 @@ function RAT:_GetLife(group) if unit then life=unit:GetLife()/unit:GetLife0()*100 else - self:T2(RAT.id.."ERROR! Unit does not exist in RAT_Getlife(). Returning zero.") + self:T2(self.lid.."ERROR! Unit does not exist in RAT_Getlife(). Returning zero.") end else - self:T2(RAT.id.."ERROR! Group does not exist in RAT_Getlife(). Returning zero.") + self:T2(self.lid.."ERROR! Group does not exist in RAT_Getlife(). Returning zero.") end return life end @@ -3708,20 +3950,20 @@ function RAT:_SetStatus(group, status) if group and group:IsAlive() then -- Get index from groupname. - local index=self:GetSpawnIndexFromGroup(group) + local ratcraft=self:_GetRatcraftFromGroup(group) - if self.ratcraft[index] then + if ratcraft then -- Set new status. - self.ratcraft[index].status=status + ratcraft.status=status -- No status update message for "first waypoint", "holding" local no1 = status==RAT.status.Departure local no2 = status==RAT.status.EventBirthAir local no3 = status==RAT.status.Holding - local text=string.format("Flight %s: %s.", group:GetName(), status) - self:T(RAT.id..text) + local text=string.format("Flight %s: %s", group:GetName(), status) + self:T(self.lid..text) if not (no1 or no2 or no3) then MESSAGE:New(text, 10):ToAllIf(self.reportstatus) @@ -3732,6 +3974,26 @@ function RAT:_SetStatus(group, status) end end +--- Get RatCraft from a given group. +-- @param #RAT self +-- @param Wrapper.Group#GROUP group Group. +-- @return #RAT.RatCraft Rat craft object. +function RAT:_GetRatcraftFromGroup(group) + + if group then + + -- Get index from groupname. + local index=self:GetSpawnIndexFromGroup(group) + + if self.ratcraft[index] then + return self.ratcraft[index] + end + + end + + return nil +end + --- Get status of group. -- @param #RAT self -- @param Wrapper.Group#GROUP group Group. @@ -3741,12 +4003,12 @@ function RAT:GetStatus(group) if group and group:IsAlive() then -- Get index from groupname. - local index=self:GetSpawnIndexFromGroup(group) + local ratcraft=self:_GetRatcraftFromGroup(group) - if self.ratcraft[index] then + if ratcraft then -- Set new status. - return self.ratcraft[index].status + return ratcraft.status end @@ -3763,7 +4025,7 @@ end -- @param Core.Event#EVENTDATA EventData function RAT:_OnBirth(EventData) self:F3(EventData) - self:T3(RAT.id.."Captured event birth!") + self:T3(self.lid.."Captured event birth!") local SpawnGroup = EventData.IniGroup --Wrapper.Group#GROUP @@ -3772,108 +4034,109 @@ function RAT:_OnBirth(EventData) -- Get the template name of the group. This can be nil if this was not a spawned group. local EventPrefix = self:_GetPrefixFromGroup(SpawnGroup) - if EventPrefix then + -- Check that the template name actually belongs to this object. + if EventPrefix and EventPrefix == self.alias then - -- Check that the template name actually belongs to this object. - if EventPrefix == self.alias then - - local text="Event: Group "..SpawnGroup:GetName().." was born." - self:T(RAT.id..text) - - -- Set status. - local status="unknown in birth" - if SpawnGroup:InAir() then - status=RAT.status.EventBirthAir - elseif self.uncontrolled then - status=RAT.status.Uncontrolled - else - status=RAT.status.EventBirth - end - self:_SetStatus(SpawnGroup, status) - - -- Get some info ablout this flight. - local i=self:GetSpawnIndexFromGroup(SpawnGroup) - local _departure=self.ratcraft[i].departure:GetName() - local _destination=self.ratcraft[i].destination:GetName() - local _nrespawn=self.ratcraft[i].nrespawn - local _takeoff=self.ratcraft[i].takeoff - local _landing=self.ratcraft[i].landing - local _livery=self.ratcraft[i].livery - - -- Some is only useful for an actual airbase (not a zone). - local _airbase=AIRBASE:FindByName(_departure) - - -- Check if aircraft group was accidentally spawned on the runway. - -- This can happen due to no parking slots available and other DCS bugs. - local onrunway=false - if _airbase then - -- Check that we did not want to spawn at a runway or in air. - if self.checkonrunway and _takeoff ~= RAT.wp.runway and _takeoff ~= RAT.wp.air then - onrunway=_airbase:CheckOnRunWay(SpawnGroup, self.onrunwayradius, false) - end - end - - -- Workaround if group was spawned on runway. - if onrunway then - - -- Error message. - local text=string.format("ERROR: RAT group of %s was spawned on runway. Group #%d will be despawned immediately!", self.alias, i) - MESSAGE:New(text,30):ToAllIf(self.Debug) - self:E(RAT.id..text) - if self.Debug then - SpawnGroup:FlareRed() - end - - -- Despawn the group. - self:_Despawn(SpawnGroup) - - -- Try to respawn the group if there is at least another airport or random airport selection is used. - if (self.Ndeparture_Airports>=2 or self.random_departure) and _nrespawn=2 or self.random_departure) and _nrespawn new state %s.", SpawnGroup:GetName(), currentstate, status) - self:T(RAT.id..text) + self:T(self.lid..text) -- Respawn group. - local idx=self:GetSpawnIndexFromGroup(SpawnGroup) - local coord=SpawnGroup:GetCoordinate() - self:_Respawn(idx, coord) + self:_Respawn(SpawnGroup, nil, 3) + + else + + -- Despawn group. + text="Event: Group "..SpawnGroup:GetName().." will be destroyed now" + self:T(self.lid..text) + self:_Despawn(SpawnGroup) + end - -- Despawn group. - text="Event: Group "..SpawnGroup:GetName().." will be destroyed now." - self:T(RAT.id..text) - self:_Despawn(SpawnGroup) end @@ -4057,7 +4312,7 @@ function RAT:_OnEngineShutdown(EventData) end else - self:T2(RAT.id.."ERROR: Group does not exist in RAT:_OnEngineShutdown().") + self:T2(self.lid.."ERROR: Group does not exist in RAT:_OnEngineShutdown().") end end @@ -4066,7 +4321,7 @@ end -- @param Core.Event#EVENTDATA EventData function RAT:_OnHit(EventData) self:F3(EventData) - self:T(RAT.id..string.format("Captured event Hit by %s! Initiator %s. Target %s", self.alias, tostring(EventData.IniUnitName), tostring(EventData.TgtUnitName))) + self:T(self.lid..string.format("Captured event Hit by %s! Initiator %s. Target %s", self.alias, tostring(EventData.IniUnitName), tostring(EventData.TgtUnitName))) local SpawnGroup = EventData.TgtGroup --Wrapper.Group#GROUP @@ -4078,7 +4333,7 @@ function RAT:_OnHit(EventData) -- Check that the template name actually belongs to this object. if EventPrefix and EventPrefix == self.alias then -- Debug info. - self:T(RAT.id..string.format("Event: Group %s was hit. Unit %s.", SpawnGroup:GetName(), tostring(EventData.TgtUnitName))) + self:T(self.lid..string.format("Event: Group %s was hit. Unit %s.", SpawnGroup:GetName(), tostring(EventData.TgtUnitName))) local text=string.format("%s, unit %s was hit!", self.alias, EventData.TgtUnitName) MESSAGE:New(text, 10):ToAllIf(self.reportstatus or self.Debug) @@ -4091,7 +4346,7 @@ end -- @param Core.Event#EVENTDATA EventData function RAT:_OnDeadOrCrash(EventData) self:F3(EventData) - self:T3(RAT.id.."Captured event DeadOrCrash!") + self:T3(self.lid.."Captured event DeadOrCrash!") local SpawnGroup = EventData.IniGroup --Wrapper.Group#GROUP @@ -4110,7 +4365,7 @@ function RAT:_OnDeadOrCrash(EventData) -- Debug info. local text=string.format("Event: Group %s crashed or died. Alive counter = %d.", SpawnGroup:GetName(), self.alive) - self:T(RAT.id..text) + self:T(self.lid..text) -- Split crash and dead events. if EventData.id == world.event.S_EVENT_CRASH then @@ -4134,7 +4389,7 @@ end -- @param Core.Event#EVENTDATA EventData function RAT:_OnDead(EventData) self:F3(EventData) - self:T3(RAT.id.."Captured event Dead!") + self:T3(self.lid.."Captured event Dead!") local SpawnGroup = EventData.IniGroup --Wrapper.Group#GROUP @@ -4149,7 +4404,7 @@ function RAT:_OnDead(EventData) if EventPrefix == self.alias then local text=string.format("Event: Group %s died. Unit %s.", SpawnGroup:GetName(), EventData.IniUnitName) - self:T(RAT.id..text) + self:T(self.lid..text) -- Set status. local status=RAT.status.EventDead @@ -4159,7 +4414,7 @@ function RAT:_OnDead(EventData) end else - self:T2(RAT.id.."ERROR: Group does not exist in RAT:_OnDead().") + self:T2(self.lid.."ERROR: Group does not exist in RAT:_OnDead().") end end @@ -4168,7 +4423,7 @@ end -- @param Core.Event#EVENTDATA EventData function RAT:_OnCrash(EventData) self:F3(EventData) - self:T3(RAT.id.."Captured event Crash!") + self:T3(self.lid.."Captured event Crash!") local SpawnGroup = EventData.IniGroup --Wrapper.Group#GROUP @@ -4180,162 +4435,48 @@ function RAT:_OnCrash(EventData) -- Check that the template name actually belongs to this object. if EventPrefix and EventPrefix == self.alias then - -- Update number of alive units in the group. - local _i=self:GetSpawnIndexFromGroup(SpawnGroup) - self.ratcraft[_i].nunits=self.ratcraft[_i].nunits-1 - local _n=self.ratcraft[_i].nunits - local _n0=SpawnGroup:GetInitialSize() + -- Get ratcraft object of this group. + local ratcraft=self:_GetRatcraftFromGroup(SpawnGroup) + + if ratcraft then - -- Debug info. - local text=string.format("Event: Group %s crashed. Unit %s. Units still alive %d of %d.", SpawnGroup:GetName(), EventData.IniUnitName, _n, _n0) - self:T(RAT.id..text) - - -- Set status. - local status=RAT.status.EventCrash - self:_SetStatus(SpawnGroup, status) - - -- Respawn group if all units are dead. - if _n==0 and self.respawn_after_crash and not self.norespawn then - local text=string.format("No units left of group %s. Group will be respawned now.", SpawnGroup:GetName()) - self:T(RAT.id..text) - -- Respawn group. - local idx=self:GetSpawnIndexFromGroup(SpawnGroup) - local coord=SpawnGroup:GetCoordinate() - self:_Respawn(idx, coord) + -- Update number of alive units in the group. + ratcraft.nunits=ratcraft.nunits-1 + + -- Number of initial units. + local _n0=SpawnGroup:GetInitialSize() + + -- Debug info. + local text=string.format("Event: Group %s crashed. Unit %s. Units still alive %d of %d.", SpawnGroup:GetName(), EventData.IniUnitName, ratcraft.nunits, _n0) + self:T(self.lid..text) + + -- Set status. + local status=RAT.status.EventCrash + self:_SetStatus(SpawnGroup, status) + + -- Respawn group if all units are dead. + if ratcraft.nunits==0 and self.respawn_after_crash and not self.norespawn then + + -- Debug info. + self:T(self.lid..string.format("No units left of group %s. Group will be respawned now.", SpawnGroup:GetName())) + + -- Respawn group. + self:_Respawn(SpawnGroup) + end + + else + self:E(self.lid..string.format("ERROR: Could not find ratcraft object for crashed group %s!", SpawnGroup:GetName())) end end else if self.Debug then - self:E(RAT.id.."ERROR: Group does not exist in RAT:_OnCrash().") + self:E(self.lid.."ERROR: Group does not exist in RAT:_OnCrash()!") end end end ---- Despawn unit. Unit gets destoyed and group is set to nil. --- Index of ratcraft array is taken from spawned group name. --- @param #RAT self --- @param Wrapper.Group#GROUP group Group to be despawned. --- @param #number delay Delay in seconds before the despawn happens. -function RAT:_Despawn(group, delay) - - if group ~= nil then - - -- Get spawnindex of group. - local index=self:GetSpawnIndexFromGroup(group) - - if index ~= nil then - - self.ratcraft[index].group=nil - self.ratcraft[index]["status"]="Dead" - - --TODO: Maybe here could be some more arrays deleted? - --TODO: Somehow this causes issues. - --[[ - --self.ratcraft[index]["group"]=group - self.ratcraft[index]["destination"]=nil - self.ratcraft[index]["departure"]=nil - self.ratcraft[index]["waypoints"]=nil - self.ratcraft[index]["airborne"]=nil - self.ratcraft[index]["Tground"]=nil - self.ratcraft[index]["Pground"]=nil - self.ratcraft[index]["Tlastcheck"]=nil - self.ratcraft[index]["P0"]=nil - self.ratcraft[index]["Pnow"]=nil - self.ratcraft[index]["Distance"]=nil - self.ratcraft[index].takeoff=nil - self.ratcraft[index].landing=nil - self.ratcraft[index].wpholding=nil - self.ratcraft[index].wpfinal=nil - self.ratcraft[index].active=false - self.ratcraft[index]["status"]=nil - self.ratcraft[index].livery=nil - self.ratcraft[index].despawnme=nil - self.ratcraft[index].nrespawn=nil - ]] - -- Remove ratcraft table entry. - --table.remove(self.ratcraft, index) - - - -- We should give it at least 3 sec since this seems to be the time until free parking spots after despawn are available again (Sirri Island test). - local despawndelay=0 - if delay then - -- Explicitly requested delay time. - despawndelay=delay - elseif self.respawn_delay then - -- Despawn afer respawn_delay. Actual respawn happens in +3 seconds to allow for free parking. - despawndelay=self.respawn_delay - end - - -- This will destroy the DCS group and create a single DEAD event. - --if despawndelay>0.5 then - self:T(RAT.id..string.format("%s delayed despawn in %.1f seconds.", self.alias, despawndelay)) - SCHEDULER:New(nil, self._Destroy, {self, group}, despawndelay) - --else - --self:_Destroy(group) - --end - - -- Remove submenu for this group. - if self.f10menu and self.SubMenuName ~= nil then - self.Menu[self.SubMenuName]["groups"][index]:Remove() - end - - end - end -end - ---- Destroys the RAT DCS group and all of its DCS units. --- Note that this raises a DEAD event at run-time. --- So all event listeners will catch the DEAD event of this DCS group. --- @param #RAT self --- @param Wrapper.Group#GROUP group The RAT group to be destroyed. -function RAT:_Destroy(group) - self:F2(group) - - local DCSGroup = group:GetDCSObject() -- DCS#Group - - if DCSGroup and DCSGroup:isExist() then - - -- Cread one single Dead event and delete units from database. - local triggerdead=true - for _,DCSUnit in pairs(DCSGroup:getUnits()) do - - -- Dead event. - if DCSUnit then - if triggerdead then - self:_CreateEventDead(timer.getTime(), DCSUnit) - triggerdead=false - end - - -- Delete from data base. - _DATABASE:DeleteUnit(DCSUnit:getName()) - end - end - - -- Destroy DCS group. - DCSGroup:destroy() - DCSGroup = nil - end - - return nil -end - ---- Create a Dead event. --- @param #RAT self --- @param DCS#Time EventTime The time stamp of the event. --- @param DCS#Object Initiator The initiating object of the event. -function RAT:_CreateEventDead(EventTime, Initiator) - self:F( { EventTime, Initiator } ) - - local Event = { - id = world.event.S_EVENT_DEAD, - time = EventTime, - initiator = Initiator, - } - - world.onEvent( Event ) -end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -4413,7 +4554,7 @@ function RAT:_Waypoint(index, description, Type, Coord, Speed, Altitude, Airport _Action="Turning Point" _alttype="BARO" else - self:E(RAT.id.."ERROR: Unknown waypoint type in RAT:Waypoint() function!") + self:E(self.lid.."ERROR: Unknown waypoint type in RAT:Waypoint() function!") _Type="Turning Point" _Action="Turning Point" _alttype="RADIO" @@ -4441,7 +4582,7 @@ function RAT:_Waypoint(index, description, Type, Coord, Speed, Altitude, Airport text=text..string.format("No airport/zone specified\n") end text=text.."******************************************************\n" - self:T2(RAT.id..text) + self:T2(self.lid..text) -- define waypoint local RoutePoint = {} @@ -4475,32 +4616,9 @@ function RAT:_Waypoint(index, description, Type, Coord, Speed, Altitude, Airport elseif AirbaseCategory == Airbase.Category.AIRDROME then RoutePoint.airdromeId = AirbaseID else - self:T(RAT.id.."Unknown Airport category in _Waypoint()!") + self:T(self.lid.."Unknown Airport category in _Waypoint()!") end end - -- properties - RoutePoint.properties = { - ["vnav"] = 1, - ["scale"] = 0, - ["angle"] = 0, - ["vangle"] = 0, - ["steer"] = 2, - } - -- tasks - local TaskCombo = {} - local TaskHolding = self:_TaskHolding({x=Coord.x, y=Coord.z}, Altitude, Speed, self:_Randomize(90,0.9)) - local TaskWaypoint = self:_TaskFunction("RAT._WaypointFunction", self, index) - - RoutePoint.task = {} - RoutePoint.task.id = "ComboTask" - RoutePoint.task.params = {} - - TaskCombo[#TaskCombo+1]=TaskWaypoint - if Type==RAT.wp.holding then - TaskCombo[#TaskCombo+1]=TaskHolding - end - - RoutePoint.task.params.tasks = TaskCombo -- Return waypoint. return RoutePoint @@ -4512,8 +4630,9 @@ end -- @param #RAT self -- @param #table waypoints Waypoints of the flight plan. -- @param #string comment Some comment to identify the provided information. +-- @param #table waypointdescriptions Waypoint descriptions. -- @return #number total Total route length in meters. -function RAT:_Routeinfo(waypoints, comment) +function RAT:_Routeinfo(waypoints, comment, waypointdescriptions) local text=string.format("\n******************************************************\n") text=text..string.format("Template = %s\n", self.SpawnTemplatePrefix) if comment then @@ -4523,7 +4642,7 @@ function RAT:_Routeinfo(waypoints, comment) -- info on coordinate and altitude for i=1,#waypoints do local p=waypoints[i] - text=text..string.format("WP #%i: x = %6.1f km, y = %6.1f km, alt = %6.1f m %s\n", i-1, p.x/1000, p.y/1000, p.alt, self.waypointdescriptions[i]) + text=text..string.format("WP #%i: x = %6.1f km, y = %6.1f km, alt = %6.1f m %s\n", i-1, p.x/1000, p.y/1000, p.alt, waypointdescriptions[i]) end -- info on distance between waypoints local total=0.0 @@ -4537,13 +4656,13 @@ function RAT:_Routeinfo(waypoints, comment) local d=math.sqrt((x1-x2)^2 + (y1-y2)^2) local heading=self:_Course(point1, point2) total=total+d - text=text..string.format("Distance from WP %i-->%i = %6.1f km. Heading = %03d : %s - %s\n", i-1, i, d/1000, heading, self.waypointdescriptions[i], self.waypointdescriptions[i+1]) + text=text..string.format("Distance from WP %i-->%i = %6.1f km. Heading = %03d : %s - %s\n", i-1, i, d/1000, heading, waypointdescriptions[i], waypointdescriptions[i+1]) end text=text..string.format("Total distance = %6.1f km\n", total/1000) text=text..string.format("******************************************************\n") -- Debug info. - self:T2(RAT.id..text) + self:T2(self.lid..text) -- return total route length in meters return total @@ -4551,148 +4670,6 @@ end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---- Orbit at a specified position at a specified alititude with a specified speed. --- @param #RAT self --- @param DCS#Vec2 P1 The point to hold the position. --- @param #number Altitude The altitude ASL at which to hold the position. --- @param #number Speed The speed flying when holding the position in m/s. --- @param #number Duration Duration of holding pattern in seconds. --- @return DCS#Task DCSTask -function RAT:_TaskHolding(P1, Altitude, Speed, Duration) - - --local LandHeight = land.getHeight(P1) - - --TODO: randomize P1 - -- Second point is 3 km north of P1 and 200 m for helos. - local dx=3000 - local dy=0 - if self.category==RAT.cat.heli then - dx=200 - dy=0 - end - - local P2={} - P2.x=P1.x+dx - P2.y=P1.y+dy - local Task = { - id = 'Orbit', - params = { - pattern = AI.Task.OrbitPattern.RACE_TRACK, - --pattern = AI.Task.OrbitPattern.CIRCLE, - point = P1, - point2 = P2, - speed = Speed, - altitude = Altitude - } - } - - local DCSTask={} - DCSTask.id="ControlledTask" - DCSTask.params={} - DCSTask.params.task=Task - - if self.ATCswitch then - -- Set stop condition for holding. Either flag=1 or after max. X min holding. - local userflagname=string.format("%s#%03d", self.alias, self.SpawnIndex+1) - local maxholdingduration=60*120 - DCSTask.params.stopCondition={userFlag=userflagname, userFlagValue=1, duration=maxholdingduration} - else - DCSTask.params.stopCondition={duration=Duration} - end - - return DCSTask -end - ---- Function which is called after passing every waypoint. Info on waypoint is given and special functions are executed. --- @param Wrapper.Group#GROUP group Group of aircraft. --- @param #RAT rat RAT object. --- @param #number wp Waypoint index. Running number of the waypoints. Determines the actions to be executed. -function RAT._WaypointFunction(group, rat, wp) - - -- Current time and Spawnindex. - local Tnow=timer.getTime() - local sdx=rat:GetSpawnIndexFromGroup(group) - - -- Departure and destination names. - local departure=rat.ratcraft[sdx].departure:GetName() - local destination=rat.ratcraft[sdx].destination:GetName() - local landing=rat.ratcraft[sdx].landing - local WPholding=rat.ratcraft[sdx].wpholding - local WPfinal=rat.ratcraft[sdx].wpfinal - - - -- For messages - local text - - -- Info on passing waypoint. - text=string.format("Flight %s passing waypoint #%d %s.", group:GetName(), wp, rat.waypointdescriptions[wp]) - BASE.T(rat, RAT.id..text) - - -- New status. - local status=rat.waypointstatus[wp] - rat:_SetStatus(group, status) - - if wp==WPholding then - - -- Aircraft arrived at holding point - text=string.format("Flight %s to %s ATC: Holding and awaiting landing clearance.", group:GetName(), destination) - MESSAGE:New(text, 10):ToAllIf(rat.reportstatus) - - -- Register aircraft at ATC. - if rat.ATCswitch then - if rat.f10menu then - MENU_MISSION_COMMAND:New("Clear for landing", rat.Menu[rat.SubMenuName].groups[sdx], rat.ClearForLanding, rat, group:GetName()) - end - rat._ATCRegisterFlight(rat, group:GetName(), Tnow) - end - end - - if wp==WPfinal then - text=string.format("Flight %s arrived at final destination %s.", group:GetName(), destination) - MESSAGE:New(text, 10):ToAllIf(rat.reportstatus) - BASE.T(rat, RAT.id..text) - - if landing==RAT.wp.air then - text=string.format("Activating despawn switch for flight %s! Group will be detroyed soon.", group:GetName()) - MESSAGE:New(text, 10):ToAllIf(rat.Debug) - BASE.T(rat, RAT.id..text) - -- Enable despawn switch. Next time the status function is called, the aircraft will be despawned. - rat.ratcraft[sdx].despawnme=true - end - end -end - ---- Task function. --- @param #RAT self --- @param #string FunctionString Name of the function to be called. -function RAT:_TaskFunction(FunctionString, ... ) - self:F2({FunctionString, arg}) - - local DCSTask - local ArgumentKey - - -- Templatename and anticipated name the group will get - local templatename=self.templategroup:GetName() - local groupname=self:_AnticipatedGroupName() - - local DCSScript = {} - DCSScript[#DCSScript+1] = "local MissionControllable = GROUP:FindByName(\""..groupname.."\") " - DCSScript[#DCSScript+1] = "local RATtemplateControllable = GROUP:FindByName(\""..templatename.."\") " - - if arg and arg.n > 0 then - ArgumentKey = '_' .. tostring(arg):match("table: (.*)") - self.templategroup:SetState(self.templategroup, ArgumentKey, arg) - DCSScript[#DCSScript+1] = "local Arguments = RATtemplateControllable:GetState(RATtemplateControllable, '" .. ArgumentKey .. "' ) " - DCSScript[#DCSScript+1] = FunctionString .. "( MissionControllable, unpack( Arguments ) )" - else - DCSScript[#DCSScript+1] = FunctionString .. "( MissionControllable )" - end - - DCSTask = self.templategroup:TaskWrappedAction(self.templategroup:CommandDoScript(table.concat(DCSScript))) - - return DCSTask -end - --- Anticipated group name from alias and spawn index. -- @param #RAT self -- @param #number index Spawnindex of group if given or self.SpawnIndex+1 by default. @@ -4707,7 +4684,6 @@ end --- Randomly activates an uncontrolled aircraft. -- @param #RAT self function RAT:_ActivateUncontrolled() - self:F() -- Spawn indices of uncontrolled inactive aircraft. local idx={} @@ -4717,14 +4693,15 @@ function RAT:_ActivateUncontrolled() local nactive=0 -- Loop over RAT groups and count the active ones. - for spawnindex,ratcraft in pairs(self.ratcraft) do + for spawnindex,_ratcraft in pairs(self.ratcraft) do + local ratcraft=_ratcraft --#RAT.RatCraft local group=ratcraft.group --Wrapper.Group#GROUP if group and group:IsAlive() then - local text=string.format("Uncontrolled: Group = %s (spawnindex = %d), active = %s.", ratcraft.group:GetName(), spawnindex, tostring(ratcraft.active)) - self:T2(RAT.id..text) + local text=string.format("Uncontrolled: Group = %s (spawnindex = %d), active = %s", ratcraft.group:GetName(), spawnindex, tostring(ratcraft.active)) + self:T2(self.lid..text) if ratcraft.active then nactive=nactive+1 @@ -4736,49 +4713,47 @@ function RAT:_ActivateUncontrolled() end -- Debug message. - local text=string.format("Uncontrolled: Ninactive = %d, Nactive = %d (of max %d).", #idx, nactive, self.activate_max) - self:T(RAT.id..text) + local text=string.format("Uncontrolled: Ninactive = %d, Nactive = %d (of max %d)", #idx, nactive, self.activate_max) + self:T(self.lid..text) if #idx>0 and nactive Less effort. - self:T(RAT.id..string.format("Group %s is spawned on farp/ship/runway %s.", self.alias, departure:GetName())) + self:T(self.lid..string.format("Group %s is spawned on farp/ship/runway %s.", self.alias, departure:GetName())) nfree=departure:GetFreeParkingSpotsNumber(termtype, true) spots=departure:GetFreeParkingSpotsTable(termtype, true) + -- Had a case at a Gas Platform where nfree=1 but spots from GetFreeParkingSpotsTable were empty. + --spots=departure:GetParkingSpotsTable(termtype) + self:T(self.lid..string.format("Free nfree=%d nspots=%d", nfree, #spots)) elseif parkingdata~=nil then -- Parking data explicitly set by user as input parameter. + self:T2("Spawning with explicit parking data") nfree=#parkingdata spots=parkingdata else @@ -5226,18 +5262,18 @@ function RAT:_ModifySpawnTemplate(waypoints, livery, spawnplace, departure, take if self.category==RAT.cat.heli then if termtype==nil then -- Try exclusive helo spots first. - self:T(RAT.id..string.format("Helo group %s is spawned at %s using terminal type %d.", self.alias, departure:GetName(), AIRBASE.TerminalType.HelicopterOnly)) + self:T(self.lid..string.format("Helo group %s is spawned at %s using terminal type %d.", self.alias, departure:GetName(), AIRBASE.TerminalType.HelicopterOnly)) spots=departure:FindFreeParkingSpotForAircraft(TemplateGroup, AIRBASE.TerminalType.HelicopterOnly, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits) nfree=#spots if nfree air start!", self.SpawnTemplatePrefix, departure:GetName())) + self:E(self.lid..string.format("WARNING: Group %s has no parking spots at %s ==> air start!", self.SpawnTemplatePrefix, departure:GetName())) -- Not enough parking spots at the airport ==> Spawn in air. spawnonground=false @@ -5347,7 +5385,7 @@ function RAT:_ModifySpawnTemplate(waypoints, livery, spawnplace, departure, take PointVec3.y=PointVec3:GetLandHeight()+math.random(500,3000) end else - self:E(RAT.id..string.format("WARNING: Group %s has no parking spots at %s ==> No emergency air start or uncontrolled spawning ==> No spawn!", self.SpawnTemplatePrefix, departure:GetName())) + self:E(self.lid..string.format("WARNING: Group %s has no parking spots at %s ==> No emergency air start or uncontrolled spawning ==> No spawn!", self.SpawnTemplatePrefix, departure:GetName())) return nil end end @@ -5360,9 +5398,6 @@ function RAT:_ModifySpawnTemplate(waypoints, livery, spawnplace, departure, take end - ---- new - -- Translate the position of the Group Template to the Vec3. for UnitID = 1, nunits do @@ -5381,14 +5416,14 @@ function RAT:_ModifySpawnTemplate(waypoints, livery, spawnplace, departure, take -- Ships and FARPS seem to have a build in queue. if spawnonship or spawnonfarp or spawnonrunway or automatic then - self:T(RAT.id..string.format("RAT group %s spawning at farp, ship or runway %s.", self.alias, departure:GetName())) + self:T(self.lid..string.format("RAT group %s spawning at farp, ship or runway %s.", self.alias, departure:GetName())) -- Spawn on ship. We take only the position of the ship. SpawnTemplate.units[UnitID].x = PointVec3.x --TX SpawnTemplate.units[UnitID].y = PointVec3.z --TY SpawnTemplate.units[UnitID].alt = PointVec3.y else - self:T(RAT.id..string.format("RAT group %s spawning at airbase %s on parking spot id %d", self.alias, departure:GetName(), parkingindex[UnitID])) + self:T(self.lid..string.format("RAT group %s spawning at airbase %s on parking spot id %d", self.alias, departure:GetName(), parkingindex[UnitID])) -- Get coordinates of parking spot. SpawnTemplate.units[UnitID].x = parkingspots[UnitID].x @@ -5397,7 +5432,7 @@ function RAT:_ModifySpawnTemplate(waypoints, livery, spawnplace, departure, take end else - self:T(RAT.id..string.format("RAT group %s spawning in air at %s.", self.alias, departure:GetName())) + self:T(self.lid..string.format("RAT group %s spawning in air at %s.", self.alias, departure:GetName())) -- Spawn in air as requested initially. Original template orientation is perserved, altitude is already correctly set. SpawnTemplate.units[UnitID].x = TX @@ -5419,8 +5454,8 @@ function RAT:_ModifySpawnTemplate(waypoints, livery, spawnplace, departure, take end -- Debug info. - self:T2(RAT.id..string.format("RAT group %s unit number %d: Parking = %s",self.alias, UnitID, tostring(UnitTemplate.parking))) - self:T2(RAT.id..string.format("RAT group %s unit number %d: Parking ID = %s",self.alias, UnitID, tostring(UnitTemplate.parking_id))) + self:T2(self.lid..string.format("RAT group %s unit number %d: Parking = %s",self.alias, UnitID, tostring(UnitTemplate.parking))) + self:T2(self.lid..string.format("RAT group %s unit number %d: Parking ID = %s",self.alias, UnitID, tostring(UnitTemplate.parking_id))) -- Set initial heading. @@ -5484,30 +5519,63 @@ function RAT:_ModifySpawnTemplate(waypoints, livery, spawnplace, departure, take end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +--- RAT ATC +--- + +--- Data structure a RAT ATC airbase object. +-- @type RAT.AtcAirport +-- @field #table queue Queue. +-- @field #boolean busy Whether airport is busy. +-- @field #table onfinal List of flights on final. +-- @field #number Nonfinal Number of flights on final. +-- @field #number traffic Number of flights that landed (just for stats). +-- @field #number Tlastclearance Time stamp when last flight started final approach. + +--- Data structure a RAT ATC airbase object. +-- @type RAT.AtcFlight +-- @field #string destination Name of the destination airbase. +-- @field #number Tarrive Time stamp when flight arrived at holding. +-- @field #number holding Holding time. +-- @field #number Tonfinal Time stamp when flight started final approach. --- Initializes the ATC arrays and starts schedulers. --- @param #RAT self -- @param #table airports_map List of all airports of the map. -function RAT:_ATCInit(airports_map) +function RAT._ATCInit(airports_map) + if not RAT.ATC.init then - local text - text="Starting RAT ATC.\nSimultanious = "..RAT.ATC.Nclearance.."\n".."Delay = "..RAT.ATC.delay - BASE:T2(RAT.id..text) - RAT.ATC.init=true + + local text="Starting RAT ATC.\nSimultanious = "..RAT.ATC.Nclearance.."\n".."Delay = "..RAT.ATC.delay + BASE:I(RAT.id..text) + for _,ap in pairs(airports_map) do - local name=ap:GetName() - RAT.ATC.airport[name]={} - RAT.ATC.airport[name].queue={} - RAT.ATC.airport[name].busy=false - RAT.ATC.airport[name].onfinal={} - RAT.ATC.airport[name].Nonfinal=0 - RAT.ATC.airport[name].traffic=0 - RAT.ATC.airport[name].Tlastclearance=nil + local airbase=ap --Wrapper.Airbase#AIRBASE + local name=airbase:GetName() + + local fc=_DATABASE:GetFlightControl(name) + + if not fc then + + local airport={} --#RAT.AtcAirport + airport.queue={} + airport.busy=false + airport.onfinal={} + airport.Nonfinal=0 + airport.traffic=0 + airport.Tlastclearance=nil + + RAT.ATC.airport[name]=airport + + end end - SCHEDULER:New(nil, RAT._ATCCheck, {self}, 5, 15) - SCHEDULER:New(nil, RAT._ATCStatus, {self}, 5, 60) - RAT.ATC.T0=timer.getTime() + + SCHEDULER:New(nil, RAT._ATCCheck, {}, 5, 15) + SCHEDULER:New(nil, RAT._ATCStatus, {}, 5, 60) + + RAT.ATC.T0=timer.getTime() end + + -- Init done + RAT.ATC.init=true end --- Adds andd initializes a new flight after it was spawned. @@ -5515,21 +5583,27 @@ end -- @param #string name Group name of the flight. -- @param #string dest Name of the destination airport. function RAT:_ATCAddFlight(name, dest) - BASE:T2(string.format("%sATC %s: Adding flight %s with destination %s.", RAT.id, dest, name, dest)) - RAT.ATC.flight[name]={} - RAT.ATC.flight[name].destination=dest - RAT.ATC.flight[name].Tarrive=-1 - RAT.ATC.flight[name].holding=-1 - RAT.ATC.flight[name].Tonfinal=-1 + -- Debug info + BASE:I(RAT.id..string.format("ATC %s: Adding flight %s with destination %s.", dest, name, dest)) + + -- Create new flight + local flight={} --#RAT.AtcFlight + flight.destination=dest + flight.Tarrive=-1 + flight.holding=-1 + flight.Tarrive=-1 + --flight.Tonfinal=-1 + + RAT.ATC.flight[name]=flight end --- Deletes a flight from ATC lists after it landed. --- @param #RAT self -- @param #table t Table. -- @param #string entry Flight name which shall be deleted. -function RAT:_ATCDelFlight(t,entry) +function RAT._ATCDelFlight(t,entry) for k,_ in pairs(t) do if k==entry then + BASE:I(RAT.id..string.format("Removing flight %s from queue", entry)) t[entry]=nil end end @@ -5539,105 +5613,114 @@ end -- @param #RAT self -- @param #string name Group name of the flight. -- @param #number time Time the fight first registered. -function RAT:_ATCRegisterFlight(name, time) - BASE:T2(RAT.id.."Flight ".. name.." registered at ATC for landing clearance.") +function RAT._ATCRegisterFlight(name, time) + BASE:I(RAT.id..string.format("Flight %s registered at ATC for landing clearance.", name)) RAT.ATC.flight[name].Tarrive=time RAT.ATC.flight[name].holding=0 end --- ATC status report about flights. --- @param #RAT self -function RAT:_ATCStatus() +function RAT._ATCStatus() -- Current time. local Tnow=timer.getTime() - for name,_ in pairs(RAT.ATC.flight) do + for name,_flight in pairs(RAT.ATC.flight) do + local flight=_flight --#RAT.AtcFlight -- Holding time at destination. local hold=RAT.ATC.flight[name].holding local dest=RAT.ATC.flight[name].destination + + local airport=RAT.ATC.airport[dest] --#RAT.AtcAirport + + if airport then - if hold >= 0 then - - -- Some string whether the runway is busy or not. - local busy="Runway state is unknown" - if RAT.ATC.airport[dest].Nonfinal>0 then - busy="Runway is occupied by "..RAT.ATC.airport[dest].Nonfinal + if hold >= 0 then + + -- Some string whether the runway is busy or not. + local busy="Runway state is unknown" + if airport.Nonfinal>0 then + busy="Runway is occupied by "..airport.Nonfinal + else + busy="Runway is currently clear" + end + + -- Aircraft is holding. + local text=string.format("ATC %s: Flight %s is holding for %i:%02d. %s.", dest, name, hold/60, hold%60, busy) + BASE:I(RAT.id..text) + + elseif hold==RAT.ATC.onfinal then + + -- Aircarft is on final approach for landing. + local Tfinal=Tnow-flight.Tonfinal + + local text=string.format("ATC %s: Flight %s is on final. Waiting %i:%02d for landing event.", dest, name, Tfinal/60, Tfinal%60) + BASE:I(RAT.id..text) + + elseif hold==RAT.ATC.unregistered then + + -- Aircraft has not arrived at holding point. + --self:T(string.format("ATC %s: Flight %s is not registered yet (hold %d).", dest, name, hold)) + else - busy="Runway is currently clear" + BASE:E(RAT.id.."ERROR: Unknown holding time in RAT:_ATCStatus().") end - - -- Aircraft is holding. - local text=string.format("ATC %s: Flight %s is holding for %i:%02d. %s.", dest, name, hold/60, hold%60, busy) - BASE:T2(RAT.id..text) - - elseif hold==RAT.ATC.onfinal then - - -- Aircarft is on final approach for landing. - local Tfinal=Tnow-RAT.ATC.flight[name].Tonfinal - - local text=string.format("ATC %s: Flight %s is on final. Waiting %i:%02d for landing event.", dest, name, Tfinal/60, Tfinal%60) - BASE:T2(RAT.id..text) - - elseif hold==RAT.ATC.unregistered then - - -- Aircraft has not arrived at holding point. - --self:T(string.format("ATC %s: Flight %s is not registered yet (hold %d).", dest, name, hold)) - else - BASE:E(RAT.id.."ERROR: Unknown holding time in RAT:_ATCStatus().") + -- Not a RAT.ATC airport (should be managed by a FLIGHTCONTROL) end end end --- Main ATC function. Updates the landing queue of all airports and inceases holding time for all flights. --- @param #RAT self -function RAT:_ATCCheck() +function RAT._ATCCheck() -- Init queue of flights at all airports. - RAT:_ATCQueue() + RAT._ATCQueue() -- Current time. local Tnow=timer.getTime() - for name,_ in pairs(RAT.ATC.airport) do + for airportname,_airport in pairs(RAT.ATC.airport) do + local airport=_airport --#RAT.AtcAirport - for qID,flight in ipairs(RAT.ATC.airport[name].queue) do + for qID,flightname in pairs(airport.queue) do + local flight=RAT.ATC.flight[flightname] --#RAT.AtcFlight -- Number of aircraft in queue. - local nqueue=#RAT.ATC.airport[name].queue + local nqueue=#airport.queue -- Conditions to clear an aircraft for landing - local landing1 - if RAT.ATC.airport[name].Tlastclearance then + local landing1=false + if airport.Tlastclearance then -- Landing if time is enough and less then two planes are on final. - landing1=(Tnow-RAT.ATC.airport[name].Tlastclearance > RAT.ATC.delay) and RAT.ATC.airport[name].Nonfinal < RAT.ATC.Nclearance - else - landing1=false + landing1=(Tnow-airport.Tlastclearance > RAT.ATC.delay) and airport.Nonfinal < RAT.ATC.Nclearance end + -- No other aircraft is on final. - local landing2=RAT.ATC.airport[name].Nonfinal==0 + local landing2=airport.Nonfinal==0 if not landing1 and not landing2 then -- Update holding time. - RAT.ATC.flight[flight].holding=Tnow-RAT.ATC.flight[flight].Tarrive + flight.holding=Tnow-flight.Tarrive -- Debug message. - local text=string.format("ATC %s: Flight %s runway is busy. You are #%d of %d in landing queue. Your holding time is %i:%02d.", name, flight,qID, nqueue, RAT.ATC.flight[flight].holding/60, RAT.ATC.flight[flight].holding%60) - BASE:T2(RAT.id..text) + local text=string.format("ATC %s: Flight %s runway is busy. You are #%d of %d in landing queue. Your holding time is %i:%02d.", + airportname, flightname, qID, nqueue, flight.holding/60, flight.holding%60) + BASE:I(RAT.id..text) else - local text=string.format("ATC %s: Flight %s was cleared for landing. Your holding time was %i:%02d.", name, flight, RAT.ATC.flight[flight].holding/60, RAT.ATC.flight[flight].holding%60) - BASE:T2(RAT.id..text) + local text=string.format("ATC %s: Flight %s was cleared for landing. Your holding time was %i:%02d.", + airportname, flightname, flight.holding/60, flight.holding%60) + BASE:I(RAT.id..text) -- Clear flight for landing. - RAT:_ATCClearForLanding(name, flight) + RAT._ATCClearForLanding(airportname, flightname) end @@ -5646,93 +5729,118 @@ function RAT:_ATCCheck() end -- Update queue of flights at all airports. - RAT:_ATCQueue() + RAT._ATCQueue() end --- Giving landing clearance for aircraft by setting user flag. --- @param #RAT self --- @param #string airport Name of destination airport. --- @param #string flight Group name of flight, which gets landing clearence. -function RAT:_ATCClearForLanding(airport, flight) - -- Flight is cleared for landing. - RAT.ATC.flight[flight].holding=RAT.ATC.onfinal - -- Airport runway is busy now. - RAT.ATC.airport[airport].busy=true - -- Flight which is landing. - RAT.ATC.airport[airport].onfinal[flight]=flight - -- Number of planes on final approach. - RAT.ATC.airport[airport].Nonfinal=RAT.ATC.airport[airport].Nonfinal+1 - -- Last time an aircraft got landing clearance. - RAT.ATC.airport[airport].Tlastclearance=timer.getTime() - -- Current time. - RAT.ATC.flight[flight].Tonfinal=timer.getTime() - -- Set user flag to 1 ==> stop condition for holding. - trigger.action.setUserFlag(flight, 1) - local flagvalue=trigger.misc.getUserFlag(flight) +-- @param #string airportname Name of destination airport. +-- @param #string flightname Group name of flight, which gets landing clearence. +function RAT._ATCClearForLanding(airportname, flightname) - -- Debug message. - local text1=string.format("ATC %s: Flight %s cleared for landing (flag=%d).", airport, flight, flagvalue) - if string.find(flight,"#") then - flight = string.match(flight,"^(.+)#") + -- Find FLIGHTGROUP in database. + local flightgroup=_DATABASE:FindOpsGroup(flightname) --Ops.FlightGroup#FLIGHTGROUP + + if flightgroup then + + -- Give clear to land signal. + flightgroup:ClearToLand() + + + local flight=RAT.ATC.flight[flightname] --#RAT.AtcFlight + + -- Flight is cleared for landing. + flight.holding=RAT.ATC.onfinal + + -- Current time. + flight.Tonfinal=timer.getTime() + + + local airport=RAT.ATC.airport[airportname] --#RAT.AtcAirport + + -- Airport runway is busy now. + airport.busy=true + + -- Flight which is landing. + airport.onfinal[flightname]=flight + + -- Number of planes on final approach. + airport.Nonfinal=airport.Nonfinal+1 + + -- Last time an aircraft got landing clearance. + airport.Tlastclearance=timer.getTime() + + + -- Debug message. + BASE:I(RAT.id..string.format("ATC %s: Flight %s cleared for landing", airportname, flightname)) + + if string.find(flightname,"#") then + flightname = string.match(flightname,"^(.+)#") + end + local text=string.format("ATC %s: Flight %s you are cleared for landing.", airportname, flightname) + MESSAGE:New(text, 10):ToAllIf(RAT.ATC.messages) + + else + BASE:E("Could not clear flight for landing!") end - local text2=string.format("ATC %s: Flight %s you are cleared for landing.", airport, flight) - BASE:T2( RAT.id..text1) - MESSAGE:New(text2, 10):ToAllIf(RAT.ATC.messages) + end --- Takes care of organisational stuff after a plane has landed. --- @param #RAT self -- @param #string name Group name of flight. -function RAT:_ATCFlightLanded(name) +function RAT._ATCFlightLanded(name) - if RAT.ATC.flight[name] then + local flight=RAT.ATC.flight[name] --#RAT.AtcFlight + + if flight then -- Destination airport. - local dest=RAT.ATC.flight[name].destination + local dest=flight.destination -- Times for holding and final approach. local Tnow=timer.getTime() - local Tfinal=Tnow-RAT.ATC.flight[name].Tonfinal - local Thold=RAT.ATC.flight[name].Tonfinal-RAT.ATC.flight[name].Tarrive + local Tfinal=Tnow-flight.Tonfinal + local Thold=flight.Tonfinal-flight.Tarrive + + local airport=RAT.ATC.airport[dest] --#RAT.AtcAirport -- Airport is not busy any more. - RAT.ATC.airport[dest].busy=false + airport.busy=false -- No aircraft on final any more. - RAT.ATC.airport[dest].onfinal[name]=nil + airport.onfinal[name]=nil -- Decrease number of aircraft on final. - RAT.ATC.airport[dest].Nonfinal=RAT.ATC.airport[dest].Nonfinal-1 + airport.Nonfinal=airport.Nonfinal-1 -- Remove this flight from list of flights. - RAT:_ATCDelFlight(RAT.ATC.flight, name) + RAT._ATCDelFlight(RAT.ATC.flight, name) -- Increase landing counter to monitor traffic. - RAT.ATC.airport[dest].traffic=RAT.ATC.airport[dest].traffic+1 + airport.traffic=airport.traffic+1 -- Number of planes landing per hour. - local TrafficPerHour=RAT.ATC.airport[dest].traffic/(timer.getTime()-RAT.ATC.T0)*3600 + local TrafficPerHour=airport.traffic/(timer.getTime()-RAT.ATC.T0)*3600 -- Debug info - local text1=string.format("ATC %s: Flight %s landed. Tholding = %i:%02d, Tfinal = %i:%02d.", dest, name, Thold/60, Thold%60, Tfinal/60, Tfinal%60) - local text2=string.format("ATC %s: Number of flights still on final %d.", dest, RAT.ATC.airport[dest].Nonfinal) - local text3=string.format("ATC %s: Traffic report: Number of planes landed in total %d. Flights/hour = %3.2f.", dest, RAT.ATC.airport[dest].traffic, TrafficPerHour) - if string.find(name,"#") then - name = string.match(name,"^(.+)#") - end - local text4=string.format("ATC %s: Flight %s landed. Welcome to %s.", dest, name, dest) - BASE:T2(RAT.id..text1) - BASE:T2(RAT.id..text2) - BASE:T2(RAT.id..text3) - MESSAGE:New(text4, 10):ToAllIf(RAT.ATC.messages) + BASE:I(RAT.id..string.format("ATC %s: Flight %s landed. Tholding = %i:%02d, Tfinal = %i:%02d.", dest, name, Thold/60, Thold%60, Tfinal/60, Tfinal%60)) + BASE:I(RAT.id..string.format("ATC %s: Number of flights still on final %d.", dest, airport.Nonfinal)) + BASE:I(RAT.id..string.format("ATC %s: Traffic report: Number of planes landed in total %d. Flights/hour = %3.2f.", dest, airport.traffic, TrafficPerHour)) + + if string.find(name,"#") then + name = string.match(name,"^(.+)#") + end + local text=string.format("ATC %s: Flight %s landed. Welcome to %s.", dest, name, dest) + MESSAGE:New(text, 10):ToAllIf(RAT.ATC.messages) end end --- Creates a landing queue for all flights holding at airports. Aircraft with longest holding time gets first permission to land. --- @param #RAT self -function RAT:_ATCQueue() +function RAT._ATCQueue() + + -- Current time + local Tnow=timer.getTime() for airport,_ in pairs(RAT.ATC.airport) do @@ -5740,16 +5848,16 @@ function RAT:_ATCQueue() local _queue={} -- Loop over all flights. - for name,_ in pairs(RAT.ATC.flight) do - --fvh - local Tnow=timer.getTime() + for name,_flight in pairs(RAT.ATC.flight) do + local flight=_flight --#RAT.AtcFlight -- Update holding time (unless holing is set to onfinal=-100) - if RAT.ATC.flight[name].holding>=0 then - RAT.ATC.flight[name].holding=Tnow-RAT.ATC.flight[name].Tarrive + if flight.holding>=0 then + flight.holding=Tnow-flight.Tarrive end - local hold=RAT.ATC.flight[name].holding - local dest=RAT.ATC.flight[name].destination + + local hold=flight.holding + local dest=flight.destination -- Flight is holding at this airport. if hold>=0 and airport==dest then @@ -5861,7 +5969,7 @@ function RATMANAGER:New(ntot) self.ntot=ntot or 1 -- Debug info - self:E(RATMANAGER.id..string.format("Creating manager for %d groups.", ntot)) + self:I(RATMANAGER.id..string.format("Creating manager for %d groups", ntot)) return self end @@ -5903,68 +6011,71 @@ end function RATMANAGER:Start(delay) -- Time delay. - local delay=delay or 5 + delay=delay or 5 - -- Info text. - local text=string.format(RATMANAGER.id.."RAT manager will be started in %d seconds.\n", delay) - text=text..string.format("Managed groups:\n") - for i=1,self.nrat do - text=text..string.format("- %s with min groups %d\n", self.name[i], self.min[i]) + if delay and delay>0 then + + -- Info text. + local text=string.format(RATMANAGER.id.."RAT manager will be started in %d seconds.\n", delay) + text=text..string.format("Managed groups:\n") + for i=1,self.nrat do + text=text..string.format("- %s with min groups %d\n", self.name[i], self.min[i]) + end + text=text..string.format("Number of constantly alive groups %d", self.ntot) + self:E(text) + + -- Delayed call + self:ScheduleOnce(delay, RATMANAGER.Start, self, 0) + + else + + -- Ensure that ntot is at least sum of min RAT groups. + local n=0 + for i=1,self.nrat do + n=n+self.min[i] + end + self.ntot=math.max(self.ntot, n) + + -- Get randum number of new RAT groups. + local N=self:_RollDice(self.nrat, self.ntot, self.min, self.alive) + + -- Loop over all RAT objects and spawn groups. + local time=0.0 + for i=1,self.nrat do + for j=1,N[i] do + time=time+self.dTspawn + --SCHEDULER:New(nil, RAT._SpawnWithRoute, {self.rat[i]}, time) + self:ScheduleOnce(time, RAT._SpawnWithRoute, self.rat[i]) + end + end + + -- Start activation scheduler for uncontrolled aircraft. + for i=1,self.nrat do + local rat=self.rat[i] --#RAT + if rat.uncontrolled and rat.activate_uncontrolled then + -- Start activating stuff but not before the latest spawn has happend. + local Tactivate=math.max(time+1, rat.activate_delay) + --SCHEDULER:New(self.rat[i], self.rat[i]._ActivateUncontrolled, {self.rat[i]}, Tactivate, self.rat[i].activate_delta, self.rat[i].activate_frand) + self:ScheduleRepeat(Tactivate,rat.activate_delta, rat.activate_frand, nil,rat._ActivateUncontrolled, rat) + end + end + + -- Start the manager. But not earlier than the latest spawn has happened! + local TstartManager=math.max(time+1, self.Tcheck) + + -- Start manager scheduler. + self.manager, self.managerid = SCHEDULER:New(self, self._Manage, {self}, TstartManager, self.Tcheck) --Core.Scheduler#SCHEDULER + + -- Info + local text=string.format(RATMANAGER.id.."Starting RAT manager with scheduler ID %s in %d seconds. Repeat interval %d seconds.", self.managerid, TstartManager, self.Tcheck) + self:I(text) + + end - text=text..string.format("Number of constantly alive groups %d", self.ntot) - self:E(text) - - -- Start scheduler. - SCHEDULER:New(nil, self._Start, {self}, delay) return self end ---- Instantly starts the RAT manager and spawns the initial random number RAT groups for each RAT object. --- @param #RATMANAGER self --- @return #RATMANAGER RATMANAGER self object. -function RATMANAGER:_Start() - - -- Ensure that ntot is at least sum of min RAT groups. - local n=0 - for i=1,self.nrat do - n=n+self.min[i] - end - self.ntot=math.max(self.ntot, n) - - -- Get randum number of new RAT groups. - local N=self:_RollDice(self.nrat, self.ntot, self.min, self.alive) - - -- Loop over all RAT objects and spawn groups. - local time=0.0 - for i=1,self.nrat do - for j=1,N[i] do - time=time+self.dTspawn - SCHEDULER:New(nil, RAT._SpawnWithRoute, {self.rat[i]}, time) - end - end - - -- Start activation scheduler for uncontrolled aircraft. - for i=1,self.nrat do - if self.rat[i].uncontrolled and self.rat[i].activate_uncontrolled then - -- Start activating stuff but not before the latest spawn has happend. - local Tactivate=math.max(time+1, self.rat[i].activate_delay) - SCHEDULER:New(self.rat[i], self.rat[i]._ActivateUncontrolled, {self.rat[i]}, Tactivate, self.rat[i].activate_delta, self.rat[i].activate_frand) - end - end - - -- Start the manager. But not earlier than the latest spawn has happened! - local TstartManager=math.max(time+1, self.Tcheck) - - -- Start manager scheduler. - self.manager, self.managerid = SCHEDULER:New(self, self._Manage, {self}, TstartManager, self.Tcheck) --Core.Scheduler#SCHEDULER - - -- Info - local text=string.format(RATMANAGER.id.."Starting RAT manager with scheduler ID %s in %d seconds. Repeat interval %d seconds.", self.managerid, TstartManager, self.Tcheck) - self:E(text) - - return self -end --- Stops the RAT manager. -- @param #RATMANAGER self @@ -5972,19 +6083,26 @@ end -- @return #RATMANAGER RATMANAGER self object. function RATMANAGER:Stop(delay) delay=delay or 1 - self:E(string.format(RATMANAGER.id.."Manager will be stopped in %d seconds.", delay)) - SCHEDULER:New(nil, self._Stop, {self}, delay) + + + if delay and delay>0 then + + self:I(RATMANAGER.id..string.format("Manager will be stopped in %d seconds.", delay)) + + self:ScheduleOnce(delay, RATMANAGER.Stop, self, 0) + + else + + self:I(RATMANAGER.id..string.format("Stopping manager with scheduler ID %s", self.managerid)) + + self.manager:Stop(self.managerid) + + end + + return self end ---- Instantly stops the RAT manager by terminating its scheduler. --- @param #RATMANAGER self --- @return #RATMANAGER RATMANAGER self object. -function RATMANAGER:_Stop() - self:E(string.format(RATMANAGER.id.."Stopping manager with scheduler ID %s.", self.managerid)) - self.manager:Stop(self.managerid) - return self -end --- Sets the time interval between checks of alive RAT groups. Default is 60 seconds. -- @param #RATMANAGER self @@ -6013,8 +6131,7 @@ function RATMANAGER:_Manage() local ntot=self:_Count() -- Debug info. - local text=string.format("Number of alive groups %d. New groups to be spawned %d.", ntot, self.ntot-ntot) - self:T(RATMANAGER.id..text) + self:T(RATMANAGER.id..string.format("Number of alive groups %d. New groups to be spawned %d.", ntot, self.ntot-ntot)) -- Get number of necessary spawns. local N=self:_RollDice(self.nrat, self.ntot, self.min, self.alive) @@ -6025,7 +6142,8 @@ function RATMANAGER:_Manage() for j=1,N[i] do time=time+self.dTspawn self.planned[i]=self.planned[i]+1 - SCHEDULER:New(nil, RATMANAGER._Spawn, {self, i}, time) + --SCHEDULER:New(nil, RATMANAGER._Spawn, {self, i}, time) + self:ScheduleOnce(time, RATMANAGER._Spawn, self, i) end end end From 2fcef1f277877b268c081df849a09f52392b443b Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Tue, 7 Oct 2025 18:10:00 +0200 Subject: [PATCH 213/234] xx --- Moose Development/Moose/Functional/RAT.lua | 85 +++++++++------------- 1 file changed, 34 insertions(+), 51 deletions(-) diff --git a/Moose Development/Moose/Functional/RAT.lua b/Moose Development/Moose/Functional/RAT.lua index 97d933b9d..560410ae2 100644 --- a/Moose Development/Moose/Functional/RAT.lua +++ b/Moose Development/Moose/Functional/RAT.lua @@ -5543,10 +5543,10 @@ end function RAT._ATCInit(airports_map) if not RAT.ATC.init then - local text - text="Starting RAT ATC.\nSimultanious = "..RAT.ATC.Nclearance.."\n".."Delay = "..RAT.ATC.delay - BASE:T2(RAT.id..text) - RAT.ATC.init=true + + local text="Starting RAT ATC.\nSimultanious = "..RAT.ATC.Nclearance.."\n".."Delay = "..RAT.ATC.delay + BASE:I(RAT.id..text) + for _,ap in pairs(airports_map) do local airbase=ap --Wrapper.Airbase#AIRBASE local name=airbase:GetName() @@ -5583,12 +5583,18 @@ end -- @param #string name Group name of the flight. -- @param #string dest Name of the destination airport. function RAT:_ATCAddFlight(name, dest) - BASE:T2(string.format("%sATC %s: Adding flight %s with destination %s.", RAT.id, dest, name, dest)) - RAT.ATC.flight[name]={} - RAT.ATC.flight[name].destination=dest - RAT.ATC.flight[name].Tarrive=-1 - RAT.ATC.flight[name].holding=-1 - RAT.ATC.flight[name].Tonfinal=-1 + -- Debug info + BASE:I(RAT.id..string.format("ATC %s: Adding flight %s with destination %s.", dest, name, dest)) + + -- Create new flight + local flight={} --#RAT.AtcFlight + flight.destination=dest + flight.Tarrive=-1 + flight.holding=-1 + flight.Tarrive=-1 + --flight.Tonfinal=-1 + + RAT.ATC.flight[name]=flight end --- Deletes a flight from ATC lists after it landed. @@ -5607,8 +5613,8 @@ end -- @param #RAT self -- @param #string name Group name of the flight. -- @param #number time Time the fight first registered. -function RAT:_ATCRegisterFlight(name, time) - BASE:T2(RAT.id.."Flight ".. name.." registered at ATC for landing clearance.") +function RAT._ATCRegisterFlight(name, time) + BASE:I(RAT.id..string.format("Flight %s registered at ATC for landing clearance.", name)) RAT.ATC.flight[name].Tarrive=time RAT.ATC.flight[name].holding=0 end @@ -5661,27 +5667,6 @@ function RAT._ATCStatus() else BASE:E(RAT.id.."ERROR: Unknown holding time in RAT:_ATCStatus().") end - else - busy="Runway is currently clear" - end - - -- Aircraft is holding. - local text=string.format("ATC %s: Flight %s is holding for %i:%02d. %s.", dest, name, hold/60, hold%60, busy) - BASE:T2(RAT.id..text) - - elseif hold==RAT.ATC.onfinal then - - -- Aircarft is on final approach for landing. - local Tfinal=Tnow-RAT.ATC.flight[name].Tonfinal - - local text=string.format("ATC %s: Flight %s is on final. Waiting %i:%02d for landing event.", dest, name, Tfinal/60, Tfinal%60) - BASE:T2(RAT.id..text) - - elseif hold==RAT.ATC.unregistered then - - -- Aircraft has not arrived at holding point. - --self:T(string.format("ATC %s: Flight %s is not registered yet (hold %d).", dest, name, hold)) - else -- Not a RAT.ATC airport (should be managed by a FLIGHTCONTROL) end @@ -5724,13 +5709,15 @@ function RAT._ATCCheck() flight.holding=Tnow-flight.Tarrive -- Debug message. - local text=string.format("ATC %s: Flight %s runway is busy. You are #%d of %d in landing queue. Your holding time is %i:%02d.", name, flight,qID, nqueue, RAT.ATC.flight[flight].holding/60, RAT.ATC.flight[flight].holding%60) - BASE:T2(RAT.id..text) + local text=string.format("ATC %s: Flight %s runway is busy. You are #%d of %d in landing queue. Your holding time is %i:%02d.", + airportname, flightname, qID, nqueue, flight.holding/60, flight.holding%60) + BASE:I(RAT.id..text) else - local text=string.format("ATC %s: Flight %s was cleared for landing. Your holding time was %i:%02d.", name, flight, RAT.ATC.flight[flight].holding/60, RAT.ATC.flight[flight].holding%60) - BASE:T2(RAT.id..text) + local text=string.format("ATC %s: Flight %s was cleared for landing. Your holding time was %i:%02d.", + airportname, flightname, flight.holding/60, flight.holding%60) + BASE:I(RAT.id..text) -- Clear flight for landing. RAT._ATCClearForLanding(airportname, flightname) @@ -5796,9 +5783,7 @@ function RAT._ATCClearForLanding(airportname, flightname) else BASE:E("Could not clear flight for landing!") end - local text2=string.format("ATC %s: Flight %s you are cleared for landing.", airport, flight) - BASE:T2( RAT.id..text1) - MESSAGE:New(text2, 10):ToAllIf(RAT.ATC.messages) + end --- Takes care of organisational stuff after a plane has landed. @@ -5838,17 +5823,15 @@ function RAT._ATCFlightLanded(name) local TrafficPerHour=airport.traffic/(timer.getTime()-RAT.ATC.T0)*3600 -- Debug info - local text1=string.format("ATC %s: Flight %s landed. Tholding = %i:%02d, Tfinal = %i:%02d.", dest, name, Thold/60, Thold%60, Tfinal/60, Tfinal%60) - local text2=string.format("ATC %s: Number of flights still on final %d.", dest, RAT.ATC.airport[dest].Nonfinal) - local text3=string.format("ATC %s: Traffic report: Number of planes landed in total %d. Flights/hour = %3.2f.", dest, RAT.ATC.airport[dest].traffic, TrafficPerHour) - if string.find(name,"#") then - name = string.match(name,"^(.+)#") - end - local text4=string.format("ATC %s: Flight %s landed. Welcome to %s.", dest, name, dest) - BASE:T2(RAT.id..text1) - BASE:T2(RAT.id..text2) - BASE:T2(RAT.id..text3) - MESSAGE:New(text4, 10):ToAllIf(RAT.ATC.messages) + BASE:I(RAT.id..string.format("ATC %s: Flight %s landed. Tholding = %i:%02d, Tfinal = %i:%02d.", dest, name, Thold/60, Thold%60, Tfinal/60, Tfinal%60)) + BASE:I(RAT.id..string.format("ATC %s: Number of flights still on final %d.", dest, airport.Nonfinal)) + BASE:I(RAT.id..string.format("ATC %s: Traffic report: Number of planes landed in total %d. Flights/hour = %3.2f.", dest, airport.traffic, TrafficPerHour)) + + if string.find(name,"#") then + name = string.match(name,"^(.+)#") + end + local text=string.format("ATC %s: Flight %s landed. Welcome to %s.", dest, name, dest) + MESSAGE:New(text, 10):ToAllIf(RAT.ATC.messages) end end From 3260279cb79cad1aaccebd49afce479816c84b89 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Wed, 8 Oct 2025 12:29:59 +0200 Subject: [PATCH 214/234] xx --- .../Moose/Wrapper/Controllable.lua | 62 ++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/Moose Development/Moose/Wrapper/Controllable.lua b/Moose Development/Moose/Wrapper/Controllable.lua index 20f35ee09..2985f7baf 100644 --- a/Moose Development/Moose/Wrapper/Controllable.lua +++ b/Moose Development/Moose/Wrapper/Controllable.lua @@ -4163,7 +4163,7 @@ function CONTROLLABLE:OptionRestrictBurner( RestrictBurner ) end ---- Sets Controllable Option for A2A attack range for AIR FIGHTER units. +--- [AIR] Sets Controllable Option for A2A attack range for AIR FIGHTER units. -- @param #CONTROLLABLE self -- @param #number range Defines the range -- @return #CONTROLLABLE self @@ -4188,6 +4188,66 @@ function CONTROLLABLE:OptionAAAttackRange( range ) return nil end +--- [GROUND/AAA] Sets Controllable Option for Ground AAA minimum firing height. +-- @param #CONTROLLABLE self +-- @param #number meters The minimum height in meters. +-- @return #CONTROLLABLE self +function CONTROLLABLE:OptionAAAMinFiringHeightMeters(meters) + self:F2( { self.ControllableName } ) + local meters = meters or 20 + local DCSControllable = self:GetDCSObject() + if DCSControllable then + local Controller = self:_GetController() + if Controller then + if self:IsGround()() then + self:SetOption(27, meters) + end + end + return self + end + return nil +end + +--- [GROUND/AAA] Sets Controllable Option for Ground AAA maximum firing height. +-- @param #CONTROLLABLE self +-- @param #number meters The maximum height in meters. +-- @return #CONTROLLABLE self +function CONTROLLABLE:OptionAAAMaxFiringHeightMeters(meters) + self:F2( { self.ControllableName } ) + local meters = meters or 1000 + local DCSControllable = self:GetDCSObject() + if DCSControllable then + local Controller = self:_GetController() + if Controller then + if self:IsGround()() then + self:SetOption(29, meters) + end + end + return self + end + return nil +end + +--- [GROUND/AAA] Sets Controllable Option for Ground AAA minimum firing height. +-- @param #CONTROLLABLE self +-- @param #number feet The minimum height in feet. +-- @return #CONTROLLABLE self +function CONTROLLABLE:OptionAAAMinFiringHeightFeet(feet) + self:F2( { self.ControllableName } ) + local feet = feet or 60 + return self:OptionAAAMinFiringHeightMeters(UTILS.FeetToMeters(feet)) +end + +--- [GROUND/AAA] Sets Controllable Option for Ground AAA maximum firing height. +-- @param #CONTROLLABLE self +-- @param #number feet The maximum height in feet. +-- @return #CONTROLLABLE self +function CONTROLLABLE:OptionAAAMaxFiringHeightfeet(feet) + self:F2( { self.ControllableName } ) + local feet = feet or 3000 + return self:OptionAAAMaxFiringHeightMeters(UTILS.FeetToMeters(feet)) +end + --- Defines the range at which a GROUND unit/group is allowed to use its weapons automatically. -- @param #CONTROLLABLE self -- @param #number EngageRange Engage range limit in percent (a number between 0 and 100). Default 100. From 48b51f21de9bc6e3676dd9f70f332fb8b573bd9d Mon Sep 17 00:00:00 2001 From: smiki Date: Wed, 8 Oct 2025 13:15:22 +0200 Subject: [PATCH 215/234] [FIXED] CTLD. Memory leak adding zones of the same name and type [FIXED] CSAR. nil pointer --- Moose Development/Moose/Ops/CSAR.lua | 4 +- Moose Development/Moose/Ops/CTLD.lua | 59 ++++++++++++++++++++++++++-- 2 files changed, 57 insertions(+), 6 deletions(-) diff --git a/Moose Development/Moose/Ops/CSAR.lua b/Moose Development/Moose/Ops/CSAR.lua index 9ba328b5c..5538b3689 100644 --- a/Moose Development/Moose/Ops/CSAR.lua +++ b/Moose Development/Moose/Ops/CSAR.lua @@ -1150,11 +1150,11 @@ function CSAR:_EventHandler(EventData) local initdcscoord = nil local initcoord = nil - if _event.id == EVENTS.Ejection then + if _event.id == EVENTS.Ejection and _event.TgtDCSUnit then initdcscoord = _event.TgtDCSUnit:getPoint() initcoord = COORDINATE:NewFromVec3(initdcscoord) self:T({initdcscoord}) - else + elseif _event.IniDCSUnit then initdcscoord = _event.IniDCSUnit:getPoint() initcoord = COORDINATE:NewFromVec3(initdcscoord) self:T({initdcscoord}) diff --git a/Moose Development/Moose/Ops/CTLD.lua b/Moose Development/Moose/Ops/CTLD.lua index 0c354709c..dcab663fb 100644 --- a/Moose Development/Moose/Ops/CTLD.lua +++ b/Moose Development/Moose/Ops/CTLD.lua @@ -5670,8 +5670,14 @@ function CTLD:AddCTLDZone(Name, Type, Color, Active, HasBeacon, Shiplength, Ship return self end end - - local ctldzone = {} -- #CTLD.CargoZone + + local exists = true + local ctldzone = self:GetCTLDZone(Name, Type) -- #CTLD.CargoZone + if not ctldzone then + exists = false + ctldzone = {} + end + ctldzone.active = Active or false ctldzone.color = Color or SMOKECOLOR.Red ctldzone.name = Name or "NONE" @@ -5697,11 +5703,56 @@ function CTLD:AddCTLDZone(Name, Type, Color, Active, HasBeacon, Shiplength, Ship ctldzone.shiplength = Shiplength or 100 ctldzone.shipwidth = Shipwidth or 10 end - - self:AddZone(ctldzone) + + if not exists then + self:AddZone(ctldzone) + end return self end + +--- User function - find #CTLD.CargoZone zone by name. +-- @param #CTLD self +-- @param #string Name Name of this zone. +-- @param #string Type Type of this zone, #CTLD.CargoZoneType +-- @return #CTLD.CargoZone self +function CTLD:GetCTLDZone(Name, Type) + + if Type == CTLD.CargoZoneType.LOAD then + for _, z in pairs(self.pickupZones) do + if z.name == Name then + return z + end + end + elseif Type == CTLD.CargoZoneType.DROP then + for _, z in pairs(self.dropOffZones) do + if z.name == Name then + return z + end + end + elseif Type == CTLD.CargoZoneType.SHIP then + for _, z in pairs(self.shipZones) do + if z.name == Name then + return z + end + end + elseif Type == CTLD.CargoZoneType.BEACON then + for _, z in pairs(self.droppedBeacons) do + if z.name == Name then + return z + end + end + else + for _, z in pairs(self.wpZones) do + if z.name == Name then + return z + end + end + end + + return nil +end + --- User function - Creates and adds a #CTLD.CargoZone zone for this CTLD instance from an Airbase or FARP name. -- Zones of type LOAD: Players load crates and troops here. -- Zones of type DROP: Players can drop crates here. Note that troops can be unloaded anywhere. From 405235a59d8e44d2216562b6f8ec783d1c42cc53 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Wed, 8 Oct 2025 16:01:21 +0200 Subject: [PATCH 216/234] #CONTROLLABLE - Fix for double brackets --- Moose Development/Moose/Wrapper/Controllable.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Wrapper/Controllable.lua b/Moose Development/Moose/Wrapper/Controllable.lua index 2985f7baf..780dc31c8 100644 --- a/Moose Development/Moose/Wrapper/Controllable.lua +++ b/Moose Development/Moose/Wrapper/Controllable.lua @@ -4199,7 +4199,7 @@ function CONTROLLABLE:OptionAAAMinFiringHeightMeters(meters) if DCSControllable then local Controller = self:_GetController() if Controller then - if self:IsGround()() then + if self:IsGround() then self:SetOption(27, meters) end end @@ -4219,7 +4219,7 @@ function CONTROLLABLE:OptionAAAMaxFiringHeightMeters(meters) if DCSControllable then local Controller = self:_GetController() if Controller then - if self:IsGround()() then + if self:IsGround() then self:SetOption(29, meters) end end From 6dc6972bdb1c17d4be53746da6117c4b557748c4 Mon Sep 17 00:00:00 2001 From: smiki Date: Thu, 9 Oct 2025 13:29:45 +0200 Subject: [PATCH 217/234] [ADDED] Fuel Tanks and gunner seat loadout enums for UH-60L mod --- Moose Development/Moose/Utilities/Enums.lua | 1147 ++++++++++--------- 1 file changed, 579 insertions(+), 568 deletions(-) diff --git a/Moose Development/Moose/Utilities/Enums.lua b/Moose Development/Moose/Utilities/Enums.lua index bc1a0b2c8..ce6fe4e2e 100644 --- a/Moose Development/Moose/Utilities/Enums.lua +++ b/Moose Development/Moose/Utilities/Enums.lua @@ -101,7 +101,7 @@ ENUMS.WeaponFlag={ AntiRadarMissile2 = 1073741824, -- Air-To-Air Missiles SRAM = 4194304, - MRAAM = 8388608, + MRAAM = 8388608, LRAAM = 16777216, IR_AAM = 33554432, SAR_AAM = 67108864, @@ -126,19 +126,19 @@ ENUMS.WeaponFlag={ --- Air-To-Air Missiles AnyAAM = 264241152, -- IR_AAM + SAR_AAM + AR_AAM + SRAAM + MRAAM + LRAAM AnyAutonomousMissile = 36012032, -- IR_AAM + AntiRadarMissile + AntiShipMissile + FireAndForgetASM + CruiseMissile - AnyMissile = 268402688, -- AnyASM + AnyAAM + AnyMissile = 268402688, -- AnyASM + AnyAAM --- Guns Cannons = 805306368, -- GUN_POD + BuiltInCannon --- Torpedo Torpedo = 4294967296, --- - -- Even More Genral + -- Even More Genral Auto = 3221225470, -- Any Weapon (AnyBomb + AnyRocket + AnyMissile + Cannons) AutoDCS = 1073741822, -- Something if often see AnyAG = 2956984318, -- Any Air-To-Ground Weapon AnyAA = 264241152, -- Any Air-To-Air Weapon AnyUnguided = 2952822768, -- Any Unguided Weapon - AnyGuided = 268402702, -- Any Guided Weapon + AnyGuided = 268402702, -- Any Guided Weapon } --- Weapon types by category. See the [Weapon Flag](https://wiki.hoggitworld.com/view/DCS_enum_weapon_flag) enumerator on hoggit wiki. @@ -167,7 +167,7 @@ ENUMS.WeaponType.Bomb={ -- Combinations GuidedBomb = 14, -- (LGB + TvGB + SNSGB) AnyUnguidedBomb = 2147485680, -- (HeBomb + Penetrator + NapalmBomb + FAEBomb + ClusterBomb + Dispencer + CandleBomb + ParachuteBomb) - AnyBomb = 2147485694, -- (GuidedBomb + AnyUnguidedBomb) + AnyBomb = 2147485694, -- (GuidedBomb + AnyUnguidedBomb) } ENUMS.WeaponType.Rocket={ -- Rockets @@ -201,12 +201,12 @@ ENUMS.WeaponType.Missile={ AnyASM = 4161536, -- (AntiRadarMissile + AntiShipMissile + AntiTankMissile + FireAndForgetASM + GuidedASM + CruiseMissile) AnyASM2 = 1077903360, -- 4161536+1073741824, AnyAutonomousMissile = 36012032, -- IR_AAM + AntiRadarMissile + AntiShipMissile + FireAndForgetASM + CruiseMissile - AnyMissile = 268402688, -- AnyASM + AnyAAM + AnyMissile = 268402688, -- AnyASM + AnyAAM } ENUMS.WeaponType.AAM={ -- Air-To-Air Missiles SRAM = 4194304, - MRAAM = 8388608, + MRAAM = 8388608, LRAAM = 16777216, IR_AAM = 33554432, SAR_AAM = 67108864, @@ -219,12 +219,12 @@ ENUMS.WeaponType.Torpedo={ Torpedo = 4294967296, } ENUMS.WeaponType.Any={ - -- General combinations + -- General combinations Weapon = 3221225470, -- Any Weapon (AnyBomb + AnyRocket + AnyMissile + Cannons) AG = 2956984318, -- Any Air-To-Ground Weapon AA = 264241152, -- Any Air-To-Air Weapon Unguided = 2952822768, -- Any Unguided Weapon - Guided = 268402702, -- Any Guided Weapon + Guided = 268402702, -- Any Guided Weapon } @@ -409,7 +409,7 @@ ENUMS.Morse[" "]=" " --- ISO (639-1) 2-letter Language Codes. See the [Wikipedia](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes). -- -- @type ENUMS.ISOLang -ENUMS.ISOLang = +ENUMS.ISOLang = { Arabic = 'AR', Chinese = 'ZH', @@ -515,7 +515,7 @@ ENUMS.ReportingName = Atlas = "A400", Lancer = "B1-B", Stratofortress = "B-52H", - Hercules = "C-130", + Hercules = "C-130", Super_Hercules = "Hercules", Globemaster = "C-17", Greyhound = "C-2A", @@ -539,7 +539,7 @@ ENUMS.ReportingName = Curl = "An-26", Candid = "IL-76", Midas = "IL-78", - Mainstay = "A-50", + Mainstay = "A-50", Mainring = "KJ-2000", -- A-50 China Yak = "Yak-52", -- Helos @@ -610,562 +610,562 @@ ENUMS.Storage = { } } -ENUMS.Storage.weapons.nurs.SNEB_TYPE253_F1B = "weapons.nurs.SNEB_TYPE253_F1B" -ENUMS.Storage.weapons.missiles.P_24T = "weapons.missiles.P_24T" -ENUMS.Storage.weapons.bombs.BLU_3B_OLD = "weapons.bombs.BLU-3B_OLD" -ENUMS.Storage.weapons.missiles.AGM_154 = "weapons.missiles.AGM_154" -ENUMS.Storage.weapons.nurs.HYDRA_70_M151_M433 = "weapons.nurs.HYDRA_70_M151_M433" -ENUMS.Storage.weapons.bombs.SAM_Avenger_M1097_Skid_7090lb = "weapons.bombs.SAM Avenger M1097 Skid [7090lb]" -ENUMS.Storage.weapons.bombs.British_GP_250LB_Bomb_Mk5 = "weapons.bombs.British_GP_250LB_Bomb_Mk5" -ENUMS.Storage.weapons.containers.OV10_SMOKE = "weapons.containers.{OV10_SMOKE}" -ENUMS.Storage.weapons.bombs.BLU_4B_OLD = "weapons.bombs.BLU-4B_OLD" -ENUMS.Storage.weapons.bombs.FAB_500M54 = "weapons.bombs.FAB-500M54" -ENUMS.Storage.weapons.bombs.GBU_38 = "weapons.bombs.GBU_38" -ENUMS.Storage.weapons.containers.F_15E_AXQ_14_DATALINK = "weapons.containers.F-15E_AXQ-14_DATALINK" -ENUMS.Storage.weapons.bombs.BEER_BOMB = "weapons.bombs.BEER_BOMB" -ENUMS.Storage.weapons.bombs.P_50T = "weapons.bombs.P-50T" -ENUMS.Storage.weapons.nurs.C_8CM_GN = "weapons.nurs.C_8CM_GN" -ENUMS.Storage.weapons.bombs.FAB_500SL = "weapons.bombs.FAB-500SL" -ENUMS.Storage.weapons.bombs.KAB_1500Kr = "weapons.bombs.KAB_1500Kr" -ENUMS.Storage.weapons.bombs.two50_2 = "weapons.bombs.250-2" -ENUMS.Storage.weapons.droptanks.Spitfire_tank_1 = "weapons.droptanks.Spitfire_tank_1" -ENUMS.Storage.weapons.missiles.AGM_65G = "weapons.missiles.AGM_65G" -ENUMS.Storage.weapons.missiles.AGM_65A = "weapons.missiles.AGM_65A" -ENUMS.Storage.weapons.containers.Hercules_JATO = "weapons.containers.Hercules_JATO" -ENUMS.Storage.weapons.nurs.HYDRA_70_M259 = "weapons.nurs.HYDRA_70_M259" -ENUMS.Storage.weapons.missiles.AGM_84E = "weapons.missiles.AGM_84E" -ENUMS.Storage.weapons.bombs.AN_M30A1 = "weapons.bombs.AN_M30A1" -ENUMS.Storage.weapons.nurs.C_25 = "weapons.nurs.C_25" -ENUMS.Storage.weapons.containers.AV8BNA_ALQ164 = "weapons.containers.AV8BNA_ALQ164" -ENUMS.Storage.weapons.containers.lav_25 = "weapons.containers.lav-25" -ENUMS.Storage.weapons.missiles.P_60 = "weapons.missiles.P_60" -ENUMS.Storage.weapons.bombs.FAB_1500 = "weapons.bombs.FAB_1500" -ENUMS.Storage.weapons.droptanks.FuelTank_350L = "weapons.droptanks.FuelTank_350L" -ENUMS.Storage.weapons.bombs.AAA_Vulcan_M163_Skid_21577lb = "weapons.bombs.AAA Vulcan M163 Skid [21577lb]" -ENUMS.Storage.weapons.missiles.Kormoran = "weapons.missiles.Kormoran" -ENUMS.Storage.weapons.droptanks.HB_F14_EXT_DROPTANK_EMPTY = "weapons.droptanks.HB_F14_EXT_DROPTANK_EMPTY" -ENUMS.Storage.weapons.droptanks.FuelTank_150L = "weapons.droptanks.FuelTank_150L" -ENUMS.Storage.weapons.missiles.Rb_15F_for_A_I = "weapons.missiles.Rb 15F (for A.I.)" -ENUMS.Storage.weapons.missiles.RB75T = "weapons.missiles.RB75T" -ENUMS.Storage.weapons.missiles.Vikhr_M = "weapons.missiles.Vikhr_M" -ENUMS.Storage.weapons.nurs.FFAR_M156_WP = "weapons.nurs.FFAR M156 WP" -ENUMS.Storage.weapons.nurs.British_HE_60LBSAPNo2_3INCHNo1 = "weapons.nurs.British_HE_60LBSAPNo2_3INCHNo1" -ENUMS.Storage.weapons.missiles.DWS39_MJ2 = "weapons.missiles.DWS39_MJ2" -ENUMS.Storage.weapons.bombs.HEBOMBD = "weapons.bombs.HEBOMBD" -ENUMS.Storage.weapons.missiles.CATM_9M = "weapons.missiles.CATM_9M" -ENUMS.Storage.weapons.bombs.Mk_81 = "weapons.bombs.Mk_81" -ENUMS.Storage.weapons.droptanks.Drop_Tank_300_Liter = "weapons.droptanks.Drop_Tank_300_Liter" -ENUMS.Storage.weapons.containers.HMMWV_M1025 = "weapons.containers.HMMWV_M1025" -ENUMS.Storage.weapons.bombs.SAM_CHAPARRAL_Air_21624lb = "weapons.bombs.SAM CHAPARRAL Air [21624lb]" -ENUMS.Storage.weapons.missiles.AGM_154A = "weapons.missiles.AGM_154A" -ENUMS.Storage.weapons.bombs.Mk_84AIR_TP = "weapons.bombs.Mk_84AIR_TP" -ENUMS.Storage.weapons.bombs.GBU_31_V_3B = "weapons.bombs.GBU_31_V_3B" -ENUMS.Storage.weapons.nurs.C_8CM_WH = "weapons.nurs.C_8CM_WH" -ENUMS.Storage.weapons.missiles.Matra_Super_530D = "weapons.missiles.Matra Super 530D" -ENUMS.Storage.weapons.nurs.ARF8M3TPSM = "weapons.nurs.ARF8M3TPSM" -ENUMS.Storage.weapons.missiles.TGM_65H = "weapons.missiles.TGM_65H" -ENUMS.Storage.weapons.nurs.M8rocket = "weapons.nurs.M8rocket" -ENUMS.Storage.weapons.bombs.GBU_27 = "weapons.bombs.GBU_27" -ENUMS.Storage.weapons.missiles.AGR_20A = "weapons.missiles.AGR_20A" -ENUMS.Storage.weapons.missiles.LS_6_250 = "weapons.missiles.LS-6-250" -ENUMS.Storage.weapons.droptanks.M2KC_RPL_522_EMPTY = "weapons.droptanks.M2KC_RPL_522_EMPTY" -ENUMS.Storage.weapons.droptanks.M2KC_02_RPL541 = "weapons.droptanks.M2KC_02_RPL541" -ENUMS.Storage.weapons.missiles.AGM_45 = "weapons.missiles.AGM_45" -ENUMS.Storage.weapons.missiles.AGM_84A = "weapons.missiles.AGM_84A" -ENUMS.Storage.weapons.bombs.APC_BTR_80_Air_23936lb = "weapons.bombs.APC BTR-80 Air [23936lb]" -ENUMS.Storage.weapons.missiles.P_33E = "weapons.missiles.P_33E" -ENUMS.Storage.weapons.missiles.Ataka_9M120 = "weapons.missiles.Ataka_9M120" -ENUMS.Storage.weapons.bombs.MK76 = "weapons.bombs.MK76" -ENUMS.Storage.weapons.bombs.AB_250_2_SD_2 = "weapons.bombs.AB_250_2_SD_2" -ENUMS.Storage.weapons.missiles.Rb_05A = "weapons.missiles.Rb 05A" -ENUMS.Storage.weapons.bombs.ART_GVOZDIKA_34720lb = "weapons.bombs.ART GVOZDIKA [34720lb]" -ENUMS.Storage.weapons.bombs.Generic_Crate_20000lb = "weapons.bombs.Generic Crate [20000lb]" -ENUMS.Storage.weapons.bombs.FAB_100SV = "weapons.bombs.FAB_100SV" -ENUMS.Storage.weapons.bombs.BetAB_500 = "weapons.bombs.BetAB_500" -ENUMS.Storage.weapons.droptanks.M2KC_02_RPL541_EMPTY = "weapons.droptanks.M2KC_02_RPL541_EMPTY" -ENUMS.Storage.weapons.droptanks.PTB600_MIG15 = "weapons.droptanks.PTB600_MIG15" -ENUMS.Storage.weapons.missiles.Rb_24J = "weapons.missiles.Rb 24J" -ENUMS.Storage.weapons.nurs.C_8CM_BU = "weapons.nurs.C_8CM_BU" -ENUMS.Storage.weapons.nurs.SNEB_TYPE259E_F1B = "weapons.nurs.SNEB_TYPE259E_F1B" -ENUMS.Storage.weapons.nurs.WGr21 = "weapons.nurs.WGr21" -ENUMS.Storage.weapons.bombs.SAMP250HD = "weapons.bombs.SAMP250HD" -ENUMS.Storage.weapons.containers.alq_184long = "weapons.containers.alq-184long" -ENUMS.Storage.weapons.nurs.SNEB_TYPE259E_H1 = "weapons.nurs.SNEB_TYPE259E_H1" -ENUMS.Storage.weapons.bombs.British_SAP_250LB_Bomb_Mk5 = "weapons.bombs.British_SAP_250LB_Bomb_Mk5" -ENUMS.Storage.weapons.bombs.Transport_UAZ_469_Air_3747lb = "weapons.bombs.Transport UAZ-469 Air [3747lb]" -ENUMS.Storage.weapons.bombs.Mk_83CT = "weapons.bombs.Mk_83CT" -ENUMS.Storage.weapons.missiles.AIM_7P = "weapons.missiles.AIM-7P" -ENUMS.Storage.weapons.missiles.AT_6 = "weapons.missiles.AT_6" -ENUMS.Storage.weapons.nurs.SNEB_TYPE254_H1_GREEN = "weapons.nurs.SNEB_TYPE254_H1_GREEN" -ENUMS.Storage.weapons.nurs.SNEB_TYPE250_F1B = "weapons.nurs.SNEB_TYPE250_F1B" -ENUMS.Storage.weapons.containers.U22A = "weapons.containers.U22A" -ENUMS.Storage.weapons.bombs.British_GP_250LB_Bomb_Mk1 = "weapons.bombs.British_GP_250LB_Bomb_Mk1" -ENUMS.Storage.weapons.bombs.CBU_105 = "weapons.bombs.CBU_105" -ENUMS.Storage.weapons.droptanks.FW_190_Fuel_Tank = "weapons.droptanks.FW-190_Fuel-Tank" -ENUMS.Storage.weapons.missiles.X_58 = "weapons.missiles.X_58" -ENUMS.Storage.weapons.missiles.BK90_MJ1_MJ2 = "weapons.missiles.BK90_MJ1_MJ2" -ENUMS.Storage.weapons.missiles.TGM_65D = "weapons.missiles.TGM_65D" -ENUMS.Storage.weapons.containers.BRD_4_250 = "weapons.containers.BRD-4-250" -ENUMS.Storage.weapons.missiles.P_73 = "weapons.missiles.P_73" -ENUMS.Storage.weapons.bombs.AN_M66 = "weapons.bombs.AN_M66" -ENUMS.Storage.weapons.bombs.APC_LAV_25_Air_22520lb = "weapons.bombs.APC LAV-25 Air [22520lb]" -ENUMS.Storage.weapons.missiles.AIM_7MH = "weapons.missiles.AIM-7MH" -ENUMS.Storage.weapons.containers.MB339_TravelPod = "weapons.containers.MB339_TravelPod" -ENUMS.Storage.weapons.bombs.GBU_12 = "weapons.bombs.GBU_12" -ENUMS.Storage.weapons.bombs.SC_250_T3_J = "weapons.bombs.SC_250_T3_J" -ENUMS.Storage.weapons.missiles.KD_20 = "weapons.missiles.KD-20" -ENUMS.Storage.weapons.missiles.AGM_86C = "weapons.missiles.AGM_86C" -ENUMS.Storage.weapons.missiles.X_35 = "weapons.missiles.X_35" -ENUMS.Storage.weapons.bombs.MK106 = "weapons.bombs.MK106" -ENUMS.Storage.weapons.bombs.BETAB_500S = "weapons.bombs.BETAB-500S" -ENUMS.Storage.weapons.nurs.C_5 = "weapons.nurs.C_5" -ENUMS.Storage.weapons.nurs.S_24B = "weapons.nurs.S-24B" -ENUMS.Storage.weapons.bombs.British_MC_500LB_Bomb_Mk2 = "weapons.bombs.British_MC_500LB_Bomb_Mk2" -ENUMS.Storage.weapons.containers.ANAWW_13 = "weapons.containers.ANAWW_13" -ENUMS.Storage.weapons.droptanks.droptank_108_gal = "weapons.droptanks.droptank_108_gal" -ENUMS.Storage.weapons.droptanks.DFT_300_GAL_A4E_LR = "weapons.droptanks.DFT_300_GAL_A4E_LR" -ENUMS.Storage.weapons.bombs.CBU_87 = "weapons.bombs.CBU_87" -ENUMS.Storage.weapons.missiles.GAR_8 = "weapons.missiles.GAR-8" -ENUMS.Storage.weapons.bombs.BELOUGA = "weapons.bombs.BELOUGA" -ENUMS.Storage.weapons.containers.EclairM_33 = "weapons.containers.{EclairM_33}" -ENUMS.Storage.weapons.bombs.ART_2S9_NONA_Air_19140lb = "weapons.bombs.ART 2S9 NONA Air [19140lb]" -ENUMS.Storage.weapons.bombs.BR_250 = "weapons.bombs.BR_250" -ENUMS.Storage.weapons.bombs.IAB_500 = "weapons.bombs.IAB-500" -ENUMS.Storage.weapons.containers.AN_ASQ_228 = "weapons.containers.AN_ASQ_228" -ENUMS.Storage.weapons.missiles.P_27P = "weapons.missiles.P_27P" -ENUMS.Storage.weapons.bombs.SD_250_Stg = "weapons.bombs.SD_250_Stg" -ENUMS.Storage.weapons.missiles.R_530F_IR = "weapons.missiles.R_530F_IR" -ENUMS.Storage.weapons.bombs.British_SAP_500LB_Bomb_Mk5 = "weapons.bombs.British_SAP_500LB_Bomb_Mk5" -ENUMS.Storage.weapons.bombs.FAB_250M54 = "weapons.bombs.FAB-250M54" -ENUMS.Storage.weapons.containers.M2KC_AAF = "weapons.containers.{M2KC_AAF}" -ENUMS.Storage.weapons.missiles.CM_802AKG_AI = "weapons.missiles.CM-802AKG_AI" -ENUMS.Storage.weapons.bombs.CBU_103 = "weapons.bombs.CBU_103" -ENUMS.Storage.weapons.containers.US_M10_SMOKE_TANK_RED = "weapons.containers.{US_M10_SMOKE_TANK_RED}" -ENUMS.Storage.weapons.missiles.X_29T = "weapons.missiles.X_29T" -ENUMS.Storage.weapons.bombs.HEMTT_TFFT_34400lb = "weapons.bombs.HEMTT TFFT [34400lb]" -ENUMS.Storage.weapons.missiles.C_701IR = "weapons.missiles.C-701IR" -ENUMS.Storage.weapons.containers.fullCargoSeats = "weapons.containers.fullCargoSeats" -ENUMS.Storage.weapons.bombs.GBU_15_V_31_B = "weapons.bombs.GBU_15_V_31_B" -ENUMS.Storage.weapons.bombs.APC_M1043_HMMWV_Armament_Air_7023lb = "weapons.bombs.APC M1043 HMMWV Armament Air [7023lb]" -ENUMS.Storage.weapons.missiles.PL_5EII = "weapons.missiles.PL-5EII" -ENUMS.Storage.weapons.bombs.SC_250_T1_L2 = "weapons.bombs.SC_250_T1_L2" -ENUMS.Storage.weapons.torpedoes.mk46torp_name = "weapons.torpedoes.mk46torp_name" -ENUMS.Storage.weapons.containers.F_15E_AAQ_33_XR_ATP_SE = "weapons.containers.F-15E_AAQ-33_XR_ATP-SE" -ENUMS.Storage.weapons.missiles.AIM_7 = "weapons.missiles.AIM_7" -ENUMS.Storage.weapons.missiles.AGM_122 = "weapons.missiles.AGM_122" -ENUMS.Storage.weapons.bombs.HEBOMB = "weapons.bombs.HEBOMB" -ENUMS.Storage.weapons.bombs.CBU_97 = "weapons.bombs.CBU_97" -ENUMS.Storage.weapons.bombs.MK_81SE = "weapons.bombs.MK-81SE" -ENUMS.Storage.weapons.nurs.Zuni_127 = "weapons.nurs.Zuni_127" -ENUMS.Storage.weapons.containers.M2KC_AGF = "weapons.containers.{M2KC_AGF}" -ENUMS.Storage.weapons.droptanks.Hercules_ExtFuelTank = "weapons.droptanks.Hercules_ExtFuelTank" -ENUMS.Storage.weapons.containers.SMOKE_WHITE = "weapons.containers.{SMOKE_WHITE}" -ENUMS.Storage.weapons.droptanks.droptank_150_gal = "weapons.droptanks.droptank_150_gal" -ENUMS.Storage.weapons.nurs.HYDRA_70_WTU1B = "weapons.nurs.HYDRA_70_WTU1B" -ENUMS.Storage.weapons.missiles.GB_6_SFW = "weapons.missiles.GB-6-SFW" -ENUMS.Storage.weapons.missiles.KD_63 = "weapons.missiles.KD-63" -ENUMS.Storage.weapons.bombs.GBU_28 = "weapons.bombs.GBU_28" -ENUMS.Storage.weapons.nurs.C_8CM_YE = "weapons.nurs.C_8CM_YE" -ENUMS.Storage.weapons.droptanks.HB_F14_EXT_DROPTANK = "weapons.droptanks.HB_F14_EXT_DROPTANK" -ENUMS.Storage.weapons.missiles.Super_530F = "weapons.missiles.Super_530F" -ENUMS.Storage.weapons.missiles.Ataka_9M220 = "weapons.missiles.Ataka_9M220" -ENUMS.Storage.weapons.bombs.BDU_33 = "weapons.bombs.BDU_33" -ENUMS.Storage.weapons.bombs.British_GP_250LB_Bomb_Mk4 = "weapons.bombs.British_GP_250LB_Bomb_Mk4" -ENUMS.Storage.weapons.missiles.TOW = "weapons.missiles.TOW" -ENUMS.Storage.weapons.bombs.ATGM_M1045_HMMWV_TOW_Air_7183lb = "weapons.bombs.ATGM M1045 HMMWV TOW Air [7183lb]" -ENUMS.Storage.weapons.missiles.X_25MR = "weapons.missiles.X_25MR" -ENUMS.Storage.weapons.droptanks.fueltank230 = "weapons.droptanks.fueltank230" -ENUMS.Storage.weapons.droptanks.PTB_490C_MIG21 = "weapons.droptanks.PTB-490C-MIG21" -ENUMS.Storage.weapons.bombs.M1025_HMMWV_Air_6160lb = "weapons.bombs.M1025 HMMWV Air [6160lb]" -ENUMS.Storage.weapons.nurs.SNEB_TYPE254_F1B_GREEN = "weapons.nurs.SNEB_TYPE254_F1B_GREEN" -ENUMS.Storage.weapons.missiles.R_550 = "weapons.missiles.R_550" -ENUMS.Storage.weapons.bombs.KAB_1500LG = "weapons.bombs.KAB_1500LG" -ENUMS.Storage.weapons.missiles.AGM_84D = "weapons.missiles.AGM_84D" -ENUMS.Storage.weapons.missiles.YJ_83K = "weapons.missiles.YJ-83K" -ENUMS.Storage.weapons.missiles.AIM_54C_Mk47 = "weapons.missiles.AIM_54C_Mk47" -ENUMS.Storage.weapons.missiles.BRM_1_90MM = "weapons.missiles.BRM-1_90MM" -ENUMS.Storage.weapons.missiles.Ataka_9M120F = "weapons.missiles.Ataka_9M120F" -ENUMS.Storage.weapons.droptanks.Eleven00L_Tank = "weapons.droptanks.1100L Tank" -ENUMS.Storage.weapons.bombs.BAP_100 = "weapons.bombs.BAP_100" -ENUMS.Storage.weapons.adapters.lau_88 = "weapons.adapters.lau-88" -ENUMS.Storage.weapons.missiles.P_40T = "weapons.missiles.P_40T" -ENUMS.Storage.weapons.missiles.GB_6 = "weapons.missiles.GB-6" -ENUMS.Storage.weapons.bombs.FAB_250M54TU = "weapons.bombs.FAB-250M54TU" -ENUMS.Storage.weapons.missiles.DWS39_MJ1 = "weapons.missiles.DWS39_MJ1" -ENUMS.Storage.weapons.missiles.CM_802AKG = "weapons.missiles.CM-802AKG" -ENUMS.Storage.weapons.bombs.FAB_250 = "weapons.bombs.FAB_250" -ENUMS.Storage.weapons.missiles.C_802AK = "weapons.missiles.C_802AK" -ENUMS.Storage.weapons.bombs.SD_500_A = "weapons.bombs.SD_500_A" -ENUMS.Storage.weapons.bombs.GBU_32_V_2B = "weapons.bombs.GBU_32_V_2B" -ENUMS.Storage.weapons.containers.marder = "weapons.containers.marder" -ENUMS.Storage.weapons.missiles.ADM_141B = "weapons.missiles.ADM_141B" -ENUMS.Storage.weapons.bombs.ROCKEYE = "weapons.bombs.ROCKEYE" -ENUMS.Storage.weapons.missiles.BK90_MJ1 = "weapons.missiles.BK90_MJ1" -ENUMS.Storage.weapons.containers.BTR_80 = "weapons.containers.BTR-80" -ENUMS.Storage.weapons.bombs.SAM_ROLAND_ADS_34720lb = "weapons.bombs.SAM ROLAND ADS [34720lb]" -ENUMS.Storage.weapons.containers.wmd7 = "weapons.containers.wmd7" -ENUMS.Storage.weapons.missiles.C_701T = "weapons.missiles.C-701T" -ENUMS.Storage.weapons.missiles.AIM_7E_2 = "weapons.missiles.AIM-7E-2" -ENUMS.Storage.weapons.nurs.HVAR = "weapons.nurs.HVAR" -ENUMS.Storage.weapons.containers.HMMWV_M1043 = "weapons.containers.HMMWV_M1043" -ENUMS.Storage.weapons.droptanks.PTB_800_MIG21 = "weapons.droptanks.PTB-800-MIG21" -ENUMS.Storage.weapons.missiles.AGM_114 = "weapons.missiles.AGM_114" -ENUMS.Storage.weapons.bombs.APC_M1126_Stryker_ICV_29542lb = "weapons.bombs.APC M1126 Stryker ICV [29542lb]" -ENUMS.Storage.weapons.bombs.APC_M113_Air_21624lb = "weapons.bombs.APC M113 Air [21624lb]" -ENUMS.Storage.weapons.bombs.M_117 = "weapons.bombs.M_117" -ENUMS.Storage.weapons.missiles.AGM_65D = "weapons.missiles.AGM_65D" -ENUMS.Storage.weapons.droptanks.MB339_TT320_L = "weapons.droptanks.MB339_TT320_L" -ENUMS.Storage.weapons.missiles.AGM_86 = "weapons.missiles.AGM_86" -ENUMS.Storage.weapons.bombs.BDU_45LGB = "weapons.bombs.BDU_45LGB" -ENUMS.Storage.weapons.missiles.AGM_65H = "weapons.missiles.AGM_65H" -ENUMS.Storage.weapons.nurs.RS_82 = "weapons.nurs.RS-82" -ENUMS.Storage.weapons.nurs.SNEB_TYPE252_F1B = "weapons.nurs.SNEB_TYPE252_F1B" -ENUMS.Storage.weapons.bombs.BL_755 = "weapons.bombs.BL_755" -ENUMS.Storage.weapons.containers.F_15E_AAQ_28_LITENING = "weapons.containers.F-15E_AAQ-28_LITENING" -ENUMS.Storage.weapons.nurs.SNEB_TYPE256_F1B = "weapons.nurs.SNEB_TYPE256_F1B" -ENUMS.Storage.weapons.missiles.AGM_84H = "weapons.missiles.AGM_84H" -ENUMS.Storage.weapons.missiles.AIM_54 = "weapons.missiles.AIM_54" -ENUMS.Storage.weapons.missiles.X_31A = "weapons.missiles.X_31A" -ENUMS.Storage.weapons.bombs.KAB_500Kr = "weapons.bombs.KAB_500Kr" -ENUMS.Storage.weapons.containers.SPS_141_100 = "weapons.containers.SPS-141-100" -ENUMS.Storage.weapons.missiles.BK90_MJ2 = "weapons.missiles.BK90_MJ2" -ENUMS.Storage.weapons.missiles.Super_530D = "weapons.missiles.Super_530D" -ENUMS.Storage.weapons.bombs.CBU_52B = "weapons.bombs.CBU_52B" -ENUMS.Storage.weapons.droptanks.PTB_450 = "weapons.droptanks.PTB-450" -ENUMS.Storage.weapons.bombs.IFV_MCV_80_34720lb = "weapons.bombs.IFV MCV-80 [34720lb]" -ENUMS.Storage.weapons.containers.Two_c9 = "weapons.containers.2-c9" -ENUMS.Storage.weapons.missiles.AIM_9JULI = "weapons.missiles.AIM-9JULI" -ENUMS.Storage.weapons.droptanks.MB339_TT500_R = "weapons.droptanks.MB339_TT500_R" -ENUMS.Storage.weapons.nurs.C_8CM = "weapons.nurs.C_8CM" -ENUMS.Storage.weapons.containers.BARAX = "weapons.containers.BARAX" -ENUMS.Storage.weapons.missiles.P_40R = "weapons.missiles.P_40R" -ENUMS.Storage.weapons.missiles.YJ_12 = "weapons.missiles.YJ-12" -ENUMS.Storage.weapons.missiles.CM_802AKG = "weapons.missiles.CM_802AKG" -ENUMS.Storage.weapons.nurs.SNEB_TYPE254_H1_YELLOW = "weapons.nurs.SNEB_TYPE254_H1_YELLOW" -ENUMS.Storage.weapons.bombs.Durandal = "weapons.bombs.Durandal" -ENUMS.Storage.weapons.droptanks.i16_eft = "weapons.droptanks.i16_eft" -ENUMS.Storage.weapons.droptanks.AV8BNA_AERO1D_EMPTY = "weapons.droptanks.AV8BNA_AERO1D_EMPTY" -ENUMS.Storage.weapons.containers.Hercules_Battle_Station_TGP = "weapons.containers.Hercules_Battle_Station_TGP" -ENUMS.Storage.weapons.nurs.C_8CM_VT = "weapons.nurs.C_8CM_VT" -ENUMS.Storage.weapons.missiles.PL_12 = "weapons.missiles.PL-12" -ENUMS.Storage.weapons.missiles.R_3R = "weapons.missiles.R-3R" -ENUMS.Storage.weapons.bombs.GBU_54_V_1B = "weapons.bombs.GBU_54_V_1B" -ENUMS.Storage.weapons.droptanks.MB339_TT320_R = "weapons.droptanks.MB339_TT320_R" -ENUMS.Storage.weapons.bombs.RN_24 = "weapons.bombs.RN-24" -ENUMS.Storage.weapons.containers.Twoc6m = "weapons.containers.2c6m" -ENUMS.Storage.weapons.bombs.ARV_BRDM_2_Air_12320lb = "weapons.bombs.ARV BRDM-2 Air [12320lb]" -ENUMS.Storage.weapons.bombs.ARV_BRDM_2_Skid_12210lb = "weapons.bombs.ARV BRDM-2 Skid [12210lb]" -ENUMS.Storage.weapons.nurs.SNEB_TYPE251_F1B = "weapons.nurs.SNEB_TYPE251_F1B" -ENUMS.Storage.weapons.missiles.X_41 = "weapons.missiles.X_41" -ENUMS.Storage.weapons.containers.MIG21_SMOKE_WHITE = "weapons.containers.{MIG21_SMOKE_WHITE}" -ENUMS.Storage.weapons.bombs.MK_82AIR = "weapons.bombs.MK_82AIR" -ENUMS.Storage.weapons.missiles.R_530F_EM = "weapons.missiles.R_530F_EM" -ENUMS.Storage.weapons.bombs.SAMP400LD = "weapons.bombs.SAMP400LD" -ENUMS.Storage.weapons.bombs.FAB_50 = "weapons.bombs.FAB_50" -ENUMS.Storage.weapons.bombs.AB_250_2_SD_10A = "weapons.bombs.AB_250_2_SD_10A" -ENUMS.Storage.weapons.missiles.ADM_141A = "weapons.missiles.ADM_141A" -ENUMS.Storage.weapons.containers.KBpod = "weapons.containers.KBpod" -ENUMS.Storage.weapons.bombs.British_GP_500LB_Bomb_Mk4 = "weapons.bombs.British_GP_500LB_Bomb_Mk4" -ENUMS.Storage.weapons.missiles.AGM_65E = "weapons.missiles.AGM_65E" -ENUMS.Storage.weapons.containers.sa342_dipole_antenna = "weapons.containers.sa342_dipole_antenna" -ENUMS.Storage.weapons.bombs.OFAB_100_Jupiter = "weapons.bombs.OFAB-100 Jupiter" -ENUMS.Storage.weapons.nurs.SNEB_TYPE257_F1B = "weapons.nurs.SNEB_TYPE257_F1B" -ENUMS.Storage.weapons.missiles.Rb_04E_for_A_I = "weapons.missiles.Rb 04E (for A.I.)" -ENUMS.Storage.weapons.bombs.AN_M66A2 = "weapons.bombs.AN-M66A2" -ENUMS.Storage.weapons.missiles.P_27T = "weapons.missiles.P_27T" -ENUMS.Storage.weapons.droptanks.LNS_VIG_XTANK = "weapons.droptanks.LNS_VIG_XTANK" -ENUMS.Storage.weapons.missiles.R_55 = "weapons.missiles.R-55" -ENUMS.Storage.weapons.torpedoes.YU_6 = "weapons.torpedoes.YU-6" -ENUMS.Storage.weapons.bombs.British_MC_250LB_Bomb_Mk2 = "weapons.bombs.British_MC_250LB_Bomb_Mk2" -ENUMS.Storage.weapons.droptanks.PTB_120_F86F35 = "weapons.droptanks.PTB_120_F86F35" -ENUMS.Storage.weapons.missiles.PL_8B = "weapons.missiles.PL-8B" -ENUMS.Storage.weapons.droptanks.F_15E_Drop_Tank_Empty = "weapons.droptanks.F-15E_Drop_Tank_Empty" -ENUMS.Storage.weapons.nurs.British_HE_60LBFNo1_3INCHNo1 = "weapons.nurs.British_HE_60LBFNo1_3INCHNo1" -ENUMS.Storage.weapons.missiles.P_77 = "weapons.missiles.P_77" -ENUMS.Storage.weapons.torpedoes.LTF_5B = "weapons.torpedoes.LTF_5B" -ENUMS.Storage.weapons.missiles.R_3S = "weapons.missiles.R-3S" -ENUMS.Storage.weapons.nurs.SNEB_TYPE253_H1 = "weapons.nurs.SNEB_TYPE253_H1" -ENUMS.Storage.weapons.missiles.PL_8A = "weapons.missiles.PL-8A" -ENUMS.Storage.weapons.bombs.APC_BTR_82A_Skid_24888lb = "weapons.bombs.APC BTR-82A Skid [24888lb]" -ENUMS.Storage.weapons.containers.Sborka = "weapons.containers.Sborka" -ENUMS.Storage.weapons.missiles.AGM_65L = "weapons.missiles.AGM_65L" -ENUMS.Storage.weapons.missiles.X_28 = "weapons.missiles.X_28" -ENUMS.Storage.weapons.missiles.TGM_65G = "weapons.missiles.TGM_65G" -ENUMS.Storage.weapons.nurs.SNEB_TYPE257_H1 = "weapons.nurs.SNEB_TYPE257_H1" -ENUMS.Storage.weapons.missiles.RB75B = "weapons.missiles.RB75B" -ENUMS.Storage.weapons.missiles.X_25ML = "weapons.missiles.X_25ML" -ENUMS.Storage.weapons.droptanks.FPU_8A = "weapons.droptanks.FPU_8A" -ENUMS.Storage.weapons.bombs.BLG66 = "weapons.bombs.BLG66" -ENUMS.Storage.weapons.nurs.C_8CM_RD = "weapons.nurs.C_8CM_RD" -ENUMS.Storage.weapons.containers.EclairM_06 = "weapons.containers.{EclairM_06}" -ENUMS.Storage.weapons.bombs.RBK_500AO = "weapons.bombs.RBK_500AO" -ENUMS.Storage.weapons.missiles.AIM_9P = "weapons.missiles.AIM-9P" -ENUMS.Storage.weapons.bombs.British_GP_500LB_Bomb_Mk4_Short = "weapons.bombs.British_GP_500LB_Bomb_Mk4_Short" -ENUMS.Storage.weapons.containers.MB339_Vinten = "weapons.containers.MB339_Vinten" -ENUMS.Storage.weapons.missiles.Rb_15F = "weapons.missiles.Rb 15F" -ENUMS.Storage.weapons.nurs.ARAKM70BHE = "weapons.nurs.ARAKM70BHE" -ENUMS.Storage.weapons.bombs.AAA_Vulcan_M163_Air_21666lb = "weapons.bombs.AAA Vulcan M163 Air [21666lb]" -ENUMS.Storage.weapons.missiles.X_29L = "weapons.missiles.X_29L" -ENUMS.Storage.weapons.containers.F14_LANTIRN_TP = "weapons.containers.{F14-LANTIRN-TP}" -ENUMS.Storage.weapons.bombs.FAB_250_M62 = "weapons.bombs.FAB-250-M62" -ENUMS.Storage.weapons.missiles.AIM_120C = "weapons.missiles.AIM_120C" -ENUMS.Storage.weapons.bombs.EWR_SBORKA_Air_21624lb = "weapons.bombs.EWR SBORKA Air [21624lb]" -ENUMS.Storage.weapons.bombs.SAMP250LD = "weapons.bombs.SAMP250LD" -ENUMS.Storage.weapons.droptanks.Spitfire_slipper_tank = "weapons.droptanks.Spitfire_slipper_tank" -ENUMS.Storage.weapons.missiles.LS_6_500 = "weapons.missiles.LS-6-500" -ENUMS.Storage.weapons.bombs.GBU_31_V_4B = "weapons.bombs.GBU_31_V_4B" -ENUMS.Storage.weapons.droptanks.PTB400_MIG15 = "weapons.droptanks.PTB400_MIG15" -ENUMS.Storage.weapons.containers.m_113 = "weapons.containers.m-113" -ENUMS.Storage.weapons.bombs.SPG_M1128_Stryker_MGS_33036lb = "weapons.bombs.SPG M1128 Stryker MGS [33036lb]" -ENUMS.Storage.weapons.missiles.AIM_9L = "weapons.missiles.AIM-9L" -ENUMS.Storage.weapons.missiles.AIM_9X = "weapons.missiles.AIM_9X" -ENUMS.Storage.weapons.nurs.C_8 = "weapons.nurs.C_8" -ENUMS.Storage.weapons.bombs.SAM_CHAPARRAL_Skid_21516lb = "weapons.bombs.SAM CHAPARRAL Skid [21516lb]" -ENUMS.Storage.weapons.missiles.P_27TE = "weapons.missiles.P_27TE" -ENUMS.Storage.weapons.bombs.ODAB_500PM = "weapons.bombs.ODAB-500PM" -ENUMS.Storage.weapons.bombs.MK77mod1_WPN = "weapons.bombs.MK77mod1-WPN" -ENUMS.Storage.weapons.droptanks.PTB400_MIG19 = "weapons.droptanks.PTB400_MIG19" -ENUMS.Storage.weapons.torpedoes.Mark_46 = "weapons.torpedoes.Mark_46" -ENUMS.Storage.weapons.containers.rightSeat = "weapons.containers.rightSeat" -ENUMS.Storage.weapons.containers.US_M10_SMOKE_TANK_ORANGE = "weapons.containers.{US_M10_SMOKE_TANK_ORANGE}" -ENUMS.Storage.weapons.bombs.SAB_100MN = "weapons.bombs.SAB_100MN" -ENUMS.Storage.weapons.nurs.FFAR_Mk5_HEAT = "weapons.nurs.FFAR Mk5 HEAT" -ENUMS.Storage.weapons.bombs.IFV_TPZ_FUCH_33440lb = "weapons.bombs.IFV TPZ FUCH [33440lb]" -ENUMS.Storage.weapons.bombs.IFV_M2A2_Bradley_34720lb = "weapons.bombs.IFV M2A2 Bradley [34720lb]" -ENUMS.Storage.weapons.bombs.MK77mod0_WPN = "weapons.bombs.MK77mod0-WPN" -ENUMS.Storage.weapons.containers.ASO_2 = "weapons.containers.ASO-2" -ENUMS.Storage.weapons.bombs.Mk_84AIR_GP = "weapons.bombs.Mk_84AIR_GP" -ENUMS.Storage.weapons.nurs.S_24A = "weapons.nurs.S-24A" -ENUMS.Storage.weapons.bombs.RBK_250_275_AO_1SCH = "weapons.bombs.RBK_250_275_AO_1SCH" -ENUMS.Storage.weapons.bombs.Transport_Tigr_Skid_15730lb = "weapons.bombs.Transport Tigr Skid [15730lb]" -ENUMS.Storage.weapons.missiles.AIM_7F = "weapons.missiles.AIM-7F" -ENUMS.Storage.weapons.bombs.CBU_99 = "weapons.bombs.CBU_99" -ENUMS.Storage.weapons.bombs.LUU_2B = "weapons.bombs.LUU_2B" -ENUMS.Storage.weapons.bombs.FAB_500TA = "weapons.bombs.FAB-500TA" -ENUMS.Storage.weapons.missiles.AGR_20_M282 = "weapons.missiles.AGR_20_M282" -ENUMS.Storage.weapons.droptanks.MB339_FT330 = "weapons.droptanks.MB339_FT330" -ENUMS.Storage.weapons.bombs.SAMP125LD = "weapons.bombs.SAMP125LD" -ENUMS.Storage.weapons.missiles.X_25MP = "weapons.missiles.X_25MP" -ENUMS.Storage.weapons.nurs.SNEB_TYPE252_H1 = "weapons.nurs.SNEB_TYPE252_H1" -ENUMS.Storage.weapons.missiles.AGM_65F = "weapons.missiles.AGM_65F" -ENUMS.Storage.weapons.missiles.AIM_9P5 = "weapons.missiles.AIM-9P5" -ENUMS.Storage.weapons.bombs.Transport_Tigr_Air_15900lb = "weapons.bombs.Transport Tigr Air [15900lb]" -ENUMS.Storage.weapons.nurs.SNEB_TYPE254_H1_RED = "weapons.nurs.SNEB_TYPE254_H1_RED" -ENUMS.Storage.weapons.nurs.FFAR_Mk1_HE = "weapons.nurs.FFAR Mk1 HE" -ENUMS.Storage.weapons.nurs.SPRD_99 = "weapons.nurs.SPRD-99" -ENUMS.Storage.weapons.bombs.BIN_200 = "weapons.bombs.BIN_200" -ENUMS.Storage.weapons.bombs.BLU_4B_GROUP = "weapons.bombs.BLU_4B_GROUP" -ENUMS.Storage.weapons.bombs.GBU_24 = "weapons.bombs.GBU_24" -ENUMS.Storage.weapons.missiles.Rb_04E = "weapons.missiles.Rb 04E" -ENUMS.Storage.weapons.missiles.Rb_74 = "weapons.missiles.Rb 74" -ENUMS.Storage.weapons.containers.leftSeat = "weapons.containers.leftSeat" -ENUMS.Storage.weapons.bombs.LS_6_100 = "weapons.bombs.LS-6-100" -ENUMS.Storage.weapons.bombs.Transport_URAL_375_14815lb = "weapons.bombs.Transport URAL-375 [14815lb]" -ENUMS.Storage.weapons.containers.US_M10_SMOKE_TANK_GREEN = "weapons.containers.{US_M10_SMOKE_TANK_GREEN}" -ENUMS.Storage.weapons.missiles.X_22 = "weapons.missiles.X_22" -ENUMS.Storage.weapons.containers.FAS = "weapons.containers.FAS" -ENUMS.Storage.weapons.nurs.S_25_O = "weapons.nurs.S-25-O" -ENUMS.Storage.weapons.droptanks.para = "weapons.droptanks.para" -ENUMS.Storage.weapons.droptanks.F_15E_Drop_Tank = "weapons.droptanks.F-15E_Drop_Tank" -ENUMS.Storage.weapons.droptanks.M2KC_08_RPL541_EMPTY = "weapons.droptanks.M2KC_08_RPL541_EMPTY" -ENUMS.Storage.weapons.missiles.X_31P = "weapons.missiles.X_31P" -ENUMS.Storage.weapons.bombs.RBK_500U = "weapons.bombs.RBK_500U" -ENUMS.Storage.weapons.missiles.AIM_54A_Mk47 = "weapons.missiles.AIM_54A_Mk47" -ENUMS.Storage.weapons.droptanks.oiltank = "weapons.droptanks.oiltank" -ENUMS.Storage.weapons.missiles.AGM_154B = "weapons.missiles.AGM_154B" -ENUMS.Storage.weapons.containers.MB339_SMOKE_POD = "weapons.containers.MB339_SMOKE-POD" -ENUMS.Storage.weapons.containers.ECM_POD_L_175V = "weapons.containers.{ECM_POD_L_175V}" -ENUMS.Storage.weapons.droptanks.PTB_580G_F1 = "weapons.droptanks.PTB_580G_F1" -ENUMS.Storage.weapons.containers.EclairM_15 = "weapons.containers.{EclairM_15}" -ENUMS.Storage.weapons.containers.F_15E_AAQ_13_LANTIRN = "weapons.containers.F-15E_AAQ-13_LANTIRN" -ENUMS.Storage.weapons.droptanks.Eight00L_Tank_Empty = "weapons.droptanks.800L Tank Empty" -ENUMS.Storage.weapons.containers.One6c_hts_pod = "weapons.containers.16c_hts_pod" -ENUMS.Storage.weapons.bombs.AN_M81 = "weapons.bombs.AN-M81" -ENUMS.Storage.weapons.droptanks.Mosquito_Drop_Tank_100gal = "weapons.droptanks.Mosquito_Drop_Tank_100gal" -ENUMS.Storage.weapons.droptanks.Mosquito_Drop_Tank_50gal = "weapons.droptanks.Mosquito_Drop_Tank_50gal" -ENUMS.Storage.weapons.droptanks.DFT_150_GAL_A4E = "weapons.droptanks.DFT_150_GAL_A4E" -ENUMS.Storage.weapons.missiles.AIM_9 = "weapons.missiles.AIM_9" -ENUMS.Storage.weapons.bombs.IFV_BTR_D_Air_18040lb = "weapons.bombs.IFV BTR-D Air [18040lb]" -ENUMS.Storage.weapons.containers.EclairM_42 = "weapons.containers.{EclairM_42}" -ENUMS.Storage.weapons.bombs.KAB_1500T = "weapons.bombs.KAB_1500T" -ENUMS.Storage.weapons.droptanks.PTB_490_MIG21 = "weapons.droptanks.PTB-490-MIG21" -ENUMS.Storage.weapons.droptanks.PTB_200_F86F35 = "weapons.droptanks.PTB_200_F86F35" -ENUMS.Storage.weapons.droptanks.PTB760_MIG19 = "weapons.droptanks.PTB760_MIG19" -ENUMS.Storage.weapons.bombs.GBU_43_B_MOAB = "weapons.bombs.GBU-43/B(MOAB)" -ENUMS.Storage.weapons.torpedoes.G7A_T1 = "weapons.torpedoes.G7A_T1" -ENUMS.Storage.weapons.bombs.IFV_BMD_1_Air_18040lb = "weapons.bombs.IFV BMD-1 Air [18040lb]" -ENUMS.Storage.weapons.bombs.SAM_LINEBACKER_34720lb = "weapons.bombs.SAM LINEBACKER [34720lb]" -ENUMS.Storage.weapons.containers.ais_pod_t50_r = "weapons.containers.ais-pod-t50_r" -ENUMS.Storage.weapons.containers.CE2_SMOKE_WHITE = "weapons.containers.{CE2_SMOKE_WHITE}" -ENUMS.Storage.weapons.droptanks.fuel_tank_230 = "weapons.droptanks.fuel_tank_230" -ENUMS.Storage.weapons.droptanks.M2KC_RPL_522 = "weapons.droptanks.M2KC_RPL_522" -ENUMS.Storage.weapons.missiles.AGM_130 = "weapons.missiles.AGM_130" -ENUMS.Storage.weapons.droptanks.Eight00L_Tank = "weapons.droptanks.800L Tank" -ENUMS.Storage.weapons.bombs.IFV_BTR_D_Skid_17930lb = "weapons.bombs.IFV BTR-D Skid [17930lb]" -ENUMS.Storage.weapons.containers.bmp_1 = "weapons.containers.bmp-1" -ENUMS.Storage.weapons.bombs.GBU_31 = "weapons.bombs.GBU_31" -ENUMS.Storage.weapons.containers.aaq_28LEFT_litening = "weapons.containers.aaq-28LEFT litening" -ENUMS.Storage.weapons.missiles.Kh_66_Grom = "weapons.missiles.Kh-66_Grom" -ENUMS.Storage.weapons.containers.MIG21_SMOKE_RED = "weapons.containers.{MIG21_SMOKE_RED}" -ENUMS.Storage.weapons.containers.U22 = "weapons.containers.U22" -ENUMS.Storage.weapons.bombs.IFV_BMD_1_Skid_17930lb = "weapons.bombs.IFV BMD-1 Skid [17930lb]" -ENUMS.Storage.weapons.droptanks.Bidon = "weapons.droptanks.Bidon" -ENUMS.Storage.weapons.bombs.GBU_31_V_2B = "weapons.bombs.GBU_31_V_2B" -ENUMS.Storage.weapons.bombs.Mk_82Y = "weapons.bombs.Mk_82Y" -ENUMS.Storage.weapons.containers.pl5eii = "weapons.containers.pl5eii" -ENUMS.Storage.weapons.bombs.RBK_500U_OAB_2_5RT = "weapons.bombs.RBK_500U_OAB_2_5RT" -ENUMS.Storage.weapons.bombs.British_GP_500LB_Bomb_Mk5 = "weapons.bombs.British_GP_500LB_Bomb_Mk5" -ENUMS.Storage.weapons.containers.Eclair = "weapons.containers.{Eclair}" -ENUMS.Storage.weapons.nurs.S5MO_HEFRAG_FFAR = "weapons.nurs.S5MO_HEFRAG_FFAR" -ENUMS.Storage.weapons.bombs.BETAB_500M = "weapons.bombs.BETAB-500M" -ENUMS.Storage.weapons.bombs.Transport_M818_16000lb = "weapons.bombs.Transport M818 [16000lb]" -ENUMS.Storage.weapons.bombs.British_MC_250LB_Bomb_Mk1 = "weapons.bombs.British_MC_250LB_Bomb_Mk1" -ENUMS.Storage.weapons.nurs.SNEB_TYPE251_H1 = "weapons.nurs.SNEB_TYPE251_H1" -ENUMS.Storage.weapons.bombs.TYPE_200A = "weapons.bombs.TYPE-200A" -ENUMS.Storage.weapons.nurs.HYDRA_70_M151 = "weapons.nurs.HYDRA_70_M151" -ENUMS.Storage.weapons.bombs.IFV_BMP_3_32912lb = "weapons.bombs.IFV BMP-3 [32912lb]" -ENUMS.Storage.weapons.bombs.APC_MTLB_Air_26400lb = "weapons.bombs.APC MTLB Air [26400lb]" -ENUMS.Storage.weapons.nurs.HYDRA_70_M229 = "weapons.nurs.HYDRA_70_M229" -ENUMS.Storage.weapons.bombs.BDU_45 = "weapons.bombs.BDU_45" -ENUMS.Storage.weapons.bombs.OFAB_100_120TU = "weapons.bombs.OFAB-100-120TU" -ENUMS.Storage.weapons.missiles.AIM_9J = "weapons.missiles.AIM-9J" -ENUMS.Storage.weapons.nurs.ARF8M3API = "weapons.nurs.ARF8M3API" -ENUMS.Storage.weapons.bombs.BetAB_500ShP = "weapons.bombs.BetAB_500ShP" -ENUMS.Storage.weapons.nurs.C_8OFP2 = "weapons.nurs.C_8OFP2" -ENUMS.Storage.weapons.bombs.GBU_10 = "weapons.bombs.GBU_10" -ENUMS.Storage.weapons.bombs.APC_MTLB_Skid_26290lb = "weapons.bombs.APC MTLB Skid [26290lb]" -ENUMS.Storage.weapons.nurs.SNEB_TYPE254_F1B_RED = "weapons.nurs.SNEB_TYPE254_F1B_RED" -ENUMS.Storage.weapons.missiles.X_65 = "weapons.missiles.X_65" -ENUMS.Storage.weapons.missiles.R_550_M1 = "weapons.missiles.R_550_M1" -ENUMS.Storage.weapons.missiles.AGM_65K = "weapons.missiles.AGM_65K" -ENUMS.Storage.weapons.nurs.SNEB_TYPE254_F1B_YELLOW = "weapons.nurs.SNEB_TYPE254_F1B_YELLOW" -ENUMS.Storage.weapons.missiles.AGM_88 = "weapons.missiles.AGM_88" -ENUMS.Storage.weapons.nurs.C_8OM = "weapons.nurs.C_8OM" -ENUMS.Storage.weapons.bombs.SAM_ROLAND_LN_34720b = "weapons.bombs.SAM ROLAND LN [34720b]" -ENUMS.Storage.weapons.missiles.AIM_120 = "weapons.missiles.AIM_120" -ENUMS.Storage.weapons.missiles.HOT3_MBDA = "weapons.missiles.HOT3_MBDA" -ENUMS.Storage.weapons.missiles.R_13M = "weapons.missiles.R-13M" -ENUMS.Storage.weapons.missiles.AIM_54C_Mk60 = "weapons.missiles.AIM_54C_Mk60" -ENUMS.Storage.weapons.bombs.AAA_GEPARD_34720lb = "weapons.bombs.AAA GEPARD [34720lb]" -ENUMS.Storage.weapons.missiles.R_13M1 = "weapons.missiles.R-13M1" -ENUMS.Storage.weapons.bombs.APC_Cobra_Air_10912lb = "weapons.bombs.APC Cobra Air [10912lb]" -ENUMS.Storage.weapons.bombs.RBK_250 = "weapons.bombs.RBK_250" -ENUMS.Storage.weapons.bombs.SC_500_J = "weapons.bombs.SC_500_J" -ENUMS.Storage.weapons.missiles.AGM_114K = "weapons.missiles.AGM_114K" -ENUMS.Storage.weapons.missiles.ALARM = "weapons.missiles.ALARM" -ENUMS.Storage.weapons.bombs.Mk_83 = "weapons.bombs.Mk_83" -ENUMS.Storage.weapons.missiles.AGM_65B = "weapons.missiles.AGM_65B" -ENUMS.Storage.weapons.bombs.MK_82SNAKEYE = "weapons.bombs.MK_82SNAKEYE" -ENUMS.Storage.weapons.nurs.HYDRA_70_MK1 = "weapons.nurs.HYDRA_70_MK1" -ENUMS.Storage.weapons.bombs.BLG66_BELOUGA = "weapons.bombs.BLG66_BELOUGA" -ENUMS.Storage.weapons.containers.EclairM_51 = "weapons.containers.{EclairM_51}" -ENUMS.Storage.weapons.missiles.AIM_54A_Mk60 = "weapons.missiles.AIM_54A_Mk60" -ENUMS.Storage.weapons.droptanks.DFT_300_GAL_A4E = "weapons.droptanks.DFT_300_GAL_A4E" -ENUMS.Storage.weapons.bombs.ATGM_M1134_Stryker_30337lb = "weapons.bombs.ATGM M1134 Stryker [30337lb]" -ENUMS.Storage.weapons.bombs.BAT_120 = "weapons.bombs.BAT-120" -ENUMS.Storage.weapons.missiles.DWS39_MJ1_MJ2 = "weapons.missiles.DWS39_MJ1_MJ2" -ENUMS.Storage.weapons.containers.SPRD = "weapons.containers.SPRD" -ENUMS.Storage.weapons.bombs.BR_500 = "weapons.bombs.BR_500" -ENUMS.Storage.weapons.bombs.British_GP_500LB_Bomb_Mk1 = "weapons.bombs.British_GP_500LB_Bomb_Mk1" -ENUMS.Storage.weapons.bombs.BDU_50HD = "weapons.bombs.BDU_50HD" -ENUMS.Storage.weapons.missiles.RS2US = "weapons.missiles.RS2US" -ENUMS.Storage.weapons.bombs.IFV_BMP_2_25168lb = "weapons.bombs.IFV BMP-2 [25168lb]" -ENUMS.Storage.weapons.bombs.SAMP400HD = "weapons.bombs.SAMP400HD" -ENUMS.Storage.weapons.containers.Hercules_Battle_Station = "weapons.containers.Hercules_Battle_Station" -ENUMS.Storage.weapons.bombs.AN_M64 = "weapons.bombs.AN_M64" -ENUMS.Storage.weapons.containers.rearCargoSeats = "weapons.containers.rearCargoSeats" -ENUMS.Storage.weapons.bombs.Mk_82 = "weapons.bombs.Mk_82" -ENUMS.Storage.weapons.missiles.AKD_10 = "weapons.missiles.AKD-10" -ENUMS.Storage.weapons.bombs.BDU_50LGB = "weapons.bombs.BDU_50LGB" -ENUMS.Storage.weapons.missiles.SD_10 = "weapons.missiles.SD-10" -ENUMS.Storage.weapons.containers.IRDeflector = "weapons.containers.IRDeflector" -ENUMS.Storage.weapons.bombs.FAB_500 = "weapons.bombs.FAB_500" -ENUMS.Storage.weapons.bombs.KAB_500 = "weapons.bombs.KAB_500" -ENUMS.Storage.weapons.nurs.S_5M = "weapons.nurs.S-5M" -ENUMS.Storage.weapons.missiles.MICA_R = "weapons.missiles.MICA_R" -ENUMS.Storage.weapons.missiles.X_59M = "weapons.missiles.X_59M" -ENUMS.Storage.weapons.nurs.UG_90MM = "weapons.nurs.UG_90MM" -ENUMS.Storage.weapons.bombs.LYSBOMB = "weapons.bombs.LYSBOMB" -ENUMS.Storage.weapons.nurs.R4M = "weapons.nurs.R4M" -ENUMS.Storage.weapons.containers.dlpod_akg = "weapons.containers.dlpod_akg" -ENUMS.Storage.weapons.missiles.LD_10 = "weapons.missiles.LD-10" -ENUMS.Storage.weapons.bombs.SC_50 = "weapons.bombs.SC_50" -ENUMS.Storage.weapons.nurs.HYDRA_70_MK5 = "weapons.nurs.HYDRA_70_MK5" -ENUMS.Storage.weapons.bombs.FAB_100M = "weapons.bombs.FAB_100M" -ENUMS.Storage.weapons.missiles.Rb_24 = "weapons.missiles.Rb 24" -ENUMS.Storage.weapons.bombs.BDU_45B = "weapons.bombs.BDU_45B" -ENUMS.Storage.weapons.missiles.GB_6_HE = "weapons.missiles.GB-6-HE" -ENUMS.Storage.weapons.missiles.KD_63B = "weapons.missiles.KD-63B" -ENUMS.Storage.weapons.missiles.P_27PE = "weapons.missiles.P_27PE" -ENUMS.Storage.weapons.droptanks.PTB300_MIG15 = "weapons.droptanks.PTB300_MIG15" -ENUMS.Storage.weapons.bombs.Two50_3 = "weapons.bombs.250-3" -ENUMS.Storage.weapons.bombs.SC_500_L2 = "weapons.bombs.SC_500_L2" -ENUMS.Storage.weapons.containers.HMMWV_M1045 = "weapons.containers.HMMWV_M1045" -ENUMS.Storage.weapons.bombs.FAB_500M54TU = "weapons.bombs.FAB-500M54TU" -ENUMS.Storage.weapons.containers.US_M10_SMOKE_TANK_YELLOW = "weapons.containers.{US_M10_SMOKE_TANK_YELLOW}" -ENUMS.Storage.weapons.containers.EclairM_60 = "weapons.containers.{EclairM_60}" -ENUMS.Storage.weapons.bombs.SAB_250_200 = "weapons.bombs.SAB_250_200" -ENUMS.Storage.weapons.bombs.FAB_100 = "weapons.bombs.FAB_100" -ENUMS.Storage.weapons.bombs.KAB_500S = "weapons.bombs.KAB_500S" -ENUMS.Storage.weapons.missiles.AGM_45A = "weapons.missiles.AGM_45A" -ENUMS.Storage.weapons.missiles.Kh25MP_PRGS1VP = "weapons.missiles.Kh25MP_PRGS1VP" -ENUMS.Storage.weapons.nurs.S5M1_HEFRAG_FFAR = "weapons.nurs.S5M1_HEFRAG_FFAR" -ENUMS.Storage.weapons.containers.kg600 = "weapons.containers.kg600" -ENUMS.Storage.weapons.bombs.AN_M65 = "weapons.bombs.AN_M65" -ENUMS.Storage.weapons.bombs.AN_M57 = "weapons.bombs.AN_M57" -ENUMS.Storage.weapons.bombs.BLU_3B_GROUP = "weapons.bombs.BLU_3B_GROUP" -ENUMS.Storage.weapons.bombs.BAP_100 = "weapons.bombs.BAP-100" -ENUMS.Storage.weapons.containers.HEMTT = "weapons.containers.HEMTT" -ENUMS.Storage.weapons.bombs.British_MC_500LB_Bomb_Mk1_Short = "weapons.bombs.British_MC_500LB_Bomb_Mk1_Short" -ENUMS.Storage.weapons.nurs.ARAKM70BAP = "weapons.nurs.ARAKM70BAP" -ENUMS.Storage.weapons.missiles.AGM_119 = "weapons.missiles.AGM_119" -ENUMS.Storage.weapons.missiles.MMagicII = "weapons.missiles.MMagicII" -ENUMS.Storage.weapons.bombs.AB_500_1_SD_10A = "weapons.bombs.AB_500_1_SD_10A" -ENUMS.Storage.weapons.nurs.HYDRA_70_M282 = "weapons.nurs.HYDRA_70_M282" -ENUMS.Storage.weapons.droptanks.DFT_400_GAL_A4E = "weapons.droptanks.DFT_400_GAL_A4E" -ENUMS.Storage.weapons.nurs.HYDRA_70_M257 = "weapons.nurs.HYDRA_70_M257" -ENUMS.Storage.weapons.droptanks.AV8BNA_AERO1D = "weapons.droptanks.AV8BNA_AERO1D" -ENUMS.Storage.weapons.containers.US_M10_SMOKE_TANK_BLUE = "weapons.containers.{US_M10_SMOKE_TANK_BLUE}" -ENUMS.Storage.weapons.nurs.ARF8M3HEI = "weapons.nurs.ARF8M3HEI" -ENUMS.Storage.weapons.bombs.RN_28 = "weapons.bombs.RN-28" -ENUMS.Storage.weapons.bombs.Squad_30_x_Soldier_7950lb = "weapons.bombs.Squad 30 x Soldier [7950lb]" -ENUMS.Storage.weapons.containers.uaz_469 = "weapons.containers.uaz-469" -ENUMS.Storage.weapons.containers.Otokar_Cobra = "weapons.containers.Otokar_Cobra" -ENUMS.Storage.weapons.bombs.APC_BTR_82A_Air_24998lb = "weapons.bombs.APC BTR-82A Air [24998lb]" -ENUMS.Storage.weapons.nurs.HYDRA_70_M274 = "weapons.nurs.HYDRA_70_M274" -ENUMS.Storage.weapons.missiles.P_24R = "weapons.missiles.P_24R" -ENUMS.Storage.weapons.nurs.HYDRA_70_MK61 = "weapons.nurs.HYDRA_70_MK61" -ENUMS.Storage.weapons.missiles.Igla_1E = "weapons.missiles.Igla_1E" -ENUMS.Storage.weapons.missiles.C_802AK = "weapons.missiles.C-802AK" -ENUMS.Storage.weapons.nurs.C_24 = "weapons.nurs.C_24" -ENUMS.Storage.weapons.droptanks.M2KC_08_RPL541 = "weapons.droptanks.M2KC_08_RPL541" -ENUMS.Storage.weapons.nurs.C_13 = "weapons.nurs.C_13" -ENUMS.Storage.weapons.droptanks.droptank_110_gal = "weapons.droptanks.droptank_110_gal" -ENUMS.Storage.weapons.bombs.Mk_84 = "weapons.bombs.Mk_84" -ENUMS.Storage.weapons.missiles.Sea_Eagle = "weapons.missiles.Sea_Eagle" -ENUMS.Storage.weapons.droptanks.PTB_1200_F1 = "weapons.droptanks.PTB_1200_F1" -ENUMS.Storage.weapons.nurs.SNEB_TYPE256_H1 = "weapons.nurs.SNEB_TYPE256_H1" -ENUMS.Storage.weapons.containers.MATRA_PHIMAT = "weapons.containers.MATRA-PHIMAT" -ENUMS.Storage.weapons.containers.smoke_pod = "weapons.containers.smoke_pod" -ENUMS.Storage.weapons.containers.F_15E_AAQ_14_LANTIRN = "weapons.containers.F-15E_AAQ-14_LANTIRN" -ENUMS.Storage.weapons.containers.EclairM_24 = "weapons.containers.{EclairM_24}" -ENUMS.Storage.weapons.bombs.GBU_16 = "weapons.bombs.GBU_16" -ENUMS.Storage.weapons.nurs.HYDRA_70_M156 = "weapons.nurs.HYDRA_70_M156" -ENUMS.Storage.weapons.missiles.R_60 = "weapons.missiles.R-60" -ENUMS.Storage.weapons.containers.zsu_23_4 = "weapons.containers.zsu-23-4" -ENUMS.Storage.weapons.missiles.RB75 = "weapons.missiles.RB75" -ENUMS.Storage.weapons.missiles.Mistral = "weapons.missiles.Mistral" -ENUMS.Storage.weapons.droptanks.MB339_TT500_L = "weapons.droptanks.MB339_TT500_L" -ENUMS.Storage.weapons.bombs.SAM_SA_13_STRELA_21624lb = "weapons.bombs.SAM SA-13 STRELA [21624lb]" -ENUMS.Storage.weapons.bombs.SAM_Avenger_M1097_Air_7200lb = "weapons.bombs.SAM Avenger M1097 Air [7200lb]" -ENUMS.Storage.weapons.droptanks.Eleven00L_Tank_Empty = "weapons.droptanks.1100L Tank Empty" -ENUMS.Storage.weapons.bombs.AN_M88 = "weapons.bombs.AN-M88" -ENUMS.Storage.weapons.missiles.S_25L = "weapons.missiles.S_25L" -ENUMS.Storage.weapons.nurs.British_AP_25LBNo1_3INCHNo1 = "weapons.nurs.British_AP_25LBNo1_3INCHNo1" +ENUMS.Storage.weapons.nurs.SNEB_TYPE253_F1B = "weapons.nurs.SNEB_TYPE253_F1B" +ENUMS.Storage.weapons.missiles.P_24T = "weapons.missiles.P_24T" +ENUMS.Storage.weapons.bombs.BLU_3B_OLD = "weapons.bombs.BLU-3B_OLD" +ENUMS.Storage.weapons.missiles.AGM_154 = "weapons.missiles.AGM_154" +ENUMS.Storage.weapons.nurs.HYDRA_70_M151_M433 = "weapons.nurs.HYDRA_70_M151_M433" +ENUMS.Storage.weapons.bombs.SAM_Avenger_M1097_Skid_7090lb = "weapons.bombs.SAM Avenger M1097 Skid [7090lb]" +ENUMS.Storage.weapons.bombs.British_GP_250LB_Bomb_Mk5 = "weapons.bombs.British_GP_250LB_Bomb_Mk5" +ENUMS.Storage.weapons.containers.OV10_SMOKE = "weapons.containers.{OV10_SMOKE}" +ENUMS.Storage.weapons.bombs.BLU_4B_OLD = "weapons.bombs.BLU-4B_OLD" +ENUMS.Storage.weapons.bombs.FAB_500M54 = "weapons.bombs.FAB-500M54" +ENUMS.Storage.weapons.bombs.GBU_38 = "weapons.bombs.GBU_38" +ENUMS.Storage.weapons.containers.F_15E_AXQ_14_DATALINK = "weapons.containers.F-15E_AXQ-14_DATALINK" +ENUMS.Storage.weapons.bombs.BEER_BOMB = "weapons.bombs.BEER_BOMB" +ENUMS.Storage.weapons.bombs.P_50T = "weapons.bombs.P-50T" +ENUMS.Storage.weapons.nurs.C_8CM_GN = "weapons.nurs.C_8CM_GN" +ENUMS.Storage.weapons.bombs.FAB_500SL = "weapons.bombs.FAB-500SL" +ENUMS.Storage.weapons.bombs.KAB_1500Kr = "weapons.bombs.KAB_1500Kr" +ENUMS.Storage.weapons.bombs.two50_2 = "weapons.bombs.250-2" +ENUMS.Storage.weapons.droptanks.Spitfire_tank_1 = "weapons.droptanks.Spitfire_tank_1" +ENUMS.Storage.weapons.missiles.AGM_65G = "weapons.missiles.AGM_65G" +ENUMS.Storage.weapons.missiles.AGM_65A = "weapons.missiles.AGM_65A" +ENUMS.Storage.weapons.containers.Hercules_JATO = "weapons.containers.Hercules_JATO" +ENUMS.Storage.weapons.nurs.HYDRA_70_M259 = "weapons.nurs.HYDRA_70_M259" +ENUMS.Storage.weapons.missiles.AGM_84E = "weapons.missiles.AGM_84E" +ENUMS.Storage.weapons.bombs.AN_M30A1 = "weapons.bombs.AN_M30A1" +ENUMS.Storage.weapons.nurs.C_25 = "weapons.nurs.C_25" +ENUMS.Storage.weapons.containers.AV8BNA_ALQ164 = "weapons.containers.AV8BNA_ALQ164" +ENUMS.Storage.weapons.containers.lav_25 = "weapons.containers.lav-25" +ENUMS.Storage.weapons.missiles.P_60 = "weapons.missiles.P_60" +ENUMS.Storage.weapons.bombs.FAB_1500 = "weapons.bombs.FAB_1500" +ENUMS.Storage.weapons.droptanks.FuelTank_350L = "weapons.droptanks.FuelTank_350L" +ENUMS.Storage.weapons.bombs.AAA_Vulcan_M163_Skid_21577lb = "weapons.bombs.AAA Vulcan M163 Skid [21577lb]" +ENUMS.Storage.weapons.missiles.Kormoran = "weapons.missiles.Kormoran" +ENUMS.Storage.weapons.droptanks.HB_F14_EXT_DROPTANK_EMPTY = "weapons.droptanks.HB_F14_EXT_DROPTANK_EMPTY" +ENUMS.Storage.weapons.droptanks.FuelTank_150L = "weapons.droptanks.FuelTank_150L" +ENUMS.Storage.weapons.missiles.Rb_15F_for_A_I = "weapons.missiles.Rb 15F (for A.I.)" +ENUMS.Storage.weapons.missiles.RB75T = "weapons.missiles.RB75T" +ENUMS.Storage.weapons.missiles.Vikhr_M = "weapons.missiles.Vikhr_M" +ENUMS.Storage.weapons.nurs.FFAR_M156_WP = "weapons.nurs.FFAR M156 WP" +ENUMS.Storage.weapons.nurs.British_HE_60LBSAPNo2_3INCHNo1 = "weapons.nurs.British_HE_60LBSAPNo2_3INCHNo1" +ENUMS.Storage.weapons.missiles.DWS39_MJ2 = "weapons.missiles.DWS39_MJ2" +ENUMS.Storage.weapons.bombs.HEBOMBD = "weapons.bombs.HEBOMBD" +ENUMS.Storage.weapons.missiles.CATM_9M = "weapons.missiles.CATM_9M" +ENUMS.Storage.weapons.bombs.Mk_81 = "weapons.bombs.Mk_81" +ENUMS.Storage.weapons.droptanks.Drop_Tank_300_Liter = "weapons.droptanks.Drop_Tank_300_Liter" +ENUMS.Storage.weapons.containers.HMMWV_M1025 = "weapons.containers.HMMWV_M1025" +ENUMS.Storage.weapons.bombs.SAM_CHAPARRAL_Air_21624lb = "weapons.bombs.SAM CHAPARRAL Air [21624lb]" +ENUMS.Storage.weapons.missiles.AGM_154A = "weapons.missiles.AGM_154A" +ENUMS.Storage.weapons.bombs.Mk_84AIR_TP = "weapons.bombs.Mk_84AIR_TP" +ENUMS.Storage.weapons.bombs.GBU_31_V_3B = "weapons.bombs.GBU_31_V_3B" +ENUMS.Storage.weapons.nurs.C_8CM_WH = "weapons.nurs.C_8CM_WH" +ENUMS.Storage.weapons.missiles.Matra_Super_530D = "weapons.missiles.Matra Super 530D" +ENUMS.Storage.weapons.nurs.ARF8M3TPSM = "weapons.nurs.ARF8M3TPSM" +ENUMS.Storage.weapons.missiles.TGM_65H = "weapons.missiles.TGM_65H" +ENUMS.Storage.weapons.nurs.M8rocket = "weapons.nurs.M8rocket" +ENUMS.Storage.weapons.bombs.GBU_27 = "weapons.bombs.GBU_27" +ENUMS.Storage.weapons.missiles.AGR_20A = "weapons.missiles.AGR_20A" +ENUMS.Storage.weapons.missiles.LS_6_250 = "weapons.missiles.LS-6-250" +ENUMS.Storage.weapons.droptanks.M2KC_RPL_522_EMPTY = "weapons.droptanks.M2KC_RPL_522_EMPTY" +ENUMS.Storage.weapons.droptanks.M2KC_02_RPL541 = "weapons.droptanks.M2KC_02_RPL541" +ENUMS.Storage.weapons.missiles.AGM_45 = "weapons.missiles.AGM_45" +ENUMS.Storage.weapons.missiles.AGM_84A = "weapons.missiles.AGM_84A" +ENUMS.Storage.weapons.bombs.APC_BTR_80_Air_23936lb = "weapons.bombs.APC BTR-80 Air [23936lb]" +ENUMS.Storage.weapons.missiles.P_33E = "weapons.missiles.P_33E" +ENUMS.Storage.weapons.missiles.Ataka_9M120 = "weapons.missiles.Ataka_9M120" +ENUMS.Storage.weapons.bombs.MK76 = "weapons.bombs.MK76" +ENUMS.Storage.weapons.bombs.AB_250_2_SD_2 = "weapons.bombs.AB_250_2_SD_2" +ENUMS.Storage.weapons.missiles.Rb_05A = "weapons.missiles.Rb 05A" +ENUMS.Storage.weapons.bombs.ART_GVOZDIKA_34720lb = "weapons.bombs.ART GVOZDIKA [34720lb]" +ENUMS.Storage.weapons.bombs.Generic_Crate_20000lb = "weapons.bombs.Generic Crate [20000lb]" +ENUMS.Storage.weapons.bombs.FAB_100SV = "weapons.bombs.FAB_100SV" +ENUMS.Storage.weapons.bombs.BetAB_500 = "weapons.bombs.BetAB_500" +ENUMS.Storage.weapons.droptanks.M2KC_02_RPL541_EMPTY = "weapons.droptanks.M2KC_02_RPL541_EMPTY" +ENUMS.Storage.weapons.droptanks.PTB600_MIG15 = "weapons.droptanks.PTB600_MIG15" +ENUMS.Storage.weapons.missiles.Rb_24J = "weapons.missiles.Rb 24J" +ENUMS.Storage.weapons.nurs.C_8CM_BU = "weapons.nurs.C_8CM_BU" +ENUMS.Storage.weapons.nurs.SNEB_TYPE259E_F1B = "weapons.nurs.SNEB_TYPE259E_F1B" +ENUMS.Storage.weapons.nurs.WGr21 = "weapons.nurs.WGr21" +ENUMS.Storage.weapons.bombs.SAMP250HD = "weapons.bombs.SAMP250HD" +ENUMS.Storage.weapons.containers.alq_184long = "weapons.containers.alq-184long" +ENUMS.Storage.weapons.nurs.SNEB_TYPE259E_H1 = "weapons.nurs.SNEB_TYPE259E_H1" +ENUMS.Storage.weapons.bombs.British_SAP_250LB_Bomb_Mk5 = "weapons.bombs.British_SAP_250LB_Bomb_Mk5" +ENUMS.Storage.weapons.bombs.Transport_UAZ_469_Air_3747lb = "weapons.bombs.Transport UAZ-469 Air [3747lb]" +ENUMS.Storage.weapons.bombs.Mk_83CT = "weapons.bombs.Mk_83CT" +ENUMS.Storage.weapons.missiles.AIM_7P = "weapons.missiles.AIM-7P" +ENUMS.Storage.weapons.missiles.AT_6 = "weapons.missiles.AT_6" +ENUMS.Storage.weapons.nurs.SNEB_TYPE254_H1_GREEN = "weapons.nurs.SNEB_TYPE254_H1_GREEN" +ENUMS.Storage.weapons.nurs.SNEB_TYPE250_F1B = "weapons.nurs.SNEB_TYPE250_F1B" +ENUMS.Storage.weapons.containers.U22A = "weapons.containers.U22A" +ENUMS.Storage.weapons.bombs.British_GP_250LB_Bomb_Mk1 = "weapons.bombs.British_GP_250LB_Bomb_Mk1" +ENUMS.Storage.weapons.bombs.CBU_105 = "weapons.bombs.CBU_105" +ENUMS.Storage.weapons.droptanks.FW_190_Fuel_Tank = "weapons.droptanks.FW-190_Fuel-Tank" +ENUMS.Storage.weapons.missiles.X_58 = "weapons.missiles.X_58" +ENUMS.Storage.weapons.missiles.BK90_MJ1_MJ2 = "weapons.missiles.BK90_MJ1_MJ2" +ENUMS.Storage.weapons.missiles.TGM_65D = "weapons.missiles.TGM_65D" +ENUMS.Storage.weapons.containers.BRD_4_250 = "weapons.containers.BRD-4-250" +ENUMS.Storage.weapons.missiles.P_73 = "weapons.missiles.P_73" +ENUMS.Storage.weapons.bombs.AN_M66 = "weapons.bombs.AN_M66" +ENUMS.Storage.weapons.bombs.APC_LAV_25_Air_22520lb = "weapons.bombs.APC LAV-25 Air [22520lb]" +ENUMS.Storage.weapons.missiles.AIM_7MH = "weapons.missiles.AIM-7MH" +ENUMS.Storage.weapons.containers.MB339_TravelPod = "weapons.containers.MB339_TravelPod" +ENUMS.Storage.weapons.bombs.GBU_12 = "weapons.bombs.GBU_12" +ENUMS.Storage.weapons.bombs.SC_250_T3_J = "weapons.bombs.SC_250_T3_J" +ENUMS.Storage.weapons.missiles.KD_20 = "weapons.missiles.KD-20" +ENUMS.Storage.weapons.missiles.AGM_86C = "weapons.missiles.AGM_86C" +ENUMS.Storage.weapons.missiles.X_35 = "weapons.missiles.X_35" +ENUMS.Storage.weapons.bombs.MK106 = "weapons.bombs.MK106" +ENUMS.Storage.weapons.bombs.BETAB_500S = "weapons.bombs.BETAB-500S" +ENUMS.Storage.weapons.nurs.C_5 = "weapons.nurs.C_5" +ENUMS.Storage.weapons.nurs.S_24B = "weapons.nurs.S-24B" +ENUMS.Storage.weapons.bombs.British_MC_500LB_Bomb_Mk2 = "weapons.bombs.British_MC_500LB_Bomb_Mk2" +ENUMS.Storage.weapons.containers.ANAWW_13 = "weapons.containers.ANAWW_13" +ENUMS.Storage.weapons.droptanks.droptank_108_gal = "weapons.droptanks.droptank_108_gal" +ENUMS.Storage.weapons.droptanks.DFT_300_GAL_A4E_LR = "weapons.droptanks.DFT_300_GAL_A4E_LR" +ENUMS.Storage.weapons.bombs.CBU_87 = "weapons.bombs.CBU_87" +ENUMS.Storage.weapons.missiles.GAR_8 = "weapons.missiles.GAR-8" +ENUMS.Storage.weapons.bombs.BELOUGA = "weapons.bombs.BELOUGA" +ENUMS.Storage.weapons.containers.EclairM_33 = "weapons.containers.{EclairM_33}" +ENUMS.Storage.weapons.bombs.ART_2S9_NONA_Air_19140lb = "weapons.bombs.ART 2S9 NONA Air [19140lb]" +ENUMS.Storage.weapons.bombs.BR_250 = "weapons.bombs.BR_250" +ENUMS.Storage.weapons.bombs.IAB_500 = "weapons.bombs.IAB-500" +ENUMS.Storage.weapons.containers.AN_ASQ_228 = "weapons.containers.AN_ASQ_228" +ENUMS.Storage.weapons.missiles.P_27P = "weapons.missiles.P_27P" +ENUMS.Storage.weapons.bombs.SD_250_Stg = "weapons.bombs.SD_250_Stg" +ENUMS.Storage.weapons.missiles.R_530F_IR = "weapons.missiles.R_530F_IR" +ENUMS.Storage.weapons.bombs.British_SAP_500LB_Bomb_Mk5 = "weapons.bombs.British_SAP_500LB_Bomb_Mk5" +ENUMS.Storage.weapons.bombs.FAB_250M54 = "weapons.bombs.FAB-250M54" +ENUMS.Storage.weapons.containers.M2KC_AAF = "weapons.containers.{M2KC_AAF}" +ENUMS.Storage.weapons.missiles.CM_802AKG_AI = "weapons.missiles.CM-802AKG_AI" +ENUMS.Storage.weapons.bombs.CBU_103 = "weapons.bombs.CBU_103" +ENUMS.Storage.weapons.containers.US_M10_SMOKE_TANK_RED = "weapons.containers.{US_M10_SMOKE_TANK_RED}" +ENUMS.Storage.weapons.missiles.X_29T = "weapons.missiles.X_29T" +ENUMS.Storage.weapons.bombs.HEMTT_TFFT_34400lb = "weapons.bombs.HEMTT TFFT [34400lb]" +ENUMS.Storage.weapons.missiles.C_701IR = "weapons.missiles.C-701IR" +ENUMS.Storage.weapons.containers.fullCargoSeats = "weapons.containers.fullCargoSeats" +ENUMS.Storage.weapons.bombs.GBU_15_V_31_B = "weapons.bombs.GBU_15_V_31_B" +ENUMS.Storage.weapons.bombs.APC_M1043_HMMWV_Armament_Air_7023lb = "weapons.bombs.APC M1043 HMMWV Armament Air [7023lb]" +ENUMS.Storage.weapons.missiles.PL_5EII = "weapons.missiles.PL-5EII" +ENUMS.Storage.weapons.bombs.SC_250_T1_L2 = "weapons.bombs.SC_250_T1_L2" +ENUMS.Storage.weapons.torpedoes.mk46torp_name = "weapons.torpedoes.mk46torp_name" +ENUMS.Storage.weapons.containers.F_15E_AAQ_33_XR_ATP_SE = "weapons.containers.F-15E_AAQ-33_XR_ATP-SE" +ENUMS.Storage.weapons.missiles.AIM_7 = "weapons.missiles.AIM_7" +ENUMS.Storage.weapons.missiles.AGM_122 = "weapons.missiles.AGM_122" +ENUMS.Storage.weapons.bombs.HEBOMB = "weapons.bombs.HEBOMB" +ENUMS.Storage.weapons.bombs.CBU_97 = "weapons.bombs.CBU_97" +ENUMS.Storage.weapons.bombs.MK_81SE = "weapons.bombs.MK-81SE" +ENUMS.Storage.weapons.nurs.Zuni_127 = "weapons.nurs.Zuni_127" +ENUMS.Storage.weapons.containers.M2KC_AGF = "weapons.containers.{M2KC_AGF}" +ENUMS.Storage.weapons.droptanks.Hercules_ExtFuelTank = "weapons.droptanks.Hercules_ExtFuelTank" +ENUMS.Storage.weapons.containers.SMOKE_WHITE = "weapons.containers.{SMOKE_WHITE}" +ENUMS.Storage.weapons.droptanks.droptank_150_gal = "weapons.droptanks.droptank_150_gal" +ENUMS.Storage.weapons.nurs.HYDRA_70_WTU1B = "weapons.nurs.HYDRA_70_WTU1B" +ENUMS.Storage.weapons.missiles.GB_6_SFW = "weapons.missiles.GB-6-SFW" +ENUMS.Storage.weapons.missiles.KD_63 = "weapons.missiles.KD-63" +ENUMS.Storage.weapons.bombs.GBU_28 = "weapons.bombs.GBU_28" +ENUMS.Storage.weapons.nurs.C_8CM_YE = "weapons.nurs.C_8CM_YE" +ENUMS.Storage.weapons.droptanks.HB_F14_EXT_DROPTANK = "weapons.droptanks.HB_F14_EXT_DROPTANK" +ENUMS.Storage.weapons.missiles.Super_530F = "weapons.missiles.Super_530F" +ENUMS.Storage.weapons.missiles.Ataka_9M220 = "weapons.missiles.Ataka_9M220" +ENUMS.Storage.weapons.bombs.BDU_33 = "weapons.bombs.BDU_33" +ENUMS.Storage.weapons.bombs.British_GP_250LB_Bomb_Mk4 = "weapons.bombs.British_GP_250LB_Bomb_Mk4" +ENUMS.Storage.weapons.missiles.TOW = "weapons.missiles.TOW" +ENUMS.Storage.weapons.bombs.ATGM_M1045_HMMWV_TOW_Air_7183lb = "weapons.bombs.ATGM M1045 HMMWV TOW Air [7183lb]" +ENUMS.Storage.weapons.missiles.X_25MR = "weapons.missiles.X_25MR" +ENUMS.Storage.weapons.droptanks.fueltank230 = "weapons.droptanks.fueltank230" +ENUMS.Storage.weapons.droptanks.PTB_490C_MIG21 = "weapons.droptanks.PTB-490C-MIG21" +ENUMS.Storage.weapons.bombs.M1025_HMMWV_Air_6160lb = "weapons.bombs.M1025 HMMWV Air [6160lb]" +ENUMS.Storage.weapons.nurs.SNEB_TYPE254_F1B_GREEN = "weapons.nurs.SNEB_TYPE254_F1B_GREEN" +ENUMS.Storage.weapons.missiles.R_550 = "weapons.missiles.R_550" +ENUMS.Storage.weapons.bombs.KAB_1500LG = "weapons.bombs.KAB_1500LG" +ENUMS.Storage.weapons.missiles.AGM_84D = "weapons.missiles.AGM_84D" +ENUMS.Storage.weapons.missiles.YJ_83K = "weapons.missiles.YJ-83K" +ENUMS.Storage.weapons.missiles.AIM_54C_Mk47 = "weapons.missiles.AIM_54C_Mk47" +ENUMS.Storage.weapons.missiles.BRM_1_90MM = "weapons.missiles.BRM-1_90MM" +ENUMS.Storage.weapons.missiles.Ataka_9M120F = "weapons.missiles.Ataka_9M120F" +ENUMS.Storage.weapons.droptanks.Eleven00L_Tank = "weapons.droptanks.1100L Tank" +ENUMS.Storage.weapons.bombs.BAP_100 = "weapons.bombs.BAP_100" +ENUMS.Storage.weapons.adapters.lau_88 = "weapons.adapters.lau-88" +ENUMS.Storage.weapons.missiles.P_40T = "weapons.missiles.P_40T" +ENUMS.Storage.weapons.missiles.GB_6 = "weapons.missiles.GB-6" +ENUMS.Storage.weapons.bombs.FAB_250M54TU = "weapons.bombs.FAB-250M54TU" +ENUMS.Storage.weapons.missiles.DWS39_MJ1 = "weapons.missiles.DWS39_MJ1" +ENUMS.Storage.weapons.missiles.CM_802AKG = "weapons.missiles.CM-802AKG" +ENUMS.Storage.weapons.bombs.FAB_250 = "weapons.bombs.FAB_250" +ENUMS.Storage.weapons.missiles.C_802AK = "weapons.missiles.C_802AK" +ENUMS.Storage.weapons.bombs.SD_500_A = "weapons.bombs.SD_500_A" +ENUMS.Storage.weapons.bombs.GBU_32_V_2B = "weapons.bombs.GBU_32_V_2B" +ENUMS.Storage.weapons.containers.marder = "weapons.containers.marder" +ENUMS.Storage.weapons.missiles.ADM_141B = "weapons.missiles.ADM_141B" +ENUMS.Storage.weapons.bombs.ROCKEYE = "weapons.bombs.ROCKEYE" +ENUMS.Storage.weapons.missiles.BK90_MJ1 = "weapons.missiles.BK90_MJ1" +ENUMS.Storage.weapons.containers.BTR_80 = "weapons.containers.BTR-80" +ENUMS.Storage.weapons.bombs.SAM_ROLAND_ADS_34720lb = "weapons.bombs.SAM ROLAND ADS [34720lb]" +ENUMS.Storage.weapons.containers.wmd7 = "weapons.containers.wmd7" +ENUMS.Storage.weapons.missiles.C_701T = "weapons.missiles.C-701T" +ENUMS.Storage.weapons.missiles.AIM_7E_2 = "weapons.missiles.AIM-7E-2" +ENUMS.Storage.weapons.nurs.HVAR = "weapons.nurs.HVAR" +ENUMS.Storage.weapons.containers.HMMWV_M1043 = "weapons.containers.HMMWV_M1043" +ENUMS.Storage.weapons.droptanks.PTB_800_MIG21 = "weapons.droptanks.PTB-800-MIG21" +ENUMS.Storage.weapons.missiles.AGM_114 = "weapons.missiles.AGM_114" +ENUMS.Storage.weapons.bombs.APC_M1126_Stryker_ICV_29542lb = "weapons.bombs.APC M1126 Stryker ICV [29542lb]" +ENUMS.Storage.weapons.bombs.APC_M113_Air_21624lb = "weapons.bombs.APC M113 Air [21624lb]" +ENUMS.Storage.weapons.bombs.M_117 = "weapons.bombs.M_117" +ENUMS.Storage.weapons.missiles.AGM_65D = "weapons.missiles.AGM_65D" +ENUMS.Storage.weapons.droptanks.MB339_TT320_L = "weapons.droptanks.MB339_TT320_L" +ENUMS.Storage.weapons.missiles.AGM_86 = "weapons.missiles.AGM_86" +ENUMS.Storage.weapons.bombs.BDU_45LGB = "weapons.bombs.BDU_45LGB" +ENUMS.Storage.weapons.missiles.AGM_65H = "weapons.missiles.AGM_65H" +ENUMS.Storage.weapons.nurs.RS_82 = "weapons.nurs.RS-82" +ENUMS.Storage.weapons.nurs.SNEB_TYPE252_F1B = "weapons.nurs.SNEB_TYPE252_F1B" +ENUMS.Storage.weapons.bombs.BL_755 = "weapons.bombs.BL_755" +ENUMS.Storage.weapons.containers.F_15E_AAQ_28_LITENING = "weapons.containers.F-15E_AAQ-28_LITENING" +ENUMS.Storage.weapons.nurs.SNEB_TYPE256_F1B = "weapons.nurs.SNEB_TYPE256_F1B" +ENUMS.Storage.weapons.missiles.AGM_84H = "weapons.missiles.AGM_84H" +ENUMS.Storage.weapons.missiles.AIM_54 = "weapons.missiles.AIM_54" +ENUMS.Storage.weapons.missiles.X_31A = "weapons.missiles.X_31A" +ENUMS.Storage.weapons.bombs.KAB_500Kr = "weapons.bombs.KAB_500Kr" +ENUMS.Storage.weapons.containers.SPS_141_100 = "weapons.containers.SPS-141-100" +ENUMS.Storage.weapons.missiles.BK90_MJ2 = "weapons.missiles.BK90_MJ2" +ENUMS.Storage.weapons.missiles.Super_530D = "weapons.missiles.Super_530D" +ENUMS.Storage.weapons.bombs.CBU_52B = "weapons.bombs.CBU_52B" +ENUMS.Storage.weapons.droptanks.PTB_450 = "weapons.droptanks.PTB-450" +ENUMS.Storage.weapons.bombs.IFV_MCV_80_34720lb = "weapons.bombs.IFV MCV-80 [34720lb]" +ENUMS.Storage.weapons.containers.Two_c9 = "weapons.containers.2-c9" +ENUMS.Storage.weapons.missiles.AIM_9JULI = "weapons.missiles.AIM-9JULI" +ENUMS.Storage.weapons.droptanks.MB339_TT500_R = "weapons.droptanks.MB339_TT500_R" +ENUMS.Storage.weapons.nurs.C_8CM = "weapons.nurs.C_8CM" +ENUMS.Storage.weapons.containers.BARAX = "weapons.containers.BARAX" +ENUMS.Storage.weapons.missiles.P_40R = "weapons.missiles.P_40R" +ENUMS.Storage.weapons.missiles.YJ_12 = "weapons.missiles.YJ-12" +ENUMS.Storage.weapons.missiles.CM_802AKG = "weapons.missiles.CM_802AKG" +ENUMS.Storage.weapons.nurs.SNEB_TYPE254_H1_YELLOW = "weapons.nurs.SNEB_TYPE254_H1_YELLOW" +ENUMS.Storage.weapons.bombs.Durandal = "weapons.bombs.Durandal" +ENUMS.Storage.weapons.droptanks.i16_eft = "weapons.droptanks.i16_eft" +ENUMS.Storage.weapons.droptanks.AV8BNA_AERO1D_EMPTY = "weapons.droptanks.AV8BNA_AERO1D_EMPTY" +ENUMS.Storage.weapons.containers.Hercules_Battle_Station_TGP = "weapons.containers.Hercules_Battle_Station_TGP" +ENUMS.Storage.weapons.nurs.C_8CM_VT = "weapons.nurs.C_8CM_VT" +ENUMS.Storage.weapons.missiles.PL_12 = "weapons.missiles.PL-12" +ENUMS.Storage.weapons.missiles.R_3R = "weapons.missiles.R-3R" +ENUMS.Storage.weapons.bombs.GBU_54_V_1B = "weapons.bombs.GBU_54_V_1B" +ENUMS.Storage.weapons.droptanks.MB339_TT320_R = "weapons.droptanks.MB339_TT320_R" +ENUMS.Storage.weapons.bombs.RN_24 = "weapons.bombs.RN-24" +ENUMS.Storage.weapons.containers.Twoc6m = "weapons.containers.2c6m" +ENUMS.Storage.weapons.bombs.ARV_BRDM_2_Air_12320lb = "weapons.bombs.ARV BRDM-2 Air [12320lb]" +ENUMS.Storage.weapons.bombs.ARV_BRDM_2_Skid_12210lb = "weapons.bombs.ARV BRDM-2 Skid [12210lb]" +ENUMS.Storage.weapons.nurs.SNEB_TYPE251_F1B = "weapons.nurs.SNEB_TYPE251_F1B" +ENUMS.Storage.weapons.missiles.X_41 = "weapons.missiles.X_41" +ENUMS.Storage.weapons.containers.MIG21_SMOKE_WHITE = "weapons.containers.{MIG21_SMOKE_WHITE}" +ENUMS.Storage.weapons.bombs.MK_82AIR = "weapons.bombs.MK_82AIR" +ENUMS.Storage.weapons.missiles.R_530F_EM = "weapons.missiles.R_530F_EM" +ENUMS.Storage.weapons.bombs.SAMP400LD = "weapons.bombs.SAMP400LD" +ENUMS.Storage.weapons.bombs.FAB_50 = "weapons.bombs.FAB_50" +ENUMS.Storage.weapons.bombs.AB_250_2_SD_10A = "weapons.bombs.AB_250_2_SD_10A" +ENUMS.Storage.weapons.missiles.ADM_141A = "weapons.missiles.ADM_141A" +ENUMS.Storage.weapons.containers.KBpod = "weapons.containers.KBpod" +ENUMS.Storage.weapons.bombs.British_GP_500LB_Bomb_Mk4 = "weapons.bombs.British_GP_500LB_Bomb_Mk4" +ENUMS.Storage.weapons.missiles.AGM_65E = "weapons.missiles.AGM_65E" +ENUMS.Storage.weapons.containers.sa342_dipole_antenna = "weapons.containers.sa342_dipole_antenna" +ENUMS.Storage.weapons.bombs.OFAB_100_Jupiter = "weapons.bombs.OFAB-100 Jupiter" +ENUMS.Storage.weapons.nurs.SNEB_TYPE257_F1B = "weapons.nurs.SNEB_TYPE257_F1B" +ENUMS.Storage.weapons.missiles.Rb_04E_for_A_I = "weapons.missiles.Rb 04E (for A.I.)" +ENUMS.Storage.weapons.bombs.AN_M66A2 = "weapons.bombs.AN-M66A2" +ENUMS.Storage.weapons.missiles.P_27T = "weapons.missiles.P_27T" +ENUMS.Storage.weapons.droptanks.LNS_VIG_XTANK = "weapons.droptanks.LNS_VIG_XTANK" +ENUMS.Storage.weapons.missiles.R_55 = "weapons.missiles.R-55" +ENUMS.Storage.weapons.torpedoes.YU_6 = "weapons.torpedoes.YU-6" +ENUMS.Storage.weapons.bombs.British_MC_250LB_Bomb_Mk2 = "weapons.bombs.British_MC_250LB_Bomb_Mk2" +ENUMS.Storage.weapons.droptanks.PTB_120_F86F35 = "weapons.droptanks.PTB_120_F86F35" +ENUMS.Storage.weapons.missiles.PL_8B = "weapons.missiles.PL-8B" +ENUMS.Storage.weapons.droptanks.F_15E_Drop_Tank_Empty = "weapons.droptanks.F-15E_Drop_Tank_Empty" +ENUMS.Storage.weapons.nurs.British_HE_60LBFNo1_3INCHNo1 = "weapons.nurs.British_HE_60LBFNo1_3INCHNo1" +ENUMS.Storage.weapons.missiles.P_77 = "weapons.missiles.P_77" +ENUMS.Storage.weapons.torpedoes.LTF_5B = "weapons.torpedoes.LTF_5B" +ENUMS.Storage.weapons.missiles.R_3S = "weapons.missiles.R-3S" +ENUMS.Storage.weapons.nurs.SNEB_TYPE253_H1 = "weapons.nurs.SNEB_TYPE253_H1" +ENUMS.Storage.weapons.missiles.PL_8A = "weapons.missiles.PL-8A" +ENUMS.Storage.weapons.bombs.APC_BTR_82A_Skid_24888lb = "weapons.bombs.APC BTR-82A Skid [24888lb]" +ENUMS.Storage.weapons.containers.Sborka = "weapons.containers.Sborka" +ENUMS.Storage.weapons.missiles.AGM_65L = "weapons.missiles.AGM_65L" +ENUMS.Storage.weapons.missiles.X_28 = "weapons.missiles.X_28" +ENUMS.Storage.weapons.missiles.TGM_65G = "weapons.missiles.TGM_65G" +ENUMS.Storage.weapons.nurs.SNEB_TYPE257_H1 = "weapons.nurs.SNEB_TYPE257_H1" +ENUMS.Storage.weapons.missiles.RB75B = "weapons.missiles.RB75B" +ENUMS.Storage.weapons.missiles.X_25ML = "weapons.missiles.X_25ML" +ENUMS.Storage.weapons.droptanks.FPU_8A = "weapons.droptanks.FPU_8A" +ENUMS.Storage.weapons.bombs.BLG66 = "weapons.bombs.BLG66" +ENUMS.Storage.weapons.nurs.C_8CM_RD = "weapons.nurs.C_8CM_RD" +ENUMS.Storage.weapons.containers.EclairM_06 = "weapons.containers.{EclairM_06}" +ENUMS.Storage.weapons.bombs.RBK_500AO = "weapons.bombs.RBK_500AO" +ENUMS.Storage.weapons.missiles.AIM_9P = "weapons.missiles.AIM-9P" +ENUMS.Storage.weapons.bombs.British_GP_500LB_Bomb_Mk4_Short = "weapons.bombs.British_GP_500LB_Bomb_Mk4_Short" +ENUMS.Storage.weapons.containers.MB339_Vinten = "weapons.containers.MB339_Vinten" +ENUMS.Storage.weapons.missiles.Rb_15F = "weapons.missiles.Rb 15F" +ENUMS.Storage.weapons.nurs.ARAKM70BHE = "weapons.nurs.ARAKM70BHE" +ENUMS.Storage.weapons.bombs.AAA_Vulcan_M163_Air_21666lb = "weapons.bombs.AAA Vulcan M163 Air [21666lb]" +ENUMS.Storage.weapons.missiles.X_29L = "weapons.missiles.X_29L" +ENUMS.Storage.weapons.containers.F14_LANTIRN_TP = "weapons.containers.{F14-LANTIRN-TP}" +ENUMS.Storage.weapons.bombs.FAB_250_M62 = "weapons.bombs.FAB-250-M62" +ENUMS.Storage.weapons.missiles.AIM_120C = "weapons.missiles.AIM_120C" +ENUMS.Storage.weapons.bombs.EWR_SBORKA_Air_21624lb = "weapons.bombs.EWR SBORKA Air [21624lb]" +ENUMS.Storage.weapons.bombs.SAMP250LD = "weapons.bombs.SAMP250LD" +ENUMS.Storage.weapons.droptanks.Spitfire_slipper_tank = "weapons.droptanks.Spitfire_slipper_tank" +ENUMS.Storage.weapons.missiles.LS_6_500 = "weapons.missiles.LS-6-500" +ENUMS.Storage.weapons.bombs.GBU_31_V_4B = "weapons.bombs.GBU_31_V_4B" +ENUMS.Storage.weapons.droptanks.PTB400_MIG15 = "weapons.droptanks.PTB400_MIG15" +ENUMS.Storage.weapons.containers.m_113 = "weapons.containers.m-113" +ENUMS.Storage.weapons.bombs.SPG_M1128_Stryker_MGS_33036lb = "weapons.bombs.SPG M1128 Stryker MGS [33036lb]" +ENUMS.Storage.weapons.missiles.AIM_9L = "weapons.missiles.AIM-9L" +ENUMS.Storage.weapons.missiles.AIM_9X = "weapons.missiles.AIM_9X" +ENUMS.Storage.weapons.nurs.C_8 = "weapons.nurs.C_8" +ENUMS.Storage.weapons.bombs.SAM_CHAPARRAL_Skid_21516lb = "weapons.bombs.SAM CHAPARRAL Skid [21516lb]" +ENUMS.Storage.weapons.missiles.P_27TE = "weapons.missiles.P_27TE" +ENUMS.Storage.weapons.bombs.ODAB_500PM = "weapons.bombs.ODAB-500PM" +ENUMS.Storage.weapons.bombs.MK77mod1_WPN = "weapons.bombs.MK77mod1-WPN" +ENUMS.Storage.weapons.droptanks.PTB400_MIG19 = "weapons.droptanks.PTB400_MIG19" +ENUMS.Storage.weapons.torpedoes.Mark_46 = "weapons.torpedoes.Mark_46" +ENUMS.Storage.weapons.containers.rightSeat = "weapons.containers.rightSeat" +ENUMS.Storage.weapons.containers.US_M10_SMOKE_TANK_ORANGE = "weapons.containers.{US_M10_SMOKE_TANK_ORANGE}" +ENUMS.Storage.weapons.bombs.SAB_100MN = "weapons.bombs.SAB_100MN" +ENUMS.Storage.weapons.nurs.FFAR_Mk5_HEAT = "weapons.nurs.FFAR Mk5 HEAT" +ENUMS.Storage.weapons.bombs.IFV_TPZ_FUCH_33440lb = "weapons.bombs.IFV TPZ FUCH [33440lb]" +ENUMS.Storage.weapons.bombs.IFV_M2A2_Bradley_34720lb = "weapons.bombs.IFV M2A2 Bradley [34720lb]" +ENUMS.Storage.weapons.bombs.MK77mod0_WPN = "weapons.bombs.MK77mod0-WPN" +ENUMS.Storage.weapons.containers.ASO_2 = "weapons.containers.ASO-2" +ENUMS.Storage.weapons.bombs.Mk_84AIR_GP = "weapons.bombs.Mk_84AIR_GP" +ENUMS.Storage.weapons.nurs.S_24A = "weapons.nurs.S-24A" +ENUMS.Storage.weapons.bombs.RBK_250_275_AO_1SCH = "weapons.bombs.RBK_250_275_AO_1SCH" +ENUMS.Storage.weapons.bombs.Transport_Tigr_Skid_15730lb = "weapons.bombs.Transport Tigr Skid [15730lb]" +ENUMS.Storage.weapons.missiles.AIM_7F = "weapons.missiles.AIM-7F" +ENUMS.Storage.weapons.bombs.CBU_99 = "weapons.bombs.CBU_99" +ENUMS.Storage.weapons.bombs.LUU_2B = "weapons.bombs.LUU_2B" +ENUMS.Storage.weapons.bombs.FAB_500TA = "weapons.bombs.FAB-500TA" +ENUMS.Storage.weapons.missiles.AGR_20_M282 = "weapons.missiles.AGR_20_M282" +ENUMS.Storage.weapons.droptanks.MB339_FT330 = "weapons.droptanks.MB339_FT330" +ENUMS.Storage.weapons.bombs.SAMP125LD = "weapons.bombs.SAMP125LD" +ENUMS.Storage.weapons.missiles.X_25MP = "weapons.missiles.X_25MP" +ENUMS.Storage.weapons.nurs.SNEB_TYPE252_H1 = "weapons.nurs.SNEB_TYPE252_H1" +ENUMS.Storage.weapons.missiles.AGM_65F = "weapons.missiles.AGM_65F" +ENUMS.Storage.weapons.missiles.AIM_9P5 = "weapons.missiles.AIM-9P5" +ENUMS.Storage.weapons.bombs.Transport_Tigr_Air_15900lb = "weapons.bombs.Transport Tigr Air [15900lb]" +ENUMS.Storage.weapons.nurs.SNEB_TYPE254_H1_RED = "weapons.nurs.SNEB_TYPE254_H1_RED" +ENUMS.Storage.weapons.nurs.FFAR_Mk1_HE = "weapons.nurs.FFAR Mk1 HE" +ENUMS.Storage.weapons.nurs.SPRD_99 = "weapons.nurs.SPRD-99" +ENUMS.Storage.weapons.bombs.BIN_200 = "weapons.bombs.BIN_200" +ENUMS.Storage.weapons.bombs.BLU_4B_GROUP = "weapons.bombs.BLU_4B_GROUP" +ENUMS.Storage.weapons.bombs.GBU_24 = "weapons.bombs.GBU_24" +ENUMS.Storage.weapons.missiles.Rb_04E = "weapons.missiles.Rb 04E" +ENUMS.Storage.weapons.missiles.Rb_74 = "weapons.missiles.Rb 74" +ENUMS.Storage.weapons.containers.leftSeat = "weapons.containers.leftSeat" +ENUMS.Storage.weapons.bombs.LS_6_100 = "weapons.bombs.LS-6-100" +ENUMS.Storage.weapons.bombs.Transport_URAL_375_14815lb = "weapons.bombs.Transport URAL-375 [14815lb]" +ENUMS.Storage.weapons.containers.US_M10_SMOKE_TANK_GREEN = "weapons.containers.{US_M10_SMOKE_TANK_GREEN}" +ENUMS.Storage.weapons.missiles.X_22 = "weapons.missiles.X_22" +ENUMS.Storage.weapons.containers.FAS = "weapons.containers.FAS" +ENUMS.Storage.weapons.nurs.S_25_O = "weapons.nurs.S-25-O" +ENUMS.Storage.weapons.droptanks.para = "weapons.droptanks.para" +ENUMS.Storage.weapons.droptanks.F_15E_Drop_Tank = "weapons.droptanks.F-15E_Drop_Tank" +ENUMS.Storage.weapons.droptanks.M2KC_08_RPL541_EMPTY = "weapons.droptanks.M2KC_08_RPL541_EMPTY" +ENUMS.Storage.weapons.missiles.X_31P = "weapons.missiles.X_31P" +ENUMS.Storage.weapons.bombs.RBK_500U = "weapons.bombs.RBK_500U" +ENUMS.Storage.weapons.missiles.AIM_54A_Mk47 = "weapons.missiles.AIM_54A_Mk47" +ENUMS.Storage.weapons.droptanks.oiltank = "weapons.droptanks.oiltank" +ENUMS.Storage.weapons.missiles.AGM_154B = "weapons.missiles.AGM_154B" +ENUMS.Storage.weapons.containers.MB339_SMOKE_POD = "weapons.containers.MB339_SMOKE-POD" +ENUMS.Storage.weapons.containers.ECM_POD_L_175V = "weapons.containers.{ECM_POD_L_175V}" +ENUMS.Storage.weapons.droptanks.PTB_580G_F1 = "weapons.droptanks.PTB_580G_F1" +ENUMS.Storage.weapons.containers.EclairM_15 = "weapons.containers.{EclairM_15}" +ENUMS.Storage.weapons.containers.F_15E_AAQ_13_LANTIRN = "weapons.containers.F-15E_AAQ-13_LANTIRN" +ENUMS.Storage.weapons.droptanks.Eight00L_Tank_Empty = "weapons.droptanks.800L Tank Empty" +ENUMS.Storage.weapons.containers.One6c_hts_pod = "weapons.containers.16c_hts_pod" +ENUMS.Storage.weapons.bombs.AN_M81 = "weapons.bombs.AN-M81" +ENUMS.Storage.weapons.droptanks.Mosquito_Drop_Tank_100gal = "weapons.droptanks.Mosquito_Drop_Tank_100gal" +ENUMS.Storage.weapons.droptanks.Mosquito_Drop_Tank_50gal = "weapons.droptanks.Mosquito_Drop_Tank_50gal" +ENUMS.Storage.weapons.droptanks.DFT_150_GAL_A4E = "weapons.droptanks.DFT_150_GAL_A4E" +ENUMS.Storage.weapons.missiles.AIM_9 = "weapons.missiles.AIM_9" +ENUMS.Storage.weapons.bombs.IFV_BTR_D_Air_18040lb = "weapons.bombs.IFV BTR-D Air [18040lb]" +ENUMS.Storage.weapons.containers.EclairM_42 = "weapons.containers.{EclairM_42}" +ENUMS.Storage.weapons.bombs.KAB_1500T = "weapons.bombs.KAB_1500T" +ENUMS.Storage.weapons.droptanks.PTB_490_MIG21 = "weapons.droptanks.PTB-490-MIG21" +ENUMS.Storage.weapons.droptanks.PTB_200_F86F35 = "weapons.droptanks.PTB_200_F86F35" +ENUMS.Storage.weapons.droptanks.PTB760_MIG19 = "weapons.droptanks.PTB760_MIG19" +ENUMS.Storage.weapons.bombs.GBU_43_B_MOAB = "weapons.bombs.GBU-43/B(MOAB)" +ENUMS.Storage.weapons.torpedoes.G7A_T1 = "weapons.torpedoes.G7A_T1" +ENUMS.Storage.weapons.bombs.IFV_BMD_1_Air_18040lb = "weapons.bombs.IFV BMD-1 Air [18040lb]" +ENUMS.Storage.weapons.bombs.SAM_LINEBACKER_34720lb = "weapons.bombs.SAM LINEBACKER [34720lb]" +ENUMS.Storage.weapons.containers.ais_pod_t50_r = "weapons.containers.ais-pod-t50_r" +ENUMS.Storage.weapons.containers.CE2_SMOKE_WHITE = "weapons.containers.{CE2_SMOKE_WHITE}" +ENUMS.Storage.weapons.droptanks.fuel_tank_230 = "weapons.droptanks.fuel_tank_230" +ENUMS.Storage.weapons.droptanks.M2KC_RPL_522 = "weapons.droptanks.M2KC_RPL_522" +ENUMS.Storage.weapons.missiles.AGM_130 = "weapons.missiles.AGM_130" +ENUMS.Storage.weapons.droptanks.Eight00L_Tank = "weapons.droptanks.800L Tank" +ENUMS.Storage.weapons.bombs.IFV_BTR_D_Skid_17930lb = "weapons.bombs.IFV BTR-D Skid [17930lb]" +ENUMS.Storage.weapons.containers.bmp_1 = "weapons.containers.bmp-1" +ENUMS.Storage.weapons.bombs.GBU_31 = "weapons.bombs.GBU_31" +ENUMS.Storage.weapons.containers.aaq_28LEFT_litening = "weapons.containers.aaq-28LEFT litening" +ENUMS.Storage.weapons.missiles.Kh_66_Grom = "weapons.missiles.Kh-66_Grom" +ENUMS.Storage.weapons.containers.MIG21_SMOKE_RED = "weapons.containers.{MIG21_SMOKE_RED}" +ENUMS.Storage.weapons.containers.U22 = "weapons.containers.U22" +ENUMS.Storage.weapons.bombs.IFV_BMD_1_Skid_17930lb = "weapons.bombs.IFV BMD-1 Skid [17930lb]" +ENUMS.Storage.weapons.droptanks.Bidon = "weapons.droptanks.Bidon" +ENUMS.Storage.weapons.bombs.GBU_31_V_2B = "weapons.bombs.GBU_31_V_2B" +ENUMS.Storage.weapons.bombs.Mk_82Y = "weapons.bombs.Mk_82Y" +ENUMS.Storage.weapons.containers.pl5eii = "weapons.containers.pl5eii" +ENUMS.Storage.weapons.bombs.RBK_500U_OAB_2_5RT = "weapons.bombs.RBK_500U_OAB_2_5RT" +ENUMS.Storage.weapons.bombs.British_GP_500LB_Bomb_Mk5 = "weapons.bombs.British_GP_500LB_Bomb_Mk5" +ENUMS.Storage.weapons.containers.Eclair = "weapons.containers.{Eclair}" +ENUMS.Storage.weapons.nurs.S5MO_HEFRAG_FFAR = "weapons.nurs.S5MO_HEFRAG_FFAR" +ENUMS.Storage.weapons.bombs.BETAB_500M = "weapons.bombs.BETAB-500M" +ENUMS.Storage.weapons.bombs.Transport_M818_16000lb = "weapons.bombs.Transport M818 [16000lb]" +ENUMS.Storage.weapons.bombs.British_MC_250LB_Bomb_Mk1 = "weapons.bombs.British_MC_250LB_Bomb_Mk1" +ENUMS.Storage.weapons.nurs.SNEB_TYPE251_H1 = "weapons.nurs.SNEB_TYPE251_H1" +ENUMS.Storage.weapons.bombs.TYPE_200A = "weapons.bombs.TYPE-200A" +ENUMS.Storage.weapons.nurs.HYDRA_70_M151 = "weapons.nurs.HYDRA_70_M151" +ENUMS.Storage.weapons.bombs.IFV_BMP_3_32912lb = "weapons.bombs.IFV BMP-3 [32912lb]" +ENUMS.Storage.weapons.bombs.APC_MTLB_Air_26400lb = "weapons.bombs.APC MTLB Air [26400lb]" +ENUMS.Storage.weapons.nurs.HYDRA_70_M229 = "weapons.nurs.HYDRA_70_M229" +ENUMS.Storage.weapons.bombs.BDU_45 = "weapons.bombs.BDU_45" +ENUMS.Storage.weapons.bombs.OFAB_100_120TU = "weapons.bombs.OFAB-100-120TU" +ENUMS.Storage.weapons.missiles.AIM_9J = "weapons.missiles.AIM-9J" +ENUMS.Storage.weapons.nurs.ARF8M3API = "weapons.nurs.ARF8M3API" +ENUMS.Storage.weapons.bombs.BetAB_500ShP = "weapons.bombs.BetAB_500ShP" +ENUMS.Storage.weapons.nurs.C_8OFP2 = "weapons.nurs.C_8OFP2" +ENUMS.Storage.weapons.bombs.GBU_10 = "weapons.bombs.GBU_10" +ENUMS.Storage.weapons.bombs.APC_MTLB_Skid_26290lb = "weapons.bombs.APC MTLB Skid [26290lb]" +ENUMS.Storage.weapons.nurs.SNEB_TYPE254_F1B_RED = "weapons.nurs.SNEB_TYPE254_F1B_RED" +ENUMS.Storage.weapons.missiles.X_65 = "weapons.missiles.X_65" +ENUMS.Storage.weapons.missiles.R_550_M1 = "weapons.missiles.R_550_M1" +ENUMS.Storage.weapons.missiles.AGM_65K = "weapons.missiles.AGM_65K" +ENUMS.Storage.weapons.nurs.SNEB_TYPE254_F1B_YELLOW = "weapons.nurs.SNEB_TYPE254_F1B_YELLOW" +ENUMS.Storage.weapons.missiles.AGM_88 = "weapons.missiles.AGM_88" +ENUMS.Storage.weapons.nurs.C_8OM = "weapons.nurs.C_8OM" +ENUMS.Storage.weapons.bombs.SAM_ROLAND_LN_34720b = "weapons.bombs.SAM ROLAND LN [34720b]" +ENUMS.Storage.weapons.missiles.AIM_120 = "weapons.missiles.AIM_120" +ENUMS.Storage.weapons.missiles.HOT3_MBDA = "weapons.missiles.HOT3_MBDA" +ENUMS.Storage.weapons.missiles.R_13M = "weapons.missiles.R-13M" +ENUMS.Storage.weapons.missiles.AIM_54C_Mk60 = "weapons.missiles.AIM_54C_Mk60" +ENUMS.Storage.weapons.bombs.AAA_GEPARD_34720lb = "weapons.bombs.AAA GEPARD [34720lb]" +ENUMS.Storage.weapons.missiles.R_13M1 = "weapons.missiles.R-13M1" +ENUMS.Storage.weapons.bombs.APC_Cobra_Air_10912lb = "weapons.bombs.APC Cobra Air [10912lb]" +ENUMS.Storage.weapons.bombs.RBK_250 = "weapons.bombs.RBK_250" +ENUMS.Storage.weapons.bombs.SC_500_J = "weapons.bombs.SC_500_J" +ENUMS.Storage.weapons.missiles.AGM_114K = "weapons.missiles.AGM_114K" +ENUMS.Storage.weapons.missiles.ALARM = "weapons.missiles.ALARM" +ENUMS.Storage.weapons.bombs.Mk_83 = "weapons.bombs.Mk_83" +ENUMS.Storage.weapons.missiles.AGM_65B = "weapons.missiles.AGM_65B" +ENUMS.Storage.weapons.bombs.MK_82SNAKEYE = "weapons.bombs.MK_82SNAKEYE" +ENUMS.Storage.weapons.nurs.HYDRA_70_MK1 = "weapons.nurs.HYDRA_70_MK1" +ENUMS.Storage.weapons.bombs.BLG66_BELOUGA = "weapons.bombs.BLG66_BELOUGA" +ENUMS.Storage.weapons.containers.EclairM_51 = "weapons.containers.{EclairM_51}" +ENUMS.Storage.weapons.missiles.AIM_54A_Mk60 = "weapons.missiles.AIM_54A_Mk60" +ENUMS.Storage.weapons.droptanks.DFT_300_GAL_A4E = "weapons.droptanks.DFT_300_GAL_A4E" +ENUMS.Storage.weapons.bombs.ATGM_M1134_Stryker_30337lb = "weapons.bombs.ATGM M1134 Stryker [30337lb]" +ENUMS.Storage.weapons.bombs.BAT_120 = "weapons.bombs.BAT-120" +ENUMS.Storage.weapons.missiles.DWS39_MJ1_MJ2 = "weapons.missiles.DWS39_MJ1_MJ2" +ENUMS.Storage.weapons.containers.SPRD = "weapons.containers.SPRD" +ENUMS.Storage.weapons.bombs.BR_500 = "weapons.bombs.BR_500" +ENUMS.Storage.weapons.bombs.British_GP_500LB_Bomb_Mk1 = "weapons.bombs.British_GP_500LB_Bomb_Mk1" +ENUMS.Storage.weapons.bombs.BDU_50HD = "weapons.bombs.BDU_50HD" +ENUMS.Storage.weapons.missiles.RS2US = "weapons.missiles.RS2US" +ENUMS.Storage.weapons.bombs.IFV_BMP_2_25168lb = "weapons.bombs.IFV BMP-2 [25168lb]" +ENUMS.Storage.weapons.bombs.SAMP400HD = "weapons.bombs.SAMP400HD" +ENUMS.Storage.weapons.containers.Hercules_Battle_Station = "weapons.containers.Hercules_Battle_Station" +ENUMS.Storage.weapons.bombs.AN_M64 = "weapons.bombs.AN_M64" +ENUMS.Storage.weapons.containers.rearCargoSeats = "weapons.containers.rearCargoSeats" +ENUMS.Storage.weapons.bombs.Mk_82 = "weapons.bombs.Mk_82" +ENUMS.Storage.weapons.missiles.AKD_10 = "weapons.missiles.AKD-10" +ENUMS.Storage.weapons.bombs.BDU_50LGB = "weapons.bombs.BDU_50LGB" +ENUMS.Storage.weapons.missiles.SD_10 = "weapons.missiles.SD-10" +ENUMS.Storage.weapons.containers.IRDeflector = "weapons.containers.IRDeflector" +ENUMS.Storage.weapons.bombs.FAB_500 = "weapons.bombs.FAB_500" +ENUMS.Storage.weapons.bombs.KAB_500 = "weapons.bombs.KAB_500" +ENUMS.Storage.weapons.nurs.S_5M = "weapons.nurs.S-5M" +ENUMS.Storage.weapons.missiles.MICA_R = "weapons.missiles.MICA_R" +ENUMS.Storage.weapons.missiles.X_59M = "weapons.missiles.X_59M" +ENUMS.Storage.weapons.nurs.UG_90MM = "weapons.nurs.UG_90MM" +ENUMS.Storage.weapons.bombs.LYSBOMB = "weapons.bombs.LYSBOMB" +ENUMS.Storage.weapons.nurs.R4M = "weapons.nurs.R4M" +ENUMS.Storage.weapons.containers.dlpod_akg = "weapons.containers.dlpod_akg" +ENUMS.Storage.weapons.missiles.LD_10 = "weapons.missiles.LD-10" +ENUMS.Storage.weapons.bombs.SC_50 = "weapons.bombs.SC_50" +ENUMS.Storage.weapons.nurs.HYDRA_70_MK5 = "weapons.nurs.HYDRA_70_MK5" +ENUMS.Storage.weapons.bombs.FAB_100M = "weapons.bombs.FAB_100M" +ENUMS.Storage.weapons.missiles.Rb_24 = "weapons.missiles.Rb 24" +ENUMS.Storage.weapons.bombs.BDU_45B = "weapons.bombs.BDU_45B" +ENUMS.Storage.weapons.missiles.GB_6_HE = "weapons.missiles.GB-6-HE" +ENUMS.Storage.weapons.missiles.KD_63B = "weapons.missiles.KD-63B" +ENUMS.Storage.weapons.missiles.P_27PE = "weapons.missiles.P_27PE" +ENUMS.Storage.weapons.droptanks.PTB300_MIG15 = "weapons.droptanks.PTB300_MIG15" +ENUMS.Storage.weapons.bombs.Two50_3 = "weapons.bombs.250-3" +ENUMS.Storage.weapons.bombs.SC_500_L2 = "weapons.bombs.SC_500_L2" +ENUMS.Storage.weapons.containers.HMMWV_M1045 = "weapons.containers.HMMWV_M1045" +ENUMS.Storage.weapons.bombs.FAB_500M54TU = "weapons.bombs.FAB-500M54TU" +ENUMS.Storage.weapons.containers.US_M10_SMOKE_TANK_YELLOW = "weapons.containers.{US_M10_SMOKE_TANK_YELLOW}" +ENUMS.Storage.weapons.containers.EclairM_60 = "weapons.containers.{EclairM_60}" +ENUMS.Storage.weapons.bombs.SAB_250_200 = "weapons.bombs.SAB_250_200" +ENUMS.Storage.weapons.bombs.FAB_100 = "weapons.bombs.FAB_100" +ENUMS.Storage.weapons.bombs.KAB_500S = "weapons.bombs.KAB_500S" +ENUMS.Storage.weapons.missiles.AGM_45A = "weapons.missiles.AGM_45A" +ENUMS.Storage.weapons.missiles.Kh25MP_PRGS1VP = "weapons.missiles.Kh25MP_PRGS1VP" +ENUMS.Storage.weapons.nurs.S5M1_HEFRAG_FFAR = "weapons.nurs.S5M1_HEFRAG_FFAR" +ENUMS.Storage.weapons.containers.kg600 = "weapons.containers.kg600" +ENUMS.Storage.weapons.bombs.AN_M65 = "weapons.bombs.AN_M65" +ENUMS.Storage.weapons.bombs.AN_M57 = "weapons.bombs.AN_M57" +ENUMS.Storage.weapons.bombs.BLU_3B_GROUP = "weapons.bombs.BLU_3B_GROUP" +ENUMS.Storage.weapons.bombs.BAP_100 = "weapons.bombs.BAP-100" +ENUMS.Storage.weapons.containers.HEMTT = "weapons.containers.HEMTT" +ENUMS.Storage.weapons.bombs.British_MC_500LB_Bomb_Mk1_Short = "weapons.bombs.British_MC_500LB_Bomb_Mk1_Short" +ENUMS.Storage.weapons.nurs.ARAKM70BAP = "weapons.nurs.ARAKM70BAP" +ENUMS.Storage.weapons.missiles.AGM_119 = "weapons.missiles.AGM_119" +ENUMS.Storage.weapons.missiles.MMagicII = "weapons.missiles.MMagicII" +ENUMS.Storage.weapons.bombs.AB_500_1_SD_10A = "weapons.bombs.AB_500_1_SD_10A" +ENUMS.Storage.weapons.nurs.HYDRA_70_M282 = "weapons.nurs.HYDRA_70_M282" +ENUMS.Storage.weapons.droptanks.DFT_400_GAL_A4E = "weapons.droptanks.DFT_400_GAL_A4E" +ENUMS.Storage.weapons.nurs.HYDRA_70_M257 = "weapons.nurs.HYDRA_70_M257" +ENUMS.Storage.weapons.droptanks.AV8BNA_AERO1D = "weapons.droptanks.AV8BNA_AERO1D" +ENUMS.Storage.weapons.containers.US_M10_SMOKE_TANK_BLUE = "weapons.containers.{US_M10_SMOKE_TANK_BLUE}" +ENUMS.Storage.weapons.nurs.ARF8M3HEI = "weapons.nurs.ARF8M3HEI" +ENUMS.Storage.weapons.bombs.RN_28 = "weapons.bombs.RN-28" +ENUMS.Storage.weapons.bombs.Squad_30_x_Soldier_7950lb = "weapons.bombs.Squad 30 x Soldier [7950lb]" +ENUMS.Storage.weapons.containers.uaz_469 = "weapons.containers.uaz-469" +ENUMS.Storage.weapons.containers.Otokar_Cobra = "weapons.containers.Otokar_Cobra" +ENUMS.Storage.weapons.bombs.APC_BTR_82A_Air_24998lb = "weapons.bombs.APC BTR-82A Air [24998lb]" +ENUMS.Storage.weapons.nurs.HYDRA_70_M274 = "weapons.nurs.HYDRA_70_M274" +ENUMS.Storage.weapons.missiles.P_24R = "weapons.missiles.P_24R" +ENUMS.Storage.weapons.nurs.HYDRA_70_MK61 = "weapons.nurs.HYDRA_70_MK61" +ENUMS.Storage.weapons.missiles.Igla_1E = "weapons.missiles.Igla_1E" +ENUMS.Storage.weapons.missiles.C_802AK = "weapons.missiles.C-802AK" +ENUMS.Storage.weapons.nurs.C_24 = "weapons.nurs.C_24" +ENUMS.Storage.weapons.droptanks.M2KC_08_RPL541 = "weapons.droptanks.M2KC_08_RPL541" +ENUMS.Storage.weapons.nurs.C_13 = "weapons.nurs.C_13" +ENUMS.Storage.weapons.droptanks.droptank_110_gal = "weapons.droptanks.droptank_110_gal" +ENUMS.Storage.weapons.bombs.Mk_84 = "weapons.bombs.Mk_84" +ENUMS.Storage.weapons.missiles.Sea_Eagle = "weapons.missiles.Sea_Eagle" +ENUMS.Storage.weapons.droptanks.PTB_1200_F1 = "weapons.droptanks.PTB_1200_F1" +ENUMS.Storage.weapons.nurs.SNEB_TYPE256_H1 = "weapons.nurs.SNEB_TYPE256_H1" +ENUMS.Storage.weapons.containers.MATRA_PHIMAT = "weapons.containers.MATRA-PHIMAT" +ENUMS.Storage.weapons.containers.smoke_pod = "weapons.containers.smoke_pod" +ENUMS.Storage.weapons.containers.F_15E_AAQ_14_LANTIRN = "weapons.containers.F-15E_AAQ-14_LANTIRN" +ENUMS.Storage.weapons.containers.EclairM_24 = "weapons.containers.{EclairM_24}" +ENUMS.Storage.weapons.bombs.GBU_16 = "weapons.bombs.GBU_16" +ENUMS.Storage.weapons.nurs.HYDRA_70_M156 = "weapons.nurs.HYDRA_70_M156" +ENUMS.Storage.weapons.missiles.R_60 = "weapons.missiles.R-60" +ENUMS.Storage.weapons.containers.zsu_23_4 = "weapons.containers.zsu-23-4" +ENUMS.Storage.weapons.missiles.RB75 = "weapons.missiles.RB75" +ENUMS.Storage.weapons.missiles.Mistral = "weapons.missiles.Mistral" +ENUMS.Storage.weapons.droptanks.MB339_TT500_L = "weapons.droptanks.MB339_TT500_L" +ENUMS.Storage.weapons.bombs.SAM_SA_13_STRELA_21624lb = "weapons.bombs.SAM SA-13 STRELA [21624lb]" +ENUMS.Storage.weapons.bombs.SAM_Avenger_M1097_Air_7200lb = "weapons.bombs.SAM Avenger M1097 Air [7200lb]" +ENUMS.Storage.weapons.droptanks.Eleven00L_Tank_Empty = "weapons.droptanks.1100L Tank Empty" +ENUMS.Storage.weapons.bombs.AN_M88 = "weapons.bombs.AN-M88" +ENUMS.Storage.weapons.missiles.S_25L = "weapons.missiles.S_25L" +ENUMS.Storage.weapons.nurs.British_AP_25LBNo1_3INCHNo1 = "weapons.nurs.British_AP_25LBNo1_3INCHNo1" ENUMS.Storage.weapons.bombs.BDU_50LD = "weapons.bombs.BDU_50LD" ENUMS.Storage.weapons.bombs.AGM_62 = "weapons.bombs.AGM_62" -ENUMS.Storage.weapons.containers.US_M10_SMOKE_TANK_WHITE = "weapons.containers.{US_M10_SMOKE_TANK_WHITE}" -ENUMS.Storage.weapons.missiles.MICA_T = "weapons.missiles.MICA_T" +ENUMS.Storage.weapons.containers.US_M10_SMOKE_TANK_WHITE = "weapons.containers.{US_M10_SMOKE_TANK_WHITE}" +ENUMS.Storage.weapons.missiles.MICA_T = "weapons.missiles.MICA_T" ENUMS.Storage.weapons.containers.HVAR_rocket = "weapons.containers.HVAR_rocket" -- 2025 ENUMS.Storage.weapons.containers.LANTIRN = "weapons.containers.LANTIRN" @@ -1323,7 +1323,18 @@ ENUMS.Storage.weapons.UH60L.M229_HYDRA = {4, 7, 33, 148} -- 2.75" Hydra, UnGd Rk ENUMS.Storage.weapons.UH60L.M257_HYDRA = {4, 7, 33, 151} -- 2.75" Hydra, UnGd Rkts M257, Para Illum ENUMS.Storage.weapons.UH60L.M259_HYDRA = {4, 7, 33, 151} -- 2.75" Hydra, UnGd Rkts M259, Smoke Marker ENUMS.Storage.weapons.UH60L.M274_HYDRA = {4, 7, 33, 150} -- 2.75" Hydra, UnGd Rkts M274, Practice Smk - +ENUMS.Storage.weapons.UH60L.M134_DOOR_GUN = {4, 15, 46, 3031} +ENUMS.Storage.weapons.UH60L.M3M = {4, 15, 46, 2496} +ENUMS.Storage.weapons.UH60L.M3M_DOOR_GUN = {4, 15, 46, 3032} +ENUMS.Storage.weapons.UH60L.M60_DOOR_GUN = {4, 15, 46, 3033} +ENUMS.Storage.weapons.UH60L.FUEL_TANK_200 = {1,3,43,3023} +ENUMS.Storage.weapons.UH60L.FUEL_TANK_230 = {1,3,43,3024} +ENUMS.Storage.weapons.UH60L.FUEL_TANK_450 = {1,3,43,3025} +ENUMS.Storage.weapons.UH60L.FUEL_TANK_DUAL_AUX = {1,3,43,3026} +ENUMS.Storage.weapons.UH60L.CARGO_SEAT_REAR_ROW = {1,3,43,3030} +ENUMS.Storage.weapons.UH60L.CARGO_SEAT_THREE_ROWS = {1,3,43,3029} +ENUMS.Storage.weapons.UH60L.EMPTY_GUNNER_SEAT_1 = {1,3,43,3027} +ENUMS.Storage.weapons.UH60L.EMPTY_GUNNER_SEAT_2 = {1,3,43,3028} -- Kiowa ENUMS.Storage.weapons.OH58.FIM92 = {4,4,7,449} @@ -1358,7 +1369,7 @@ ENUMS.FARPType = { FARP = "FARP", INVISIBLE = "INVISIBLE", HELIPADSINGLE = "HELIPADSINGLE", - PADSINGLE = "PADSINGLE", + PADSINGLE = "PADSINGLE", } From 3a61581608fa3f11a256f3a693e55450b29218cc Mon Sep 17 00:00:00 2001 From: leka1986 Date: Thu, 9 Oct 2025 17:33:15 +0200 Subject: [PATCH 218/234] #Added a new option ( true by default), returntroopstobase. If set to false, troops would not return to base when dropped at load zone. --- Moose Development/Moose/Ops/CTLD.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Ops/CTLD.lua b/Moose Development/Moose/Ops/CTLD.lua index 7b46d1439..f1700111b 100644 --- a/Moose Development/Moose/Ops/CTLD.lua +++ b/Moose Development/Moose/Ops/CTLD.lua @@ -1554,6 +1554,7 @@ function CTLD:New(Coalition, Prefixes, Alias) self.smokedistance = 2000 self.movetroopstowpzone = true self.movetroopsdistance = 5000 + self.returntroopstobase = true -- if set to false, troops would stay after deployment inside a load zone. self.troopdropzoneradius = 100 self.VehicleMoveFormation = AI.Task.VehicleFormation.VEE @@ -3671,7 +3672,7 @@ function CTLD:_UnloadTroops(Group, Unit) inzone, zonename, zone, distance = self:IsUnitInZone(Unit,CTLD.CargoZoneType.SHIP) end if inzone then - droppingatbase = true + droppingatbase = self.returntroopstobase end -- check for hover unload local hoverunload = self:IsCorrectHover(Unit) --if true we\'re hovering in parameters @@ -5126,7 +5127,7 @@ function CTLD:_UnloadSingleTroopByID(Group, Unit, chunkID) inzone, zonename, zone, distance = self:IsUnitInZone(Unit, CTLD.CargoZoneType.SHIP) end if inzone then - droppingatbase = true + droppingatbase = self.returntroopstobase end if self.pilotmustopendoors and not UTILS.IsLoadingDoorOpen(Unit:GetName()) then From 534f445f8cdc28e2c20ec679d538e6fd5dcd0f0b Mon Sep 17 00:00:00 2001 From: smiki Date: Fri, 10 Oct 2025 09:19:23 +0200 Subject: [PATCH 219/234] [ADDED] UH-60L 'DAP' to `UTILS.IsLoadingDoorOpen` check --- Moose Development/Moose/Utilities/Utils.lua | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Moose Development/Moose/Utilities/Utils.lua b/Moose Development/Moose/Utilities/Utils.lua index e4d85fbff..8c337b178 100644 --- a/Moose Development/Moose/Utilities/Utils.lua +++ b/Moose Development/Moose/Utilities/Utils.lua @@ -2330,6 +2330,16 @@ function UTILS.IsLoadingDoorOpen( unit_name ) return true end + if type_name == "UH-60L_DAP" and (unit:getDrawArgumentValue(401) == 1 or unit:getDrawArgumentValue(402) == 1) then + BASE:T(unit_name .. " cargo door is open") + return true + end + + if type_name == "UH-60L_DAP" and (unit:getDrawArgumentValue(38) > 0 or unit:getDrawArgumentValue(400) == 1 ) then + BASE:T(unit_name .. " front door(s) are open") + return true + end + if type_name == "AH-64D_BLK_II" then BASE:T(unit_name .. " front door(s) are open") return true -- no doors on this one ;) From 69e649765504ae323bc73c23206eae64efc4ea15 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sun, 12 Oct 2025 17:23:49 +0200 Subject: [PATCH 220/234] #CTLD - Small fix for subcats --- Moose Development/Moose/Ops/CTLD.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Ops/CTLD.lua b/Moose Development/Moose/Ops/CTLD.lua index bb2f7a67d..525f94b87 100644 --- a/Moose Development/Moose/Ops/CTLD.lua +++ b/Moose Development/Moose/Ops/CTLD.lua @@ -25,7 +25,7 @@ -- @module Ops.CTLD -- @image OPS_CTLD.jpg --- Last Update July 2025 +-- Last Update Oct 2025 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -4560,7 +4560,7 @@ function CTLD:_RefreshF10Menus() end end else - if self.usesubcats then + if self.usesubcats == true then local subcatmenus = {} for catName, _ in pairs(self.subcats) do subcatmenus[catName] = MENU_GROUP:New(_group, catName, cratesmenu) -- fixed variable case From 2e0d1fd90f2669977a38e1e6e57454afebf3d786 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sun, 12 Oct 2025 19:14:59 +0200 Subject: [PATCH 221/234] #DYNAMICCARGO - Added Mi-8 type and dimensions --- .../Moose/Wrapper/DynamicCargo.lua | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/Moose Development/Moose/Wrapper/DynamicCargo.lua b/Moose Development/Moose/Wrapper/DynamicCargo.lua index db0d79834..eb033972e 100644 --- a/Moose Development/Moose/Wrapper/DynamicCargo.lua +++ b/Moose Development/Moose/Wrapper/DynamicCargo.lua @@ -108,6 +108,8 @@ DYNAMICCARGO.State = { -- @type DYNAMICCARGO.AircraftTypes DYNAMICCARGO.AircraftTypes = { ["CH-47Fbl1"] = "CH-47Fbl1", + ["Mi-8MTV2"] = "CH-47Fbl1", + ["Mi-8MT"] = "CH-47Fbl1", } --- Helo types possible. @@ -120,17 +122,30 @@ DYNAMICCARGO.AircraftDimensions = { ["length"] = 11, ["ropelength"] = 30, }, + ["Mi-8MTV2"] = { + ["width"] = 6, + ["height"] = 6, + ["length"] = 15, + ["ropelength"] = 30, + }, + ["Mi-8MT"] = { + ["width"] = 6, + ["height"] = 6, + ["length"] = 15, + ["ropelength"] = 30, + }, } --- DYNAMICCARGO class version. -- @field #string version -DYNAMICCARGO.version="0.0.7" +DYNAMICCARGO.version="0.0.9" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO list ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO: A lot... +-- DONE: Added Mi-8 type and dimensions ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- Constructor From f7d58a0b76b0e1e1b3f183eb3ecd9eb38f5d1495 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Mon, 13 Oct 2025 18:51:22 +0200 Subject: [PATCH 222/234] #ZONE - Added missing ZONE_UNIT:UpdateFromUnit() and ZONE_GROUP:UpdateFromGroup() --- Moose Development/Moose/Core/Zone.lua | 31 +++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/Moose Development/Moose/Core/Zone.lua b/Moose Development/Moose/Core/Zone.lua index c2deb6823..39c1a46f6 100644 --- a/Moose Development/Moose/Core/Zone.lua +++ b/Moose Development/Moose/Core/Zone.lua @@ -1934,6 +1934,21 @@ function ZONE_UNIT:New( ZoneName, ZoneUNIT, Radius, Offset) return self end +--- Updates the current location from a @{Wrapper.Group}. +-- @param #ZONE_UNIT self +-- @param Wrapper.Group#GROUP Group (optional) Update from this Unit, if nil, update from the UNIT this zone is based on. +-- @return self +function ZONE_UNIT:UpdateFromUnit(Unit) + if Unit and Unit:IsAlive() then + local vec2 = Unit:GetVec2() + self.LastVec2 = vec2 + elseif self.ZoneUNIT and self.ZoneUNIT:IsAlive() then + local ZoneVec2 = self.ZoneUNIT:GetVec2() + self.LastVec2 = ZoneVec2 + end + return self +end + --- Returns the current location of the @{Wrapper.Unit#UNIT}. -- @param #ZONE_UNIT self @@ -2071,6 +2086,22 @@ function ZONE_GROUP:GetVec2() return ZoneVec2 end +--- Updates the current location from a @{Wrapper.Group}. +-- @param #ZONE_GROUP self +-- @param Wrapper.Group#GROUP Group (optional) Update from this Group, if nil, update from the GROUP this zone is based on. +-- @return self +function ZONE_GROUP:UpdateFromGroup(Group) + if Group and Group:IsAlive() then + local vec2 = Group:GetVec2() + self.Vec2 = vec2 + elseif self._.ZoneGROUP and self._.ZoneGROUP:IsAlive() then + local ZoneVec2 = self._.ZoneGROUP:GetVec2() + self.Vec2 = ZoneVec2 + self._.ZoneVec2Cache = ZoneVec2 + end + return self +end + --- Returns a random location within the zone of the @{Wrapper.Group}. -- @param #ZONE_GROUP self -- @return DCS#Vec2 The random location of the zone based on the @{Wrapper.Group} location. From dbae37f15148a0fc2715ef5a6b2313491b879dd6 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Mon, 13 Oct 2025 18:51:55 +0200 Subject: [PATCH 223/234] xx --- Moose Development/Moose/Core/Zone.lua | 31 +++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/Moose Development/Moose/Core/Zone.lua b/Moose Development/Moose/Core/Zone.lua index c2deb6823..39c1a46f6 100644 --- a/Moose Development/Moose/Core/Zone.lua +++ b/Moose Development/Moose/Core/Zone.lua @@ -1934,6 +1934,21 @@ function ZONE_UNIT:New( ZoneName, ZoneUNIT, Radius, Offset) return self end +--- Updates the current location from a @{Wrapper.Group}. +-- @param #ZONE_UNIT self +-- @param Wrapper.Group#GROUP Group (optional) Update from this Unit, if nil, update from the UNIT this zone is based on. +-- @return self +function ZONE_UNIT:UpdateFromUnit(Unit) + if Unit and Unit:IsAlive() then + local vec2 = Unit:GetVec2() + self.LastVec2 = vec2 + elseif self.ZoneUNIT and self.ZoneUNIT:IsAlive() then + local ZoneVec2 = self.ZoneUNIT:GetVec2() + self.LastVec2 = ZoneVec2 + end + return self +end + --- Returns the current location of the @{Wrapper.Unit#UNIT}. -- @param #ZONE_UNIT self @@ -2071,6 +2086,22 @@ function ZONE_GROUP:GetVec2() return ZoneVec2 end +--- Updates the current location from a @{Wrapper.Group}. +-- @param #ZONE_GROUP self +-- @param Wrapper.Group#GROUP Group (optional) Update from this Group, if nil, update from the GROUP this zone is based on. +-- @return self +function ZONE_GROUP:UpdateFromGroup(Group) + if Group and Group:IsAlive() then + local vec2 = Group:GetVec2() + self.Vec2 = vec2 + elseif self._.ZoneGROUP and self._.ZoneGROUP:IsAlive() then + local ZoneVec2 = self._.ZoneGROUP:GetVec2() + self.Vec2 = ZoneVec2 + self._.ZoneVec2Cache = ZoneVec2 + end + return self +end + --- Returns a random location within the zone of the @{Wrapper.Group}. -- @param #ZONE_GROUP self -- @return DCS#Vec2 The random location of the zone based on the @{Wrapper.Group} location. From 512c3c57e994a553548127a5cdb98534f0e3ce10 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sun, 19 Oct 2025 14:38:50 +0200 Subject: [PATCH 224/234] #TIRESIAS - Fixed a problem when a script wants to add exceptions pre-start. --- .../Moose/Functional/Tiresias.lua | 34 ++++++++++--------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/Moose Development/Moose/Functional/Tiresias.lua b/Moose Development/Moose/Functional/Tiresias.lua index b0ed49798..9d5168748 100644 --- a/Moose Development/Moose/Functional/Tiresias.lua +++ b/Moose Development/Moose/Functional/Tiresias.lua @@ -33,7 +33,7 @@ -- @module Functional.Tiresias -- @image Functional.Tiresias.jpg ---- Last Update: July 2025 +--- Last Update: Oct 2025 --- **TIRESIAS** class, extends Core.Base#BASE -- @type TIRESIAS @@ -104,8 +104,8 @@ -- @field #TIRESIAS TIRESIAS = { ClassName = "TIRESIAS", - debug = true, - version = " 0.0.7-OPT" , + debug = false, + version = " 0.0.8" , Interval = 20, GroundSet = nil, VehicleSet = nil, @@ -140,7 +140,7 @@ function TIRESIAS:New() self:AddTransition("*", "Status", "*") -- TIRESIAS status update. self:AddTransition("*", "Stop", "Stopped") -- Stop FSM. - self.ExceptionSet = nil --SET_GROUP:New():Clear(false) + self.ExceptionSet = SET_GROUP:New() --:Clear(false) self._cached_zones = {} -- Initialize zone cache self:HandleEvent(EVENTS.PlayerEnterAircraft, self._EventHandler) @@ -224,10 +224,10 @@ function TIRESIAS:AddExceptionSet(Set) Set:ForEachGroupAlive( function(grp) - local inAAASet = self.AAASet:IsIncludeObject(grp) - local inVehSet = self.VehicleSet:IsIncludeObject(grp) - local inSAMSet = self.SAMSet:IsIncludeObject(grp) - if grp:IsGround() and (not grp.Tiresias) and (not inAAASet) and (not inVehSet) and (not inSAMSet) then + --local inAAASet = self.AAASet:IsIncludeObject(grp) + --local inVehSet = self.VehicleSet:IsIncludeObject(grp) + --local inSAMSet = self.SAMSet:IsIncludeObject(grp) + if grp:IsGround() and (not grp.Tiresias) then --and (not inAAASet) and (not inVehSet) and (not inSAMSet) then grp.Tiresias = exception_data exceptions:AddGroup(grp, true) BASE:T(" TIRESIAS: Added exception group: " .. grp:GetName()) @@ -419,8 +419,8 @@ function TIRESIAS:_SwitchOnGroups(group, radius) -- Use cached zones to reduce object creation local group_name = group:GetName() local cache_key = group_name .. " _" .. radius - local zone = self._cached_zones[cache_key] - local ground = self._cached_groupsets[cache_key] + local zone = self._cached_zones[cache_key] -- Core.Zone#ZONE_RADIUS + --local ground = self._cached_groupsets[cache_key] -- Core.Set#SET_GROUP if not zone then zone = ZONE_GROUP:New(" Zone-" .. group_name, group, UTILS.NMToMeters(radius)) @@ -430,12 +430,14 @@ function TIRESIAS:_SwitchOnGroups(group, radius) zone:UpdateFromGroup(group) end - if not ground then - ground = SET_GROUP:New():FilterCategoryGround():FilterZones({zone}):FilterOnce() - self._cached_groupsets[cache_key] = ground - else - ground:FilterZones({zone},true):FilterOnce() - end + --if not ground then + --ground = SET_GROUP:New():FilterCategoryGround():FilterZones({zone}):FilterOnce() + --self._cached_groupsets[cache_key] = ground + --else + --ground:FilterZones({zone},true):FilterOnce() + zone:Scan({Object.Category.UNIT},{Unit.Category.GROUND_UNIT}) + local ground = zone:GetScannedSetGroup() + --end local count = ground:CountAlive() From 5fc3798c42e08b9cb50af92f7efd925560edab88 Mon Sep 17 00:00:00 2001 From: nasgroup94 Date: Tue, 21 Oct 2025 05:44:19 -0400 Subject: [PATCH 225/234] Update Airboss.lua Fixed possible bug where a player will get points deducted when getting a perfect groove time --- Moose Development/Moose/Ops/Airboss.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Moose Development/Moose/Ops/Airboss.lua b/Moose Development/Moose/Ops/Airboss.lua index 246e960d1..324a32a9d 100644 --- a/Moose Development/Moose/Ops/Airboss.lua +++ b/Moose Development/Moose/Ops/Airboss.lua @@ -12682,7 +12682,8 @@ function AIRBOSS:_LSOgrade( playerData ) local nL=count(G, '_')/2 local nS=count(G, '%(') local nN=N-nS-nL - + + if TIG=="_OK_" then nL = nL -1 --Circuit added to prevent grade deduction for perfect groove -- Groove time 15-18.99 sec for a unicorn. Or 60-65 for V/STOL unicorn. local Tgroove=playerData.Tgroove From 1644c1dc5ba629ba6ca6cd80e03df05d14022d9e Mon Sep 17 00:00:00 2001 From: nasgroup94 Date: Tue, 21 Oct 2025 16:49:51 -0400 Subject: [PATCH 226/234] fixes to goshawk AOA f14 AA and TIG bug --- Moose Development/Moose/Ops/Airboss.lua | 52 +++++++++++++++++++------ 1 file changed, 41 insertions(+), 11 deletions(-) diff --git a/Moose Development/Moose/Ops/Airboss.lua b/Moose Development/Moose/Ops/Airboss.lua index 324a32a9d..f73fd7e24 100644 --- a/Moose Development/Moose/Ops/Airboss.lua +++ b/Moose Development/Moose/Ops/Airboss.lua @@ -5498,15 +5498,15 @@ function AIRBOSS:_GetAircraftAoA( playerData ) aoa.OnSpeedMin = self:_AoAUnit2Deg( playerData, 14.0 ) -- 14.17 --14.5 units -- VNAO Edit - Original value 14.5 aoa.Fast = self:_AoAUnit2Deg( playerData, 13.5 ) -- 13.33 --14.0 units -- VNAO Edit - Original value 14 aoa.FAST = self:_AoAUnit2Deg( playerData, 12.5 ) -- 11.67 --13.0 units -- VNAO Edit - Original value 13 - elseif goshawk then + elseif goshawk then -- These parameters tweaked by Circuit for new T45 flight model -- T-45C Goshawk parameters. - aoa.SLOW = 8.00 -- 19 - aoa.Slow = 7.75 -- 18 - aoa.OnSpeedMax = 7.25 -- 17.5 - aoa.OnSpeed = 7.00 -- 17 - aoa.OnSpeedMin = 6.75 -- 16.5 - aoa.Fast = 6.25 -- 16 - aoa.FAST = 6.00 -- 15 + aoa.SLOW = 9.5 --8.00 -- 19 + aoa.Slow = 9.25 --7.75 -- 18 + aoa.OnSpeedMax = 9.0 --7.25 -- 17.5 + aoa.OnSpeed = 8.5 --7.00 -- 17 + aoa.OnSpeedMin = 8.25 --6.75 -- 16.5 + aoa.Fast = 7.75 -- 6.25 -- 16 + aoa.FAST = 7.5 -- 6.00 -- 15 elseif skyhawk then -- A-4E-C Skyhawk parameters from https://forums.eagle.ru/showpost.php?p=3703467&postcount=390 -- Note that these are arbitrary UNITS and not degrees. We need a conversion formula! @@ -8150,7 +8150,11 @@ function AIRBOSS:_CheckPlayerStatus() local playerData = _playerData -- #AIRBOSS.PlayerData if playerData then - + local hornet = playerData.actype == AIRBOSS.AircraftCarrier.HORNET + or playerData.actype == AIRBOSS.AircraftCarrier.RHINOE + or playerData.actype == AIRBOSS.AircraftCarrier.RHINOF + or playerData.actype == AIRBOSS.AircraftCarrier.GROWLER + local tomcat = playerData.actype == AIRBOSS.AircraftCarrier.F14A or playerData.actype == AIRBOSS.AircraftCarrier.F14B -- Player unit. local unit = playerData.unit @@ -8161,8 +8165,8 @@ function AIRBOSS:_CheckPlayerStatus() -- TODO: This might cause problems if the CCA is set to be very small! if unit:IsInZone( self.zoneCCA ) then - -- VNAO Edit - Added wrapped up call to LSO grading - if playerData.step==AIRBOSS.PatternStep.WAKE then-- VNAO Edit - Added + -- VNAO Edit - Added wrapped up call to LSO grading Hornet + if playerData.step==AIRBOSS.PatternStep.WAKE and hornet then-- VNAO Edit - Added if math.abs(playerData.unit:GetRoll())>35 and math.abs(playerData.unit:GetRoll())<=40 then-- VNAO Edit - Added playerData.wrappedUpAtWakeLittle = true -- VNAO Edit - Added elseif math.abs(playerData.unit:GetRoll()) >40 and math.abs(playerData.unit:GetRoll())<=45 then-- VNAO Edit - Added @@ -8178,6 +8182,32 @@ function AIRBOSS:_CheckPlayerStatus() else -- VNAO Edit - Added end -- VNAO Edit - Added + if math.abs(playerData.unit:GetAoA())>= 15 then -- VNAO Edit - Added + playerData.AFU = true -- VNAO Edit - Added + elseif math.abs(playerData.unit:GetAoA())<= 5 then -- VNAO Edit - Added + playerData.AFU = true -- VNAO Edit - Added + else -- VNAO Edit - Added + end -- VNAO Edit - Added + end-- VNAO Edit - Added + + + -- VNAO Edit - Added wrapped up call to LSO grading Tomcat + if playerData.step==AIRBOSS.PatternStep.WAKE and tomcat then-- VNAO Edit - Added + if math.abs(playerData.unit:GetRoll())>35 and math.abs(playerData.unit:GetRoll())<=40 then-- VNAO Edit - Added + playerData.wrappedUpAtWakeLittle = true -- VNAO Edit - Added + elseif math.abs(playerData.unit:GetRoll()) >40 and math.abs(playerData.unit:GetRoll())<=45 then-- VNAO Edit - Added + playerData.wrappedUpAtWakeFull = true-- VNAO Edit - Added + elseif math.abs(playerData.unit:GetRoll()) >45 then-- VNAO Edit - Added + playerData.wrappedUpAtWakeUnderline = true -- VNAO Edit - Added + elseif math.abs(playerData.unit:GetRoll()) <12 and math.abs(playerData.unit:GetRoll()) >=5 then -- VNAO Edit - Added a new AA comment based on discussion with Lipps today, and going to replace the AA at the X with the original LUL comments + playerData.AAatWakeLittle = true -- VNAO Edit - Added + elseif math.abs(playerData.unit:GetRoll()) <5 and math.abs(playerData.unit:GetRoll()) >=2 then -- VNAO Edit - Added a new AA comment based on discussion with Lipps today, and going to replace the AA at the X with the original LUL comments + playerData.AAatWakeFull = true -- VNAO Edit - Added + elseif math.abs(playerData.unit:GetRoll()) <2 then -- VNAO Edit - Added a new AA comment based on discussion with Lipps today, and going to replace the AA at the X with the original LUL comments + playerData.AAatWakeUnderline = true -- VNAO Edit - Added + else -- VNAO Edit - Added + end -- VNAO Edit - Added + if math.abs(playerData.unit:GetAoA())>= 15 then -- VNAO Edit - Added playerData.AFU = true -- VNAO Edit - Added elseif math.abs(playerData.unit:GetAoA())<= 5 then -- VNAO Edit - Added From 1f1a068d459b0752558eb51897cbdf018054f58a Mon Sep 17 00:00:00 2001 From: Thomas <72444570+Applevangelist@users.noreply.github.com> Date: Wed, 22 Oct 2025 07:16:33 +0200 Subject: [PATCH 227/234] Revert "Merge from master" --- Moose Development/Moose/Ops/Airboss.lua | 55 ++++++------------------- 1 file changed, 12 insertions(+), 43 deletions(-) diff --git a/Moose Development/Moose/Ops/Airboss.lua b/Moose Development/Moose/Ops/Airboss.lua index f73fd7e24..246e960d1 100644 --- a/Moose Development/Moose/Ops/Airboss.lua +++ b/Moose Development/Moose/Ops/Airboss.lua @@ -5498,15 +5498,15 @@ function AIRBOSS:_GetAircraftAoA( playerData ) aoa.OnSpeedMin = self:_AoAUnit2Deg( playerData, 14.0 ) -- 14.17 --14.5 units -- VNAO Edit - Original value 14.5 aoa.Fast = self:_AoAUnit2Deg( playerData, 13.5 ) -- 13.33 --14.0 units -- VNAO Edit - Original value 14 aoa.FAST = self:_AoAUnit2Deg( playerData, 12.5 ) -- 11.67 --13.0 units -- VNAO Edit - Original value 13 - elseif goshawk then -- These parameters tweaked by Circuit for new T45 flight model + elseif goshawk then -- T-45C Goshawk parameters. - aoa.SLOW = 9.5 --8.00 -- 19 - aoa.Slow = 9.25 --7.75 -- 18 - aoa.OnSpeedMax = 9.0 --7.25 -- 17.5 - aoa.OnSpeed = 8.5 --7.00 -- 17 - aoa.OnSpeedMin = 8.25 --6.75 -- 16.5 - aoa.Fast = 7.75 -- 6.25 -- 16 - aoa.FAST = 7.5 -- 6.00 -- 15 + aoa.SLOW = 8.00 -- 19 + aoa.Slow = 7.75 -- 18 + aoa.OnSpeedMax = 7.25 -- 17.5 + aoa.OnSpeed = 7.00 -- 17 + aoa.OnSpeedMin = 6.75 -- 16.5 + aoa.Fast = 6.25 -- 16 + aoa.FAST = 6.00 -- 15 elseif skyhawk then -- A-4E-C Skyhawk parameters from https://forums.eagle.ru/showpost.php?p=3703467&postcount=390 -- Note that these are arbitrary UNITS and not degrees. We need a conversion formula! @@ -8150,11 +8150,7 @@ function AIRBOSS:_CheckPlayerStatus() local playerData = _playerData -- #AIRBOSS.PlayerData if playerData then - local hornet = playerData.actype == AIRBOSS.AircraftCarrier.HORNET - or playerData.actype == AIRBOSS.AircraftCarrier.RHINOE - or playerData.actype == AIRBOSS.AircraftCarrier.RHINOF - or playerData.actype == AIRBOSS.AircraftCarrier.GROWLER - local tomcat = playerData.actype == AIRBOSS.AircraftCarrier.F14A or playerData.actype == AIRBOSS.AircraftCarrier.F14B + -- Player unit. local unit = playerData.unit @@ -8165,8 +8161,8 @@ function AIRBOSS:_CheckPlayerStatus() -- TODO: This might cause problems if the CCA is set to be very small! if unit:IsInZone( self.zoneCCA ) then - -- VNAO Edit - Added wrapped up call to LSO grading Hornet - if playerData.step==AIRBOSS.PatternStep.WAKE and hornet then-- VNAO Edit - Added + -- VNAO Edit - Added wrapped up call to LSO grading + if playerData.step==AIRBOSS.PatternStep.WAKE then-- VNAO Edit - Added if math.abs(playerData.unit:GetRoll())>35 and math.abs(playerData.unit:GetRoll())<=40 then-- VNAO Edit - Added playerData.wrappedUpAtWakeLittle = true -- VNAO Edit - Added elseif math.abs(playerData.unit:GetRoll()) >40 and math.abs(playerData.unit:GetRoll())<=45 then-- VNAO Edit - Added @@ -8182,32 +8178,6 @@ function AIRBOSS:_CheckPlayerStatus() else -- VNAO Edit - Added end -- VNAO Edit - Added - if math.abs(playerData.unit:GetAoA())>= 15 then -- VNAO Edit - Added - playerData.AFU = true -- VNAO Edit - Added - elseif math.abs(playerData.unit:GetAoA())<= 5 then -- VNAO Edit - Added - playerData.AFU = true -- VNAO Edit - Added - else -- VNAO Edit - Added - end -- VNAO Edit - Added - end-- VNAO Edit - Added - - - -- VNAO Edit - Added wrapped up call to LSO grading Tomcat - if playerData.step==AIRBOSS.PatternStep.WAKE and tomcat then-- VNAO Edit - Added - if math.abs(playerData.unit:GetRoll())>35 and math.abs(playerData.unit:GetRoll())<=40 then-- VNAO Edit - Added - playerData.wrappedUpAtWakeLittle = true -- VNAO Edit - Added - elseif math.abs(playerData.unit:GetRoll()) >40 and math.abs(playerData.unit:GetRoll())<=45 then-- VNAO Edit - Added - playerData.wrappedUpAtWakeFull = true-- VNAO Edit - Added - elseif math.abs(playerData.unit:GetRoll()) >45 then-- VNAO Edit - Added - playerData.wrappedUpAtWakeUnderline = true -- VNAO Edit - Added - elseif math.abs(playerData.unit:GetRoll()) <12 and math.abs(playerData.unit:GetRoll()) >=5 then -- VNAO Edit - Added a new AA comment based on discussion with Lipps today, and going to replace the AA at the X with the original LUL comments - playerData.AAatWakeLittle = true -- VNAO Edit - Added - elseif math.abs(playerData.unit:GetRoll()) <5 and math.abs(playerData.unit:GetRoll()) >=2 then -- VNAO Edit - Added a new AA comment based on discussion with Lipps today, and going to replace the AA at the X with the original LUL comments - playerData.AAatWakeFull = true -- VNAO Edit - Added - elseif math.abs(playerData.unit:GetRoll()) <2 then -- VNAO Edit - Added a new AA comment based on discussion with Lipps today, and going to replace the AA at the X with the original LUL comments - playerData.AAatWakeUnderline = true -- VNAO Edit - Added - else -- VNAO Edit - Added - end -- VNAO Edit - Added - if math.abs(playerData.unit:GetAoA())>= 15 then -- VNAO Edit - Added playerData.AFU = true -- VNAO Edit - Added elseif math.abs(playerData.unit:GetAoA())<= 5 then -- VNAO Edit - Added @@ -12712,8 +12682,7 @@ function AIRBOSS:_LSOgrade( playerData ) local nL=count(G, '_')/2 local nS=count(G, '%(') local nN=N-nS-nL - - if TIG=="_OK_" then nL = nL -1 --Circuit added to prevent grade deduction for perfect groove + -- Groove time 15-18.99 sec for a unicorn. Or 60-65 for V/STOL unicorn. local Tgroove=playerData.Tgroove From eb4e7b928191f57eefe71ecd9f8bffcf82abdcba Mon Sep 17 00:00:00 2001 From: Thomas <72444570+Applevangelist@users.noreply.github.com> Date: Wed, 22 Oct 2025 07:23:21 +0200 Subject: [PATCH 228/234] Revert "Minor fixes" --- Moose Development/Moose/Ops/Airboss.lua | 55 ++++++------------------- 1 file changed, 12 insertions(+), 43 deletions(-) diff --git a/Moose Development/Moose/Ops/Airboss.lua b/Moose Development/Moose/Ops/Airboss.lua index f73fd7e24..246e960d1 100644 --- a/Moose Development/Moose/Ops/Airboss.lua +++ b/Moose Development/Moose/Ops/Airboss.lua @@ -5498,15 +5498,15 @@ function AIRBOSS:_GetAircraftAoA( playerData ) aoa.OnSpeedMin = self:_AoAUnit2Deg( playerData, 14.0 ) -- 14.17 --14.5 units -- VNAO Edit - Original value 14.5 aoa.Fast = self:_AoAUnit2Deg( playerData, 13.5 ) -- 13.33 --14.0 units -- VNAO Edit - Original value 14 aoa.FAST = self:_AoAUnit2Deg( playerData, 12.5 ) -- 11.67 --13.0 units -- VNAO Edit - Original value 13 - elseif goshawk then -- These parameters tweaked by Circuit for new T45 flight model + elseif goshawk then -- T-45C Goshawk parameters. - aoa.SLOW = 9.5 --8.00 -- 19 - aoa.Slow = 9.25 --7.75 -- 18 - aoa.OnSpeedMax = 9.0 --7.25 -- 17.5 - aoa.OnSpeed = 8.5 --7.00 -- 17 - aoa.OnSpeedMin = 8.25 --6.75 -- 16.5 - aoa.Fast = 7.75 -- 6.25 -- 16 - aoa.FAST = 7.5 -- 6.00 -- 15 + aoa.SLOW = 8.00 -- 19 + aoa.Slow = 7.75 -- 18 + aoa.OnSpeedMax = 7.25 -- 17.5 + aoa.OnSpeed = 7.00 -- 17 + aoa.OnSpeedMin = 6.75 -- 16.5 + aoa.Fast = 6.25 -- 16 + aoa.FAST = 6.00 -- 15 elseif skyhawk then -- A-4E-C Skyhawk parameters from https://forums.eagle.ru/showpost.php?p=3703467&postcount=390 -- Note that these are arbitrary UNITS and not degrees. We need a conversion formula! @@ -8150,11 +8150,7 @@ function AIRBOSS:_CheckPlayerStatus() local playerData = _playerData -- #AIRBOSS.PlayerData if playerData then - local hornet = playerData.actype == AIRBOSS.AircraftCarrier.HORNET - or playerData.actype == AIRBOSS.AircraftCarrier.RHINOE - or playerData.actype == AIRBOSS.AircraftCarrier.RHINOF - or playerData.actype == AIRBOSS.AircraftCarrier.GROWLER - local tomcat = playerData.actype == AIRBOSS.AircraftCarrier.F14A or playerData.actype == AIRBOSS.AircraftCarrier.F14B + -- Player unit. local unit = playerData.unit @@ -8165,8 +8161,8 @@ function AIRBOSS:_CheckPlayerStatus() -- TODO: This might cause problems if the CCA is set to be very small! if unit:IsInZone( self.zoneCCA ) then - -- VNAO Edit - Added wrapped up call to LSO grading Hornet - if playerData.step==AIRBOSS.PatternStep.WAKE and hornet then-- VNAO Edit - Added + -- VNAO Edit - Added wrapped up call to LSO grading + if playerData.step==AIRBOSS.PatternStep.WAKE then-- VNAO Edit - Added if math.abs(playerData.unit:GetRoll())>35 and math.abs(playerData.unit:GetRoll())<=40 then-- VNAO Edit - Added playerData.wrappedUpAtWakeLittle = true -- VNAO Edit - Added elseif math.abs(playerData.unit:GetRoll()) >40 and math.abs(playerData.unit:GetRoll())<=45 then-- VNAO Edit - Added @@ -8182,32 +8178,6 @@ function AIRBOSS:_CheckPlayerStatus() else -- VNAO Edit - Added end -- VNAO Edit - Added - if math.abs(playerData.unit:GetAoA())>= 15 then -- VNAO Edit - Added - playerData.AFU = true -- VNAO Edit - Added - elseif math.abs(playerData.unit:GetAoA())<= 5 then -- VNAO Edit - Added - playerData.AFU = true -- VNAO Edit - Added - else -- VNAO Edit - Added - end -- VNAO Edit - Added - end-- VNAO Edit - Added - - - -- VNAO Edit - Added wrapped up call to LSO grading Tomcat - if playerData.step==AIRBOSS.PatternStep.WAKE and tomcat then-- VNAO Edit - Added - if math.abs(playerData.unit:GetRoll())>35 and math.abs(playerData.unit:GetRoll())<=40 then-- VNAO Edit - Added - playerData.wrappedUpAtWakeLittle = true -- VNAO Edit - Added - elseif math.abs(playerData.unit:GetRoll()) >40 and math.abs(playerData.unit:GetRoll())<=45 then-- VNAO Edit - Added - playerData.wrappedUpAtWakeFull = true-- VNAO Edit - Added - elseif math.abs(playerData.unit:GetRoll()) >45 then-- VNAO Edit - Added - playerData.wrappedUpAtWakeUnderline = true -- VNAO Edit - Added - elseif math.abs(playerData.unit:GetRoll()) <12 and math.abs(playerData.unit:GetRoll()) >=5 then -- VNAO Edit - Added a new AA comment based on discussion with Lipps today, and going to replace the AA at the X with the original LUL comments - playerData.AAatWakeLittle = true -- VNAO Edit - Added - elseif math.abs(playerData.unit:GetRoll()) <5 and math.abs(playerData.unit:GetRoll()) >=2 then -- VNAO Edit - Added a new AA comment based on discussion with Lipps today, and going to replace the AA at the X with the original LUL comments - playerData.AAatWakeFull = true -- VNAO Edit - Added - elseif math.abs(playerData.unit:GetRoll()) <2 then -- VNAO Edit - Added a new AA comment based on discussion with Lipps today, and going to replace the AA at the X with the original LUL comments - playerData.AAatWakeUnderline = true -- VNAO Edit - Added - else -- VNAO Edit - Added - end -- VNAO Edit - Added - if math.abs(playerData.unit:GetAoA())>= 15 then -- VNAO Edit - Added playerData.AFU = true -- VNAO Edit - Added elseif math.abs(playerData.unit:GetAoA())<= 5 then -- VNAO Edit - Added @@ -12712,8 +12682,7 @@ function AIRBOSS:_LSOgrade( playerData ) local nL=count(G, '_')/2 local nS=count(G, '%(') local nN=N-nS-nL - - if TIG=="_OK_" then nL = nL -1 --Circuit added to prevent grade deduction for perfect groove + -- Groove time 15-18.99 sec for a unicorn. Or 60-65 for V/STOL unicorn. local Tgroove=playerData.Tgroove From 8432f46e484daaec415537a5bbec3a3e51b2ab70 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 23 Oct 2025 08:10:22 +0200 Subject: [PATCH 229/234] #AIRBOSS - Fixed omission of magnetic in expected BRC call --- Moose Development/Moose/Ops/Airboss.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/Ops/Airboss.lua b/Moose Development/Moose/Ops/Airboss.lua index 246e960d1..8b8644165 100644 --- a/Moose Development/Moose/Ops/Airboss.lua +++ b/Moose Development/Moose/Ops/Airboss.lua @@ -12230,7 +12230,7 @@ function AIRBOSS:GetHeadingIntoWind_new( vdeck, magnetic, coord ) -- Ship heading so cross wind is min for the given wind. -- local intowind = (540 + (windto - magvar + math.deg(theta) )) % 360 -- VNAO Edit: Using old heading into wind algorithm - local intowind = self:GetHeadingIntoWind_old(vdeck) -- VNAO Edit: Using old heading into wind algorithm + local intowind = self:GetHeadingIntoWind_old(vdeck,magnetic) -- VNAO Edit: Using old heading into wind algorithm return intowind, v end From 0f270a6a35ebcfe2430659092d934beeb495d489 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 23 Oct 2025 12:10:05 +0200 Subject: [PATCH 230/234] #UTILS - FARP helper - add options to spawn multiple pads --- Moose Development/Moose/Utilities/Utils.lua | 128 +++++++++++++++----- 1 file changed, 98 insertions(+), 30 deletions(-) diff --git a/Moose Development/Moose/Utilities/Utils.lua b/Moose Development/Moose/Utilities/Utils.lua index 8c337b178..9d52ee972 100644 --- a/Moose Development/Moose/Utilities/Utils.lua +++ b/Moose Development/Moose/Utilities/Utils.lua @@ -4137,6 +4137,45 @@ function UTILS.LCGRandom() return UTILS.lcg.seed / UTILS.lcg.m end +--- Create a table of grid-points for n points. +-- @param #number startVec2 Starting DCS#Vec2 map coordinate, e.g. `{x=63598575,y=-63598575}` +-- @param #number n Number of points to generate. +-- @param #number spacingX Horizonzal spacing (meters). +-- @param #number spacingY Vertical spacing (meters). +-- @return #table Grid Table of DCS#Vec2 entries. +function UTILS.GenerateGridPoints(startVec2, n, spacingX, spacingY) + local points = {} + local gridSize = math.ceil(math.sqrt(n)) + local count = 0 + local n = n or 1 + local spacingX = spacingX or 100 + local spacingY = spacingY or 100 + local startX = startVec2.x or 100 + local startY = startVec2.y or 100 + + for row = 0, gridSize - 1 do + for col = 0, gridSize - 1 do + if count >= n then + break + end + + local point = { + x = startX + (col * spacingX), + y = startY + (row * spacingY) + } + + table.insert(points, point) + count = count + 1 + end + + if count >= n then + break + end + end + + return points +end + --- Spawns a new FARP of a defined type and coalition and functional statics (fuel depot, ammo storage, tent, windsock) around that FARP to make it operational. -- Adds vehicles from template if given. Fills the FARP warehouse with liquids and known materiels. -- References: [DCS Forum Topic](https://forum.dcs.world/topic/282989-farp-equipment-to-run-it) @@ -4157,10 +4196,38 @@ end -- @param #string F10Text Text to display on F10 map if given. Handy to post things like the ADF beacon Frequency, Callsign and ATC Frequency. -- @param #boolean DynamicSpawns If true, allow Dynamic Spawns from this FARP. -- @param #boolean HotStart If true and DynamicSpawns is true, allow hot starts for Dynamic Spawns from this FARP. +-- @param #number NumberPads If given, spawn this number of pads. +-- @param #number SpacingX For NumberPads > 1, space this many meters horizontally. Defaults to 100. +-- @param #number SpacingY For NumberPads > 1, space this many meters vertically. Defaults to 100. -- @return #list Table of spawned objects and vehicle object (if given). -- @return #string ADFBeaconName Name of the ADF beacon, to be able to remove/stop it later. -- @return #number MarkerID ID of the F10 Text, to be able to remove it later. -function UTILS.SpawnFARPAndFunctionalStatics(Name,Coordinate,FARPType,Coalition,Country,CallSign,Frequency,Modulation,ADF,SpawnRadius,VehicleTemplate,Liquids,Equipment,Airframes,F10Text,DynamicSpawns,HotStart) +function UTILS.SpawnFARPAndFunctionalStatics(Name,Coordinate,FARPType,Coalition,Country,CallSign,Frequency,Modulation,ADF,SpawnRadius,VehicleTemplate,Liquids,Equipment,Airframes,F10Text,DynamicSpawns,HotStart,NumberPads,SpacingX,SpacingY) + + local function PopulateStorage(Name,liquids,equip,airframes) + local newWH = STORAGE:New(Name) + if liquids and liquids > 0 then + -- Storage fill-up + newWH:SetLiquid(STORAGE.Liquid.DIESEL,liquids) -- kgs to tons + newWH:SetLiquid(STORAGE.Liquid.GASOLINE,liquids) + newWH:SetLiquid(STORAGE.Liquid.JETFUEL,liquids) + newWH:SetLiquid(STORAGE.Liquid.MW50,liquids) + end + + if equip and equip > 0 then + for cat,nitem in pairs(ENUMS.Storage.weapons) do + for name,item in pairs(nitem) do + newWH:SetItem(item,equip) + end + end + end + + if airframes and airframes > 0 then + for typename in pairs (CSAR.AircraftType) do + newWH:SetItem(typename,airframes) + end + end + end -- Set Defaults local farplocation = Coordinate @@ -4181,12 +4248,36 @@ function UTILS.SpawnFARPAndFunctionalStatics(Name,Coordinate,FARPType,Coalition, local Country = Country or (Coalition == coalition.side.BLUE and country.id.USA or country.id.RUSSIA) local ReturnObjects = {} - -- Spawn FARP - local newfarp = SPAWNSTATIC:NewFromType(STypeName,"Heliports",Country) -- "Invisible FARP" "FARP" - newfarp:InitShape(SShapeName) -- "invisiblefarp" "FARPS" - newfarp:InitFARP(callsign,freq,mod,DynamicSpawns,HotStart) - local spawnedfarp = newfarp:SpawnFromCoordinate(farplocation,0,Name) - table.insert(ReturnObjects,spawnedfarp) + -- many FARPs + local NumberPads = NumberPads or 1 + local SpacingX = SpacingX or 100 + local SpacingY = SpacingY or 100 + local FarpVec2 = Coordinate:GetVec2() + + if NumberPads > 1 then + local Grid = UTILS.GenerateGridPoints(FarpVec2, NumberPads, SpacingX, SpacingY) + for id,gridpoint in ipairs(Grid) do + -- Spawn FARP + local location = COORDINATE:NewFromVec2(gridpoint) + local newfarp = SPAWNSTATIC:NewFromType(STypeName,"Heliports",Country) -- "Invisible FARP" "FARP" + newfarp:InitShape(SShapeName) -- "invisiblefarp" "FARPS" + newfarp:InitFARP(callsign,freq,mod,DynamicSpawns,HotStart) + local spawnedfarp = newfarp:SpawnFromCoordinate(location,0,Name.."-"..id) + table.insert(ReturnObjects,spawnedfarp) + + PopulateStorage(Name.."-"..id,liquids,equip,airframes) + end + else + -- Spawn FARP + local newfarp = SPAWNSTATIC:NewFromType(STypeName,"Heliports",Country) -- "Invisible FARP" "FARP" + newfarp:InitShape(SShapeName) -- "invisiblefarp" "FARPS" + newfarp:InitFARP(callsign,freq,mod,DynamicSpawns,HotStart) + local spawnedfarp = newfarp:SpawnFromCoordinate(farplocation,0,Name) + table.insert(ReturnObjects,spawnedfarp) + + PopulateStorage(Name,liquids,equip,airframes) + end + -- Spawn Objects local FARPStaticObjectsNato = { ["FUEL"] = { TypeName = "FARP Fuel Depot", ShapeName = "GSM Rus", Category = "Fortifications"}, @@ -4220,29 +4311,6 @@ function UTILS.SpawnFARPAndFunctionalStatics(Name,Coordinate,FARPType,Coalition, table.insert(ReturnObjects,spawnedvehicle) end - local newWH = STORAGE:New(Name) - if liquids and liquids > 0 then - -- Storage fill-up - newWH:SetLiquid(STORAGE.Liquid.DIESEL,liquids) -- kgs to tons - newWH:SetLiquid(STORAGE.Liquid.GASOLINE,liquids) - newWH:SetLiquid(STORAGE.Liquid.JETFUEL,liquids) - newWH:SetLiquid(STORAGE.Liquid.MW50,liquids) - end - - if equip and equip > 0 then - for cat,nitem in pairs(ENUMS.Storage.weapons) do - for name,item in pairs(nitem) do - newWH:SetItem(item,equip) - end - end - end - - if airframes and airframes > 0 then - for typename in pairs (CSAR.AircraftType) do - newWH:SetItem(typename,airframes) - end - end - local ADFName if ADF and type(ADF) == "number" then local ADFFreq = ADF*1000 -- KHz to Hz From f3af0262dfa6dbd55970ab4a6aa5e22208b381ad Mon Sep 17 00:00:00 2001 From: leka1986 <83298840+leka1986@users.noreply.github.com> Date: Fri, 24 Oct 2025 14:02:06 +0200 Subject: [PATCH 231/234] Update CTLD.lua Added Crates amount to the menus and AddCratesCargoNoMove. --- Moose Development/Moose/Ops/CTLD.lua | 78 ++++++++++++++++++++++++---- 1 file changed, 69 insertions(+), 9 deletions(-) diff --git a/Moose Development/Moose/Ops/CTLD.lua b/Moose Development/Moose/Ops/CTLD.lua index 525f94b87..e9d413642 100644 --- a/Moose Development/Moose/Ops/CTLD.lua +++ b/Moose Development/Moose/Ops/CTLD.lua @@ -783,6 +783,7 @@ do -- my_ctld:AddCratesCargo("Humvee",{"Humvee"},CTLD_CARGO.Enum.VEHICLE,2,2775,10) -- -- additionally, you can limit **where** the stock is available (one location only!) - this one is available in a zone called "Vehicle Store". -- my_ctld:AddCratesCargo("Humvee",{"Humvee"},CTLD_CARGO.Enum.VEHICLE,2,2775,10,nil,nil,"Vehicle Store") +-- -- Tip: if you want the spawned/built group NOT to move to a MOVE zone, replace AddCratesCargo with AddCratesCargoNoMove (same parameters). -- -- -- add infantry unit called "Forward Ops Base" using template "FOB", of type FOB, size 4, i.e. needs four crates to be build: -- my_ctld:AddCratesCargo("Forward Ops Base",{"FOB"},CTLD_CARGO.Enum.FOB,4) @@ -4514,7 +4515,8 @@ function CTLD:_RefreshF10Menus() end for _,cargoObj in pairs(self.Cargo_Crates) do if not cargoObj.DontShowInMenu then - local txt = string.format("Crate %s (%dkg)",cargoObj.Name,cargoObj.PerCrateMass or 0) + local needed = cargoObj:GetCratesNeeded() or 1 + local txt = string.format("%d crate%s %s (%dkg)",needed,needed==1 and "" or "s",cargoObj.Name,cargoObj.PerCrateMass or 0) if cargoObj.Location then txt = txt.."[R]" end local stock = cargoObj:GetStock() if stock>=0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end @@ -4525,7 +4527,8 @@ function CTLD:_RefreshF10Menus() end for _,cargoObj in pairs(self.Cargo_Statics) do if not cargoObj.DontShowInMenu then - local txt = string.format("Crate %s (%dkg)",cargoObj.Name,cargoObj.PerCrateMass or 0) + local needed = cargoObj:GetCratesNeeded() or 1 + local txt = string.format("%d crate%s %s (%dkg)",needed,needed==1 and "" or "s",cargoObj.Name,cargoObj.PerCrateMass or 0) if cargoObj.Location then txt = txt.."[R]" end local stock = cargoObj:GetStock() if stock>=0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end @@ -4537,7 +4540,8 @@ function CTLD:_RefreshF10Menus() else for _,cargoObj in pairs(self.Cargo_Crates) do if not cargoObj.DontShowInMenu then - local txt = string.format("Crate %s (%dkg)",cargoObj.Name,cargoObj.PerCrateMass or 0) + local needed = cargoObj:GetCratesNeeded() or 1 + local txt = string.format("%d crate%s %s (%dkg)",needed,needed==1 and "" or "s",cargoObj.Name,cargoObj.PerCrateMass or 0) if cargoObj.Location then txt = txt.."[R]" end local stock = cargoObj:GetStock() if stock>=0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end @@ -4548,7 +4552,8 @@ function CTLD:_RefreshF10Menus() end for _,cargoObj in pairs(self.Cargo_Statics) do if not cargoObj.DontShowInMenu then - local txt = string.format("Crate %s (%dkg)",cargoObj.Name,cargoObj.PerCrateMass or 0) + local needed = cargoObj:GetCratesNeeded() or 1 + local txt = string.format("%d crate%s %s (%dkg)",needed,needed==1 and "" or "s",cargoObj.Name,cargoObj.PerCrateMass or 0) if cargoObj.Location then txt = txt.."[R]" end local stock = cargoObj:GetStock() if stock>=0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end @@ -4567,7 +4572,8 @@ function CTLD:_RefreshF10Menus() end for _, cargoObj in pairs(self.Cargo_Crates) do if not cargoObj.DontShowInMenu then - local txt = string.format("Crate %s (%dkg)", cargoObj.Name, cargoObj.PerCrateMass or 0) + local needed = cargoObj:GetCratesNeeded() or 1 + local txt = string.format("%d crate%s %s (%dkg)", needed, needed==1 and "" or "s", cargoObj.Name, cargoObj.PerCrateMass or 0) if cargoObj.Location then txt = txt.."[R]" end local stock = cargoObj:GetStock() if stock >= 0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end @@ -4576,7 +4582,8 @@ function CTLD:_RefreshF10Menus() end for _, cargoObj in pairs(self.Cargo_Statics) do if not cargoObj.DontShowInMenu then - local txt = string.format("Crate %s (%dkg)", cargoObj.Name, cargoObj.PerCrateMass or 0) + local needed = cargoObj:GetCratesNeeded() or 1 + local txt = string.format("%d crate%s %s (%dkg)", needed, needed==1 and "" or "s", cargoObj.Name, cargoObj.PerCrateMass or 0) if cargoObj.Location then txt = txt.."[R]" end local stock = cargoObj:GetStock() if stock >= 0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end @@ -4586,7 +4593,8 @@ function CTLD:_RefreshF10Menus() else for _, cargoObj in pairs(self.Cargo_Crates) do if not cargoObj.DontShowInMenu then - local txt = string.format("Crate %s (%dkg)", cargoObj.Name, cargoObj.PerCrateMass or 0) + local needed = cargoObj:GetCratesNeeded() or 1 + local txt = string.format("%d crate%s %s (%dkg)", needed, needed==1 and "" or "s", cargoObj.Name, cargoObj.PerCrateMass or 0) if cargoObj.Location then txt = txt.."[R]" end local stock = cargoObj:GetStock() if stock >= 0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end @@ -4595,7 +4603,8 @@ function CTLD:_RefreshF10Menus() end for _, cargoObj in pairs(self.Cargo_Statics) do if not cargoObj.DontShowInMenu then - local txt = string.format("Crate %s (%dkg)", cargoObj.Name, cargoObj.PerCrateMass or 0) + local needed = cargoObj:GetCratesNeeded() or 1 + local txt = string.format("%d crate%s %s (%dkg)", needed, needed==1 and "" or "s", cargoObj.Name, cargoObj.PerCrateMass or 0) if cargoObj.Location then txt = txt.."[R]" end local stock = cargoObj:GetStock() if stock >= 0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end @@ -5427,6 +5436,50 @@ function CTLD:AddCratesCargo(Name,Templates,Type,NoCrates,PerCrateMass,Stock,Sub return self end +--- Identical to AddCratesCargo, but registers the cargo so the spawned/built group does not move to MOVE zones. +--- User function - Add *generic* crate-type loadable as cargo. This type will create crates that need to be loaded, moved, dropped and built. +-- @param #CTLD self +-- @param #string Name Unique name of this type of cargo. E.g. "Humvee". +-- @param #table Templates Table of #string names of late activated Wrapper.Group#GROUP building this cargo. +-- @param #CTLD_CARGO.Enum Type Type of cargo. I.e. VEHICLE or FOB. VEHICLE will move to destination zones when dropped/build, FOB stays put. +-- @param #number NoCrates Number of crates needed to build this cargo. +-- @param #number PerCrateMass Mass in kg of each crate +-- @param #number Stock Number of buildable groups in stock. Nil for unlimited. +-- @param #string SubCategory Name of sub-category (optional). +-- @param #boolean DontShowInMenu (optional) If set to "true" this won't show up in the menu. +-- @param Core.Zone#ZONE Location (optional) If set, the cargo item is **only** available here. Can be a #ZONE object or the name of a zone as #string. +-- @param #string UnitTypes Unit type names (optional). If set, only these unit types can pick up the cargo, e.g. "UH-1H" or {"UH-1H","OH58D"}. +-- @param #string Category Static category name (optional). If set, spawn cargo crate with an alternate category type, e.g. "Cargos". +-- @param #string TypeName Static type name (optional). If set, spawn cargo crate with an alternate type shape, e.g. "iso_container". +-- @param #string ShapeName Static shape name (optional). If set, spawn cargo crate with an alternate type sub-shape, e.g. "iso_container_cargo". +-- @return #CTLD self +function CTLD:AddCratesCargoNoMove(Name,Templates,Type,NoCrates,PerCrateMass,Stock,SubCategory,DontShowInMenu,Location,UnitTypes,Category,TypeName,ShapeName) + self:T(self.lid .. " AddCratesCargoNoMove") + if not self:_CheckTemplates(Templates) then + self:E(self.lid .. "Crates Cargo for " .. Name .. " has missing template(s)!" ) + return self + end + self.CargoCounter = self.CargoCounter + 1 + -- Crates are not directly loadable + local cargo = CTLD_CARGO:New(self.CargoCounter,Name,Templates,Type,false,false,NoCrates,nil,nil,PerCrateMass,Stock,SubCategory,DontShowInMenu,Location) + if UnitTypes then + cargo:AddUnitTypeName(UnitTypes) + end + cargo:SetStaticTypeAndShape("Cargos",self.basetype) + if TypeName then + cargo:SetStaticTypeAndShape(Category,TypeName,ShapeName) + end + table.insert(self.Cargo_Crates,cargo) + if SubCategory and self.usesubcats ~= true then self.usesubcats=true end + self.nomovetozone_templates = self.nomovetozone_templates or {} + if type(Templates)=="table" then + for _,t in pairs(Templates) do self.nomovetozone_templates[t] = true end + else + self.nomovetozone_templates[Templates] = true + end + return self +end + --- User function - Add *generic* static-type loadable as cargo. This type will create cargo that needs to be loaded, moved and dropped. -- @param #CTLD self -- @param #string Name Unique name of this type of cargo as set in the mission editor (note: UNIT name!), e.g. "Ammunition-1". @@ -7496,7 +7549,14 @@ end function CTLD:onafterCratesBuild(From, Event, To, Group, Unit, Vehicle) self:T({From, Event, To}) if self.movetroopstowpzone then - self:_MoveGroupToZone(Vehicle) + local gname = Vehicle and Vehicle:GetName() or nil + local block = false + if gname and self.nomovetozone_templates then + for t,_ in pairs(self.nomovetozone_templates) do + if gname==t or string.sub(gname,1,#t+1)==t.."-" then block = true break end + end + end + if not block then self:_MoveGroupToZone(Vehicle) end end return self end From 8c07573f8f02ca66905f935f7324b26a96ec8e61 Mon Sep 17 00:00:00 2001 From: leka1986 <83298840+leka1986@users.noreply.github.com> Date: Fri, 24 Oct 2025 16:13:18 +0200 Subject: [PATCH 232/234] Update CTLD.lua --- Moose Development/Moose/Ops/CTLD.lua | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/Moose Development/Moose/Ops/CTLD.lua b/Moose Development/Moose/Ops/CTLD.lua index e9d413642..3f844a1a8 100644 --- a/Moose Development/Moose/Ops/CTLD.lua +++ b/Moose Development/Moose/Ops/CTLD.lua @@ -119,6 +119,7 @@ CTLD_CARGO = { -- @param #boolean DontShowInMenu Show this item in menu or not (default: false == show it). -- @param Core.Zone#ZONE Location (optional) Where the cargo is available (one location only). -- @return #CTLD_CARGO self + function CTLD_CARGO:New(ID, Name, Templates, Sorte, HasBeenMoved, LoadDirectly, CratesNeeded, Positionable, Dropped, PerCrateMass, Stock, Subcategory, DontShowInMenu, Location) function CTLD_CARGO:New(ID, Name, Templates, Sorte, HasBeenMoved, LoadDirectly, CratesNeeded, Positionable, Dropped, PerCrateMass, Stock, Subcategory, DontShowInMenu, Location) -- Inherit everything from BASE class. local self=BASE:Inherit(self, BASE:New()) -- #CTLD_CARGO @@ -147,6 +148,7 @@ CTLD_CARGO = { Location = ZONE:New(Location) end self.Location = Location + self.NoMoveToZone = false return self end @@ -5460,8 +5462,8 @@ function CTLD:AddCratesCargoNoMove(Name,Templates,Type,NoCrates,PerCrateMass,Sto return self end self.CargoCounter = self.CargoCounter + 1 - -- Crates are not directly loadable local cargo = CTLD_CARGO:New(self.CargoCounter,Name,Templates,Type,false,false,NoCrates,nil,nil,PerCrateMass,Stock,SubCategory,DontShowInMenu,Location) + cargo.NoMoveToZone = true if UnitTypes then cargo:AddUnitTypeName(UnitTypes) end @@ -5470,13 +5472,15 @@ function CTLD:AddCratesCargoNoMove(Name,Templates,Type,NoCrates,PerCrateMass,Sto cargo:SetStaticTypeAndShape(Category,TypeName,ShapeName) end table.insert(self.Cargo_Crates,cargo) - if SubCategory and self.usesubcats ~= true then self.usesubcats=true end - self.nomovetozone_templates = self.nomovetozone_templates or {} + self.templateToCargoName = self.templateToCargoName or {} if type(Templates)=="table" then - for _,t in pairs(Templates) do self.nomovetozone_templates[t] = true end + for _,t in pairs(Templates) do self.templateToCargoName[t] = Name end else - self.nomovetozone_templates[Templates] = true + self.templateToCargoName[Templates] = Name end + self.nomovetozone_names = self.nomovetozone_names or {} + self.nomovetozone_names[Name] = true + if SubCategory and self.usesubcats ~= true then self.usesubcats=true end return self end @@ -7548,15 +7552,11 @@ end -- @return #CTLD self function CTLD:onafterCratesBuild(From, Event, To, Group, Unit, Vehicle) self:T({From, Event, To}) - if self.movetroopstowpzone then - local gname = Vehicle and Vehicle:GetName() or nil - local block = false - if gname and self.nomovetozone_templates then - for t,_ in pairs(self.nomovetozone_templates) do - if gname==t or string.sub(gname,1,#t+1)==t.."-" then block = true break end - end + if self.movetroopstowpzone and Vehicle then + local cg = self:GetGenericCargoObjectFromGroupName(Vehicle:GetName()) + if not (cg and (cg.NoMoveToZone or (self.nomovetozone_names and self.nomovetozone_names[cg:GetName()]))) then + self:_MoveGroupToZone(Vehicle) end - if not block then self:_MoveGroupToZone(Vehicle) end end return self end From 86798ae9ea7dc803059feb3f367cfedaf0fe1131 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Fri, 24 Oct 2025 16:27:17 +0200 Subject: [PATCH 233/234] #CTLD - fix --- Moose Development/Moose/Ops/CTLD.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/Moose Development/Moose/Ops/CTLD.lua b/Moose Development/Moose/Ops/CTLD.lua index 3f844a1a8..87d394e01 100644 --- a/Moose Development/Moose/Ops/CTLD.lua +++ b/Moose Development/Moose/Ops/CTLD.lua @@ -119,7 +119,6 @@ CTLD_CARGO = { -- @param #boolean DontShowInMenu Show this item in menu or not (default: false == show it). -- @param Core.Zone#ZONE Location (optional) Where the cargo is available (one location only). -- @return #CTLD_CARGO self - function CTLD_CARGO:New(ID, Name, Templates, Sorte, HasBeenMoved, LoadDirectly, CratesNeeded, Positionable, Dropped, PerCrateMass, Stock, Subcategory, DontShowInMenu, Location) function CTLD_CARGO:New(ID, Name, Templates, Sorte, HasBeenMoved, LoadDirectly, CratesNeeded, Positionable, Dropped, PerCrateMass, Stock, Subcategory, DontShowInMenu, Location) -- Inherit everything from BASE class. local self=BASE:Inherit(self, BASE:New()) -- #CTLD_CARGO From 3da618778278fe81a785ccb3b67937556f1af02f Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sat, 25 Oct 2025 16:53:53 +0200 Subject: [PATCH 234/234] #AUFTRAG, #OPSGROUP - close issue #2201 --- Moose Development/Moose/Ops/Auftrag.lua | 4 +++- Moose Development/Moose/Ops/OpsGroup.lua | 7 ++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Ops/Auftrag.lua b/Moose Development/Moose/Ops/Auftrag.lua index f14440690..a425eacae 100644 --- a/Moose Development/Moose/Ops/Auftrag.lua +++ b/Moose Development/Moose/Ops/Auftrag.lua @@ -2324,8 +2324,9 @@ end -- @param #number Speed Speed in knots. -- @param #number Altitude Altitude in feet. Only for airborne units. Default 2000 feet ASL. -- @param #string Formation Formation used by ground units during patrol. Default "Off Road". +-- @param #number StayInZoneTime Stay this many seconds in the zone when done, only then drive back. -- @return #AUFTRAG self -function AUFTRAG:NewCAPTUREZONE(OpsZone, Coalition, Speed, Altitude, Formation) +function AUFTRAG:NewCAPTUREZONE(OpsZone, Coalition, Speed, Altitude, Formation, StayInZoneTime) local mission=AUFTRAG:New(AUFTRAG.Type.CAPTUREZONE) @@ -2339,6 +2340,7 @@ function AUFTRAG:NewCAPTUREZONE(OpsZone, Coalition, Speed, Altitude, Formation) mission.optionROE=ENUMS.ROE.ReturnFire mission.optionROT=ENUMS.ROT.PassiveDefense mission.optionAlarm=ENUMS.AlarmState.Auto + mission.StayInZoneTime = StayInZoneTime mission.missionFraction=0.1 mission.missionSpeed=Speed and UTILS.KnotsToKmph(Speed) or nil diff --git a/Moose Development/Moose/Ops/OpsGroup.lua b/Moose Development/Moose/Ops/OpsGroup.lua index 4a49abaef..24fc98f2d 100644 --- a/Moose Development/Moose/Ops/OpsGroup.lua +++ b/Moose Development/Moose/Ops/OpsGroup.lua @@ -4631,7 +4631,12 @@ function OPSGROUP:_UpdateTask(Task, Mission) self:T(self.lid..string.format("Zone %s captured ==> Task DONE!", zoneCurr:GetName())) -- Task done. - self:TaskDone(Task) + if Task.StayInZoneTime then + local stay = Task.StayInZoneTime + self:__TaskDone(stay,Task) + else + self:TaskDone(Task) + end else -- Current zone NOT captured yet ==> Find Target