From 3c710613a80ab2a6159ab5729737081886e071e8 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 6 Mar 2025 14:51:49 +0100 Subject: [PATCH 1/3] CONTROLLABLE added HasIRMarker --- Moose Development/Moose/Wrapper/Controllable.lua | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Wrapper/Controllable.lua b/Moose Development/Moose/Wrapper/Controllable.lua index dd95b441e..2623dc6d5 100644 --- a/Moose Development/Moose/Wrapper/Controllable.lua +++ b/Moose Development/Moose/Wrapper/Controllable.lua @@ -1777,8 +1777,6 @@ function CONTROLLABLE:TaskFAC_AttackGroup( AttackGroup, WeaponType, Designation, return DCSTask end --- EN-ACT_ROUTE TASKS FOR AIRBORNE CONTROLLABLES - --- (AIR) Engaging targets of defined types. -- @param #CONTROLLABLE self -- @param DCS#Distance Distance Maximal distance from the target to a route leg. If the target is on a greater distance it will be ignored. @@ -5735,6 +5733,14 @@ function CONTROLLABLE:DisableIRMarkerForGroup() return self end +--- [GROUND] Check if an IR Spot exists. +-- @param #CONTROLLABLE self +-- @return #boolean outcome +function CONTROLLABLE:HasIRMarker() + if self.spot then return true end + return false +end + --- [Internal] This method is called by the scheduler after enabling the IR marker. -- @param #CONTROLLABLE self -- @return #CONTROLLABLE self From c00eff8b23af2bacb3b829710598198eee115d78 Mon Sep 17 00:00:00 2001 From: Frank Date: Sat, 8 Mar 2025 21:37:43 +0100 Subject: [PATCH 2/3] AIRBASE - AIRBASE: Workaround for DCS bug that helipads have category of airdrome - SET_AIRBASE: Added FilterZones function --- Moose Development/Moose/Core/Set.lua | 40 +++++++++++ Moose Development/Moose/DCS.lua | 8 ++- Moose Development/Moose/Utilities/Utils.lua | 2 +- Moose Development/Moose/Wrapper/Airbase.lua | 76 ++++++++++++++++++--- 4 files changed, 114 insertions(+), 12 deletions(-) diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua index f2b6e6d3c..3f4fa2e71 100644 --- a/Moose Development/Moose/Core/Set.lua +++ b/Moose Development/Moose/Core/Set.lua @@ -5403,6 +5403,7 @@ do -- SET_AIRBASE Airbases = {}, Filter = { Coalitions = nil, + Zones = nil, }, FilterMeta = { Coalitions = { @@ -5554,6 +5555,31 @@ do -- SET_AIRBASE end return self end + + --- Builds a set of airbase objects in zones. + -- @param #SET_AIRBASE self + -- @param #table Zones Table of Core.Zone#ZONE Zone objects, or a Core.Set#SET_ZONE + -- @return #SET_AIRBASE self + function SET_AIRBASE:FilterZones( Zones ) + if not self.Filter.Zones then + self.Filter.Zones = {} + end + local zones = {} + if Zones.ClassName and Zones.ClassName == "SET_ZONE" then + zones = Zones.Set + elseif type( Zones ) ~= "table" or (type( Zones ) == "table" and Zones.ClassName ) then + self:E("***** FilterZones needs either a table of ZONE Objects or a SET_ZONE as parameter!") + return self + else + zones = Zones + end + for _,Zone in pairs( zones ) do + local zonename = Zone:GetName() + --self:T((zonename) + self.Filter.Zones[zonename] = Zone + end + return self + end --- Starts the filtering. -- @param #SET_AIRBASE self @@ -5692,6 +5718,20 @@ do -- SET_AIRBASE --self:T(( { "Evaluated Category", MAirbaseCategory } ) MAirbaseInclude = MAirbaseInclude and MAirbaseCategory end + + if self.Filter.Zones and MAirbaseInclude then + local MAirbaseZone = false + for ZoneName, Zone in pairs( self.Filter.Zones ) do + --self:T(( "Zone:", ZoneName ) + local coord = MAirbase:GetCoordinate() + if coord and Zone:IsCoordinateInZone(coord) then + MAirbaseZone = true + end + --self:T(( { "Evaluated Zone", MSceneryZone } ) + end + MAirbaseInclude = MAirbaseInclude and MAirbaseZone + end + end if self.Filter.Functions and MAirbaseInclude then diff --git a/Moose Development/Moose/DCS.lua b/Moose Development/Moose/DCS.lua index 44049cecf..8e01b8a73 100644 --- a/Moose Development/Moose/DCS.lua +++ b/Moose Development/Moose/DCS.lua @@ -630,9 +630,13 @@ do -- Object --- @function [parent=#Object] destroy -- @param #Object self - --- @function [parent=#Object] getCategory + --- Returns an enumerator of the category for the specific object. + -- The enumerator returned is dependent on the category of the object and how the function is called. + -- As of DCS 2.9.2 when this function is called on an Object, Unit, Weapon, or Airbase a 2nd value will be returned which details the object sub-category value. + -- @function [parent=#Object] getCategory -- @param #Object self - -- @return #Object.Category + -- @return #Object.Category The object category (1=UNIT, 2=WEAPON, 3=STATIC, 4=BASE, 5=SCENERY, 6=Cargo) + -- @return #number The subcategory of the passed object, e.g. Unit.Category if a unit object was passed. --- Returns type name of the Object. -- @function [parent=#Object] getTypeName diff --git a/Moose Development/Moose/Utilities/Utils.lua b/Moose Development/Moose/Utilities/Utils.lua index eeff81f26..626580dff 100644 --- a/Moose Development/Moose/Utilities/Utils.lua +++ b/Moose Development/Moose/Utilities/Utils.lua @@ -514,7 +514,7 @@ function UTILS.PrintTableToLog(table, indent, noprint) env.info(string.rep(" ", indent) .. tostring(k) .. " = {") end text = text ..string.rep(" ", indent) .. tostring(k) .. " = {\n" - text = text .. tostring(UTILS.PrintTableToLog(v, indent + 1)).."\n" + text = text .. tostring(UTILS.PrintTableToLog(v, indent + 1), noprint).."\n" if not noprint then env.info(string.rep(" ", indent) .. "},") end diff --git a/Moose Development/Moose/Wrapper/Airbase.lua b/Moose Development/Moose/Wrapper/Airbase.lua index 93d672750..21fd34fda 100644 --- a/Moose Development/Moose/Wrapper/Airbase.lua +++ b/Moose Development/Moose/Wrapper/Airbase.lua @@ -994,7 +994,7 @@ function AIRBASE:Register(AirbaseName) -- Debug info. --self:I({airbase=AirbaseName, descriptors=self.descriptors}) - + -- Category. self.category=self.descriptors and self.descriptors.category or Airbase.Category.AIRDROME @@ -1009,6 +1009,7 @@ if self.category==Airbase.Category.AIRDROME then self.isAirdrome=true elseif self.category==Airbase.Category.HELIPAD or self.descriptors.typeName=="FARP_SINGLE_01" then self.isHelipad=true + self.category=Airbase.Category.HELIPAD elseif self.category==Airbase.Category.SHIP then self.isShip=true -- DCS bug: Oil rigs and gas platforms have category=2 (ship). Also they cannot be retrieved by coalition.getStaticObjects() @@ -1024,20 +1025,33 @@ end -- Init Runways. self:_InitRunways() - + + -- Number of runways + local Nrunways=#self.runways + -- Set the active runways based on wind direction. - if self.isAirdrome then + if Nrunways>0 then self:SetActiveRunway() end -- Init parking spots. self:_InitParkingSpots() + + -- Some heliports identify as airdromes in the airbase category. This is buggy in the descriptors category but also in the getCategory() and getCategoryEx() functions. + if self.category==Airbase.Category.AIRDROME and (Nrunways==0 or self.NparkingTotal==self.NparkingTerminal[AIRBASE.TerminalType.HelicopterOnly]) then + self:E(string.format("WARNING: %s identifies as airdrome (category=0) but has no runways or just helo parking ==> will change to helipad (category=1)", self.AirbaseName)) + self.category=Airbase.Category.HELIPAD + self.isAirdrome=false + self.isHelipad=true + --self:GetCoordinate():MarkToAll("Helipad not airdrome") + end -- Get 2D position vector. local vec2=self:GetVec2() -- Init coordinate. self:GetCoordinate() + -- Storage. self.storage=_DATABASE:AddStorage(AirbaseName) @@ -1061,6 +1075,46 @@ end return self end +--- Get the category of this airbase. This is only a debug function because DCS 2.9 incorrectly returns heliports as airdromes. +-- @param #AIRBASE self +function AIRBASE:_GetCategory() + + local name=self.AirbaseName + + local static=StaticObject.getByName(name) + local airbase=Airbase.getByName(name) + local unit=Unit.getByName(name) + + local text=string.format("\n=====================================================") + text=text..string.format("\nAirbase %s:", name) + if static then + local oc, uc=static:getCategory() + local ex=static:getCategoryEx() + text=text..string.format("\nSTATIC: oc=%d, uc=%d, ex=%d", oc, uc, ex) + --text=text..UTILS.PrintTableToLog(static:getDesc(), nil, true) + text=text..string.format("\n--------------------------------------------------") + end + if unit then + local oc, uc=unit:getCategory() + local ex=unit:getCategoryEx() + text=text..string.format("\nUNIT: oc=%d, uc=%d, ex=%d", oc, uc, ex) + --text=text..UTILS.PrintTableToLog(unit:getDesc(), nil, true) + text=text..string.format("\n--------------------------------------------------") + end + if airbase then + local oc, uc=airbase:getCategory() + local ex=airbase:getCategoryEx() + text=text..string.format("\nAIRBASE: oc=%d, uc=%d, ex=%d", oc, uc, ex) + text=text..string.format("\n--------------------------------------------------") + text=text..UTILS.PrintTableToLog(airbase:getDesc(), nil, true) + end + + text=text..string.format("\n=====================================================") + + + env.info(text) +end + ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- Reference methods ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -1592,6 +1646,9 @@ function AIRBASE:_InitParkingSpots() self.parkingByID[park.TerminalID]=park table.insert(self.parking, park) end + + -- Runways are not included in total number of parking spots + self.NparkingTotal=self.NparkingTotal-self.NparkingTerminal[AIRBASE.TerminalType.Runway] return self end @@ -2079,11 +2136,6 @@ function AIRBASE:_InitRunways(IncludeInverse) -- Runway table. local Runways={} - if self:GetAirbaseCategory()~=Airbase.Category.AIRDROME then - self.runways={} - return {} - end - --- Function to create a runway data table. local function _createRunway(name, course, width, length, center) @@ -2169,7 +2221,7 @@ function AIRBASE:_InitRunways(IncludeInverse) -- Debug info. self:T2(runways) - if runways then + if runways and #runways>0 then -- Loop over runways. for _,rwy in pairs(runways) do @@ -2202,6 +2254,12 @@ function AIRBASE:_InitRunways(IncludeInverse) end end + + else + + -- No runways + self.runways={} + return {} end From 4976cd86f23460924c29a5c02cf0c154c469539e Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sun, 9 Mar 2025 14:36:38 +0100 Subject: [PATCH 3/3] ZONE_ELASTIC - function to remove vertices --- Moose Development/Moose/Core/Zone.lua | 34 +++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Core/Zone.lua b/Moose Development/Moose/Core/Zone.lua index 463629249..32ec18222 100644 --- a/Moose Development/Moose/Core/Zone.lua +++ b/Moose Development/Moose/Core/Zone.lua @@ -2054,7 +2054,7 @@ end -- @param #_ZONE_TRIANGLE self -- @param #table pt The point to check -- @param #table points (optional) The points of the triangle, or 3 other points if you're just using the TRIANGLE class without an object of it --- @return #bool True if the point is contained, false otherwise +-- @return #boolean True if the point is contained, false otherwise function _ZONE_TRIANGLE:ContainsPoint(pt, points) points = points or self.Points @@ -3536,7 +3536,37 @@ do -- ZONE_ELASTIC return self end + + --- Remove a vertex (point) from the polygon. + -- @param #ZONE_ELASTIC self + -- @param DCS#Vec2 Vec2 Point in 2D (with x and y coordinates). + -- @return #ZONE_ELASTIC self + function ZONE_ELASTIC:RemoveVertex2D(Vec2) + + local found = false + local findex = 0 + for _id,_vec2 in pairs(self.points) do + if _vec2.x == Vec2.x and _vec2.y == Vec2.y then + found = true + findex = _id + break + end + end + + if found == true and findex > 0 then + table.remove(self.points,findex) + end + return self + end + + --- Remove a vertex (point) from the polygon. + -- @param #ZONE_ELASTIC self + -- @param DCS#Vec3 Vec3 Point in 3D (with x, y and z coordinates). Only the x and z coordinates are used. + -- @return #ZONE_ELASTIC self + function ZONE_ELASTIC:RemoveVertex3D(Vec3) + return self:RemoveVertex2D({x=Vec3.x, y=Vec3.z}) + end --- Add a vertex (point) to the polygon. -- @param #ZONE_ELASTIC self @@ -3793,7 +3823,7 @@ end --- Checks if a point is contained within the oval. -- @param #ZONE_OVAL self -- @param #table point The point to check --- @return #bool True if the point is contained, false otherwise +-- @return #boolean True if the point is contained, false otherwise function ZONE_OVAL:IsVec2InZone(vec2) local cos, sin = math.cos, math.sin local dx = vec2.x - self.CenterVec2.x