From 3fa5c920581f159ea882f622454c1002bbdcf6ed Mon Sep 17 00:00:00 2001 From: Shafik Date: Mon, 20 Oct 2025 14:57:01 +0300 Subject: [PATCH 1/5] [ADDED] `UNIT:IsEWR()` --- Moose Development/Moose/Ops/CTLD.lua | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/Moose Development/Moose/Ops/CTLD.lua b/Moose Development/Moose/Ops/CTLD.lua index 7e3fadcfd..5b09d4e19 100644 --- a/Moose Development/Moose/Ops/CTLD.lua +++ b/Moose Development/Moose/Ops/CTLD.lua @@ -4462,8 +4462,8 @@ end end end -function CTLD:_UnloadSingleTroopByID(Group, Unit, cargoID) - self:T(self.lid .. " _UnloadSingleTroopByID for cargo ID " .. tostring(cargoID)) +function CTLD:_UnloadSingleTroopByName(Group, Unit, CargoName) + self:T(self.lid .. " _UnloadSingleTroopByID for cargo ID " .. tostring(CargoName)) -- check if we are in LOAD zone local droppingatbase = false @@ -4511,7 +4511,7 @@ function CTLD:_UnloadSingleTroopByID(Group, Unit, cargoID) for _, cargoObj in ipairs(cargoList) do if (cargoObj:GetType() == CTLD_CARGO.Enum.TROOPS or cargoObj:GetType() == CTLD_CARGO.Enum.ENGINEERS) and not cargoObj:WasDropped() - and (cargoObj:GetID() == cargoID) + and (cargoObj:GetName() == CargoName) then foundCargo = cargoObj break @@ -4593,7 +4593,7 @@ function CTLD:_UnloadSingleTroopByID(Group, Unit, cargoID) local cargoList = loadedCargoData.Cargo or {} for _, cObj in ipairs(cargoList) do if (cObj:GetType() == CTLD_CARGO.Enum.TROOPS or cObj:GetType() == CTLD_CARGO.Enum.ENGINEERS) - and (cObj:GetID() == cargoID) + and (cObj:GetName() == CargoName) then -- Return this one cargo to stock local cName = cObj:GetName() @@ -4608,6 +4608,7 @@ function CTLD:_UnloadSingleTroopByID(Group, Unit, cargoID) end -- Mark it as dropped so we remove it from the loaded cargo cObj:SetWasDropped(true) + break end end end @@ -4671,6 +4672,20 @@ function CTLD:_RefreshDropTroopsMenu(Group, Unit) MENU_GROUP_COMMAND:New(theGroup,"Drop ALL troops",dropTroopsMenu,self._UnloadTroops,self,theGroup,theUnit) local loadedData=self.Loaded_Cargo[theUnit:GetName()] if loadedData and loadedData.Cargo then + local loaded = {} + for i,cargoObj in ipairs(loadedData.Cargo) do + if cargoObj and (cargoObj:GetType()==CTLD_CARGO.Enum.TROOPS or cargoObj:GetType()==CTLD_CARGO.Enum.ENGINEERS) + and not cargoObj:WasDropped() + then + local name=cargoObj:GetName()or"Unknown" + loaded[name]=loaded[name] or 0 + end + end + + for name,count in pairs(loaded) do + local line=string.format("Drop %s (%d)",name,count) + MENU_GROUP_COMMAND:New(theGroup,line,dropTroopsMenu,self._UnloadSingleTroopByID,self,theGroup,theUnit,name) + end for i,cargoObj in ipairs(loadedData.Cargo) do if cargoObj and (cargoObj:GetType()==CTLD_CARGO.Enum.TROOPS or cargoObj:GetType()==CTLD_CARGO.Enum.ENGINEERS) and not cargoObj:WasDropped() From 5929b7b0ed7c98fbc3ec9ed58c6ed486c04bcb68 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sun, 16 Nov 2025 16:53:59 +0100 Subject: [PATCH 2/5] #COORDINATE * Remove POINT_VEC2/3 classses --- Moose Development/Moose/Core/Point.lua | 170 ------------------------- 1 file changed, 170 deletions(-) diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index 729a5116d..066c358ec 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -3,8 +3,6 @@ -- ## Features: -- -- * Provides a COORDINATE class, which allows to manage points in 3D space and perform various operations on it. --- * Provides a POINT\_VEC2 class, which is derived from COORDINATE, and allows to manage points in 3D space, but from a Lat/Lon and Altitude perspective. --- * Provides a POINT\_VEC3 class, which is derived from COORDINATE, and allows to manage points in 3D space, but from a X, Z and Y vector perspective. -- -- === -- @@ -3875,171 +3873,3 @@ do -- COORDINATE end end - -do - - --- The POINT_VEC3 class - -- @type POINT_VEC3 - -- @field #number x The x coordinate in 3D space. - -- @field #number y The y coordinate in 3D space. - -- @field #number z The z COORDINATE in 3D space. - -- @field Utilities.Utils#SMOKECOLOR SmokeColor - -- @field Utilities.Utils#FLARECOLOR FlareColor - -- @field #POINT_VEC3.RoutePointAltType RoutePointAltType - -- @field #POINT_VEC3.RoutePointType RoutePointType - -- @field #POINT_VEC3.RoutePointAction RoutePointAction - -- @extends #COORDINATE - - - --- Defines a 3D point in the simulator and with its methods, you can use or manipulate the point in 3D space. - -- - -- **DEPRECATED - PLEASE USE COORDINATE!** - -- - -- **Important Note:** Most of the functions in this section were taken from MIST, and reworked to OO concepts. - -- In order to keep the credibility of the the author, - -- I want to emphasize that the formulas embedded in the MIST framework were created by Grimes or previous authors, - -- who you can find on the Eagle Dynamics Forums. - -- - -- - -- ## POINT_VEC3 constructor - -- - -- A new POINT_VEC3 object can be created with: - -- - -- * @{#POINT_VEC3.New}(): a 3D point. - -- * @{#POINT_VEC3.NewFromVec3}(): a 3D point created from a @{DCS#Vec3}. - -- - -- - -- ## Manupulate the X, Y, Z coordinates of the POINT_VEC3 - -- - -- A POINT_VEC3 class works in 3D space. It contains internally an X, Y, Z coordinate. - -- Methods exist to manupulate these coordinates. - -- - -- The current X, Y, Z axis can be retrieved with the methods @{#POINT_VEC3.GetX}(), @{#POINT_VEC3.GetY}(), @{#POINT_VEC3.GetZ}() respectively. - -- The methods @{#POINT_VEC3.SetX}(), @{#POINT_VEC3.SetY}(), @{#POINT_VEC3.SetZ}() change the respective axis with a new value. - -- The current axis values can be changed by using the methods @{#POINT_VEC3.AddX}(), @{#POINT_VEC3.AddY}(), @{#POINT_VEC3.AddZ}() - -- to add or substract a value from the current respective axis value. - -- Note that the Set and Add methods return the current POINT_VEC3 object, so these manipulation methods can be chained... For example: - -- - -- local Vec3 = PointVec3:AddX( 100 ):AddZ( 150 ):GetVec3() - -- - -- - -- ## 3D calculation methods - -- - -- Various calculation methods exist to use or manipulate 3D space. Find below a short description of each method: - -- - -- - -- ## Point Randomization - -- - -- Various methods exist to calculate random locations around a given 3D point. - -- - -- * @{#POINT_VEC3.GetRandomPointVec3InRadius}(): Provides a random 3D point around the current 3D point, in the given inner to outer band. - -- - -- - -- @field #POINT_VEC3 - POINT_VEC3 = { - ClassName = "POINT_VEC3", - Metric = true, - RoutePointAltType = { - BARO = "BARO", - }, - RoutePointType = { - TakeOffParking = "TakeOffParking", - TurningPoint = "Turning Point", - }, - RoutePointAction = { - FromParkingArea = "From Parking Area", - TurningPoint = "Turning Point", - }, - } - - --- RoutePoint AltTypes - -- @type POINT_VEC3.RoutePointAltType - -- @field BARO "BARO" - - --- RoutePoint Types - -- @type POINT_VEC3.RoutePointType - -- @field TakeOffParking "TakeOffParking" - -- @field TurningPoint "Turning Point" - - --- RoutePoint Actions - -- @type POINT_VEC3.RoutePointAction - -- @field FromParkingArea "From Parking Area" - -- @field TurningPoint "Turning Point" - - -- Constructor. - - --- Create a new POINT_VEC3 object. - -- @param #POINT_VEC3 self - -- @param DCS#Distance x The x coordinate of the Vec3 point, pointing to the North. - -- @param DCS#Distance y The y coordinate of the Vec3 point, pointing Upwards. - -- @param DCS#Distance z The z coordinate of the Vec3 point, pointing to the Right. - -- @return Core.Point#POINT_VEC3 - function POINT_VEC3:New( x, y, z ) - - local self = BASE:Inherit( self, COORDINATE:New( x, y, z ) ) -- Core.Point#POINT_VEC3 - self:F2( self ) - - return self - end - -end - -do - - --- @type POINT_VEC2 - -- @field DCS#Distance x The x coordinate in meters. - -- @field DCS#Distance y the y coordinate in meters. - -- @extends Core.Point#COORDINATE - - --- Defines a 2D point in the simulator. The height coordinate (if needed) will be the land height + an optional added height specified. - -- - -- **DEPRECATED - PLEASE USE COORDINATE!** - -- - -- ## POINT_VEC2 constructor - -- - -- A new POINT_VEC2 instance can be created with: - -- - -- * @{Core.Point#POINT_VEC2.New}(): a 2D point, taking an additional height parameter. - -- * @{Core.Point#POINT_VEC2.NewFromVec2}(): a 2D point created from a @{DCS#Vec2}. - -- - -- ## Manupulate the X, Altitude, Y coordinates of the 2D point - -- - -- A POINT_VEC2 class works in 2D space, with an altitude setting. It contains internally an X, Altitude, Y coordinate. - -- Methods exist to manupulate these coordinates. - -- - -- The current X, Altitude, Y axis can be retrieved with the methods @{#POINT_VEC2.GetX}(), @{#POINT_VEC2.GetAlt}(), @{#POINT_VEC2.GetY}() respectively. - -- The methods @{#POINT_VEC2.SetX}(), @{#POINT_VEC2.SetAlt}(), @{#POINT_VEC2.SetY}() change the respective axis with a new value. - -- The current Lat(itude), Alt(itude), Lon(gitude) values can also be retrieved with the methods @{#POINT_VEC2.GetLat}(), @{#POINT_VEC2.GetAlt}(), @{#POINT_VEC2.GetLon}() respectively. - -- The current axis values can be changed by using the methods @{#POINT_VEC2.AddX}(), @{#POINT_VEC2.AddAlt}(), @{#POINT_VEC2.AddY}() - -- to add or substract a value from the current respective axis value. - -- Note that the Set and Add methods return the current POINT_VEC2 object, so these manipulation methods can be chained... For example: - -- - -- local Vec2 = PointVec2:AddX( 100 ):AddY( 2000 ):GetVec2() - -- - -- @field #POINT_VEC2 - POINT_VEC2 = { - ClassName = "POINT_VEC2", - } - - - - --- POINT_VEC2 constructor. - -- @param #POINT_VEC2 self - -- @param DCS#Distance x The x coordinate of the Vec3 point, pointing to the North. - -- @param DCS#Distance y The y coordinate of the Vec3 point, pointing to the Right. - -- @param DCS#Distance LandHeightAdd (optional) The default height if required to be evaluated will be the land height of the x, y coordinate. You can specify an extra height to be added to the land height. - -- @return Core.Point#POINT_VEC2 - function POINT_VEC2:New( x, y, LandHeightAdd ) - - local LandHeight = land.getHeight( { ["x"] = x, ["y"] = y } ) - - LandHeightAdd = LandHeightAdd or 0 - LandHeight = LandHeight + LandHeightAdd - - local self = BASE:Inherit( self, COORDINATE:New( x, LandHeight, y ) ) -- Core.Point#POINT_VEC2 - self:F2( self ) - - return self - end - -end From 5d1123e7df5a5578924c48a5dd93386739269191 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sun, 16 Nov 2025 16:54:04 +0100 Subject: [PATCH 3/5] xx --- Moose Development/Moose/Navigation/Beacons.lua | 1 + Moose Development/Moose/Navigation/Radios.lua | 1 + Moose Development/Moose/Navigation/Towns.lua | 1 + 3 files changed, 3 insertions(+) diff --git a/Moose Development/Moose/Navigation/Beacons.lua b/Moose Development/Moose/Navigation/Beacons.lua index a391d1a0b..84ecf218d 100644 --- a/Moose Development/Moose/Navigation/Beacons.lua +++ b/Moose Development/Moose/Navigation/Beacons.lua @@ -43,6 +43,7 @@ -- -- **Note** that try to avoid hard coding stuff in Moose since DCS is updated frequently and things change. Therefore, the main source of information is either a file `beacons.lua` that can be -- found in the installation directory of DCS for each map or a table that the user needs to provide. +-- **Note** your `MissionScripting` environment needs to be desanitized to read this data. `Package` als needs to be available. -- -- # Basic Setup -- diff --git a/Moose Development/Moose/Navigation/Radios.lua b/Moose Development/Moose/Navigation/Radios.lua index d14a11d11..4fe1dad72 100644 --- a/Moose Development/Moose/Navigation/Radios.lua +++ b/Moose Development/Moose/Navigation/Radios.lua @@ -43,6 +43,7 @@ -- -- **Note** that try to avoid hard coding stuff in Moose since DCS is updated frequently and things change. Therefore, the main source of information is either a file `radio.lua` that can be -- found in the installation directory of DCS for each map or a table that the user needs to provide. +-- **Note** your `MissionScripting` environment needs to be desanitized to read this data. -- -- # Basic Setup -- diff --git a/Moose Development/Moose/Navigation/Towns.lua b/Moose Development/Moose/Navigation/Towns.lua index 71b75b307..3825854f9 100644 --- a/Moose Development/Moose/Navigation/Towns.lua +++ b/Moose Development/Moose/Navigation/Towns.lua @@ -43,6 +43,7 @@ -- -- **Note** that try to avoid hard coding stuff in Moose since DCS is updated frequently and things change. Therefore, the main source of information is either a file `towns.lua` that can be -- found in the installation directory of DCS for each map or a table that the user needs to provide. +-- **Note** your `MissionScripting` environment needs to be desanitized to read this data. -- -- # Basic Setup -- From 95e2bf4a21d59329275ffa8ac054beb11ffe11e7 Mon Sep 17 00:00:00 2001 From: Shafik Date: Sat, 22 Nov 2025 13:37:22 +0200 Subject: [PATCH 4/5] [FIXED] attempt to index local 'asset' (a nil value) --- Moose Development/Moose/Ops/OpsGroup.lua | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/Moose Development/Moose/Ops/OpsGroup.lua b/Moose Development/Moose/Ops/OpsGroup.lua index d3d212670..760e6d2e6 100644 --- a/Moose Development/Moose/Ops/OpsGroup.lua +++ b/Moose Development/Moose/Ops/OpsGroup.lua @@ -8019,14 +8019,16 @@ function OPSGROUP:onafterDead(From, Event, To) -- Get asset. local asset=self.legion:GetAssetByName(self.groupname) - - -- Get request. - local request=self.legion:GetRequestByID(asset.rid) - - -- Trigger asset dead event. - self.legion:AssetDead(asset, request) + + if asset then + -- Get request. + local request=self.legion:GetRequestByID(asset.rid) + + -- Trigger asset dead event. + self.legion:AssetDead(asset, request) + end end - + -- Stop in 5 sec to give possible respawn attempts a chance. self:__Stop(-5) From 9e55118d3e8e9c02e3d8b452a38447009159cf37 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sat, 22 Nov 2025 16:18:28 +0100 Subject: [PATCH 5/5] #AUFTRAG/#OPS/#RESCUEHELO - make the NewRescueHelo AUFTRAG use Ops.Rescuehelo as basis. #2199 --- Moose Development/Moose/Ops/Auftrag.lua | 2 +- Moose Development/Moose/Ops/OpsGroup.lua | 59 +++++++++++++++------- Moose Development/Moose/Ops/RescueHelo.lua | 36 +++++++++---- 3 files changed, 68 insertions(+), 29 deletions(-) diff --git a/Moose Development/Moose/Ops/Auftrag.lua b/Moose Development/Moose/Ops/Auftrag.lua index cdad223f1..a3ac50a46 100644 --- a/Moose Development/Moose/Ops/Auftrag.lua +++ b/Moose Development/Moose/Ops/Auftrag.lua @@ -2037,7 +2037,7 @@ function AUFTRAG:NewRESCUEHELO(Carrier) -- Mission options: mission.missionTask=ENUMS.MissionTask.NOTHING - mission.missionFraction=0.5 + mission.missionFraction=0.9 mission.optionROE=ENUMS.ROE.WeaponHold mission.optionROT=ENUMS.ROT.NoReaction diff --git a/Moose Development/Moose/Ops/OpsGroup.lua b/Moose Development/Moose/Ops/OpsGroup.lua index 760e6d2e6..13b4597f4 100644 --- a/Moose Development/Moose/Ops/OpsGroup.lua +++ b/Moose Development/Moose/Ops/OpsGroup.lua @@ -4302,7 +4302,27 @@ function OPSGROUP:_UpdateTask(Task, Mission) Mission=Mission or self:GetMissionByTaskID(self.taskcurrent) if Task.dcstask.id==AUFTRAG.SpecialTask.FORMATION then - + + if Mission.type == AUFTRAG.Type.RESCUEHELO then + self:T("**********") + self:T("** RESCUEHELO USED") + self:T("**********") + local param=Task.dcstask.params + local followUnit=UNIT:FindByName(param.unitname) + local helogroupname = self:GetGroup():GetName() + Task.formation = RESCUEHELO:New(followUnit,helogroupname) + Task.formation:SetRespawnOnOff(false) + Task.formation.respawninair=false + Task.formation:SetTakeoffCold() + Task.formation:SetHomeBase(followUnit) + Task.formation.helo = self:GetGroup() + -- Start formation FSM. + Task.formation:Start() + if self:IsFlightgroup() then + self:SetDespawnAfterLanding() + end + else + -- Set of group(s) to follow Mother. local followSet=SET_GROUP:New():AddGroup(self.group) @@ -4320,11 +4340,13 @@ function OPSGROUP:_UpdateTask(Task, Mission) Task.formation:SetFollowTimeInterval(param.dtFollow) -- Formation mode. - Task.formation:SetFlightModeFormation(self.group) + --Task.formation:SetFlightModeFormation(self.group) -- Start formation FSM. Task.formation:Start() - + + end + elseif Task.dcstask.id==AUFTRAG.SpecialTask.PATROLZONE then --- @@ -8019,16 +8041,19 @@ function OPSGROUP:onafterDead(From, Event, To) -- Get asset. local asset=self.legion:GetAssetByName(self.groupname) - + if asset then - -- Get request. - local request=self.legion:GetRequestByID(asset.rid) - - -- Trigger asset dead event. - self.legion:AssetDead(asset, request) + + -- Get request. + local request=self.legion:GetRequestByID(asset.rid) + + -- Trigger asset dead event. + self.legion:AssetDead(asset, request) + end + end - + -- Stop in 5 sec to give possible respawn attempts a chance. self:__Stop(-5) @@ -12719,7 +12744,7 @@ end -- @return #OPSGROUP self function OPSGROUP:SetDefaultCallsign(CallsignName, CallsignNumber) - self:T(self.lid..string.format("Setting Default callsing %s-%s", tostring(CallsignName), tostring(CallsignNumber))) + self:T(self.lid..string.format("Setting Default callsign %s-%s", tostring(CallsignName), tostring(CallsignNumber))) self.callsignDefault={} --#OPSGROUP.Callsign self.callsignDefault.NumberSquad=CallsignName @@ -13478,8 +13503,8 @@ function OPSGROUP:GetAmmoUnit(unit, display) if ammotable then local weapons=#ammotable - --self:I(ammotable) - --UTILS.PrintTableToLog(ammotable) + --self:I(ammotable) + --UTILS.PrintTableToLog(ammotable) -- Loop over all weapons. for w=1,weapons do @@ -13487,9 +13512,9 @@ function OPSGROUP:GetAmmoUnit(unit, display) -- Number of current weapon. local Nammo=ammotable[w]["count"] - -- Range in meters. Seems only to exist for missiles (not shells). - local rmin=ammotable[w]["desc"]["rangeMin"] or 0 - local rmax=ammotable[w]["desc"]["rangeMaxAltMin"] or 0 + -- Range in meters. Seems only to exist for missiles (not shells). + local rmin=ammotable[w]["desc"]["rangeMin"] or 0 + local rmax=ammotable[w]["desc"]["rangeMaxAltMin"] or 0 -- Type name of current weapon. local Tammo=ammotable[w]["desc"]["typeName"] @@ -13511,7 +13536,7 @@ function OPSGROUP:GetAmmoUnit(unit, display) -- Add up all shells. nshells=nshells+Nammo - + -- Add small and large caliber shells for guns and cannons if ammotable[w]["desc"]["warhead"] and ammotable[w]["desc"]["warhead"]["caliber"] then local caliber=ammotable[w]["desc"]["warhead"]["caliber"] diff --git a/Moose Development/Moose/Ops/RescueHelo.lua b/Moose Development/Moose/Ops/RescueHelo.lua index 954735153..62b54cfa8 100644 --- a/Moose Development/Moose/Ops/RescueHelo.lua +++ b/Moose Development/Moose/Ops/RescueHelo.lua @@ -234,7 +234,7 @@ _RESCUEHELOID=0 --- Class version. -- @field #string version -RESCUEHELO.version="1.1.0" +RESCUEHELO.version="1.2.0" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO list @@ -247,6 +247,7 @@ RESCUEHELO.version="1.1.0" -- DONE: Possibility to add already present/spawned aircraft, e.g. for warehouse. -- DONE: Add rescue event when aircraft crashes. -- DONE: Make offset input parameter. +-- DONE: Make useable for AUFTRAG ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- Constructor @@ -336,6 +337,9 @@ function RESCUEHELO:New(carrierunit, helogroupname) self:AddTransition("*", "Status", "*") self:AddTransition("*", "Stop", "Stopped") + + self:I(self.lid.."Started.") + --- Triggers the FSM event "Start" that starts the rescue helo. Initializes parameters and starts event handlers. -- @function [parent=#RESCUEHELO] Start @@ -870,15 +874,25 @@ function RESCUEHELO:onafterStart(From, Event, To) -- Delay before formation is started. local delay=120 - - -- Spawn helo. We need to introduce an alias in case this class is used twice. This would confuse the spawn routine. - local Spawn=SPAWN:NewWithAlias(self.helogroupname, self.alias) - -- Set modex for spawn. - Spawn:InitModex(self.modex) - + local UsesAliveGroup=false + local Spawn = GROUP:FindByName(self.helogroupname) + if Spawn and Spawn:IsAlive() then + self.helo=Spawn + UsesAliveGroup = true + delay = 1 + else + + -- Spawn helo. We need to introduce an alias in case this class is used twice. This would confuse the spawn routine. + local Spawn=SPAWN:NewWithAlias(self.helogroupname, self.alias) + + -- Set modex for spawn. + Spawn:InitModex(self.modex) + + end + -- Spawn in air or at airbase. - if self.takeoff==SPAWN.Takeoff.Air then + if UsesAliveGroup==false and self.takeoff==SPAWN.Takeoff.Air then -- Carrier heading local hdg=self.carrier:GetHeading() @@ -898,7 +912,7 @@ function RESCUEHELO:onafterStart(From, Event, To) -- Start formation in 1 seconds delay=1 - else + elseif UsesAliveGroup==false and self.uncontrolledac then -- Check if an uncontrolled helo group was requested. if self.uncontrolledac then @@ -918,9 +932,9 @@ function RESCUEHELO:onafterStart(From, Event, To) -- No group of that name! self:E(string.format("ERROR: No uncontrolled (alive) rescue helo group with name %s could be found!", self.helogroupname)) return - end + end - else + elseif UsesAliveGroup==false then -- Spawn at airbase. self.helo=Spawn:SpawnAtAirbase(self.airbase, self.takeoff, nil, AIRBASE.TerminalType.HelicopterUsable)