diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index e99cd3e7e..e007998ce 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -294,15 +294,18 @@ do -- COORDINATE --- Returns if the 2 coordinates are at the same 2D position. -- @param #COORDINATE self - -- @param #number radius Scan radius in meters. + -- @param #number radius (Optional) Scan radius in meters. Default 100 m. + -- @param #boolean scanunits (Optional) If true scan for units. Default true. + -- @param #boolean scanstatics (Optional) If true scan for static objects. Default true. + -- @param #boolean scanscenery (Optional) If true scan for scenery objects. Default false. -- @return True if units were found. -- @return True if statics were found. -- @return True if scenery objects were found. -- @return Unit objects found. -- @return Static objects found. -- @return Scenery objects found. - function COORDINATE:ScanObjects(radius) - self:T(string.format("Scanning in radius %.1f m.", radius)) + function COORDINATE:ScanObjects(radius, scanunits, scanstatics, scanscenery) + self:F(string.format("Scanning in radius %.1f m.", radius)) local SphereSearch = { id = world.VolumeType.SPHERE, @@ -312,6 +315,30 @@ do -- COORDINATE } } + -- Defaults + radius=radius or 100 + if scanunits==nil then + scanunits=true + end + if scanstatics==nil then + scanstatics=true + end + if scanscenery==nil then + scanscenery=false + end + + --{Object.Category.UNIT, Object.Category.STATIC, Object.Category.SCENERY} + local scanobjects={} + if scanunits then + table.insert(scanobjects, Object.Category.UNIT) + end + if scanstatics then + table.insert(scanobjects, Object.Category.STATIC) + end + if scanscenery then + table.insert(scanobjects, Object.Category.SCENERY) + end + -- Found stuff. local Units = {} local Statics = {} @@ -352,7 +379,7 @@ do -- COORDINATE end -- Search the world. - world.searchObjects({Object.Category.UNIT, Object.Category.STATIC, Object.Category.SCENERY}, SphereSearch, EvaluateZone) + world.searchObjects(scanobjects, SphereSearch, EvaluateZone) for _,unit in pairs(Units) do self:T(string.format("Scan found unit %s", unit:getName())) @@ -361,7 +388,7 @@ do -- COORDINATE self:T(string.format("Scan found static %s", static:getName())) end for _,scenery in pairs(Scenery) do - self:T(string.format("Scan found scenery %s", scenery:getName())) + self:T(string.format("Scan found scenery %s", scenery:getTypeName())) end return gotunits, gotstatics, gotscenery, Units, Statics, Scenery @@ -1021,22 +1048,28 @@ do -- COORDINATE --- Gets the nearest parking spot. -- @param #COORDINATE self - -- @param #boolean free (Optional) Only look for free parking spots. By default the closest parking spot is returned regardless of whether it is free or not. - -- @param Wrapper.Airbase#AIRBASE airbase (Optional) Search only parking spots at that airbase. - -- @param Wrapper.Airbase#Terminaltype terminaltype Type of the terminal. + -- @param Wrapper.Airbase#AIRBASE airbase (Optional) Search only parking spots at this airbase. + -- @param Wrapper.Airbase#Terminaltype terminaltype (Optional) Type of the terminal. Default any execpt valid spawn points on runway. + -- @param #boolean free (Optional) If true, returns the closest free spot. If false, returns the closest occupied spot. If nil, returns the closest spot regardless of free or occupied. -- @return Core.Point#COORDINATE Coordinate of the nearest parking spot. - -- @return #number Distance to closest parking spot. - function COORDINATE:GetClosestParkingSpot(free, airbase, terminaltype) - + -- @return #number Terminal ID. + -- @return #number Distance to closest parking spot in meters. + function COORDINATE:GetClosestParkingSpot(airbase, terminaltype, free) + + -- Get airbase table. local airbases={} if airbase then table.insert(airbases,airbase) else - airbases=AIRBASE:GetAllAirbases() + airbases=AIRBASE.GetAllAirbases() end + -- Init. local _closest=nil --Core.Point#COORDINATE + local _termID=nil local _distmin=nil + + -- Loop over all airbases. for _,_airbase in pairs(airbases) do local mybase=_airbase --Wrapper.Airbase#AIRBASE @@ -1044,44 +1077,51 @@ do -- COORDINATE for _,_spot in pairs(parkingdata) do - -- Get coordinate if it matches the requirements. - local _coord=nil --Core.Point#COORDINATE - if (free and _spot.Free) or free==nil then - if (terminaltype and _spot.TerminalType==terminaltype) or terminaltype==nil then - _coord=_spot.Coordinate - end - end - - -- Compare distance to closest one found so far. - if _coord then + -- Check for parameters. + if (free==true and _spot.Free==true) or (free==false and _spot.Free==false) or free==nil then + + local _coord=_spot.Coordinate --Core.Point#COORDINATE + local _dist=self:Get2DDistance(_coord) if _distmin==nil then _closest=_coord _distmin=_dist - else - local _dist=self:Get2DDistance(_coord) + _termID=_spot.TerminalID + else if _dist<_distmin then _distmin=_dist _closest=_coord + _termID=_spot.TerminalID end end - - end - + + end end end - - return _closest, _distmin + + return _closest, _termID, _distmin end --- Gets the nearest free parking spot. -- @param #COORDINATE self -- @param Wrapper.Airbase#AIRBASE airbase (Optional) Search only parking spots at that airbase. - -- @param Wrapper.Airbase#Terminaltype terminaltype Type of the terminal. + -- @param Wrapper.Airbase#Terminaltype terminaltype (Optional) Type of the terminal. -- @return #COORDINATE Coordinate of the nearest free parking spot. - -- @return #number Distance to closest free parking spot. + -- @return #number Terminal ID. + -- @return #number Distance to closest free parking spot in meters. function COORDINATE:GetClosestFreeParkingSpot(airbase, terminaltype) - return self:GetClosestParkingSpot(true, airbase, terminaltype) + return self:GetClosestParkingSpot(airbase, terminaltype, true) + end + + --- Gets the nearest occupied parking spot. + -- @param #COORDINATE self + -- @param Wrapper.Airbase#AIRBASE airbase (Optional) Search only parking spots at that airbase. + -- @param Wrapper.Airbase#Terminaltype terminaltype (Optional) Type of the terminal. + -- @return #COORDINATE Coordinate of the nearest occupied parking spot. + -- @return #number Terminal ID. + -- @return #number Distance to closest occupied parking spot in meters. + function COORDINATE:GetClosestOccupiedParkingSpot(airbase, terminaltype) + return self:GetClosestParkingSpot(airbase, terminaltype, false) end --- Gets the nearest coordinate to a road. diff --git a/Moose Development/Moose/Core/Spawn.lua b/Moose Development/Moose/Core/Spawn.lua index 3258feb80..ec7e7414d 100644 --- a/Moose Development/Moose/Core/Spawn.lua +++ b/Moose Development/Moose/Core/Spawn.lua @@ -1218,7 +1218,8 @@ end -- @param Wrapper.Airbase#AIRBASE SpawnAirbase The @{Wrapper.Airbase} where to spawn the group. -- @param #SPAWN.Takeoff Takeoff (optional) The location and takeoff method. Default is Hot. -- @param #number TakeoffAltitude (optional) The altitude above the ground. --- @param #number TerminalType (optional) The terminal type the aircraft should be spawned at. +-- @param Wrapper.Airbase#AIRBASE.TerminalType TerminalType (optional) The terminal type the aircraft should be spawned at. See @{Wrapper.Airbase#AIRBASE.TerminalType}. +-- @param #boolean EmergencyAirSpawn (optional) If true (default), groups are spawned in air if there is no parking spot at the airbase. If false, nothing is spawned if no parking spot is available. -- @return Wrapper.Group#GROUP that was spawned or nil when nothing was spawned. -- @usage -- Spawn_Plane = SPAWN:New( "Plane" ) @@ -1239,7 +1240,7 @@ end -- -- Spawn_Plane:SpawnAtAirbase( AIRBASE:FindByName( AIRBASE.Caucasus.Krymsk ), SPAWN.Takeoff.Cold, nil, AIRBASE.TerminalType.OpenBig ) -- -function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalType ) -- R2.2, R2.4 +function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalType, EmergencyAirSpawn ) -- R2.2, R2.4 self:F( { self.SpawnTemplatePrefix, SpawnAirbase, Takeoff, TakeoffAltitude, TerminalType } ) -- Get position of airbase. @@ -1249,6 +1250,11 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT -- Set take off type. Default is hot. Takeoff = Takeoff or SPAWN.Takeoff.Hot + -- By default, groups are spawned in air if no parking spot is available. + if EmergencyAirSpawn==nil then + EmergencyAirSpawn=true + end + if self:_GetSpawnIndex( self.SpawnIndex + 1 ) then -- Get group template. @@ -1259,9 +1265,13 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT -- Debug output self:T( { "Current point of ", self.SpawnTemplatePrefix, SpawnAirbase } ) - -- Template group and unit. + -- Template group, unit and its attributes. local TemplateGroup = GROUP:FindByName(self.SpawnTemplatePrefix) - local ishelo=TemplateGroup:GetUnit(1):HasAttribute("Helicopters") + local TemplateUnit=TemplateGroup:GetUnit(1) + local ishelo=TemplateUnit:HasAttribute("Helicopters") + local isbomber=TemplateUnit:HasAttribute("Bombers") + local istransport=TemplateUnit:HasAttribute("Transports") + local isfighter=TemplateUnit:HasAttribute("Battleplanes") -- First waypoint of the group. local SpawnPoint = SpawnTemplate.route.points[1] @@ -1332,32 +1342,64 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT -- Number of free parking spots at the airbase. if spawnonship or spawnonfarp or spawnonrunway then -- These places work procedural and have some kind of build in queue ==> Less effort. + self:T(string.format("Group %s is spawned on farp/ship/runway %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName())) nfree=SpawnAirbase:GetFreeParkingSpotsNumber(termtype, spawnonship or spawnonfarp or spawnonrunway) spots=SpawnAirbase:GetFreeParkingSpotsTable(termtype, spawnonship or spawnonfarp or spawnonrunway) else - if ishelo and termtype==nil then - -- Helo is spawned. - -- Try helo spots first. - spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, AIRBASE.TerminalType.HelicopterOnly) - nfree=#spots - if nfree<#SpawnTemplate.units then - -- Not enough helo ports. Let's try all terminal types. - spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, AIRBASE.TerminalType.HelicopterUsable) + if ishelo then + if termtype==nil then + -- Helo is spawned. Try exclusive helo spots first. + self:T(string.format("Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.HelicopterOnly)) + spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, AIRBASE.TerminalType.HelicopterOnly) nfree=#spots + if nfree<#SpawnTemplate.units then + -- Not enough helo ports. Let's try also other terminal types. + self:T(string.format("Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.HelicopterUsable)) + spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, AIRBASE.TerminalType.HelicopterUsable) + nfree=#spots + end + else + -- No terminal type specified. We try all spots except shelters. + self:T(string.format("Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), termtype)) + spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, termtype) + nfree=#spots end else -- Fixed wing aircraft is spawned. + if termtype==nil then --TODO: Add some default cases for transport, bombers etc. if no explicit terminal type is provided. - spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, termtype) - nfree=#spots + --TODO: We don't want Bombers to spawn in shelters. But I don't know a good attribute for just fighers. + --TODO: Some attributes are "Helicopters", "Bombers", "Transports", "Battleplanes". Need to check it out. + if isbomber or istransport then + -- First we fill the potentially bigger spots. + self:T(string.format("Transport/bomber group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.OpenBig)) + spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, AIRBASE.TerminalType.OpenBig) + nfree=#spots + if nfree<#SpawnTemplate.units then + -- Now we try the smaller ones. + self:T(string.format("Transport/bomber group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.OpenMedOrBig)) + spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, AIRBASE.TerminalType.OpenMedOrBig) + nfree=#spots + end + else + self:T(string.format("Fighter group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.FighterAircraft)) + spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, AIRBASE.TerminalType.FighterAircraft) + nfree=#spots + end + else + -- Terminal type explicitly given. + self:T(string.format("Plane group %s is at %s using terminal type %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), tostring(termtype))) + spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, termtype) + nfree=#spots + end end end -- Get parking data. local parkingdata=SpawnAirbase:GetParkingSpotsTable(termtype) - self:T(string.format("Parking at %s, terminal type %s:", SpawnAirbase:GetName(), tostring(termtype))) + self:T2(string.format("Parking at %s, terminal type %s:", SpawnAirbase:GetName(), tostring(termtype))) for _,_spot in pairs(parkingdata) do - self:T(string.format("%s, Termin Index = %3d, Term Type = %03d, Free = %5s, TOAC = %5s, Term ID0 = %3d, Dist2Rwy = %4d", + self:T2(string.format("%s, Termin Index = %3d, Term Type = %03d, Free = %5s, TOAC = %5s, Term ID0 = %3d, Dist2Rwy = %4d", SpawnAirbase:GetName(), _spot.TerminalID, _spot.TerminalType,tostring(_spot.Free),tostring(_spot.TOAC),_spot.TerminalID0,_spot.DistToRwy)) end self:T(string.format("%s at %s: free parking spots = %d - number of units = %d", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), nfree, #SpawnTemplate.units)) @@ -1371,7 +1413,7 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT end else - if not self.SpawnUnControlled then + if EmergencyAirSpawn and not self.SpawnUnControlled then self:E(string.format("WARNING: Group %s has no parking spots at %s ==> air start!", self.SpawnTemplatePrefix, SpawnAirbase:GetName())) -- Not enough parking spots at the airport ==> Spawn in air. @@ -1388,15 +1430,15 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT PointVec3.x=PointVec3.x+math.random(-500,500) PointVec3.z=PointVec3.z+math.random(-500,500) if ishelo then - PointVec3.y=PointVec3:GetLandHeight()+math.random(200,1200) + PointVec3.y=PointVec3:GetLandHeight()+math.random(100,1000) else -- Randomize position so that multiple AC wont be spawned on top even in air. - PointVec3.y=PointVec3:GetLandHeight()+math.random(500,5000) + PointVec3.y=PointVec3:GetLandHeight()+math.random(500,2500) end Takeoff=GROUP.Takeoff.Air else - self:E(string.format("WARNING: Group %s has no parking spots at %s ==> Uncontrolled spawning ==> No spawn!", self.SpawnTemplatePrefix, SpawnAirbase:GetName())) + self:E(string.format("WARNING: Group %s has no parking spots at %s ==> No emergency air start or uncontrolled spawning ==> No spawn!", self.SpawnTemplatePrefix, SpawnAirbase:GetName())) return nil end end @@ -1475,23 +1517,26 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT -- Spawn group. local GroupSpawned = self:SpawnWithIndex( self.SpawnIndex ) - + -- When spawned in the air, we need to generate a Takeoff Event. if Takeoff == GROUP.Takeoff.Air then for UnitID, UnitSpawned in pairs( GroupSpawned:GetUnits() ) do SCHEDULER:New( nil, BASE.CreateEventTakeoff, { GroupSpawned, timer.getTime(), UnitSpawned:GetDCSObject() } , 1 ) end end - - return GroupSpawned + + -- Check if we accidentally spawned on the runway. Needs to be schedules, because group is not immidiately alive. + if Takeoff~=SPAWN.Takeoff.Runway and Takeoff~=SPAWN.Takeoff.Air and spawnonairport then + SCHEDULER:New(nil, AIRBASE.CheckOnRunWay, {SpawnAirbase, GroupSpawned, 25, true} , 1.0) + end + + return GroupSpawned end end return nil end - - --- Will spawn a group from a Vec3 in 3D space. -- This method is mostly advisable to be used if you want to simulate spawning units in the air, like helicopters or airplanes. -- Note that each point in the route assigned to the spawning group is reset to the point of the spawn. diff --git a/Moose Development/Moose/Functional/RAT.lua b/Moose Development/Moose/Functional/RAT.lua index 16381f87e..a3c54a281 100644 --- a/Moose Development/Moose/Functional/RAT.lua +++ b/Moose Development/Moose/Functional/RAT.lua @@ -129,7 +129,6 @@ -- @field #string livery Livery of the aircraft set by user. -- @field #string skill Skill of AI. -- @field #boolean ATCswitch Enable/disable ATC if set to true/false. --- @field #string parking_id String with a special parking ID for the aircraft. -- @field #boolean radio If true/false disables radio messages from the RAT groups. -- @field #number frequency Radio frequency used by the RAT groups. -- @field #string modulation Ratio modulation. Either "FM" or "AM". @@ -365,7 +364,6 @@ RAT={ livery=nil, -- Livery of the aircraft. skill="High", -- Skill of AI. ATCswitch=true, -- Enable ATC. - parking_id=nil, -- Specific parking ID when aircraft are spawned at airports. radio=nil, -- If true/false disables radio messages from the RAT groups. frequency=nil, -- Radio frequency used by the RAT groups. modulation=nil, -- Ratio modulation. Either "FM" or "AM". @@ -997,6 +995,36 @@ function RAT:SetTakeoff(type) self.takeoff=_Type end +--- Set takeoff type cold. Aircraft will spawn at a parking spot with engines off. +-- @param #RAT self +function RAT:SetTakeoffCold() + self.takeoff=RAT.wp.cold +end + +--- Set takeoff type to hot. Aircraft will spawn at a parking spot with engines on. +-- @param #RAT self +function RAT:SetTakeoffHot() + self.takeoff=RAT.wp.hot +end + +--- Set takeoff type to runway. Aircraft will spawn directly on the runway. +-- @param #RAT self +function RAT:SetTakeoffRunway() + self.takeoff=RAT.wp.runway +end + +--- Set takeoff type to cold or hot. Aircraft will spawn at a parking spot with 50:50 change of engines on or off. +-- @param #RAT self +function RAT:SetTakeoffColdOrHot() + self.takeoff=RAT.wp.coldorhot +end + +--- Set takeoff type to air. Aircraft will spawn in the air. +-- @param #RAT self +function RAT:SetTakeoffAir() + self.takeoff=RAT.wp.air +end + --- Set possible departure ports. This can be an airport or a zone defined in the mission editor. -- @param #RAT self -- @param #string departurenames Name or table of names of departure airports or zones. @@ -1332,15 +1360,6 @@ function RAT:ParkingSpotDB(switch) self.useparkingdb=switch end ---- Set parking id of aircraft. --- @param #RAT self --- @param #string id Parking ID of the aircraft. -function RAT:SetParkingID(id) - self:F2(id) - self.parking_id=id - self:T(RAT.id.."Setting parking ID to "..self.parking_id) -end - --- Enable Radio. Overrules the ME setting. -- @param #RAT self function RAT:RadioON() @@ -4920,8 +4939,9 @@ end -- @param Core.Point#COORDINATE spawnplace (Optional) Place where spawning should happen. If not present, first waypoint is taken. -- @param Wrapper.Airbase#AIRBASE departure Departure airbase or zone. -- @param #number takeoff Takeoff type. +-- @return #boolean True if modification was successful or nil if not, e.g. when no parking space was found and spawn in air is disabled. function RAT:_ModifySpawnTemplate(waypoints, livery, spawnplace, departure, takeoff) - self:F2({waypoints=waypoints, livery=livery, spawnplace=spawnplace}) + self:F2({waypoints=waypoints, livery=livery, spawnplace=spawnplace, departure=departure, takeoff=takeoff}) -- The 3D vector of the first waypoint, i.e. where we actually spawn the template group. local PointVec3 = COORDINATE:New(waypoints[1].x, waypoints[1].alt, waypoints[1].y) @@ -4931,6 +4951,7 @@ function RAT:_ModifySpawnTemplate(waypoints, livery, spawnplace, departure, take -- Template group and unit. local TemplateGroup = GROUP:FindByName(self.SpawnTemplatePrefix) + local TemplateUnit=TemplateGroup:GetUnit(1) -- Check if we spawn on ground. local spawnonground=takeoff==RAT.wp.cold or takeoff==RAT.wp.hot or takeoff==RAT.wp.runway @@ -4986,41 +5007,76 @@ function RAT:_ModifySpawnTemplate(waypoints, livery, spawnplace, departure, take -- Number of free parking spots. local nfree=0 - -- Set terminal type. + -- Set terminal type. Can also be nil. local termtype=self.termtype if spawnonrunway then termtype=AIRBASE.TerminalType.Runway end - -- Number of free parking spots at the airbase. + -- Get free parking spots depending on where we spawn. if spawnonship or spawnonfarp or spawnonrunway then -- These places work procedural and have some kind of build in queue ==> Less effort. + self:T(RAT.id..string.format("Group %s is spawned on farp/ship/runway %s.", self.alias, departure:GetName())) nfree=departure:GetFreeParkingSpotsNumber(termtype, spawnonship or spawnonfarp or spawnonrunway) spots=departure:GetFreeParkingSpotsTable(termtype, spawnonship or spawnonfarp or spawnonrunway) else - if self.category==RAT.cat.heli and termtype==nil then - -- Helo is spawned. - -- Try helo spots first. - spots=departure:FindFreeParkingSpotForAircraft(TemplateGroup, AIRBASE.TerminalType.HelicopterOnly) - nfree=#spots - if nfree<#SpawnTemplate.units then - -- Not enough helo ports. Let's try all terminal types. - spots=departure:FindFreeParkingSpotForAircraft(TemplateGroup, AIRBASE.TerminalType.HelicopterUsable) + -- Helo is spawned. + 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)) + spots=departure:FindFreeParkingSpotForAircraft(TemplateGroup, AIRBASE.TerminalType.HelicopterOnly) nfree=#spots + if nfree<#SpawnTemplate.units then + -- Not enough helo ports. Let's try also other terminal types. + self:T(RAT.id..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.HelicopterUsable) + nfree=#spots + end + else + -- Terminal type specified explicitly. + self:T(RAT.id..string.format("Helo group %s is at %s using terminal type %d.", self.alias, departure:GetName(), termtype)) + spots=departure:FindFreeParkingSpotForAircraft(TemplateGroup, termtype) + nfree=#spots end else -- Fixed wing aircraft is spawned. + if termtype==nil then --TODO: Add some default cases for transport, bombers etc. if no explicit terminal type is provided. - spots=departure:FindFreeParkingSpotForAircraft(TemplateGroup, termtype) - nfree=#spots + --TODO: We don't want Bombers to spawn in shelters. But I don't know a good attribute for just fighers. + --TODO: Some attributes are "Helicopters", "Bombers", "Transports", "Battleplanes". Need to check it out. + local bomber=TemplateUnit:HasAttribute("Bombers") + local transport=TemplateUnit:HasAttribute("Transports") + if bomber or transport then + -- First we fill the potentially bigger spots. + self:T(RAT.id..string.format("Transport/bomber group %s is spawned at %s using terminal type %d.", self.alias, departure:GetName(), AIRBASE.TerminalType.OpenBig)) + spots=departure:FindFreeParkingSpotForAircraft(TemplateGroup, AIRBASE.TerminalType.OpenBig) + nfree=#spots + if nfree<#SpawnTemplate.units then + -- Now we try the smaller ones. + self:T(RAT.id..string.format("Transport/bomber group %s is at %s using terminal type %d.", self.alias, departure:GetName(), AIRBASE.TerminalType.OpenMed)) + spots=departure:FindFreeParkingSpotForAircraft(TemplateGroup, AIRBASE.TerminalType.OpenMed) + nfree=#spots + end + else + self:T(RAT.id..string.format("Fighter group %s is spawned at %s using terminal type %d.", self.alias, departure:GetName(), AIRBASE.TerminalType.FighterAircraft)) + spots=departure:FindFreeParkingSpotForAircraft(TemplateGroup, AIRBASE.TerminalType.FighterAircraft) + nfree=#spots + end + else + -- Terminal type explicitly given. + self:T(RAT.id..string.format("Plane group %s is spawned at %s using terminal type %d.", self.alias, departure:GetName(), termtype)) + spots=departure:FindFreeParkingSpotForAircraft(TemplateGroup, termtype) + nfree=#spots + end end end - -- Get parking data. + -- Get parking data (just for debugging). local parkingdata=departure:GetParkingSpotsTable(termtype) - self:T(RAT.id..string.format("Parking at %s, terminal type %s:", departure:GetName(), tostring(termtype))) + self:T2(RAT.id..string.format("Parking at %s, terminal type %s:", departure:GetName(), tostring(termtype))) for _,_spot in pairs(parkingdata) do - self:T(RAT.id..string.format("%s, Termin Index = %3d, Term Type = %03d, Free = %5s, TOAC = %5s, Term ID0 = %3d, Dist2Rwy = %4d", + self:T2(RAT.id..string.format("%s, Termin Index = %3d, Term Type = %03d, Free = %5s, TOAC = %5s, Term ID0 = %3d, Dist2Rwy = %4d", departure:GetName(), _spot.TerminalID, _spot.TerminalType,tostring(_spot.Free),tostring(_spot.TOAC),_spot.TerminalID0,_spot.DistToRwy)) end self:T(RAT.id..string.format("%s at %s: free parking spots = %d - number of units = %d", self.alias, departure:GetName(), nfree, #SpawnTemplate.units)) @@ -5032,10 +5088,6 @@ function RAT:_ModifySpawnTemplate(waypoints, livery, spawnplace, departure, take table.insert(parkingspots, spots[i].Coordinate) table.insert(parkingindex, spots[i].TerminalID) end - - if spawnonrunway then - --PointVec3=spots[1] - end else if self.respawn_inair or self.uncontrolled then @@ -5051,8 +5103,14 @@ function RAT:_ModifySpawnTemplate(waypoints, livery, spawnplace, departure, take waypoints[1].type = GROUPTEMPLATE.Takeoff[GROUP.Takeoff.Air][1] -- type = Turning Point waypoints[1].action = GROUPTEMPLATE.Takeoff[GROUP.Takeoff.Air][2] -- action = Turning Point - -- Adjust altitude to be 500-1000 m above the airbase. - PointVec3.y=PointVec3:GetLandHeight()+math.random(500,1000) + -- Adjust and randomize position and altitude of the spawn point. + PointVec3.x=PointVec3.x+math.random(-500,500) + PointVec3.z=PointVec3.z+math.random(-500,500) + if self.category==RAT.cat.heli then + PointVec3.y=PointVec3:GetLandHeight()+math.random(100,1000) + else + PointVec3.y=PointVec3:GetLandHeight()+math.random(500,2500) + end else self:E(RAT.id..string.format("WARNING: RAT group %s has no parking spots at %s. Air start deactivated or uncontrolled AC!", self.alias, departure:GetName())) return nil @@ -5063,7 +5121,6 @@ function RAT:_ModifySpawnTemplate(waypoints, livery, spawnplace, departure, take -- Translate the position of the Group Template to the Vec3. for UnitID = 1, #SpawnTemplate.units do - self:T2('Before Translation SpawnTemplate.units['..UnitID..'].x = '..SpawnTemplate.units[UnitID].x..', SpawnTemplate.units['..UnitID..'].y = '..SpawnTemplate.units[UnitID].y) -- Template of the current unit. local UnitTemplate = SpawnTemplate.units[UnitID] @@ -5080,34 +5137,28 @@ function RAT:_ModifySpawnTemplate(waypoints, livery, spawnplace, departure, take -- Shíps 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())) -- 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 - + 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])) -- Get coordinates of parking spot. SpawnTemplate.units[UnitID].x = parkingspots[UnitID].x SpawnTemplate.units[UnitID].y = parkingspots[UnitID].z - SpawnTemplate.units[UnitID].alt = parkingspots[UnitID].y - + SpawnTemplate.units[UnitID].alt = parkingspots[UnitID].y end - else - + else self:T(RAT.id..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 SpawnTemplate.units[UnitID].y = TY - SpawnTemplate.units[UnitID].alt = PointVec3.y - + SpawnTemplate.units[UnitID].alt = PointVec3.y end -- Place marker at spawn position. @@ -5123,6 +5174,7 @@ function RAT:_ModifySpawnTemplate(waypoints, livery, spawnplace, departure, take UnitTemplate.parking = parkingindex[UnitID] 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))) @@ -5155,7 +5207,6 @@ function RAT:_ModifySpawnTemplate(waypoints, livery, spawnplace, departure, take SpawnTemplate.CountryID=self.country end - self:T2('After Translation SpawnTemplate.units['..UnitID..'].x = '..SpawnTemplate.units[UnitID].x..', SpawnTemplate.units['..UnitID..'].y = '..SpawnTemplate.units[UnitID].y) end -- Copy waypoints into spawntemplate. By this we avoid the nasty DCS "landing bug" :) diff --git a/Moose Development/Moose/Utilities/Utils.lua b/Moose Development/Moose/Utilities/Utils.lua index 5dab11d52..3ac8ca74e 100644 --- a/Moose Development/Moose/Utilities/Utils.lua +++ b/Moose Development/Moose/Utilities/Utils.lua @@ -495,4 +495,100 @@ function UTILS.BeaufortScale(speed) bd="Hurricane" end return bn,bd +end + +--- Split string at seperators. C.f. http://stackoverflow.com/questions/1426954/split-string-in-lua +-- @param #string str Sting to split. +-- @param #string sep Speparator for split. +-- @return #table Split text. +function UTILS.Split(str, sep) + local result = {} + local regex = ("([^%s]+)"):format(sep) + for each in str:gmatch(regex) do + table.insert(result, each) + end + return result +end + +--- Convert time in seconds to hours, minutes and seconds. +-- @param #number seconds Time in seconds, e.g. from timer.getAbsTime() function. +-- @return #string Time in format Hours:Minutes:Seconds+Days (HH:MM:SS+D). +function UTILS.SecondsToClock(seconds) + + -- Nil check. + if seconds==nil then + return nil + end + + -- Seconds + local seconds = tonumber(seconds) + + -- Seconds of this day. + local _seconds=seconds%(60*60*24) + + if seconds <= 0 then + return nil + else + local hours = string.format("%02.f", math.floor(_seconds/3600)) + local mins = string.format("%02.f", math.floor(_seconds/60 - (hours*60))) + local secs = string.format("%02.f", math.floor(_seconds - hours*3600 - mins *60)) + local days = string.format("%d", seconds/(60*60*24)) + return hours..":"..mins..":"..secs.."+"..days + end +end + +--- Convert clock time from hours, minutes and seconds to seconds. +-- @param #string clock String of clock time. E.g., "06:12:35" or "5:1:30+1". Format is (H)H:(M)M:((S)S)(+D) H=Hours, M=Minutes, S=Seconds, D=Days. +-- @param #number Seconds. Corresponds to what you cet from timer.getAbsTime() function. +function UTILS.ClockToSeconds(clock) + + -- Nil check. + if clock==nil then + return nil + end + + -- Seconds init. + local seconds=0 + + -- Split additional days. + local dsplit=UTILS.split(clock, "+") + + -- Convert days to seconds. + if #dsplit>1 then + seconds=seconds+tonumber(dsplit[2])*60*60*24 + end + + -- Split hours, minutes, seconds + local tsplit=UTILS.Split(dsplit[1], ":") + + -- Get time in seconds + local i=1 + for _,time in ipairs(tsplit) do + if i==1 then + -- Hours + seconds=seconds+tonumber(time)*60*60 + elseif i==2 then + -- Minutes + seconds=seconds+tonumber(time)*60 + elseif i==3 then + -- Seconds + seconds=seconds+tonumber(time) + end + i=i+1 + end + + return seconds +end + +--- Display clock and mission time on screen as a message to all. +-- @param #number duration Duration in seconds how long the time is displayed. Default is 5 seconds. +function UTILS.DisplayMissionTime(duration) + duration=duration or 5 + local Tnow=timer.getAbsTime() + local mission_time=Tnow-timer.getTime0() + local mission_time_minutes=mission_time/60 + local mission_time_seconds=mission_time%60 + local local_time=UTILS.SecondsToClock(Tnow) + local text=string.format("Time: %s - %02d:%02d", local_time, mission_time_minutes, mission_time_seconds) + MESSAGE:New(text, duration):ToAll() end \ No newline at end of file diff --git a/Moose Development/Moose/Wrapper/Airbase.lua b/Moose Development/Moose/Wrapper/Airbase.lua index 2b02fbd5b..143dbf368 100644 --- a/Moose Development/Moose/Wrapper/Airbase.lua +++ b/Moose Development/Moose/Wrapper/Airbase.lua @@ -339,10 +339,9 @@ function AIRBASE:GetZone() end --- Get all airbases of the current map. This includes ships and FARPS. --- @param #AIRBASE self -- @param DCS#Coalition coalition (Optional) Return only airbases belonging to the specified coalition. By default, all airbases of the map are returned. -- @return #table Table containing all airbase objects of the current map. -function AIRBASE:GetAllAirbases(coalition) +function AIRBASE.GetAllAirbases(coalition) local airbases={} for _,airbase in pairs(_DATABASE.AIRBASES) do @@ -402,7 +401,7 @@ function AIRBASE:GetParkingSpotsNumber(termtype) local nspots=0 for _,parkingspot in pairs(parkingdata) do - if self:_CheckTerminalType(parkingspot.Term_Type, termtype) then + if AIRBASE._CheckTerminalType(parkingspot.Term_Type, termtype) then nspots=nspots+1 end end @@ -423,7 +422,7 @@ function AIRBASE:GetFreeParkingSpotsNumber(termtype, allowTOAC) local nfree=0 for _,parkingspot in pairs(parkingdata) do -- Spots on runway are not counted unless explicitly requested. - if self:_CheckTerminalType(parkingspot.Term_Type, termtype) then + if AIRBASE._CheckTerminalType(parkingspot.Term_Type, termtype) then if (allowTOAC and allowTOAC==true) or parkingspot.TO_AC==false then nfree=nfree+1 end @@ -447,7 +446,7 @@ function AIRBASE:GetFreeParkingSpotsCoordinates(termtype, allowTOAC) local spots={} for _,parkingspot in pairs(parkingdata) do -- Coordinates on runway are not returned unless explicitly requested. - if self:_CheckTerminalType(parkingspot.Term_Type, termtype) then + if AIRBASE._CheckTerminalType(parkingspot.Term_Type, termtype) then if (allowTOAC and allowTOAC==true) or parkingspot.TO_AC==false then table.insert(spots, COORDINATE:NewFromVec3(parkingspot.vTerminalPos)) end @@ -471,7 +470,7 @@ function AIRBASE:GetParkingSpotsCoordinates(termtype) for _,parkingspot in pairs(parkingdata) do -- Coordinates on runway are not returned unless explicitly requested. - if self:_CheckTerminalType(parkingspot.Term_Type, termtype) then + if AIRBASE._CheckTerminalType(parkingspot.Term_Type, termtype) then -- Get coordinate from Vec3 terminal position. local _coord=COORDINATE:NewFromVec3(parkingspot.vTerminalPos) @@ -510,7 +509,7 @@ function AIRBASE:GetParkingSpotsTable(termtype) -- Put coordinates of parking spots into table. local spots={} for _,_spot in pairs(parkingdata) do - if self:_CheckTerminalType(_spot.Term_Type, termtype) then + if AIRBASE._CheckTerminalType(_spot.Term_Type, termtype) then local _free=_isfree(_spot) local _coord=COORDINATE:NewFromVec3(_spot.vTerminalPos) table.insert(spots, {Coordinate=_coord, TerminalID=_spot.Term_Index, TerminalType=_spot.Term_Type, TOAC=_spot.TO_AC, Free=_free, TerminalID0=_spot.Term_Index_0, DistToRwy=_spot.fDistToRW}) @@ -533,7 +532,7 @@ function AIRBASE:GetFreeParkingSpotsTable(termtype, allowTOAC) -- Put coordinates of free spots into table. local freespots={} for _,_spot in pairs(parkingfree) do - if self:_CheckTerminalType(_spot.Term_Type, termtype) then + if AIRBASE._CheckTerminalType(_spot.Term_Type, termtype) then if (allowTOAC and allowTOAC==true) or _spot.TO_AC==false then local _coord=COORDINATE:NewFromVec3(_spot.vTerminalPos) table.insert(freespots, {Coordinate=_coord, TerminalID=_spot.Term_Index, TerminalType=_spot.Term_Type, TOAC=_spot.TO_AC, Free=true, TerminalID0=_spot.Term_Index_0, DistToRwy=_spot.fDistToRW}) @@ -572,55 +571,8 @@ function AIRBASE:MarkParkingSpots(termtype) end end - ---- Helper function to check for the correct terminal type including "artificial" ones. --- @param #AIRBASE self --- @param #number Term_Type Termial type from getParking routine. --- @param #number termtype Terminal type from AIRBASE.TerminalType enumerator. --- @return True if terminal types match. -function AIRBASE:_CheckTerminalType(Term_Type, termtype) - - -- Nill check for Term_Type. - if Term_Type==nil then - return false - end - - -- If no terminal type is requested, we return true. BUT runways are excluded unless explicitly requested. - if termtype==nil then - if Term_Type==AIRBASE.TerminalType.Runway then - return false - else - return true - end - end - - -- Init no match. - local match=false - - -- Standar case. - if Term_Type==termtype then - match=true - end - - -- Artificial cases. Combination of terminal types. - if termtype==AIRBASE.TerminalType.OpenMedOrBig then - if Term_Type==AIRBASE.TerminalType.OpenMed or Term_Type==AIRBASE.TerminalType.OpenBig then - match=true - end - elseif termtype==AIRBASE.TerminalType.HelicopterUsable then - if Term_Type==AIRBASE.TerminalType.OpenMed or Term_Type==AIRBASE.TerminalType.OpenBig or Term_Type==AIRBASE.TerminalType.HelicopterOnly then - match=true - end - elseif termtype==AIRBASE.TerminalType.FighterAircraft then - if Term_Type==AIRBASE.TerminalType.OpenMed or Term_Type==AIRBASE.TerminalType.OpenBig or Term_Type==AIRBASE.TerminalType.Shelter then - match=true - end - end - - return match -end - ---- Seach an unoccupied parking spot at a specific airport and for a specific aircraft. +--- Seach unoccupied parking spots at the airbase for a specific group of aircraft. The routine also optionally checks for other unit, static and scenery options in a certain radius around the parking spot. +-- The dimension of the spawned aircraft and of the potential obstacle are taken into account. Note that the routine can only return so many spots that are free. -- @param #AIRBASE self -- @param Wrapper.Group#GROUP group Aircraft group for which the parking spots are requested. -- @param #number terminaltype (Optional) Only search spots at a specific terminal type. Default is all types execpt on runway. @@ -628,7 +580,7 @@ end -- @param #boolean scanunits (Optional) Scan for units as obstacles. Default true. -- @param #boolean scanstatics (Optional) Scan for statics as obstacles. Default true. -- @param #boolean scanscenery (Optional) Scan for scenery as obstacles. Default false. Can cause problems with e.g. shelters. --- @return #table Table of coordinates and terminal IDs of the parking spots or nil, if no valid parking spots for the whole group could be found. +-- @return #table Table of coordinates and terminal IDs of free parking spots. Each table entry has the elements .Coordinate and .TerminalID. function AIRBASE:FindFreeParkingSpotForAircraft(group, terminaltype, scanradius, scanunits, scanstatics, scanscenery) -- Init default @@ -643,6 +595,9 @@ function AIRBASE:FindFreeParkingSpotForAircraft(group, terminaltype, scanradius, scanscenery=false end + -- Mark all found obstacles on F10 map. + local markobstacles=false + -- Get the size of an object. local function _GetObjectSize(unit,mooseobject) if mooseobject then @@ -681,7 +636,7 @@ function AIRBASE:FindFreeParkingSpotForAircraft(group, terminaltype, scanradius, local _aircraftsize, ax,ay,az=_GetObjectSize(aircraft, true) -- Debug info. - self:T(string.format("Looking for %d parking spot(s) at %s for aircraft of size %.1f m (x=%.1f,y=%.1f,z=%.1f) at termial type %s.", nspots, airport, _aircraftsize, ax,ay,az, tostring(terminaltype))) + self:E(string.format("Looking for %d parking spot(s) at %s for aircraft of size %.1f m (x=%.1f,y=%.1f,z=%.1f) at termial type %s.", nspots, airport, _aircraftsize, ax, ay, az, tostring(terminaltype))) -- Table of valid spots. local validspots={} @@ -691,74 +646,81 @@ function AIRBASE:FindFreeParkingSpotForAircraft(group, terminaltype, scanradius, for _,parkingspot in pairs(parkingdata) do -- Check for requested terminal type if any. - if self:_CheckTerminalType(parkingspot.TerminalType, terminaltype) then - end + if AIRBASE._CheckTerminalType(parkingspot.TerminalType, terminaltype) then - -- Coordinate of the parking spot. - local _spot=parkingspot.Coordinate --Core.Point#COORDINATE + -- Coordinate of the parking spot. + local _spot=parkingspot.Coordinate -- Core.Point#COORDINATE + local _termid=parkingspot.TerminalID + + -- Scan a radius of 50 meters around the spot. + local _,_,_,_units,_statics,_sceneries=_spot:ScanObjects(scanradius, scanunits, scanstatics, scanscenery) + + -- Loop over objects within scan radius. + local occupied=false + + -- Check all units. + for _,unit in pairs(_units) do + + local _vec3=unit:getPoint() + local _coord=COORDINATE:NewFromVec3(_vec3) + local _dist=_coord:Get2DDistance(_spot) + local _safe=_overlap(aircraft, unit, _dist) - -- Scan a radius of 50 meters around the spot. - local _,_,_,_units,_statics,_sceneries=_spot:ScanObjects(scanradius) - - - -- Loop over objects within scan radius. - local occupied=false - - -- Check all units. - for _,unit in pairs(_units) do - - local _vec3=unit:getPoint() - local _coord=COORDINATE:NewFromVec3(_vec3) - local _dist=_coord:Get2DDistance(_spot) - local _safe=_overlap(aircraft, unit, _dist) - - --local l,x,y,z=_GetObjectSize(unit) - --_coord:MarkToAll(string.format("scan found unit %s\nx=%.2f y=%.2f z=%.2f\nl=%.2f d=%.2f safe=%s", unit:getName(), x, y, z, l, _dist, tostring(_safe))) - - if scanunits and not _safe then - occupied=true - end - end - - -- Check all statics. - for _,static in pairs(_statics) do - local _vec3=static:getPoint() - local _coord=COORDINATE:NewFromVec3(_vec3) - local _dist=_coord:Get2DDistance(_spot) - local _safe=_overlap(aircraft, static, _dist) - - --local l,x,y,z=_GetObjectSize(static) - --_coord:MarkToAll(string.format("scan found static %s\nx=%.2f y=%.2f z=%.2f\nl=%.2f d=%.2f safe=%s", static:getName(),x,y,z,l,_dist, tostring(_safe))) - - if scanstatics and not _safe then - occupied=true - end - end - - -- Check all scenery. - for _,scenery in pairs(_sceneries) do - local _vec3=scenery:getPoint() - local _coord=COORDINATE:NewFromVec3(_vec3) - local _dist=_coord:Get2DDistance(_spot) - local _safe=_overlap(aircraft, scenery, _dist) - - --local l,x,y,z=_GetObjectSize(scenery) - --_coord:MarkToAll(string.format("scan found scenery %s\nx=%.2f y=%.2f z=%.2f\nl=%.2f d=%.2f", scenery:getName(),x,y,z,l,_dist)) - - if scanscenery and not _safe then - occupied=true - end - end - - --_spot:MarkToAll(string.format("Parking spot %d free=%s", parkingspot.TerminalID, tostring(not occupied))) - if occupied then - self:T(string.format("%s: Parking spot id %d occupied.", airport, parkingspot.TerminalID)) - else - self:T(string.format("%s: Parking spot id %d free.", airport, parkingspot.TerminalID)) - if nvalid radius %.1f m. Despawn = %s.", self:GetName(), unit:GetName(), group:GetName(),_i, dist, radius, tostring(despawn))) + --unit:FlareGreen() + end + + end + else + self:T(string.format("%s, checking if unit %s of group %s is on runway. Unit is NOT alive.",self:GetName(), unit:GetName(), group:GetName())) + end + end + else + self:T(string.format("%s, checking if group %s is on runway. Group is NOT alive.",self:GetName(), group:GetName())) + end + + return false +end + +--- Helper function to check for the correct terminal type including "artificial" ones. +-- @param #number Term_Type Termial type from getParking routine. +-- @param #number termtype Terminal type from AIRBASE.TerminalType enumerator. +-- @return #boolean True if terminal types match. +function AIRBASE._CheckTerminalType(Term_Type, termtype) + + -- Nill check for Term_Type. + if Term_Type==nil then + return false + end + + -- If no terminal type is requested, we return true. BUT runways are excluded unless explicitly requested. + if termtype==nil then + if Term_Type==AIRBASE.TerminalType.Runway then + return false + else + return true + end + end + + -- Init no match. + local match=false + + -- Standar case. + if Term_Type==termtype then + match=true + end + + -- Artificial cases. Combination of terminal types. + if termtype==AIRBASE.TerminalType.OpenMedOrBig then + if Term_Type==AIRBASE.TerminalType.OpenMed or Term_Type==AIRBASE.TerminalType.OpenBig then + match=true + end + elseif termtype==AIRBASE.TerminalType.HelicopterUsable then + if Term_Type==AIRBASE.TerminalType.OpenMed or Term_Type==AIRBASE.TerminalType.OpenBig or Term_Type==AIRBASE.TerminalType.HelicopterOnly then + match=true + end + elseif termtype==AIRBASE.TerminalType.FighterAircraft then + if Term_Type==AIRBASE.TerminalType.OpenMed or Term_Type==AIRBASE.TerminalType.OpenBig or Term_Type==AIRBASE.TerminalType.Shelter then + match=true + end + end + + return match +end \ No newline at end of file