From b51e758516150d45a841a4d51d7373fb3e61f681 Mon Sep 17 00:00:00 2001 From: smiki Date: Tue, 30 Sep 2025 21:17:29 +0200 Subject: [PATCH 01/39] [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 02/39] [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 03/39] [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 04/39] [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 05/39] [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 06/39] #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 07/39] #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 08/39] [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 09/39] 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 10/39] 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 11/39] 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 12/39] #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 13/39] [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 14/39] 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 15/39] #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 16/39] #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 17/39] #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 18/39] 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 19/39] 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 20/39] [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 21/39] #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 22/39] [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 23/39] #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 24/39] [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 25/39] #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 26/39] #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 27/39] #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 28/39] 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 29/39] #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 30/39] 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 31/39] 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 32/39] 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 33/39] 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 34/39] #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 35/39] #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 36/39] 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 37/39] 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 38/39] #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 39/39] #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