diff --git a/Moose Development/Moose/.lua-format b/Moose Development/Moose/.lua-format index 26b4f5897..6fa8431a8 100644 --- a/Moose Development/Moose/.lua-format +++ b/Moose Development/Moose/.lua-format @@ -21,9 +21,9 @@ chop_down_table: true chop_down_kv_table: true column_table_limit: 500 table_sep: ',' -extra_sep_at_table_end: false +extra_sep_at_table_end: true break_after_operator: true -single_quote_to_double_quote: true +single_quote_to_double_quote: false double_quote_to_single_quote: false spaces_before_call: 1 spaces_inside_functiondef_parens: true diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index 1851db807..87fbc64fd 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -1,11 +1,11 @@ --- **Core** - Defines an extensive API to manage 3D points in the DCS World 3D simulation space. -- -- ## 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. --- +-- -- === -- -- # Demo Missions @@ -33,15 +33,11 @@ -- @module Core.Point -- @image Core_Coordinate.JPG - - - do -- COORDINATE --- @type COORDINATE -- @extends Core.Base#BASE - - + --- Defines a 3D point in the simulator and with its methods, you can use or manipulate the point in 3D space. -- -- # 1) Create a COORDINATE object. @@ -52,7 +48,6 @@ do -- COORDINATE -- * @{#COORDINATE.NewFromVec2}(): from a @{DCS#Vec2} and possible altitude. -- * @{#COORDINATE.NewFromVec3}(): from a @{DCS#Vec3}. -- - -- -- # 2) Smoke, flare, explode, illuminate at the coordinate. -- -- At the point a smoke, flare, explosion and illumination bomb can be triggered. Use the following methods: @@ -82,19 +77,18 @@ do -- COORDINATE -- -- * @{#COORDINATE.IlluminationBomb}(): To illuminate the point. -- - -- -- # 3) Create markings on the map. - -- + -- -- Place markers (text boxes with clarifications for briefings, target locations or any other reference point) -- on the map for all players, coalitions or specific groups: - -- + -- -- * @{#COORDINATE.MarkToAll}(): Place a mark to all players. -- * @{#COORDINATE.MarkToCoalition}(): Place a mark to a coalition. -- * @{#COORDINATE.MarkToCoalitionRed}(): Place a mark to the red coalition. -- * @{#COORDINATE.MarkToCoalitionBlue}(): Place a mark to the blue coalition. -- * @{#COORDINATE.MarkToGroup}(): Place a mark to a group (needs to have a client in it or a CA group (CA group is bugged)). -- * @{#COORDINATE.RemoveMark}(): Removes a mark from the map. - -- + -- -- # 4) Coordinate calculation methods. -- -- Various calculation methods exist to use or manipulate 3D space. Find below a short description of each method: @@ -124,37 +118,35 @@ do -- COORDINATE -- -- * @{#COORDINATE.GetRandomVec2InRadius}(): Provides a random 2D vector around the current 3D point, in the given inner to outer band. -- * @{#COORDINATE.GetRandomVec3InRadius}(): Provides a random 3D vector around the current 3D point, in the given inner to outer band. - -- + -- -- ## 4.6) LOS between coordinates. - -- + -- -- Calculate if the coordinate has Line of Sight (LOS) with the other given coordinate. - -- Mountains, trees and other objects can be positioned between the two 3D points, preventing visibilty in a straight continuous line. - -- The method @{#COORDINATE.IsLOS}() returns if the two coodinates have LOS. - -- + -- Mountains, trees and other objects can be positioned between the two 3D points, preventing visibility in a straight continuous line. + -- The method @{#COORDINATE.IsLOS}() returns if the two coordinates have LOS. + -- -- ## 4.7) Check the coordinate position. - -- + -- -- Various methods are available that allow to check if a coordinate is: - -- + -- -- * @{#COORDINATE.IsInRadius}(): in a give radius. -- * @{#COORDINATE.IsInSphere}(): is in a given sphere. -- * @{#COORDINATE.IsAtCoordinate2D}(): is in a given coordinate within a specific precision. - -- - -- -- -- # 5) Measure the simulation environment at the coordinate. - -- + -- -- ## 5.1) Weather specific. - -- + -- -- Within the DCS simulator, a coordinate has specific environmental properties, like wind, temperature, humidity etc. - -- + -- -- * @{#COORDINATE.GetWind}(): Retrieve the wind at the specific coordinate within the DCS simulator. -- * @{#COORDINATE.GetTemperature}(): Retrieve the temperature at the specific height within the DCS simulator. -- * @{#COORDINATE.GetPressure}(): Retrieve the pressure at the specific height within the DCS simulator. - -- + -- -- ## 5.2) Surface specific. - -- + -- -- Within the DCS simulator, the surface can have various objects placed at the coordinate, and the surface height will vary. - -- + -- -- * @{#COORDINATE.GetLandHeight}(): Retrieve the height of the surface (on the ground) within the DCS simulator. -- * @{#COORDINATE.GetSurfaceType}(): Retrieve the surface type (on the ground) within the DCS simulator. -- @@ -169,13 +161,13 @@ do -- COORDINATE -- Route points can be used in the Route methods of the @{Wrapper.Group#GROUP} class. -- -- ## 7) Manage the roads. - -- + -- -- Important for ground vehicle transportation and movement, the method @{#COORDINATE.GetClosestPointToRoad}() will calculate -- the closest point on the nearest road. - -- + -- -- In order to use the most optimal road system to transport vehicles, the method @{#COORDINATE.GetPathOnRoad}() will calculate -- the most optimal path following the road between two coordinates. - -- + -- -- ## 8) Metric or imperial system -- -- * @{#COORDINATE.IsMetric}(): Returns if the 3D point is Metric or Nautical Miles. @@ -183,12 +175,12 @@ do -- COORDINATE -- -- -- ## 9) Coordinate text generation - -- + -- -- * @{#COORDINATE.ToStringBR}(): Generates a Bearing & Range text in the format of DDD for DI where DDD is degrees and DI is distance. - -- * @{#COORDINATE.ToStringLL}(): Generates a Latutude & Longutude text. + -- * @{#COORDINATE.ToStringLL}(): Generates a Latitude & Longitude text. -- -- ## 10) Drawings on F10 map - -- + -- -- * @{#COORDINATE.CircleToAll}(): Draw a circle on the F10 map. -- * @{#COORDINATE.LineToAll}(): Draw a line on the F10 map. -- * @{#COORDINATE.RectToAll}(): Draw a rectangle on the F10 map. @@ -201,13 +193,13 @@ do -- COORDINATE ClassName = "COORDINATE", } - --- @field COORDINATE.WaypointAltType + --- @field COORDINATE.WaypointAltType COORDINATE.WaypointAltType = { - BARO = "BARO", + BARO = "BARO", RADIO = "RADIO", } - - --- @field COORDINATE.WaypointAction + + --- @field COORDINATE.WaypointAction COORDINATE.WaypointAction = { TurningPoint = "Turning Point", FlyoverPoint = "Fly Over Point", @@ -218,7 +210,7 @@ do -- COORDINATE LandingReFuAr = "LandingReFuAr", } - --- @field COORDINATE.WaypointType + --- @field COORDINATE.WaypointType COORDINATE.WaypointType = { TakeOffParking = "TakeOffParking", TakeOffParkingHot = "TakeOffParkingHot", @@ -228,21 +220,20 @@ do -- COORDINATE LandingReFuAr = "LandingReFuAr", } - --- COORDINATE constructor. -- @param #COORDINATE 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 z The z coordinate of the Vec3 point, pointing to the Right. -- @return #COORDINATE - function COORDINATE:New( x, y, z ) + function COORDINATE:New( x, y, z ) - --env.info("FF COORDINATE New") + -- env.info("FF COORDINATE New") local self = BASE:Inherit( self, BASE:New() ) -- #COORDINATE self.x = x self.y = y self.z = z - + return self end @@ -250,13 +241,13 @@ do -- COORDINATE -- @param #COORDINATE self -- @param #COORDINATE Coordinate. -- @return #COORDINATE - function COORDINATE:NewFromCoordinate( Coordinate ) + function COORDINATE:NewFromCoordinate( Coordinate ) local self = BASE:Inherit( self, BASE:New() ) -- #COORDINATE self.x = Coordinate.x self.y = Coordinate.y self.z = Coordinate.z - + return self end @@ -265,10 +256,10 @@ do -- COORDINATE -- @param DCS#Vec2 Vec2 The Vec2 point. -- @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 #COORDINATE - function COORDINATE:NewFromVec2( Vec2, LandHeightAdd ) + function COORDINATE:NewFromVec2( Vec2, LandHeightAdd ) local LandHeight = land.getHeight( Vec2 ) - + LandHeightAdd = LandHeightAdd or 0 LandHeight = LandHeight + LandHeightAdd @@ -284,7 +275,7 @@ do -- COORDINATE -- @param #COORDINATE self -- @param DCS#Vec3 Vec3 The Vec3 point. -- @return #COORDINATE - function COORDINATE:NewFromVec3( Vec3 ) + function COORDINATE:NewFromVec3( Vec3 ) local self = self:New( Vec3.x, Vec3.y, Vec3.z ) -- #COORDINATE @@ -292,7 +283,6 @@ do -- COORDINATE return self end - --- Return the coordinates of the COORDINATE in Vec3 format. -- @param #COORDINATE self @@ -301,7 +291,6 @@ do -- COORDINATE return { x = self.x, y = self.y, z = self.z } end - --- Return the coordinates of the COORDINATE in Vec2 format. -- @param #COORDINATE self -- @return DCS#Vec2 The Vec2 format coordinate. @@ -313,11 +302,11 @@ do -- COORDINATE -- @param #COORDINATE self -- @param DCS#Vec3 Vec3 The 3D vector with x,y,z components. -- @return #COORDINATE The modified COORDINATE itself. - function COORDINATE:UpdateFromVec3(Vec3) + function COORDINATE:UpdateFromVec3( Vec3 ) - self.x=Vec3.x - self.y=Vec3.y - self.z=Vec3.z + self.x = Vec3.x + self.y = Vec3.y + self.z = Vec3.z return self end @@ -326,11 +315,11 @@ do -- COORDINATE -- @param #COORDINATE self -- @param #COORDINATE Coordinate The coordinate with the new x,y,z positions. -- @return #COORDINATE The modified COORDINATE itself. - function COORDINATE:UpdateFromCoordinate(Coordinate) + function COORDINATE:UpdateFromCoordinate( Coordinate ) - self.x=Coordinate.x - self.y=Coordinate.y - self.z=Coordinate.z + self.x = Coordinate.x + self.y = Coordinate.y + self.z = Coordinate.z return self end @@ -339,10 +328,10 @@ do -- COORDINATE -- @param #COORDINATE self -- @param DCS#Vec2 Vec2 The 2D vector with x,y components. x is overwriting COORDINATE.x while y is overwriting COORDINATE.z. -- @return #COORDINATE The modified COORDINATE itself. - function COORDINATE:UpdateFromVec2(Vec2) + function COORDINATE:UpdateFromVec2( Vec2 ) - self.x=Vec2.x - self.z=Vec2.y + self.x = Vec2.x + self.z = Vec2.y return self end @@ -353,19 +342,19 @@ do -- COORDINATE -- @param #number longitude Longitude in decimal degrees. -- @param #number altitude (Optional) Altitude in meters. Default is the land height at the coordinate. -- @return #COORDINATE - function COORDINATE:NewFromLLDD( latitude, longitude, altitude) + function COORDINATE:NewFromLLDD( latitude, longitude, altitude ) -- Returns a point from latitude and longitude in the vec3 format. - local vec3=coord.LLtoLO(latitude, longitude) + local vec3 = coord.LLtoLO( latitude, longitude ) -- Convert vec3 to coordinate object. - local _coord=self:NewFromVec3(vec3) + local _coord = self:NewFromVec3( vec3 ) -- Adjust height - if altitude==nil then - _coord.y=self:GetLandHeight() + if altitude == nil then + _coord.y = self:GetLandHeight() else - _coord.y=altitude + _coord.y = altitude end return _coord @@ -384,7 +373,7 @@ do -- COORDINATE local x = Coordinate.x local z = Coordinate.z - return x - Precision <= self.x and x + Precision >= self.x and z - Precision <= self.z and z + Precision >= self.z + return x - Precision <= self.x and x + Precision >= self.x and z - Precision <= self.z and z + Precision >= self.z end --- Scan/find objects (units, statics, scenery) within a certain radius around the coordinate using the world.searchObjects() DCS API function. @@ -399,50 +388,50 @@ do -- COORDINATE -- @return #table Table of MOOSE @[#Wrapper.Unit#UNIT} objects found. -- @return #table Table of DCS static objects found. -- @return #table Table of DCS scenery objects found. - function COORDINATE:ScanObjects(radius, scanunits, scanstatics, scanscenery) - self:F(string.format("Scanning in radius %.1f m.", radius or 100)) + function COORDINATE:ScanObjects( radius, scanunits, scanstatics, scanscenery ) + self:F( string.format( "Scanning in radius %.1f m.", radius or 100 ) ) local SphereSearch = { id = world.VolumeType.SPHERE, - params = { + params = { point = self:GetVec3(), - radius = radius, - } + radius = radius } + } -- Defaults - radius=radius or 100 - if scanunits==nil then - scanunits=true + radius = radius or 100 + if scanunits == nil then + scanunits = true end - if scanstatics==nil then - scanstatics=true + if scanstatics == nil then + scanstatics = true end - if scanscenery==nil then - scanscenery=false + if scanscenery == nil then + scanscenery = false end - --{Object.Category.UNIT, Object.Category.STATIC, Object.Category.SCENERY} - local scanobjects={} + -- {Object.Category.UNIT, Object.Category.STATIC, Object.Category.SCENERY} + local scanobjects = {} if scanunits then - table.insert(scanobjects, Object.Category.UNIT) + table.insert( scanobjects, Object.Category.UNIT ) end if scanstatics then - table.insert(scanobjects, Object.Category.STATIC) + table.insert( scanobjects, Object.Category.STATIC ) end if scanscenery then - table.insert(scanobjects, Object.Category.SCENERY) + table.insert( scanobjects, Object.Category.SCENERY ) end -- Found stuff. local Units = {} local Statics = {} local Scenery = {} - local gotstatics=false - local gotunits=false - local gotscenery=false + local gotstatics = false + local gotunits = false + local gotscenery = false - local function EvaluateZone(ZoneObject) + local function EvaluateZone( ZoneObject ) if ZoneObject then @@ -450,20 +439,20 @@ do -- COORDINATE local ObjectCategory = ZoneObject:getCategory() -- Check for unit or static objects - if ObjectCategory==Object.Category.UNIT and ZoneObject:isExist() then + if ObjectCategory == Object.Category.UNIT and ZoneObject:isExist() then - table.insert(Units, UNIT:Find(ZoneObject)) - gotunits=true + table.insert( Units, UNIT:Find( ZoneObject ) ) + gotunits = true - elseif ObjectCategory==Object.Category.STATIC and ZoneObject:isExist() then + elseif ObjectCategory == Object.Category.STATIC and ZoneObject:isExist() then - table.insert(Statics, ZoneObject) - gotstatics=true + table.insert( Statics, ZoneObject ) + gotstatics = true - elseif ObjectCategory==Object.Category.SCENERY then + elseif ObjectCategory == Object.Category.SCENERY then - table.insert(Scenery, ZoneObject) - gotscenery=true + table.insert( Scenery, ZoneObject ) + gotscenery = true end @@ -473,64 +462,63 @@ do -- COORDINATE end -- Search the world. - world.searchObjects(scanobjects, SphereSearch, EvaluateZone) + world.searchObjects( scanobjects, SphereSearch, EvaluateZone ) - for _,unit in pairs(Units) do - self:T(string.format("Scan found unit %s", unit:GetName())) + for _, unit in pairs( Units ) do + self:T( string.format( "Scan found unit %s", unit:GetName() ) ) end - for _,static in pairs(Statics) do - self:T(string.format("Scan found static %s", static:getName())) - _DATABASE:AddStatic(static:getName()) + for _, static in pairs( Statics ) do + self:T( string.format( "Scan found static %s", static:getName() ) ) + _DATABASE:AddStatic( static:getName() ) end - for _,scenery in pairs(Scenery) do - self:T(string.format("Scan found scenery %s typename=%s", scenery:getName(), scenery:getTypeName())) - SCENERY:Register(scenery:getName(), scenery) + for _, scenery in pairs( Scenery ) do + self:T( string.format( "Scan found scenery %s typename=%s", scenery:getName(), scenery:getTypeName() ) ) + SCENERY:Register( scenery:getName(), scenery ) end - + return gotunits, gotstatics, gotscenery, Units, Statics, Scenery end - + --- Scan/find UNITS within a certain radius around the coordinate using the world.searchObjects() DCS API function. -- @param #COORDINATE self -- @param #number radius (Optional) Scan radius in meters. Default 100 m. -- @return Core.Set#SET_UNIT Set of units. - function COORDINATE:ScanUnits(radius) - - local _,_,_,units=self:ScanObjects(radius, true, false, false) - - local set=SET_UNIT:New() - - for _,unit in pairs(units) do - set:AddUnit(unit) + function COORDINATE:ScanUnits( radius ) + + local _, _, _, units = self:ScanObjects( radius, true, false, false ) + + local set = SET_UNIT:New() + + for _, unit in pairs( units ) do + set:AddUnit( unit ) end - + return set end - + --- Find the closest unit to the COORDINATE within a certain radius. -- @param #COORDINATE self -- @param #number radius Scan radius in meters. Default 100 m. -- @return Wrapper.Unit#UNIT The closest unit or #nil if no unit is inside the given radius. - function COORDINATE:FindClosestUnit(radius) - - local units=self:ScanUnits(radius) - - local umin=nil --Wrapper.Unit#UNIT - local dmin=math.huge - for _,_unit in pairs(units.Set) do - local unit=_unit --Wrapper.Unit#UNIT - local coordinate=unit:GetCoordinate() - local d=self:Get2DDistance(coordinate) - if d 180 then - direction = direction-180 + direction = direction - 180 else - direction = direction+180 + direction = direction + 180 end - local strength=math.sqrt((wind.x)^2+(wind.z)^2) + local strength = math.sqrt( (wind.x) ^ 2 + (wind.z) ^ 2 ) -- Return wind direction and strength km/h. return direction, strength end - + --- Returns the wind direction (from) and strength. -- @param #COORDINATE self -- @param height (Optional) parameter specifying the height ASL. The minimum height will be always be the land height since the wind is zero below the ground. -- @return Direction the wind is blowing from in degrees. - function COORDINATE:GetWindWithTurbulenceVec3(height) - - -- AGL height if - local landheight=self:GetLandHeight()+0.1 -- we at 0.1 meters to be sure to be above ground since wind is zero below ground level. - - -- Point at which the wind is evaluated. - local point={x=self.x, y=math.max(height or self.y, landheight), z=self.z} - - -- Get wind velocity vector including turbulences. - local vec3 = atmosphere.getWindWithTurbulence(point) - - return vec3 - end + function COORDINATE:GetWindWithTurbulenceVec3( height ) + -- AGL height if + local landheight = self:GetLandHeight() + 0.1 -- we at 0.1 meters to be sure to be above ground since wind is zero below ground level. + + -- Point at which the wind is evaluated. + local point = { x = self.x, y = math.max( height or self.y, landheight ), z = self.z } + + -- Get wind velocity vector including turbulences. + local vec3 = atmosphere.getWindWithTurbulence( point ) + + return vec3 + end --- Returns a text documenting the wind direction (from) and strength according the measurement system @{Settings}. -- The text will reflect the wind like this: - -- + -- -- - For Russian and European aircraft using the metric system - Wind direction in degrees (°) and wind speed in meters per second (mps). - -- - For Americain aircraft we link to the imperial system - Wind direction in degrees (°) and wind speed in knots per second (kps). - -- - -- A text containing a pressure will look like this: - -- - -- - `Wind: %n ° at n.d mps` + -- - For American aircraft we link to the imperial system - Wind direction in degrees (°) and wind speed in knots per second (kps). + -- + -- A text containing a pressure will look like this: + -- + -- - `Wind: %n ° at n.d mps` -- - `Wind: %n ° at n.d kps` - -- + -- -- @param #COORDINATE self -- @param height (Optional) parameter specifying the height ASL. The minimum height will be always be the land height since the wind is zero below the ground. -- @return #string Wind direction and strength according the measurement system @{Settings}. @@ -969,7 +945,7 @@ do -- COORDINATE else return " no wind" end - + return nil end @@ -980,13 +956,12 @@ do -- COORDINATE function COORDINATE:Get3DDistance( TargetCoordinate ) local TargetVec3 = TargetCoordinate:GetVec3() local SourceVec3 = self:GetVec3() - return ( ( TargetVec3.x - SourceVec3.x ) ^ 2 + ( TargetVec3.y - SourceVec3.y ) ^ 2 + ( TargetVec3.z - SourceVec3.z ) ^ 2 ) ^ 0.5 + return ((TargetVec3.x - SourceVec3.x) ^ 2 + (TargetVec3.y - SourceVec3.y) ^ 2 + (TargetVec3.z - SourceVec3.z) ^ 2) ^ 0.5 end - --- Provides a bearing text in degrees. -- @param #COORDINATE self - -- @param #number AngleRadians The angle in randians. + -- @param #number AngleRadians The angle in radians. -- @param #number Precision The precision. -- @param Core.Settings#SETTINGS Settings -- @return #string The bearing text in degrees. @@ -995,9 +970,9 @@ do -- COORDINATE local Settings = Settings or _SETTINGS -- Core.Settings#SETTINGS local AngleDegrees = UTILS.Round( UTILS.ToDegree( AngleRadians ), Precision ) - - local s = string.format( '%03d°', AngleDegrees ) - + + local s = string.format( '%03d°', AngleDegrees ) + return s end @@ -1014,19 +989,19 @@ do -- COORDINATE local DistanceText if Settings:IsMetric() then - if Language == "EN" then + if Language == "EN" then DistanceText = " for " .. UTILS.Round( Distance / 1000, 2 ) .. " km" elseif Language == "RU" then DistanceText = " за " .. UTILS.Round( Distance / 1000, 2 ) .. " километров" end else - if Language == "EN" then + if Language == "EN" then DistanceText = " for " .. UTILS.Round( UTILS.MetersToNM( Distance ), 2 ) .. " miles" elseif Language == "RU" then DistanceText = " за " .. UTILS.Round( UTILS.MetersToNM( Distance ), 2 ) .. " миль" end end - + return DistanceText end @@ -1037,16 +1012,16 @@ do -- COORDINATE local Altitude = self.y local Settings = Settings or _SETTINGS local Language = Language or "EN" - + if Altitude ~= 0 then if Settings:IsMetric() then - if Language == "EN" then + if Language == "EN" then return " at " .. UTILS.Round( self.y, -3 ) .. " meters" elseif Language == "RU" then return " в " .. UTILS.Round( self.y, -3 ) .. " метры" end else - if Language == "EN" then + if Language == "EN" then return " at " .. UTILS.Round( UTILS.MetersToFeet( self.y ), -3 ) .. " feet" elseif Language == "RU" then return " в " .. UTILS.Round( self.y, -3 ) .. " ноги" @@ -1057,8 +1032,6 @@ do -- COORDINATE end end - - --- Return the velocity text of the COORDINATE. -- @param #COORDINATE self -- @return #string Velocity text. @@ -1076,7 +1049,6 @@ do -- COORDINATE end end - --- Return the heading text of the COORDINATE. -- @param #COORDINATE self -- @return #string Heading text. @@ -1089,10 +1061,9 @@ do -- COORDINATE end end - --- Provides a Bearing / Range string -- @param #COORDINATE self - -- @param #number AngleRadians The angle in randians + -- @param #number AngleRadians The angle in radians -- @param #number Distance The distance -- @param Core.Settings#SETTINGS Settings -- @return #string The BR Text @@ -1102,7 +1073,7 @@ do -- COORDINATE local BearingText = self:GetBearingText( AngleRadians, 0, Settings, Language ) local DistanceText = self:GetDistanceText( Distance, Settings, Language ) - + local BRText = BearingText .. DistanceText return BRText @@ -1110,7 +1081,7 @@ do -- COORDINATE --- Provides a Bearing / Range / Altitude string -- @param #COORDINATE self - -- @param #number AngleRadians The angle in randians + -- @param #number AngleRadians The angle in radians -- @param #number Distance The distance -- @param Core.Settings#SETTINGS Settings -- @return #string The BRA Text @@ -1119,28 +1090,27 @@ do -- COORDINATE local Settings = Settings or _SETTINGS -- Core.Settings#SETTINGS local BearingText = self:GetBearingText( AngleRadians, 0, Settings, Language ) - local DistanceText = self:GetDistanceText( Distance, Settings, Language ) - local AltitudeText = self:GetAltitudeText( Settings, Language ) + local DistanceText = self:GetDistanceText( Distance, Settings, Language ) + local AltitudeText = self:GetAltitudeText( Settings, Language ) local BRAText = BearingText .. DistanceText .. AltitudeText -- When the POINT is a VEC2, there will be no altitude shown. return BRAText end - --- Set altitude. -- @param #COORDINATE self -- @param #number altitude New altitude in meters. -- @param #boolean asl Altitude above sea level. Default is above ground level. -- @return #COORDINATE The COORDINATE with adjusted altitude. - function COORDINATE:SetAltitude(altitude, asl) - local alt=altitude + function COORDINATE:SetAltitude( altitude, asl ) + local alt = altitude if asl then - alt=altitude + alt = altitude else - alt=self:GetLandHeight()+altitude + alt = self:GetLandHeight() + altitude end - self.y=alt + self.y = alt return self end @@ -1158,44 +1128,44 @@ do -- COORDINATE -- @return #table The route point. function COORDINATE:WaypointAir( AltType, Type, Action, Speed, SpeedLocked, airbase, DCSTasks, description, timeReFuAr ) self:F2( { AltType, Type, Action, Speed, SpeedLocked } ) - + -- Set alttype or "RADIO" which is AGL. - AltType=AltType or "RADIO" - + AltType = AltType or "RADIO" + -- Speedlocked by default - if SpeedLocked==nil then - SpeedLocked=true + if SpeedLocked == nil then + SpeedLocked = true end - + -- Speed or default 500 km/h. - Speed=Speed or 500 - + Speed = Speed or 500 + -- Waypoint array. local RoutePoint = {} - + -- Coordinates. RoutePoint.x = self.x RoutePoint.y = self.z - + -- Altitude. RoutePoint.alt = self.y RoutePoint.alt_type = AltType - + -- Waypoint type. RoutePoint.type = Type or nil - RoutePoint.action = Action or nil - + RoutePoint.action = Action or nil + -- Speed. - RoutePoint.speed = Speed/3.6 + RoutePoint.speed = Speed / 3.6 RoutePoint.speed_locked = SpeedLocked - + -- ETA. - RoutePoint.ETA=0 - RoutePoint.ETA_locked=false - + RoutePoint.ETA = 0 + RoutePoint.ETA_locked = false + -- Waypoint description. - RoutePoint.name=description - + RoutePoint.name = description + -- Airbase parameters for takeoff and landing points. if airbase then local AirbaseID = airbase:GetID() @@ -1206,34 +1176,33 @@ do -- COORDINATE elseif AirbaseCategory == Airbase.Category.AIRDROME then RoutePoint.airdromeId = AirbaseID else - self:E("ERROR: Unknown airbase category in COORDINATE:WaypointAir()!") + self:E( "ERROR: Unknown airbase category in COORDINATE:WaypointAir()!" ) end end - + -- Time in minutes to stay at the airbase before resuming route. - if Type==COORDINATE.WaypointType.LandingReFuAr then - RoutePoint.timeReFuAr=timeReFuAr or 10 + if Type == COORDINATE.WaypointType.LandingReFuAr then + RoutePoint.timeReFuAr = timeReFuAr or 10 end - + -- Waypoint tasks. RoutePoint.task = {} RoutePoint.task.id = "ComboTask" RoutePoint.task.params = {} RoutePoint.task.params.tasks = DCSTasks or {} - - --RoutePoint.properties={} - --RoutePoint.properties.addopt={} - - --RoutePoint.formation_template="" + + -- RoutePoint.properties={} + -- RoutePoint.properties.addopt={} + + -- RoutePoint.formation_template="" -- Debug. - self:T({RoutePoint=RoutePoint}) - + self:T( { RoutePoint = RoutePoint } ) + -- Return waypoint. return RoutePoint end - --- Build a Waypoint Air "Turning Point". -- @param #COORDINATE self -- @param #COORDINATE.WaypointAltType AltType The altitude type. @@ -1245,7 +1214,6 @@ do -- COORDINATE return self:WaypointAir( AltType, COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint, Speed, true, nil, DCSTasks, description ) end - --- Build a Waypoint Air "Fly Over Point". -- @param #COORDINATE self -- @param #COORDINATE.WaypointAltType AltType The altitude type. @@ -1254,8 +1222,7 @@ do -- COORDINATE function COORDINATE:WaypointAirFlyOverPoint( AltType, Speed ) return self:WaypointAir( AltType, COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.FlyoverPoint, Speed ) end - - + --- Build a Waypoint Air "Take Off Parking Hot". -- @param #COORDINATE self -- @param #COORDINATE.WaypointAltType AltType The altitude type. @@ -1264,7 +1231,6 @@ do -- COORDINATE function COORDINATE:WaypointAirTakeOffParkingHot( AltType, Speed ) return self:WaypointAir( AltType, COORDINATE.WaypointType.TakeOffParkingHot, COORDINATE.WaypointAction.FromParkingAreaHot, Speed ) end - --- Build a Waypoint Air "Take Off Parking". -- @param #COORDINATE self @@ -1274,8 +1240,7 @@ do -- COORDINATE function COORDINATE:WaypointAirTakeOffParking( AltType, Speed ) return self:WaypointAir( AltType, COORDINATE.WaypointType.TakeOffParking, COORDINATE.WaypointAction.FromParkingArea, Speed ) end - - + --- Build a Waypoint Air "Take Off Runway". -- @param #COORDINATE self -- @param #COORDINATE.WaypointAltType AltType The altitude type. @@ -1284,8 +1249,7 @@ do -- COORDINATE function COORDINATE:WaypointAirTakeOffRunway( AltType, Speed ) return self:WaypointAir( AltType, COORDINATE.WaypointType.TakeOff, COORDINATE.WaypointAction.FromRunway, Speed ) end - - + --- Build a Waypoint Air "Landing". -- @param #COORDINATE self -- @param DCS#Speed Speed Airspeed in km/h. @@ -1294,16 +1258,16 @@ do -- COORDINATE -- @param #string description A text description of the waypoint, which will be shown on the F10 map. -- @return #table The route point. -- @usage - -- + -- -- LandingZone = ZONE:New( "LandingZone" ) -- LandingCoord = LandingZone:GetCoordinate() -- LandingWaypoint = LandingCoord:WaypointAirLanding( 60 ) -- HeliGroup:Route( { LandWaypoint }, 1 ) -- Start landing the helicopter in one second. - -- + -- function COORDINATE:WaypointAirLanding( Speed, airbase, DCSTasks, description ) - return self:WaypointAir(nil, COORDINATE.WaypointType.Land, COORDINATE.WaypointAction.Landing, Speed, false, airbase, DCSTasks, description) + return self:WaypointAir( nil, COORDINATE.WaypointType.Land, COORDINATE.WaypointAction.Landing, Speed, false, airbase, DCSTasks, description ) end - + --- Build a Waypoint Air "LandingReFuAr". Mimics the aircraft ReFueling and ReArming. -- @param #COORDINATE self -- @param DCS#Speed Speed Airspeed in km/h. @@ -1313,10 +1277,9 @@ do -- COORDINATE -- @param #string description A text description of the waypoint, which will be shown on the F10 map. -- @return #table The route point. function COORDINATE:WaypointAirLandingReFu( Speed, airbase, timeReFuAr, DCSTasks, description ) - return self:WaypointAir(nil, COORDINATE.WaypointType.LandingReFuAr, COORDINATE.WaypointAction.LandingReFuAr, Speed, false, airbase, DCSTasks, description, timeReFuAr or 10) - end - - + return self:WaypointAir( nil, COORDINATE.WaypointType.LandingReFuAr, COORDINATE.WaypointAction.LandingReFuAr, Speed, false, airbase, DCSTasks, description, timeReFuAr or 10 ) + end + --- Build an ground type route point. -- @param #COORDINATE self -- @param #number Speed (Optional) Speed in km/h. The default speed is 20 km/h. @@ -1327,32 +1290,32 @@ do -- COORDINATE self:F2( { Speed, Formation, DCSTasks } ) local RoutePoint = {} - - RoutePoint.x = self.x - RoutePoint.y = self.z - - RoutePoint.alt = self:GetLandHeight()+1 - RoutePoint.alt_type = COORDINATE.WaypointAltType.BARO - - RoutePoint.type = "Turning Point" - - RoutePoint.action = Formation or "Off Road" - RoutePoint.formation_template="" - - RoutePoint.ETA=0 - RoutePoint.ETA_locked=false - RoutePoint.speed = ( Speed or 20 ) / 3.6 + RoutePoint.x = self.x + RoutePoint.y = self.z + + RoutePoint.alt = self:GetLandHeight() + 1 + RoutePoint.alt_type = COORDINATE.WaypointAltType.BARO + + RoutePoint.type = "Turning Point" + + RoutePoint.action = Formation or "Off Road" + RoutePoint.formation_template = "" + + RoutePoint.ETA = 0 + RoutePoint.ETA_locked = false + + RoutePoint.speed = (Speed or 20) / 3.6 RoutePoint.speed_locked = true RoutePoint.task = {} RoutePoint.task.id = "ComboTask" RoutePoint.task.params = {} RoutePoint.task.params.tasks = DCSTasks or {} - + return RoutePoint end - + --- Build route waypoint point for Naval units. -- @param #COORDINATE self -- @param #number Speed (Optional) Speed in km/h. The default speed is 20 km/h. @@ -1363,21 +1326,21 @@ do -- COORDINATE self:F2( { Speed, Depth, DCSTasks } ) local RoutePoint = {} - - RoutePoint.x = self.x - RoutePoint.y = self.z - - RoutePoint.alt = Depth or self.y -- Depth is for submarines only. Ships should have alt=0. + + RoutePoint.x = self.x + RoutePoint.y = self.z + + RoutePoint.alt = Depth or self.y -- Depth is for submarines only. Ships should have alt=0. RoutePoint.alt_type = "BARO" - RoutePoint.type = "Turning Point" + RoutePoint.type = "Turning Point" RoutePoint.action = "Turning Point" RoutePoint.formation_template = "" - RoutePoint.ETA=0 - RoutePoint.ETA_locked=false + RoutePoint.ETA = 0 + RoutePoint.ETA_locked = false - RoutePoint.speed = ( Speed or 20 ) / 3.6 + RoutePoint.speed = (Speed or 20) / 3.6 RoutePoint.speed_locked = true RoutePoint.task = {} @@ -1394,38 +1357,38 @@ do -- COORDINATE -- @param #number Coalition (Optional) Coalition of the airbase. -- @return Wrapper.Airbase#AIRBASE Closest Airbase to the given coordinate. -- @return #number Distance to the closest airbase in meters. - function COORDINATE:GetClosestAirbase2(Category, Coalition) - + function COORDINATE:GetClosestAirbase2( Category, Coalition ) + -- Get all airbases of the map. - local airbases=AIRBASE.GetAllAirbases(Coalition) - - local closest=nil - local distmin=nil + local airbases = AIRBASE.GetAllAirbases( Coalition ) + + local closest = nil + local distmin = nil -- Loop over all airbases. - for _,_airbase in pairs(airbases) do - local airbase=_airbase --Wrapper.Airbase#AIRBASE + for _, _airbase in pairs( airbases ) do + local airbase = _airbase -- Wrapper.Airbase#AIRBASE if airbase then - local category=airbase:GetAirbaseCategory() - if Category and Category==category or Category==nil then + local category = airbase:GetAirbaseCategory() + if Category and Category == category or Category == nil then -- Distance to airbase. - local dist=self:Get2DDistance(airbase:GetCoordinate()) - - if closest==nil then - distmin=dist - closest=airbase + local dist = self:Get2DDistance( airbase:GetCoordinate() ) + + if closest == nil then + distmin = dist + closest = airbase else - if dist=2 then - for i=1,#Path-1 do - Way=Way+Path[i+1]:Get2DDistance(Path[i]) + if #Path >= 2 then + for i = 1, #Path - 1 do + Way = Way + Path[i + 1]:Get2DDistance( Path[i] ) end else -- There are cases where no path on road can be found. - return nil,nil,false - end - + return nil, nil, false + end + return Path, Way, GotPath end @@ -1645,8 +1607,8 @@ do -- COORDINATE -- @param #COORDINATE self -- @return DCS#SurfaceType Surface type. function COORDINATE:GetSurfaceType() - local vec2=self:GetVec2() - local surface=land.getSurfaceType(vec2) + local vec2 = self:GetVec2() + local surface = land.getSurfaceType( vec2 ) return surface end @@ -1654,46 +1616,44 @@ do -- COORDINATE -- @param #COORDINATE self -- @return #boolean If true, the surface type at the coordinate is land. function COORDINATE:IsSurfaceTypeLand() - return self:GetSurfaceType()==land.SurfaceType.LAND + return self:GetSurfaceType() == land.SurfaceType.LAND end --- Checks if the surface type is road. -- @param #COORDINATE self -- @return #boolean If true, the surface type at the coordinate is land. function COORDINATE:IsSurfaceTypeLand() - return self:GetSurfaceType()==land.SurfaceType.LAND + return self:GetSurfaceType() == land.SurfaceType.LAND end - --- Checks if the surface type is road. -- @param #COORDINATE self -- @return #boolean If true, the surface type at the coordinate is a road. function COORDINATE:IsSurfaceTypeRoad() - return self:GetSurfaceType()==land.SurfaceType.ROAD + return self:GetSurfaceType() == land.SurfaceType.ROAD end --- Checks if the surface type is runway. -- @param #COORDINATE self -- @return #boolean If true, the surface type at the coordinate is a runway or taxi way. function COORDINATE:IsSurfaceTypeRunway() - return self:GetSurfaceType()==land.SurfaceType.RUNWAY + return self:GetSurfaceType() == land.SurfaceType.RUNWAY end --- Checks if the surface type is shallow water. -- @param #COORDINATE self -- @return #boolean If true, the surface type at the coordinate is a shallow water. function COORDINATE:IsSurfaceTypeShallowWater() - return self:GetSurfaceType()==land.SurfaceType.SHALLOW_WATER + return self:GetSurfaceType() == land.SurfaceType.SHALLOW_WATER end --- Checks if the surface type is water. -- @param #COORDINATE self -- @return #boolean If true, the surface type at the coordinate is a deep water. function COORDINATE:IsSurfaceTypeWater() - return self:GetSurfaceType()==land.SurfaceType.WATER + return self:GetSurfaceType() == land.SurfaceType.WATER end - --- Creates an explosion at the point of a certain intensity. -- @param #COORDINATE self -- @param #number ExplosionIntensity Intensity of the explosion in kg TNT. Default 100 kg. @@ -1701,9 +1661,9 @@ do -- COORDINATE -- @return #COORDINATE self function COORDINATE:Explosion( ExplosionIntensity, Delay ) self:F2( { ExplosionIntensity } ) - ExplosionIntensity=ExplosionIntensity or 100 - if Delay and Delay>0 then - SCHEDULER:New(nil, self.Explosion, {self,ExplosionIntensity}, Delay) + ExplosionIntensity = ExplosionIntensity or 100 + if Delay and Delay > 0 then + SCHEDULER:New( nil, self.Explosion, { self, ExplosionIntensity }, Delay ) else trigger.action.explosion( self:GetVec3(), ExplosionIntensity ) end @@ -1714,12 +1674,11 @@ do -- COORDINATE -- @param #COORDINATE self -- @param #number power Power of illumination bomb in Candela. -- @return #COORDINATE self - function COORDINATE:IlluminationBomb(power) + function COORDINATE:IlluminationBomb( power ) self:F2() trigger.action.illuminationBomb( self:GetVec3(), power ) end - --- Smokes the point in a color. -- @param #COORDINATE self -- @param Utilities.Utils#SMOKECOLOR SmokeColor @@ -1768,8 +1727,8 @@ do -- COORDINATE -- @param Utilities.Utils#BIGSMOKEPRESET preset Smoke preset (0=small smoke and fire, 1=medium smoke and fire, 2=large smoke and fire, 3=huge smoke and fire, 4=small smoke, 5=medium smoke, 6=large smoke, 7=huge smoke). -- @param #number density (Optional) Smoke density. Number in [0,...,1]. Default 0.5. function COORDINATE:BigSmokeAndFire( preset, density ) - self:F2( { preset=preset, density=density } ) - density=density or 0.5 + self:F2( { preset = preset, density = density } ) + density = density or 0.5 trigger.action.effectSmokeBig( self:GetVec3(), preset, density ) end @@ -1777,73 +1736,73 @@ do -- COORDINATE -- @param #COORDINATE self -- @number density (Optional) Smoke density. Number between 0 and 1. Default 0.5. function COORDINATE:BigSmokeAndFireSmall( density ) - self:F2( { density=density } ) - density=density or 0.5 - self:BigSmokeAndFire(BIGSMOKEPRESET.SmallSmokeAndFire, density) + self:F2( { density = density } ) + density = density or 0.5 + self:BigSmokeAndFire( BIGSMOKEPRESET.SmallSmokeAndFire, density ) end --- Medium smoke and fire at the coordinate. -- @param #COORDINATE self -- @number density (Optional) Smoke density. Number between 0 and 1. Default 0.5. function COORDINATE:BigSmokeAndFireMedium( density ) - self:F2( { density=density } ) - density=density or 0.5 - self:BigSmokeAndFire(BIGSMOKEPRESET.MediumSmokeAndFire, density) + self:F2( { density = density } ) + density = density or 0.5 + self:BigSmokeAndFire( BIGSMOKEPRESET.MediumSmokeAndFire, density ) end - + --- Large smoke and fire at the coordinate. -- @param #COORDINATE self -- @number density (Optional) Smoke density. Number between 0 and 1. Default 0.5. function COORDINATE:BigSmokeAndFireLarge( density ) - self:F2( { density=density } ) - density=density or 0.5 - self:BigSmokeAndFire(BIGSMOKEPRESET.LargeSmokeAndFire, density) + self:F2( { density = density } ) + density = density or 0.5 + self:BigSmokeAndFire( BIGSMOKEPRESET.LargeSmokeAndFire, density ) end --- Huge smoke and fire at the coordinate. -- @param #COORDINATE self -- @number density (Optional) Smoke density. Number between 0 and 1. Default 0.5. function COORDINATE:BigSmokeAndFireHuge( density ) - self:F2( { density=density } ) - density=density or 0.5 - self:BigSmokeAndFire(BIGSMOKEPRESET.HugeSmokeAndFire, density) + self:F2( { density = density } ) + density = density or 0.5 + self:BigSmokeAndFire( BIGSMOKEPRESET.HugeSmokeAndFire, density ) end - + --- Small smoke at the coordinate. -- @param #COORDINATE self -- @number density (Optional) Smoke density. Number between 0 and 1. Default 0.5. function COORDINATE:BigSmokeSmall( density ) - self:F2( { density=density } ) - density=density or 0.5 - self:BigSmokeAndFire(BIGSMOKEPRESET.SmallSmoke, density) + self:F2( { density = density } ) + density = density or 0.5 + self:BigSmokeAndFire( BIGSMOKEPRESET.SmallSmoke, density ) end - + --- Medium smoke at the coordinate. -- @param #COORDINATE self -- @number density (Optional) Smoke density. Number between 0 and 1. Default 0.5. function COORDINATE:BigSmokeMedium( density ) - self:F2( { density=density } ) - density=density or 0.5 - self:BigSmokeAndFire(BIGSMOKEPRESET.MediumSmoke, density) + self:F2( { density = density } ) + density = density or 0.5 + self:BigSmokeAndFire( BIGSMOKEPRESET.MediumSmoke, density ) end --- Large smoke at the coordinate. -- @param #COORDINATE self -- @number density (Optional) Smoke density. Number between 0 and 1. Default 0.5. function COORDINATE:BigSmokeLarge( density ) - self:F2( { density=density } ) - density=density or 0.5 - self:BigSmokeAndFire(BIGSMOKEPRESET.LargeSmoke, density) + self:F2( { density = density } ) + density = density or 0.5 + self:BigSmokeAndFire( BIGSMOKEPRESET.LargeSmoke, density ) end - + --- Huge smoke at the coordinate. -- @param #COORDINATE self -- @number density (Optional) Smoke density. Number between 0 and 1. Default 0.5. function COORDINATE:BigSmokeHuge( density ) - self:F2( { density=density } ) - density=density or 0.5 - self:BigSmokeAndFire(BIGSMOKEPRESET.HugeSmoke, density) - end + self:F2( { density = density } ) + density = density or 0.5 + self:BigSmokeAndFire( BIGSMOKEPRESET.HugeSmoke, density ) + end --- Flares the point in a color. -- @param #COORDINATE self @@ -1884,9 +1843,9 @@ do -- COORDINATE self:F2( Azimuth ) self:Flare( FLARECOLOR.Red, Azimuth ) end - + do -- Markings - + --- Mark to All -- @param #COORDINATE self -- @param #string MarkText Free format text that shows the marking clarification. @@ -1898,11 +1857,11 @@ do -- COORDINATE -- local MarkID = TargetCoord:MarkToAll( "This is a target for all players" ) function COORDINATE:MarkToAll( MarkText, ReadOnly, Text ) local MarkID = UTILS.GetMarkID() - if ReadOnly==nil then - ReadOnly=false + if ReadOnly == nil then + ReadOnly = false end - local text=Text or "" - trigger.action.markToAll( MarkID, MarkText, self:GetVec3(), ReadOnly, text) + local text = Text or "" + trigger.action.markToAll( MarkID, MarkText, self:GetVec3(), ReadOnly, text ) return MarkID end @@ -1918,10 +1877,10 @@ do -- COORDINATE -- local MarkID = TargetCoord:MarkToCoalition( "This is a target for the red coalition", coalition.side.RED ) function COORDINATE:MarkToCoalition( MarkText, Coalition, ReadOnly, Text ) local MarkID = UTILS.GetMarkID() - if ReadOnly==nil then - ReadOnly=false + if ReadOnly == nil then + ReadOnly = false end - local text=Text or "" + local text = Text or "" trigger.action.markToCoalition( MarkID, MarkText, self:GetVec3(), Coalition, ReadOnly, text ) return MarkID end @@ -1965,14 +1924,14 @@ do -- COORDINATE -- local MarkID = TargetCoord:MarkToGroup( "This is a target for the attack group", AttackGroup ) function COORDINATE:MarkToGroup( MarkText, MarkGroup, ReadOnly, Text ) local MarkID = UTILS.GetMarkID() - if ReadOnly==nil then - ReadOnly=false + if ReadOnly == nil then + ReadOnly = false end - local text=Text or "" + local text = Text or "" trigger.action.markToGroup( MarkID, MarkText, self:GetVec3(), MarkGroup:GetID(), ReadOnly, text ) return MarkID end - + --- Remove a mark -- @param #COORDINATE self -- @param #number MarkID The ID of the mark to be removed. @@ -1985,36 +1944,36 @@ do -- COORDINATE function COORDINATE:RemoveMark( MarkID ) trigger.action.removeMark( MarkID ) end - + --- Line to all. -- Creates a line on the F10 map from one point to another. -- @param #COORDINATE self - -- @param #COORDINATE Endpoint COORDIANTE to where the line is drawn. + -- @param #COORDINATE Endpoint COORDINATE to where the line is drawn. -- @param #number Coalition Coalition: All=-1, Neutral=0, Red=1, Blue=2. Default -1=All. -- @param #table Color RGB color table {r, g, b}, e.g. {1,0,0} for red (default). -- @param #number Alpha Transparency [0,1]. Default 1. - -- @param #number LineType Line type: 0=No line, 1=Solid, 2=Dashed, 3=Dotted, 4=Dot dash, 5=Long dash, 6=Two dash. Default 1=Solid. + -- @param #number LineType Line type: 0=No line, 1=Solid, 2=Dashed, 3=Dotted, 4=Dot dash, 5=Long dash, 6=Two dash. Default 1=Solid. -- @param #boolean ReadOnly (Optional) Mark is readonly and cannot be removed by users. Default false. -- @param #string Text (Optional) Text displayed when mark is added. Default none. - -- @return #number The resulting Mark ID, which is a number. Can be used to remove the object again. - function COORDINATE:LineToAll(Endpoint, Coalition, Color, Alpha, LineType, ReadOnly, Text) + -- @return #number The resulting Mark ID, which is a number. Can be used to remove the object again. + function COORDINATE:LineToAll( Endpoint, Coalition, Color, Alpha, LineType, ReadOnly, Text ) local MarkID = UTILS.GetMarkID() - if ReadOnly==nil then - ReadOnly=false + if ReadOnly == nil then + ReadOnly = false end - local vec3=Endpoint:GetVec3() - Coalition=Coalition or -1 - Color=Color or {1,0,0} - Color[4]=Alpha or 1.0 - LineType=LineType or 1 - trigger.action.lineToAll(Coalition, MarkID, self:GetVec3(), vec3, Color, LineType, ReadOnly, Text or "") + local vec3 = Endpoint:GetVec3() + Coalition = Coalition or -1 + Color = Color or { 1, 0, 0 } + Color[4] = Alpha or 1.0 + LineType = LineType or 1 + trigger.action.lineToAll( Coalition, MarkID, self:GetVec3(), vec3, Color, LineType, ReadOnly, Text or "" ) return MarkID end - + --- Circle to all. -- Creates a circle on the map with a given radius, color, fill color, and outline. -- @param #COORDINATE self - -- @param #numberr Radius Radius in meters. Default 1000 m. + -- @param #number Radius Radius in meters. Default 1000 m. -- @param #number Coalition Coalition: All=-1, Neutral=0, Red=1, Blue=2. Default -1=All. -- @param #table Color RGB color table {r, g, b}, e.g. {1,0,0} for red (default). -- @param #number Alpha Transparency [0,1]. Default 1. @@ -2023,205 +1982,205 @@ do -- COORDINATE -- @param #number LineType Line type: 0=No line, 1=Solid, 2=Dashed, 3=Dotted, 4=Dot dash, 5=Long dash, 6=Two dash. Default 1=Solid. -- @param #boolean ReadOnly (Optional) Mark is readonly and cannot be removed by users. Default false. -- @param #string Text (Optional) Text displayed when mark is added. Default none. - -- @return #number The resulting Mark ID, which is a number. Can be used to remove the object again. - function COORDINATE:CircleToAll(Radius, Coalition, Color, Alpha, FillColor, FillAlpha, LineType, ReadOnly, Text) + -- @return #number The resulting Mark ID, which is a number. Can be used to remove the object again. + function COORDINATE:CircleToAll( Radius, Coalition, Color, Alpha, FillColor, FillAlpha, LineType, ReadOnly, Text ) local MarkID = UTILS.GetMarkID() - if ReadOnly==nil then - ReadOnly=false + if ReadOnly == nil then + ReadOnly = false end - local vec3=self:GetVec3() - Radius=Radius or 1000 - Coalition=Coalition or -1 - Color=Color or {1,0,0} - Color[4]=Alpha or 1.0 - LineType=LineType or 1 - FillColor=FillColor or Color - FillColor[4]=FillAlpha or 0.15 - trigger.action.circleToAll(Coalition, MarkID, vec3, Radius, Color, FillColor, LineType, ReadOnly, Text or "") + local vec3 = self:GetVec3() + Radius = Radius or 1000 + Coalition = Coalition or -1 + Color = Color or { 1, 0, 0 } + Color[4] = Alpha or 1.0 + LineType = LineType or 1 + FillColor = FillColor or Color + FillColor[4] = FillAlpha or 0.15 + trigger.action.circleToAll( Coalition, MarkID, vec3, Radius, Color, FillColor, LineType, ReadOnly, Text or "" ) return MarkID - end - + end + end -- Markings - --- Rectangle to all. Creates a rectangle on the map from the COORDINATE in one corner to the end COORDINATE in the opposite corner. - -- Creates a line on the F10 map from one point to another. - -- @param #COORDINATE self - -- @param #COORDINATE Endpoint COORDIANTE in the opposite corner. - -- @param #number Coalition Coalition: All=-1, Neutral=0, Red=1, Blue=2. Default -1=All. - -- @param #table Color RGB color table {r, g, b}, e.g. {1,0,0} for red (default). - -- @param #number Alpha Transparency [0,1]. Default 1. - -- @param #table FillColor RGB color table {r, g, b}, e.g. {1,0,0} for red. Default is same as `Color` value. - -- @param #number FillAlpha Transparency [0,1]. Default 0.15. - -- @param #number LineType Line type: 0=No line, 1=Solid, 2=Dashed, 3=Dotted, 4=Dot dash, 5=Long dash, 6=Two dash. Default 1=Solid. - -- @param #boolean ReadOnly (Optional) Mark is readonly and cannot be removed by users. Default false. - -- @param #string Text (Optional) Text displayed when mark is added. Default none. - -- @return #number The resulting Mark ID, which is a number. Can be used to remove the object again. - function COORDINATE:RectToAll(Endpoint, Coalition, Color, Alpha, FillColor, FillAlpha, LineType, ReadOnly, Text) - local MarkID = UTILS.GetMarkID() - if ReadOnly==nil then - ReadOnly=false - end - local vec3=Endpoint:GetVec3() - Coalition=Coalition or -1 - Color=Color or {1,0,0} - Color[4]=Alpha or 1.0 - LineType=LineType or 1 - FillColor=FillColor or Color - FillColor[4]=FillAlpha or 0.15 - trigger.action.rectToAll(Coalition, MarkID, self:GetVec3(), vec3, Color, FillColor, LineType, ReadOnly, Text or "") - return MarkID + --- Rectangle to all. Creates a rectangle on the map from the COORDINATE in one corner to the end COORDINATE in the opposite corner. + -- Creates a line on the F10 map from one point to another. + -- @param #COORDINATE self + -- @param #COORDINATE Endpoint COORDINATE in the opposite corner. + -- @param #number Coalition Coalition: All=-1, Neutral=0, Red=1, Blue=2. Default -1=All. + -- @param #table Color RGB color table {r, g, b}, e.g. {1,0,0} for red (default). + -- @param #number Alpha Transparency [0,1]. Default 1. + -- @param #table FillColor RGB color table {r, g, b}, e.g. {1,0,0} for red. Default is same as `Color` value. + -- @param #number FillAlpha Transparency [0,1]. Default 0.15. + -- @param #number LineType Line type: 0=No line, 1=Solid, 2=Dashed, 3=Dotted, 4=Dot dash, 5=Long dash, 6=Two dash. Default 1=Solid. + -- @param #boolean ReadOnly (Optional) Mark is readonly and cannot be removed by users. Default false. + -- @param #string Text (Optional) Text displayed when mark is added. Default none. + -- @return #number The resulting Mark ID, which is a number. Can be used to remove the object again. + function COORDINATE:RectToAll( Endpoint, Coalition, Color, Alpha, FillColor, FillAlpha, LineType, ReadOnly, Text ) + local MarkID = UTILS.GetMarkID() + if ReadOnly == nil then + ReadOnly = false end - - --- Creates a shape defined by 4 points on the F10 map. The first point is the current COORDINATE. The remaining three points need to be specified. - -- @param #COORDINATE self - -- @param #COORDINATE Coord2 Second COORDIANTE of the quad shape. - -- @param #COORDINATE Coord3 Third COORDIANTE of the quad shape. - -- @param #COORDINATE Coord4 Fourth COORDIANTE of the quad shape. - -- @param #number Coalition Coalition: All=-1, Neutral=0, Red=1, Blue=2. Default -1=All. - -- @param #table Color RGB color table {r, g, b}, e.g. {1,0,0} for red (default). - -- @param #number Alpha Transparency [0,1]. Default 1. - -- @param #table FillColor RGB color table {r, g, b}, e.g. {1,0,0} for red. Default is same as `Color` value. - -- @param #number FillAlpha Transparency [0,1]. Default 0.15. - -- @param #number LineType Line type: 0=No line, 1=Solid, 2=Dashed, 3=Dotted, 4=Dot dash, 5=Long dash, 6=Two dash. Default 1=Solid. - -- @param #boolean ReadOnly (Optional) Mark is readonly and cannot be removed by users. Default false. - -- @param #string Text (Optional) Text displayed when mark is added. Default none. - -- @return #number The resulting Mark ID, which is a number. Can be used to remove the object again. - function COORDINATE:QuadToAll(Coord2, Coord3, Coord4, Coalition, Color, Alpha, FillColor, FillAlpha, LineType, ReadOnly, Text) - local MarkID = UTILS.GetMarkID() - if ReadOnly==nil then - ReadOnly=false - end - local point1=self:GetVec3() - local point2=Coord2:GetVec3() - local point3=Coord3:GetVec3() - local point4=Coord4:GetVec3() - Coalition=Coalition or -1 - Color=Color or {1,0,0} - Color[4]=Alpha or 1.0 - LineType=LineType or 1 - FillColor=FillColor or Color - FillColor[4]=FillAlpha or 0.15 - trigger.action.quadToAll(Coalition, MarkID, self:GetVec3(), point2, point3, point4, Color, FillColor, LineType, ReadOnly, Text or "") - return MarkID - end - - --- Creates a free form shape on the F10 map. The first point is the current COORDINATE. The remaining points need to be specified. - -- **NOTE**: A free form polygon must have **at least three points** in total and currently only **up to 10 points** in total are supported. - -- @param #COORDINATE self - -- @param #table Coordinates Table of coordinates of the remaining points of the shape. - -- @param #number Coalition Coalition: All=-1, Neutral=0, Red=1, Blue=2. Default -1=All. - -- @param #table Color RGB color table {r, g, b}, e.g. {1,0,0} for red (default). - -- @param #number Alpha Transparency [0,1]. Default 1. - -- @param #table FillColor RGB color table {r, g, b}, e.g. {1,0,0} for red. Default is same as `Color` value. - -- @param #number FillAlpha Transparency [0,1]. Default 0.15. - -- @param #number LineType Line type: 0=No line, 1=Solid, 2=Dashed, 3=Dotted, 4=Dot dash, 5=Long dash, 6=Two dash. Default 1=Solid. - -- @param #boolean ReadOnly (Optional) Mark is readonly and cannot be removed by users. Default false. - -- @param #string Text (Optional) Text displayed when mark is added. Default none. - -- @return #number The resulting Mark ID, which is a number. Can be used to remove the object again. - function COORDINATE:MarkupToAllFreeForm(Coordinates, Coalition, Color, Alpha, FillColor, FillAlpha, LineType, ReadOnly, Text) - - local MarkID = UTILS.GetMarkID() - if ReadOnly==nil then - ReadOnly=false - end - - Coalition=Coalition or -1 - - Color=Color or {1,0,0} - Color[4]=Alpha or 1.0 - - LineType=LineType or 1 - - FillColor=FillColor or UTILS.DeepCopy(Color) - FillColor[4]=FillAlpha or 0.15 - - local vecs={} - vecs[1]=self:GetVec3() - for i,coord in ipairs(Coordinates) do - vecs[i+1]=coord:GetVec3() - end + local vec3 = Endpoint:GetVec3() + Coalition = Coalition or -1 + Color = Color or { 1, 0, 0 } + Color[4] = Alpha or 1.0 + LineType = LineType or 1 + FillColor = FillColor or Color + FillColor[4] = FillAlpha or 0.15 + trigger.action.rectToAll( Coalition, MarkID, self:GetVec3(), vec3, Color, FillColor, LineType, ReadOnly, Text or "" ) + return MarkID + end - if #vecs<3 then - self:E("ERROR: A free form polygon needs at least three points!") - elseif #vecs==3 then - trigger.action.markupToAll(7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], Color, FillColor, LineType, ReadOnly, Text or "") - elseif #vecs==4 then - trigger.action.markupToAll(7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], vecs[4], Color, FillColor, LineType, ReadOnly, Text or "") - elseif #vecs==5 then - trigger.action.markupToAll(7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], vecs[4], vecs[5], Color, FillColor, LineType, ReadOnly, Text or "") - elseif #vecs==6 then - trigger.action.markupToAll(7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], vecs[4], vecs[5], vecs[6], Color, FillColor, LineType, Text or "") - elseif #vecs==7 then - trigger.action.markupToAll(7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], vecs[4], vecs[5], vecs[6], vecs[7], Color, FillColor, LineType, ReadOnly, Text or "") - elseif #vecs==8 then - trigger.action.markupToAll(7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], vecs[4], vecs[5], vecs[6], vecs[7], vecs[8], Color, FillColor, LineType, ReadOnly, Text or "") - elseif #vecs==9 then - trigger.action.markupToAll(7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], vecs[4], vecs[5], vecs[6], vecs[7], vecs[8], vecs[9], Color, FillColor, LineType, ReadOnly, Text or "") - elseif #vecs==10 then - trigger.action.markupToAll(7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], vecs[4], vecs[5], vecs[6], vecs[7], vecs[8], vecs[9], vecs[10], Color, FillColor, LineType, ReadOnly, Text or "") - else - self:E("ERROR: Currently a free form polygon can only have 10 points in total!") - -- Unfortunately, unpack(vecs) does not work! So no idea how to generalize this :( - trigger.action.markupToAll(7, Coalition, MarkID, unpack(vecs), Color, FillColor, LineType, ReadOnly, Text or "") - end - - return MarkID - end - - --- Text to all. Creates a text imposed on the map at the COORDINATE. Text scales with the map. - -- @param #COORDINATE self - -- @param #string Text Text displayed on the F10 map. - -- @param #number Coalition Coalition: All=-1, Neutral=0, Red=1, Blue=2. Default -1=All. - -- @param #table Color RGB color table {r, g, b}, e.g. {1,0,0} for red (default). - -- @param #number Alpha Transparency [0,1]. Default 1. - -- @param #table FillColor RGB color table {r, g, b}, e.g. {1,0,0} for red. Default is same as `Color` value. - -- @param #number FillAlpha Transparency [0,1]. Default 0.3. - -- @param #number FontSize Font size. Default 14. - -- @param #boolean ReadOnly (Optional) Mark is readonly and cannot be removed by users. Default false. - -- @return #number The resulting Mark ID, which is a number. Can be used to remove the object again. - function COORDINATE:TextToAll(Text, Coalition, Color, Alpha, FillColor, FillAlpha, FontSize, ReadOnly) - local MarkID = UTILS.GetMarkID() - if ReadOnly==nil then - ReadOnly=false - end - Coalition=Coalition or -1 - Color=Color or {1,0,0} - Color[4]=Alpha or 1.0 - FillColor=FillColor or Color - FillColor[4]=FillAlpha or 0.3 - FontSize=FontSize or 14 - trigger.action.textToAll(Coalition, MarkID, self:GetVec3(), Color, FillColor, FontSize, ReadOnly, Text or "Hello World") - return MarkID + --- Creates a shape defined by 4 points on the F10 map. The first point is the current COORDINATE. The remaining three points need to be specified. + -- @param #COORDINATE self + -- @param #COORDINATE Coord2 Second COORDIANTE of the quad shape. + -- @param #COORDINATE Coord3 Third COORDIANTE of the quad shape. + -- @param #COORDINATE Coord4 Fourth COORDIANTE of the quad shape. + -- @param #number Coalition Coalition: All=-1, Neutral=0, Red=1, Blue=2. Default -1=All. + -- @param #table Color RGB color table {r, g, b}, e.g. {1,0,0} for red (default). + -- @param #number Alpha Transparency [0,1]. Default 1. + -- @param #table FillColor RGB color table {r, g, b}, e.g. {1,0,0} for red. Default is same as `Color` value. + -- @param #number FillAlpha Transparency [0,1]. Default 0.15. + -- @param #number LineType Line type: 0=No line, 1=Solid, 2=Dashed, 3=Dotted, 4=Dot dash, 5=Long dash, 6=Two dash. Default 1=Solid. + -- @param #boolean ReadOnly (Optional) Mark is readonly and cannot be removed by users. Default false. + -- @param #string Text (Optional) Text displayed when mark is added. Default none. + -- @return #number The resulting Mark ID, which is a number. Can be used to remove the object again. + function COORDINATE:QuadToAll( Coord2, Coord3, Coord4, Coalition, Color, Alpha, FillColor, FillAlpha, LineType, ReadOnly, Text ) + local MarkID = UTILS.GetMarkID() + if ReadOnly == nil then + ReadOnly = false end - - --- Arrow to all. Creates an arrow from the COORDINATE to the endpoint COORDINATE on the F10 map. There is no control over other dimensions of the arrow. - -- @param #COORDINATE self - -- @param #COORDINATE Endpoint COORDINATE where the tip of the arrow is pointing at. - -- @param #number Coalition Coalition: All=-1, Neutral=0, Red=1, Blue=2. Default -1=All. - -- @param #table Color RGB color table {r, g, b}, e.g. {1,0,0} for red (default). - -- @param #number Alpha Transparency [0,1]. Default 1. - -- @param #table FillColor RGB color table {r, g, b}, e.g. {1,0,0} for red. Default is same as `Color` value. - -- @param #number FillAlpha Transparency [0,1]. Default 0.15. - -- @param #number LineType Line type: 0=No line, 1=Solid, 2=Dashed, 3=Dotted, 4=Dot dash, 5=Long dash, 6=Two dash. Default 1=Solid. - -- @param #boolean ReadOnly (Optional) Mark is readonly and cannot be removed by users. Default false. - -- @param #string Text (Optional) Text displayed when mark is added. Default none. - -- @return #number The resulting Mark ID, which is a number. Can be used to remove the object again. - function COORDINATE:ArrowToAll(Endpoint, Coalition, Color, Alpha, FillColor, FillAlpha, LineType, ReadOnly, Text) - local MarkID = UTILS.GetMarkID() - if ReadOnly==nil then - ReadOnly=false - end - local vec3=Endpoint:GetVec3() - Coalition=Coalition or -1 - Color=Color or {1,0,0} - Color[4]=Alpha or 1.0 - LineType=LineType or 1 - FillColor=FillColor or Color - FillColor[4]=FillAlpha or 0.15 - --trigger.action.textToAll(Coalition, MarkID, self:GetVec3(), Color, FillColor, FontSize, ReadOnly, Text or "Hello World") - trigger.action.arrowToAll(Coalition, MarkID, vec3, self:GetVec3(), Color, FillColor, LineType, ReadOnly, Text or "") - return MarkID - end + local point1 = self:GetVec3() + local point2 = Coord2:GetVec3() + local point3 = Coord3:GetVec3() + local point4 = Coord4:GetVec3() + Coalition = Coalition or -1 + Color = Color or { 1, 0, 0 } + Color[4] = Alpha or 1.0 + LineType = LineType or 1 + FillColor = FillColor or Color + FillColor[4] = FillAlpha or 0.15 + trigger.action.quadToAll( Coalition, MarkID, self:GetVec3(), point2, point3, point4, Color, FillColor, LineType, ReadOnly, Text or "" ) + return MarkID + end + + --- Creates a free form shape on the F10 map. The first point is the current COORDINATE. The remaining points need to be specified. + -- **NOTE**: A free form polygon must have **at least three points** in total and currently only **up to 10 points** in total are supported. + -- @param #COORDINATE self + -- @param #table Coordinates Table of coordinates of the remaining points of the shape. + -- @param #number Coalition Coalition: All=-1, Neutral=0, Red=1, Blue=2. Default -1=All. + -- @param #table Color RGB color table {r, g, b}, e.g. {1,0,0} for red (default). + -- @param #number Alpha Transparency [0,1]. Default 1. + -- @param #table FillColor RGB color table {r, g, b}, e.g. {1,0,0} for red. Default is same as `Color` value. + -- @param #number FillAlpha Transparency [0,1]. Default 0.15. + -- @param #number LineType Line type: 0=No line, 1=Solid, 2=Dashed, 3=Dotted, 4=Dot dash, 5=Long dash, 6=Two dash. Default 1=Solid. + -- @param #boolean ReadOnly (Optional) Mark is readonly and cannot be removed by users. Default false. + -- @param #string Text (Optional) Text displayed when mark is added. Default none. + -- @return #number The resulting Mark ID, which is a number. Can be used to remove the object again. + function COORDINATE:MarkupToAllFreeForm( Coordinates, Coalition, Color, Alpha, FillColor, FillAlpha, LineType, ReadOnly, Text ) + + local MarkID = UTILS.GetMarkID() + if ReadOnly == nil then + ReadOnly = false + end + + Coalition = Coalition or -1 + + Color = Color or { 1, 0, 0 } + Color[4] = Alpha or 1.0 + + LineType = LineType or 1 + + FillColor = FillColor or UTILS.DeepCopy( Color ) + FillColor[4] = FillAlpha or 0.15 + + local vecs = {} + vecs[1] = self:GetVec3() + for i, coord in ipairs( Coordinates ) do + vecs[i + 1] = coord:GetVec3() + end + + if #vecs < 3 then + self:E( "ERROR: A free form polygon needs at least three points!" ) + elseif #vecs == 3 then + trigger.action.markupToAll( 7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], Color, FillColor, LineType, ReadOnly, Text or "" ) + elseif #vecs == 4 then + trigger.action.markupToAll( 7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], vecs[4], Color, FillColor, LineType, ReadOnly, Text or "" ) + elseif #vecs == 5 then + trigger.action.markupToAll( 7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], vecs[4], vecs[5], Color, FillColor, LineType, ReadOnly, Text or "" ) + elseif #vecs == 6 then + trigger.action.markupToAll( 7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], vecs[4], vecs[5], vecs[6], Color, FillColor, LineType, Text or "" ) + elseif #vecs == 7 then + trigger.action.markupToAll( 7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], vecs[4], vecs[5], vecs[6], vecs[7], Color, FillColor, LineType, ReadOnly, Text or "" ) + elseif #vecs == 8 then + trigger.action.markupToAll( 7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], vecs[4], vecs[5], vecs[6], vecs[7], vecs[8], Color, FillColor, LineType, ReadOnly, Text or "" ) + elseif #vecs == 9 then + trigger.action.markupToAll( 7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], vecs[4], vecs[5], vecs[6], vecs[7], vecs[8], vecs[9], Color, FillColor, LineType, ReadOnly, Text or "" ) + elseif #vecs == 10 then + trigger.action.markupToAll( 7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], vecs[4], vecs[5], vecs[6], vecs[7], vecs[8], vecs[9], vecs[10], Color, FillColor, LineType, ReadOnly, Text or "" ) + else + self:E( "ERROR: Currently a free form polygon can only have 10 points in total!" ) + -- Unfortunately, unpack(vecs) does not work! So no idea how to generalize this :( + trigger.action.markupToAll( 7, Coalition, MarkID, unpack( vecs ), Color, FillColor, LineType, ReadOnly, Text or "" ) + end + + return MarkID + end + + --- Text to all. Creates a text imposed on the map at the COORDINATE. Text scales with the map. + -- @param #COORDINATE self + -- @param #string Text Text displayed on the F10 map. + -- @param #number Coalition Coalition: All=-1, Neutral=0, Red=1, Blue=2. Default -1=All. + -- @param #table Color RGB color table {r, g, b}, e.g. {1,0,0} for red (default). + -- @param #number Alpha Transparency [0,1]. Default 1. + -- @param #table FillColor RGB color table {r, g, b}, e.g. {1,0,0} for red. Default is same as `Color` value. + -- @param #number FillAlpha Transparency [0,1]. Default 0.3. + -- @param #number FontSize Font size. Default 14. + -- @param #boolean ReadOnly (Optional) Mark is readonly and cannot be removed by users. Default false. + -- @return #number The resulting Mark ID, which is a number. Can be used to remove the object again. + function COORDINATE:TextToAll( Text, Coalition, Color, Alpha, FillColor, FillAlpha, FontSize, ReadOnly ) + local MarkID = UTILS.GetMarkID() + if ReadOnly == nil then + ReadOnly = false + end + Coalition = Coalition or -1 + Color = Color or { 1, 0, 0 } + Color[4] = Alpha or 1.0 + FillColor = FillColor or Color + FillColor[4] = FillAlpha or 0.3 + FontSize = FontSize or 14 + trigger.action.textToAll( Coalition, MarkID, self:GetVec3(), Color, FillColor, FontSize, ReadOnly, Text or "Hello World" ) + return MarkID + end + + --- Arrow to all. Creates an arrow from the COORDINATE to the endpoint COORDINATE on the F10 map. There is no control over other dimensions of the arrow. + -- @param #COORDINATE self + -- @param #COORDINATE Endpoint COORDINATE where the tip of the arrow is pointing at. + -- @param #number Coalition Coalition: All=-1, Neutral=0, Red=1, Blue=2. Default -1=All. + -- @param #table Color RGB color table {r, g, b}, e.g. {1,0,0} for red (default). + -- @param #number Alpha Transparency [0,1]. Default 1. + -- @param #table FillColor RGB color table {r, g, b}, e.g. {1,0,0} for red. Default is same as `Color` value. + -- @param #number FillAlpha Transparency [0,1]. Default 0.15. + -- @param #number LineType Line type: 0=No line, 1=Solid, 2=Dashed, 3=Dotted, 4=Dot dash, 5=Long dash, 6=Two dash. Default 1=Solid. + -- @param #boolean ReadOnly (Optional) Mark is readonly and cannot be removed by users. Default false. + -- @param #string Text (Optional) Text displayed when mark is added. Default none. + -- @return #number The resulting Mark ID, which is a number. Can be used to remove the object again. + function COORDINATE:ArrowToAll( Endpoint, Coalition, Color, Alpha, FillColor, FillAlpha, LineType, ReadOnly, Text ) + local MarkID = UTILS.GetMarkID() + if ReadOnly == nil then + ReadOnly = false + end + local vec3 = Endpoint:GetVec3() + Coalition = Coalition or -1 + Color = Color or { 1, 0, 0 } + Color[4] = Alpha or 1.0 + LineType = LineType or 1 + FillColor = FillColor or Color + FillColor[4] = FillAlpha or 0.15 + -- trigger.action.textToAll(Coalition, MarkID, self:GetVec3(), Color, FillColor, FontSize, ReadOnly, Text or "Hello World") + trigger.action.arrowToAll( Coalition, MarkID, vec3, self:GetVec3(), Color, FillColor, LineType, ReadOnly, Text or "" ) + return MarkID + end --- Returns if a Coordinate has Line of Sight (LOS) with the ToCoordinate. -- @param #COORDINATE self @@ -2229,8 +2188,8 @@ do -- COORDINATE -- @param #number Offset Height offset in meters. Default 2 m. -- @return #boolean true If the ToCoordinate has LOS with the Coordinate, otherwise false. function COORDINATE:IsLOS( ToCoordinate, Offset ) - - Offset=Offset or 2 + + Offset = Offset or 2 -- Measurement of visibility should not be from the ground, so Adding a hypotethical 2 meters to each Coordinate. local FromVec3 = self:GetVec3() @@ -2244,7 +2203,6 @@ do -- COORDINATE return IsLOS end - --- Returns if a Coordinate is in a certain Radius of this Coordinate in 2D plane using the X and Z axis. -- @param #COORDINATE self -- @param #COORDINATE Coordinate The coordinate that will be tested if it is in the radius of this coordinate. @@ -2254,13 +2212,12 @@ do -- COORDINATE local InVec2 = self:GetVec2() local Vec2 = Coordinate:GetVec2() - - local InRadius = UTILS.IsInRadius( InVec2, Vec2, Radius) + + local InRadius = UTILS.IsInRadius( InVec2, Vec2, Radius ) return InRadius end - --- Returns if a Coordinate is in a certain radius of this Coordinate in 3D space using the X, Y and Z axis. -- So Radius defines the radius of the a Sphere in 3D space around this coordinate. -- @param #COORDINATE self @@ -2271,8 +2228,8 @@ do -- COORDINATE local InVec3 = self:GetVec3() local Vec3 = Coordinate:GetVec3() - - local InSphere = UTILS.IsInSphere( InVec3, Vec3, Radius) + + local InSphere = UTILS.IsInSphere( InVec3, Vec3, Radius ) return InSphere end @@ -2282,185 +2239,185 @@ do -- COORDINATE -- @param #number Day The day. -- @param #number Month The month. -- @param #number Year The year. - -- @param #boolean InSeconds If true, return the sun rise time in seconds. + -- @param #boolean InSeconds If true, return the sun rise time in seconds. -- @return #string Sunrise time, e.g. "05:41". - function COORDINATE:GetSunriseAtDate(Day, Month, Year, InSeconds) - + function COORDINATE:GetSunriseAtDate( Day, Month, Year, InSeconds ) + -- Day of the year. - local DayOfYear=UTILS.GetDayOfYear(Year, Month, Day) - - local Latitude, Longitude=self:GetLLDDM() - - local Tdiff=UTILS.GMTToLocalTimeDifference() - - local sunrise=UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, true, Tdiff) + local DayOfYear = UTILS.GetDayOfYear( Year, Month, Day ) + + local Latitude, Longitude = self:GetLLDDM() + + local Tdiff = UTILS.GMTToLocalTimeDifference() + + local sunrise = UTILS.GetSunRiseAndSet( DayOfYear, Latitude, Longitude, true, Tdiff ) if InSeconds then return sunrise else - return UTILS.SecondsToClock(sunrise, true) + return UTILS.SecondsToClock( sunrise, true ) end - + end - + --- Get sun rise time for a specific day of the year at the coordinate. -- @param #COORDINATE self -- @param #number DayOfYear The day of the year. - -- @param #boolean InSeconds If true, return the sun rise time in seconds. + -- @param #boolean InSeconds If true, return the sun rise time in seconds. -- @return #string Sunrise time, e.g. "05:41". - function COORDINATE:GetSunriseAtDayOfYear(DayOfYear, InSeconds) - - local Latitude, Longitude=self:GetLLDDM() - - local Tdiff=UTILS.GMTToLocalTimeDifference() - - local sunrise=UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, true, Tdiff) + function COORDINATE:GetSunriseAtDayOfYear( DayOfYear, InSeconds ) + + local Latitude, Longitude = self:GetLLDDM() + + local Tdiff = UTILS.GMTToLocalTimeDifference() + + local sunrise = UTILS.GetSunRiseAndSet( DayOfYear, Latitude, Longitude, true, Tdiff ) if InSeconds then return sunrise else - return UTILS.SecondsToClock(sunrise, true) + return UTILS.SecondsToClock( sunrise, true ) end - + end - + --- Get todays sun rise time. -- @param #COORDINATE self - -- @param #boolean InSeconds If true, return the sun rise time in seconds. + -- @param #boolean InSeconds If true, return the sun rise time in seconds. -- @return #string Sunrise time, e.g. "05:41". - function COORDINATE:GetSunrise(InSeconds) - + function COORDINATE:GetSunrise( InSeconds ) + -- Get current day of the year. - local DayOfYear=UTILS.GetMissionDayOfYear() - + local DayOfYear = UTILS.GetMissionDayOfYear() + -- Lat and long at this point. - local Latitude, Longitude=self:GetLLDDM() - + local Latitude, Longitude = self:GetLLDDM() + -- GMT time diff. - local Tdiff=UTILS.GMTToLocalTimeDifference() - + local Tdiff = UTILS.GMTToLocalTimeDifference() + -- Sunrise in seconds of the day. - local sunrise=UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, true, Tdiff) - - local date=UTILS.GetDCSMissionDate() - + local sunrise = UTILS.GetSunRiseAndSet( DayOfYear, Latitude, Longitude, true, Tdiff ) + + local date = UTILS.GetDCSMissionDate() + -- Debug output. - --self:I(string.format("Sun rise at lat=%.3f long=%.3f on %s (DayOfYear=%d): %s (%d sec of the day) (GMT %d)", Latitude, Longitude, date, DayOfYear, tostring(UTILS.SecondsToClock(sunrise)), sunrise, Tdiff)) - + -- self:I(string.format("Sun rise at lat=%.3f long=%.3f on %s (DayOfYear=%d): %s (%d sec of the day) (GMT %d)", Latitude, Longitude, date, DayOfYear, tostring(UTILS.SecondsToClock(sunrise)), sunrise, Tdiff)) + if InSeconds then return sunrise else - return UTILS.SecondsToClock(sunrise, true) + return UTILS.SecondsToClock( sunrise, true ) end - + end --- Get minutes until the next sun rise at this coordinate. -- @param #COORDINATE self -- @param OnlyToday If true, only calculate the sun rise of today. If sun has already risen, the time in negative minutes since sunrise is reported. -- @return #number Minutes to the next sunrise. - function COORDINATE:GetMinutesToSunrise(OnlyToday) - + function COORDINATE:GetMinutesToSunrise( OnlyToday ) + -- Seconds of today - local time=UTILS.SecondsOfToday() + local time = UTILS.SecondsOfToday() -- Next Sunrise in seconds. - local sunrise=nil - + local sunrise = nil + -- Time to sunrise. - local delta=nil - + local delta = nil + if OnlyToday then - + --- -- Sunrise of today --- - - sunrise=self:GetSunrise(true) - - delta=sunrise-time - + + sunrise = self:GetSunrise( true ) + + delta = sunrise - time + else --- -- Sunrise of tomorrow --- - - -- Tomorrows day of the year. - local DayOfYear=UTILS.GetMissionDayOfYear()+1 - local Latitude, Longitude=self:GetLLDDM() - - local Tdiff=UTILS.GMTToLocalTimeDifference() - - sunrise=UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, true, Tdiff) - - delta=sunrise+UTILS.SecondsToMidnight() + -- Tomorrows day of the year. + local DayOfYear = UTILS.GetMissionDayOfYear() + 1 + + local Latitude, Longitude = self:GetLLDDM() + + local Tdiff = UTILS.GMTToLocalTimeDifference() + + sunrise = UTILS.GetSunRiseAndSet( DayOfYear, Latitude, Longitude, true, Tdiff ) + + delta = sunrise + UTILS.SecondsToMidnight() end - return delta/60 + return delta / 60 end - + --- Check if it is day, i.e. if the sun has risen about the horizon at this coordinate. -- @param #COORDINATE self -- @param #string Clock (Optional) Time in format "HH:MM:SS+D", e.g. "05:40:00+3" to check if is day at 5:40 at third day after mission start. Default is to check right now. -- @return #boolean If true, it is day. If false, it is night time. - function COORDINATE:IsDay(Clock) - - if Clock then - - local Time=UTILS.ClockToSeconds(Clock) - - local clock=UTILS.Split(Clock, "+")[1] - - -- Tomorrows day of the year. - local DayOfYear=UTILS.GetMissionDayOfYear(Time) + function COORDINATE:IsDay( Clock ) + + if Clock then + + local Time = UTILS.ClockToSeconds( Clock ) + + local clock = UTILS.Split( Clock, "+" )[1] + + -- Tomorrows day of the year. + local DayOfYear = UTILS.GetMissionDayOfYear( Time ) + + local Latitude, Longitude = self:GetLLDDM() + + local Tdiff = UTILS.GMTToLocalTimeDifference() + + local sunrise = UTILS.GetSunRiseAndSet( DayOfYear, Latitude, Longitude, true, Tdiff ) + local sunset = UTILS.GetSunRiseAndSet( DayOfYear, Latitude, Longitude, false, Tdiff ) + + local time = UTILS.ClockToSeconds( clock ) - local Latitude, Longitude=self:GetLLDDM() - - local Tdiff=UTILS.GMTToLocalTimeDifference() - - local sunrise=UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, true, Tdiff) - local sunset=UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, false, Tdiff) - - local time=UTILS.ClockToSeconds(clock) - -- Check if time is between sunrise and sunset. - if time>sunrise and time<=sunset then - return true - else - return false - end - - else - - -- Todays sun rise in sec. - local sunrise=self:GetSunrise(true) - - -- Todays sun set in sec. - local sunset=self:GetSunset(true) - - -- Seconds passed since midnight. - local time=UTILS.SecondsOfToday() - - -- Check if time is between sunrise and sunset. - if time>sunrise and time<=sunset then + if time > sunrise and time <= sunset then return true else return false end - - end - + + else + + -- Todays sun rise in sec. + local sunrise = self:GetSunrise( true ) + + -- Todays sun set in sec. + local sunset = self:GetSunset( true ) + + -- Seconds passed since midnight. + local time = UTILS.SecondsOfToday() + + -- Check if time is between sunrise and sunset. + if time > sunrise and time <= sunset then + return true + else + return false + end + + end + end - + --- Check if it is night, i.e. if the sun has set below the horizon at this coordinate. - -- @param #COORDINATE self + -- @param #COORDINATE self -- @param #string Clock (Optional) Time in format "HH:MM:SS+D", e.g. "05:40:00+3" to check if is night at 5:40 at third day after mission start. Default is to check right now. -- @return #boolean If true, it is night. If false, it is day time. - function COORDINATE:IsNight(Clock) - return not self:IsDay(Clock) + function COORDINATE:IsNight( Clock ) + return not self:IsDay( Clock ) end --- Get sun set time for a specific date at the coordinate. @@ -2468,106 +2425,105 @@ do -- COORDINATE -- @param #number Day The day. -- @param #number Month The month. -- @param #number Year The year. - -- @param #boolean InSeconds If true, return the sun rise time in seconds. + -- @param #boolean InSeconds If true, return the sun rise time in seconds. -- @return #string Sunset time, e.g. "20:41". - function COORDINATE:GetSunsetAtDate(Day, Month, Year, InSeconds) - - -- Day of the year. - local DayOfYear=UTILS.GetDayOfYear(Year, Month, Day) - - local Latitude, Longitude=self:GetLLDDM() - - local Tdiff=UTILS.GMTToLocalTimeDifference() - - local sunset=UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, false, Tdiff) + function COORDINATE:GetSunsetAtDate( Day, Month, Year, InSeconds ) + + -- Day of the year. + local DayOfYear = UTILS.GetDayOfYear( Year, Month, Day ) + + local Latitude, Longitude = self:GetLLDDM() + + local Tdiff = UTILS.GMTToLocalTimeDifference() + + local sunset = UTILS.GetSunRiseAndSet( DayOfYear, Latitude, Longitude, false, Tdiff ) if InSeconds then return sunset else - return UTILS.SecondsToClock(sunset, true) + return UTILS.SecondsToClock( sunset, true ) end - + end --- Get todays sun set time. -- @param #COORDINATE self - -- @param #boolean InSeconds If true, return the sun set time in seconds. + -- @param #boolean InSeconds If true, return the sun set time in seconds. -- @return #string Sunrise time, e.g. "20:41". - function COORDINATE:GetSunset(InSeconds) - + function COORDINATE:GetSunset( InSeconds ) + -- Get current day of the year. - local DayOfYear=UTILS.GetMissionDayOfYear() - + local DayOfYear = UTILS.GetMissionDayOfYear() + -- Lat and long at this point. - local Latitude, Longitude=self:GetLLDDM() - + local Latitude, Longitude = self:GetLLDDM() + -- GMT time diff. - local Tdiff=UTILS.GMTToLocalTimeDifference() - + local Tdiff = UTILS.GMTToLocalTimeDifference() + -- Sunrise in seconds of the day. - local sunrise=UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, false, Tdiff) - - local date=UTILS.GetDCSMissionDate() - + local sunrise = UTILS.GetSunRiseAndSet( DayOfYear, Latitude, Longitude, false, Tdiff ) + + local date = UTILS.GetDCSMissionDate() + -- Debug output. - --self:I(string.format("Sun set at lat=%.3f long=%.3f on %s (DayOfYear=%d): %s (%d sec of the day) (GMT %d)", Latitude, Longitude, date, DayOfYear, tostring(UTILS.SecondsToClock(sunrise)), sunrise, Tdiff)) - + -- self:I(string.format("Sun set at lat=%.3f long=%.3f on %s (DayOfYear=%d): %s (%d sec of the day) (GMT %d)", Latitude, Longitude, date, DayOfYear, tostring(UTILS.SecondsToClock(sunrise)), sunrise, Tdiff)) + if InSeconds then return sunrise else - return UTILS.SecondsToClock(sunrise, true) + return UTILS.SecondsToClock( sunrise, true ) end - + end - + --- Get minutes until the next sun set at this coordinate. -- @param #COORDINATE self -- @param OnlyToday If true, only calculate the sun set of today. If sun has already set, the time in negative minutes since sunset is reported. -- @return #number Minutes to the next sunrise. - function COORDINATE:GetMinutesToSunset(OnlyToday) - + function COORDINATE:GetMinutesToSunset( OnlyToday ) + -- Seconds of today - local time=UTILS.SecondsOfToday() + local time = UTILS.SecondsOfToday() -- Next Sunset in seconds. - local sunset=nil - + local sunset = nil + -- Time to sunrise. - local delta=nil - + local delta = nil + if OnlyToday then - + --- -- Sunset of today --- - - sunset=self:GetSunset(true) - - delta=sunset-time - + + sunset = self:GetSunset( true ) + + delta = sunset - time + else --- -- Sunset of tomorrow --- - - -- Tomorrows day of the year. - local DayOfYear=UTILS.GetMissionDayOfYear()+1 - local Latitude, Longitude=self:GetLLDDM() - - local Tdiff=UTILS.GMTToLocalTimeDifference() - - sunset=UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, false, Tdiff) - - delta=sunset+UTILS.SecondsToMidnight() + -- Tomorrows day of the year. + local DayOfYear = UTILS.GetMissionDayOfYear() + 1 + + local Latitude, Longitude = self:GetLLDDM() + + local Tdiff = UTILS.GMTToLocalTimeDifference() + + sunset = UTILS.GetSunRiseAndSet( DayOfYear, Latitude, Longitude, false, Tdiff ) + + delta = sunset + UTILS.SecondsToMidnight() end - return delta/60 + return delta / 60 end - --- Return a BR string from a COORDINATE to the COORDINATE. -- @param #COORDINATE self -- @param #COORDINATE FromCoordinate The coordinate to measure the distance and the bearing from. @@ -2575,7 +2531,7 @@ do -- COORDINATE -- @return #string The BR text. function COORDINATE:ToStringBR( FromCoordinate, Settings ) local DirectionVec3 = FromCoordinate:GetDirectionVec3( self ) - local AngleRadians = self:GetAngleRadians( DirectionVec3 ) + local AngleRadians = self:GetAngleRadians( DirectionVec3 ) local Distance = self:Get2DDistance( FromCoordinate ) return "BR, " .. self:GetBRText( AngleRadians, Distance, Settings ) end @@ -2587,7 +2543,7 @@ do -- COORDINATE -- @return #string The BR text. function COORDINATE:ToStringBRA( FromCoordinate, Settings, Language ) local DirectionVec3 = FromCoordinate:GetDirectionVec3( self ) - local AngleRadians = self:GetAngleRadians( DirectionVec3 ) + local AngleRadians = self:GetAngleRadians( DirectionVec3 ) local Distance = FromCoordinate:Get2DDistance( self ) local Altitude = self:GetAltitudeText() return "BRA, " .. self:GetBRAText( AngleRadians, Distance, Settings, Language ) @@ -2601,7 +2557,7 @@ do -- COORDINATE function COORDINATE:ToStringBULLS( Coalition, Settings ) local BullsCoordinate = COORDINATE:NewFromVec3( coalition.getMainRefPoint( Coalition ) ) local DirectionVec3 = BullsCoordinate:GetDirectionVec3( self ) - local AngleRadians = self:GetAngleRadians( DirectionVec3 ) + local AngleRadians = self:GetAngleRadians( DirectionVec3 ) local Distance = self:Get2DDistance( BullsCoordinate ) local Altitude = self:GetAltitudeText() return "BULLS, " .. self:GetBRText( AngleRadians, Distance, Settings ) @@ -2615,7 +2571,7 @@ do -- COORDINATE local Heading = self.Heading local DirectionVec3 = self:GetDirectionVec3( TargetCoordinate ) local Angle = self:GetAngleDegrees( DirectionVec3 ) - + if Heading then local Aspect = Angle - Heading if Aspect > -135 and Aspect <= -45 then @@ -2638,7 +2594,7 @@ do -- COORDINATE -- @param #COORDINATE self -- @return #number Latitude in DDM. -- @return #number Lontitude in DDM. - function COORDINATE:GetLLDDM() + function COORDINATE:GetLLDDM() return coord.LOtoLL( self:GetVec3() ) end @@ -2646,7 +2602,7 @@ do -- COORDINATE -- @param #COORDINATE self -- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object. -- @return #string The LL DMS Text - function COORDINATE:ToStringLLDMS( Settings ) + function COORDINATE:ToStringLLDMS( Settings ) local LL_Accuracy = Settings and Settings.LL_Accuracy or _SETTINGS.LL_Accuracy local lat, lon = coord.LOtoLL( self:GetVec3() ) @@ -2668,7 +2624,7 @@ do -- COORDINATE -- @param #COORDINATE self -- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object. -- @return #string The MGRS Text - function COORDINATE:ToStringMGRS( Settings ) --R2.1 Fixes issue #424. + function COORDINATE:ToStringMGRS( Settings ) -- R2.1 Fixes issue #424. local MGRS_Accuracy = Settings and Settings.MGRS_Accuracy or _SETTINGS.MGRS_Accuracy local lat, lon = coord.LOtoLL( self:GetVec3() ) @@ -2686,25 +2642,25 @@ do -- COORDINATE -- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object. -- @return #string The coordinate Text in the configured coordinate system. function COORDINATE:ToStringFromRP( ReferenceCoord, ReferenceName, Controllable, Settings ) - + self:F2( { ReferenceCoord = ReferenceCoord, ReferenceName = ReferenceName } ) - local Settings = Settings or ( Controllable and _DATABASE:GetPlayerSettings( Controllable:GetPlayerName() ) ) or _SETTINGS - + local Settings = Settings or (Controllable and _DATABASE:GetPlayerSettings( Controllable:GetPlayerName() )) or _SETTINGS + local IsAir = Controllable and Controllable:IsAirPlane() or false if IsAir then local DirectionVec3 = ReferenceCoord:GetDirectionVec3( self ) - local AngleRadians = self:GetAngleRadians( DirectionVec3 ) + local AngleRadians = self:GetAngleRadians( DirectionVec3 ) local Distance = self:Get2DDistance( ReferenceCoord ) return "Targets are the last seen " .. self:GetBRText( AngleRadians, Distance, Settings ) .. " from " .. ReferenceName else local DirectionVec3 = ReferenceCoord:GetDirectionVec3( self ) - local AngleRadians = self:GetAngleRadians( DirectionVec3 ) + local AngleRadians = self:GetAngleRadians( DirectionVec3 ) local Distance = self:Get2DDistance( ReferenceCoord ) return "Target are located " .. self:GetBRText( AngleRadians, Distance, Settings ) .. " from " .. ReferenceName end - + return nil end @@ -2714,13 +2670,13 @@ do -- COORDINATE -- @param Wrapper.Controllable#CONTROLLABLE Controllable -- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object. -- @return #string The coordinate Text in the configured coordinate system. - function COORDINATE:ToStringA2G( Controllable, Settings ) - + function COORDINATE:ToStringA2G( Controllable, Settings ) + self:F2( { Controllable = Controllable and Controllable:GetName() } ) - local Settings = Settings or ( Controllable and _DATABASE:GetPlayerSettings( Controllable:GetPlayerName() ) ) or _SETTINGS + local Settings = Settings or (Controllable and _DATABASE:GetPlayerSettings( Controllable:GetPlayerName() )) or _SETTINGS - if Settings:IsA2G_BR() then + if Settings:IsA2G_BR() then -- If no Controllable is given to calculate the BR from, then MGRS will be used!!! if Controllable then local Coordinate = Controllable:GetCoordinate() @@ -2729,10 +2685,10 @@ do -- COORDINATE return self:ToStringMGRS( Settings ) end end - if Settings:IsA2G_LL_DMS() then + if Settings:IsA2G_LL_DMS() then return self:ToStringLLDMS( Settings ) end - if Settings:IsA2G_LL_DDM() then + if Settings:IsA2G_LL_DDM() then return self:ToStringLLDDM( Settings ) end if Settings:IsA2G_MGRS() then @@ -2743,22 +2699,21 @@ do -- COORDINATE end - --- Provides a coordinate string of the point, based on the A2A coordinate format system. -- @param #COORDINATE self -- @param Wrapper.Controllable#CONTROLLABLE Controllable -- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object. -- @return #string The coordinate Text in the configured coordinate system. function COORDINATE:ToStringA2A( Controllable, Settings, Language ) -- R2.2 - + self:F2( { Controllable = Controllable and Controllable:GetName() } ) - local Settings = Settings or ( Controllable and _DATABASE:GetPlayerSettings( Controllable:GetPlayerName() ) ) or _SETTINGS + local Settings = Settings or (Controllable and _DATABASE:GetPlayerSettings( Controllable:GetPlayerName() )) or _SETTINGS - if Settings:IsA2A_BRAA() then + if Settings:IsA2A_BRAA() then if Controllable then local Coordinate = Controllable:GetCoordinate() - return self:ToStringBRA( Coordinate, Settings, Language ) + return self:ToStringBRA( Coordinate, Settings, Language ) else return self:ToStringMGRS( Settings, Language ) end @@ -2767,10 +2722,10 @@ do -- COORDINATE local Coalition = Controllable:GetCoalition() return self:ToStringBULLS( Coalition, Settings, Language ) end - if Settings:IsA2A_LL_DMS() then + if Settings:IsA2A_LL_DMS() then return self:ToStringLLDMS( Settings, Language ) end - if Settings:IsA2A_LL_DDM() then + if Settings:IsA2A_LL_DDM() then return self:ToStringLLDDM( Settings, Language ) end if Settings:IsA2A_MGRS() then @@ -2790,13 +2745,13 @@ do -- COORDINATE -- @param Tasking.Task#TASK Task The task for which coordinates need to be calculated. -- @return #string The coordinate Text in the configured coordinate system. function COORDINATE:ToString( Controllable, Settings, Task ) - --- self:E( { Controllable = Controllable and Controllable:GetName() } ) - local Settings = Settings or ( Controllable and _DATABASE:GetPlayerSettings( Controllable:GetPlayerName() ) ) or _SETTINGS + -- self:E( { Controllable = Controllable and Controllable:GetName() } ) + + local Settings = Settings or (Controllable and _DATABASE:GetPlayerSettings( Controllable:GetPlayerName() )) or _SETTINGS local ModeA2A = nil - + if Task then if Task:IsInstanceOf( TASK_A2A ) then ModeA2A = true @@ -2807,30 +2762,28 @@ do -- COORDINATE if Task:IsInstanceOf( TASK_CARGO ) then ModeA2A = false end - if Task:IsInstanceOf( TASK_CAPTURE_ZONE ) then - ModeA2A = false - end + if Task:IsInstanceOf( TASK_CAPTURE_ZONE ) then + ModeA2A = false + end end end end - - + if ModeA2A == nil then - local IsAir = Controllable and ( Controllable:IsAirPlane() or Controllable:IsHelicopter() ) or false - if IsAir then + local IsAir = Controllable and (Controllable:IsAirPlane() or Controllable:IsHelicopter()) or false + if IsAir then ModeA2A = true else ModeA2A = false end end - if ModeA2A == true then return self:ToStringA2A( Controllable, Settings ) else return self:ToStringA2G( Controllable, Settings ) end - + return nil end @@ -2843,10 +2796,10 @@ do -- COORDINATE -- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object. -- @return #string The pressure text in the configured measurement system. function COORDINATE:ToStringPressure( Controllable, Settings ) -- R2.3 - + self:F2( { Controllable = Controllable and Controllable:GetName() } ) - local Settings = Settings or ( Controllable and _DATABASE:GetPlayerSettings( Controllable:GetPlayerName() ) ) or _SETTINGS + local Settings = Settings or (Controllable and _DATABASE:GetPlayerSettings( Controllable:GetPlayerName() )) or _SETTINGS return self:GetPressureText( nil, Settings ) end @@ -2859,10 +2812,10 @@ do -- COORDINATE -- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object. -- @return #string The wind text in the configured measurement system. function COORDINATE:ToStringWind( Controllable, Settings ) - + self:F2( { Controllable = Controllable and Controllable:GetName() } ) - local Settings = Settings or ( Controllable and _DATABASE:GetPlayerSettings( Controllable:GetPlayerName() ) ) or _SETTINGS + local Settings = Settings or (Controllable and _DATABASE:GetPlayerSettings( Controllable:GetPlayerName() )) or _SETTINGS return self:GetWindText( nil, Settings ) end @@ -2875,10 +2828,10 @@ do -- COORDINATE -- @param Core.Settings#SETTINGS -- @return #string The temperature text in the configured measurement system. function COORDINATE:ToStringTemperature( Controllable, Settings ) - + self:F2( { Controllable = Controllable and Controllable:GetName() } ) - local Settings = Settings or ( Controllable and _DATABASE:GetPlayerSettings( Controllable:GetPlayerName() ) ) or _SETTINGS + local Settings = Settings or (Controllable and _DATABASE:GetPlayerSettings( Controllable:GetPlayerName() )) or _SETTINGS return self:GetTemperatureText( nil, Settings ) end @@ -2898,8 +2851,7 @@ do -- POINT_VEC3 -- @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. -- -- **Important Note:** Most of the functions in this section were taken from MIST, and reworked to OO concepts. @@ -2907,7 +2859,6 @@ do -- POINT_VEC3 -- 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: @@ -2929,19 +2880,16 @@ do -- POINT_VEC3 -- -- 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", @@ -3085,7 +3033,7 @@ do -- POINT_VEC3 -- @param #number z The z coordinate value to add to the current z coodinate. -- @return #POINT_VEC3 function POINT_VEC3:AddZ( z ) - self.z = self.z +z + self.z = self.z + z return self end @@ -3107,7 +3055,7 @@ do -- 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. -- -- ## POINT_VEC2 constructor @@ -3135,8 +3083,6 @@ do -- POINT_VEC2 POINT_VEC2 = { ClassName = "POINT_VEC2", } - - --- POINT_VEC2 constructor. -- @param #POINT_VEC2 self @@ -3289,11 +3235,10 @@ do -- POINT_VEC2 -- @param #number Altitude The Altitude to add. If nothing (nil) is given, then the current land altitude is set. -- @return #POINT_VEC2 function POINT_VEC2:AddAlt( Altitude ) - self.y = land.getHeight( { x = self.x, y = self.z } ) + Altitude or 0 + self.y = land.getHeight( { x = self.x, y = self.z } ) + (Altitude or 0) return self end - --- Return a random POINT_VEC2 within an Outer Radius and optionally NOT within an Inner Radius of the POINT_VEC2. -- @param #POINT_VEC2 self -- @param DCS#Distance OuterRadius @@ -3313,7 +3258,7 @@ do -- POINT_VEC2 function POINT_VEC2:DistanceFromPointVec2( PointVec2Reference ) self:F2( PointVec2Reference ) - local Distance = ( ( PointVec2Reference.x - self.x ) ^ 2 + ( PointVec2Reference.z - self.z ) ^2 ) ^ 0.5 + local Distance = ((PointVec2Reference.x - self.x) ^ 2 + (PointVec2Reference.z - self.z) ^ 2) ^ 0.5 self:T2( Distance ) return Distance @@ -3321,4 +3266,3 @@ do -- POINT_VEC2 end - diff --git a/Moose Development/Moose/Functional/PseudoATC.lua b/Moose Development/Moose/Functional/PseudoATC.lua index 1143b00e8..7358dda2c 100644 --- a/Moose Development/Moose/Functional/PseudoATC.lua +++ b/Moose Development/Moose/Functional/PseudoATC.lua @@ -742,7 +742,7 @@ function PSEUDOATC:ReportWeather(GID, UID, position, location) local T=position:GetTemperature() -- Correct unit system. - local _T=string.format('%d°F', UTILS.CelciusToFarenheit(T)) + local _T=string.format('%d°F', UTILS.CelsiusToFahrenheit(T)) if settings:IsMetric() then _T=string.format('%d°C', T) end diff --git a/Moose Development/Moose/Functional/Range.lua b/Moose Development/Moose/Functional/Range.lua index f086917c7..845f062bf 100644 --- a/Moose Development/Moose/Functional/Range.lua +++ b/Moose Development/Moose/Functional/Range.lua @@ -260,7 +260,7 @@ -- -- Add bombing targets. A good hit is if the bomb falls less then 50 m from the target. -- GoldwaterRange:AddBombingTargets(bombtargets, 50) -- --- -- Start range. +-- -- Start Range. -- GoldwaterRange:Start() -- -- The [476th - Air Weapons Range Objects mod](http://www.476vfightergroup.com/downloads.php?do=file&id=287) is (implicitly) used in this example. @@ -288,7 +288,7 @@ RANGE = { ClassName = "RANGE", Debug = false, - verbose = 0, + verbose = 0, id = nil, rangename = nil, location = nil, @@ -329,7 +329,7 @@ RANGE = { instructor = nil, rangecontrolfreq = nil, rangecontrol = nil, - soundpath = "Range Soundfiles/" + soundpath = "Range Soundfiles/", } --- Default range parameters. @@ -345,7 +345,7 @@ RANGE.Defaults = { boxlength = 3000, -- meters boxwidth = 300, -- meters goodpass = 20, -- targethits per pass - foulline = 610 -- meters + foulline = 610, -- meters } --- Target type, i.e. unit, static, or coordinate. @@ -500,7 +500,7 @@ RANGE.Sound = { IRDecimal = { filename = "IR-Decimal.ogg", duration = 0.54 }, IRMegaHertz = { filename = "IR-MegaHertz.ogg", duration = 0.87 }, IREnterRange = { filename = "IR-EnterRange.ogg", duration = 4.83 }, - IRExitRange = { filename = "IR-ExitRange.ogg", duration = 3.10 } + IRExitRange = { filename = "IR-ExitRange.ogg", duration = 3.10 }, } --- Global list of all defined range names. @@ -1089,7 +1089,7 @@ end --- Set sound files folder within miz file. -- @param #RANGE self --- @param #string path Path for sound files. Default "ATIS Soundfiles/". Mind the slash "/" at the end! +-- @param #string path Path for sound files. Default "Range Soundfiles/". Mind the slash "/" at the end! -- @return #RANGE self function RANGE:SetSoundfilesPath( path ) self.soundpath = tostring( path or "Range Soundfiles/" ) @@ -1384,12 +1384,14 @@ end -- -- -- Setup a Range -- RangeOne = RANGE:New( "Range One" ) --- -- Find the STATIC target object as setup in the ME --- RangeOneBombTarget = STATIC:FindByName( "RangeOneBombTarget" ): --- -- Add the coordinate of the STATIC target object as a bomb target (thus keeping the bomb function active, even if the STATIC target is destroyed) +-- -- Find the STATIC target object as setup in the ME. +-- RangeOneBombTarget = STATIC:FindByName( "RangeOneBombTarget" ) +-- -- Add the coordinate of the STATIC target object as a bomb target (thus keeping the bomb function active, even if the STATIC target is destroyed). -- RangeOne:AddBombingTargetCoordinate( RangeOneBombTarget:GetCoordinate(), "RangeOneBombTarget", 50) --- -- Or, add the coordinate of the STATIC target object as a bomb target using default values (name will be "Bomb Target", goodhitrange will be 25 m) +-- -- Or, add the coordinate of the STATIC target object as a bomb target using default values (name will be "Bomb Target", goodhitrange will be 25 m). -- RangeOne:AddBombingTargetCoordinate( RangeOneBombTarget:GetCoordinate() ) +-- -- Start Range. +-- RangeOne:Start() -- function RANGE:AddBombingTargetCoordinate( coord, name, goodhitrange ) @@ -1436,6 +1438,17 @@ end -- @param #string namepit Name of the strafe pit target object. -- @param #string namefoulline Name of the foul line distance marker object. -- @return #number Foul line distance in meters. +-- @usage +-- +-- -- Setup a Range +-- RangeOne = RANGE:New( "Range One" ) +-- -- Get distance between strafe target objext and foul line distance marker object. +-- RangeOneFoulDistance = RangeOne:GetFoullineDistance( "RangeOneStrafeTarget" , "RangeOneFoulLineObject" ) +-- -- Add a strafe pit using the measured foul line distance. Where nil is used, strafe pit default values will be used - adjust as required. +-- RangeOne:AddStrafePit( "RangeOneStrafeTarget", nil, nil, nil, nil, nil, RangeOneFoulDistance ) +-- -- Start Range. +-- RangeOne:Start() +-- function RANGE:GetFoullineDistance( namepit, namefoulline ) self:F( { namepit = namepit, namefoulline = namefoulline } ) @@ -2107,7 +2120,7 @@ function RANGE:onafterSave( From, Event, To ) _savefile( filename, scores ) end ---- Function called before save event. Checks that io and lfs are desanitized. +--- Function called before load event. Checks that io and lfs are desanitized. -- @param #RANGE self -- @param #string From From state. -- @param #string Event Event. @@ -2654,7 +2667,7 @@ function RANGE:_DisplayRangeWeather( _unitname ) local tW = string.format( "%.1f m/s", Ws ) local tP = string.format( "%.1f mmHg", P * hPa2mmHg ) if settings:IsImperial() then - -- tT=string.format("%d°F", UTILS.CelciusToFarenheit(T)) + -- tT=string.format("%d°F", UTILS.CelsiusToFahrenheit(T)) tW = string.format( "%.1f knots", UTILS.MpsToKnots( Ws ) ) tP = string.format( "%.2f inHg", P * hPa2inHg ) end diff --git a/Moose Development/Moose/Functional/Warehouse.lua b/Moose Development/Moose/Functional/Warehouse.lua index 3aaf868f1..e96feb3b5 100644 --- a/Moose Development/Moose/Functional/Warehouse.lua +++ b/Moose Development/Moose/Functional/Warehouse.lua @@ -1601,7 +1601,7 @@ WAREHOUSE = { -- @field #number range Range of the unit in meters. -- @field #number speedmax Maximum speed in km/h the group can do. -- @field #number size Maximum size in length and with of the asset in meters. --- @field #number weight The weight of the whole asset group in kilo gramms. +-- @field #number weight The weight of the whole asset group in kilograms. -- @field DCS#Object.Desc DCSdesc All DCS descriptors. -- @field #WAREHOUSE.Attribute attribute Generalized attribute of the group. -- @field #table cargobay Array of cargo bays of all units in an asset group. diff --git a/Moose Development/Moose/Ops/ATIS.lua b/Moose Development/Moose/Ops/ATIS.lua index f865f98be..a225ce5c5 100644 --- a/Moose Development/Moose/Ops/ATIS.lua +++ b/Moose Development/Moose/Ops/ATIS.lua @@ -67,7 +67,7 @@ -- @field #string activerunway The active runway specified by the user. -- @field #number subduration Duration how long subtitles are displayed in seconds. -- @field #boolean metric If true, use metric units. If false, use imperial (default). --- @field #boolean PmmHg If true, give pressure in millimeters of Mercury. Default is inHg for imperial and hecto Pascal (=mili Bars) for metric units. +-- @field #boolean PmmHg If true, give pressure in millimeters of Mercury. Default is inHg for imperial and hectopascal (hPa, which is the same as millibar - mbar) for metric units. -- @field #boolean qnhonly If true, suppresses reporting QFE. Default is to report both QNH and QFE. -- @field #boolean TDegF If true, give temperature in degrees Fahrenheit. Default is in degrees Celsius independent of chosen unit system. -- @field #number zuludiff Time difference local vs. zulu in hours. @@ -239,7 +239,7 @@ -- -- atisBatumi:SetMetricUnits() -- --- With this, wind speed is given in meters per second, pressure in hecto Pascal (mbar), visibility in kilometers etc. +-- With this, wind speed is given in meters per second, pressure in hectopascal (hPa, which is the same as millibar - mbar), visibility in kilometers etc. -- -- # Sound Files -- @@ -1459,8 +1459,8 @@ function ATIS:onafterBroadcast(From, Event, To) -- Convert to °F. if self.TDegF then - temperature=UTILS.CelciusToFarenheit(temperature) - dewpoint=UTILS.CelciusToFarenheit(dewpoint) + temperature=UTILS.CelsiusToFahrenheit(temperature) + dewpoint=UTILS.CelsiusToFahrenheit(dewpoint) end local TEMPERATURE=string.format("%d", math.abs(temperature)) @@ -2280,7 +2280,7 @@ function ATIS:onafterReport(From, Event, To, Text) local text=string.gsub(text, "°F", "degrees Fahrenheit") local text=string.gsub(text, "inHg", "inches of Mercury") local text=string.gsub(text, "mmHg", "millimeters of Mercury") - local text=string.gsub(text, "hPa", "hecto Pascals") + local text=string.gsub(text, "hPa", "hectopascals") local text=string.gsub(text, "m/s", "meters per second") -- Replace ";" by "." diff --git a/Moose Development/Moose/Utilities/STTS.lua b/Moose Development/Moose/Utilities/STTS.lua index 37a6b3035..5c28dd329 100644 --- a/Moose Development/Moose/Utilities/STTS.lua +++ b/Moose Development/Moose/Utilities/STTS.lua @@ -3,9 +3,11 @@ -- -- @module Utils.STTS -- @image MOOSE.JPG + --- [DCS Enum world](https://wiki.hoggitworld.com/view/DCS_enum_world) -- @type STTS -- @field #string DIRECTORY Path of the SRS directory. + --- Simple Text-To-Speech -- -- Version 0.4 - Compatible with SRS version 1.9.6.0+ @@ -40,7 +42,7 @@ -- * OPTIONAL - Speed -10 to +10 -- * OPTIONAL - Gender male, female or neuter -- * OPTIONAL - Culture - en-US, en-GB etc --- * OPTIONAL - Voice - a specfic voice by name. Run DCS-SR-ExternalAudio.exe with --help to get the ones you can use on the command line +-- * OPTIONAL - Voice - a specific voice by name. Run DCS-SR-ExternalAudio.exe with --help to get the ones you can use on the command line -- * OPTIONAL - Google TTS - Switch to Google Text To Speech - Requires STTS.GOOGLE_CREDENTIALS path and Google project setup correctly -- -- @@ -73,11 +75,11 @@ -- -- @field #STTS STTS = { - ClassName = "STTS", - DIRECTORY = "", - SRS_PORT = 5002, - GOOGLE_CREDENTIALS = "C:\\Users\\Ciaran\\Downloads\\googletts.json", - EXECUTABLE = "DCS-SR-ExternalAudio.exe" + ClassName = "STTS", + DIRECTORY = "", + SRS_PORT = 5002, + GOOGLE_CREDENTIALS = "C:\\Users\\Ciaran\\Downloads\\googletts.json", + EXECUTABLE = "DCS-SR-ExternalAudio.exe" } --- FULL Path to the FOLDER containing DCS-SR-ExternalAudio.exe - EDIT TO CORRECT FOLDER @@ -89,7 +91,7 @@ STTS.SRS_PORT = 5002 --- Google credentials file STTS.GOOGLE_CREDENTIALS = "C:\\Users\\Ciaran\\Downloads\\googletts.json" ---- DONT CHANGE THIS UNLESS YOU KNOW WHAT YOU'RE DOING +--- DON'T CHANGE THIS UNLESS YOU KNOW WHAT YOU'RE DOING STTS.EXECUTABLE = "DCS-SR-ExternalAudio.exe" --- Function for UUID. @@ -117,11 +119,11 @@ function STTS.round( x, n ) end --- Function returns estimated speech time in seconds. --- Assumptions for time calc: 100 Words per min, avarage of 5 letters for english word so +-- Assumptions for time calc: 100 Words per min, average of 5 letters for english word so -- -- * 5 chars * 100wpm = 500 characters per min = 8.3 chars per second -- --- So lengh of msg / 8.3 = number of seconds needed to read it. rounded down to 8 chars per sec map function: +-- So length of msg / 8.3 = number of seconds needed to read it. rounded down to 8 chars per sec map function: -- -- * (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min -- diff --git a/Moose Development/Moose/Utilities/Utils.lua b/Moose Development/Moose/Utilities/Utils.lua index ea55e3357..cac4f9af7 100644 --- a/Moose Development/Moose/Utilities/Utils.lua +++ b/Moose Development/Moose/Utilities/Utils.lua @@ -11,7 +11,6 @@ -- @module Utils -- @image MOOSE.JPG - --- @type SMOKECOLOR -- @field Green -- @field Red @@ -32,14 +31,14 @@ FLARECOLOR = trigger.flareColor -- #FLARECOLOR --- Big smoke preset enum. -- @type BIGSMOKEPRESET BIGSMOKEPRESET = { - SmallSmokeAndFire=1, - MediumSmokeAndFire=2, - LargeSmokeAndFire=3, - HugeSmokeAndFire=4, - SmallSmoke=5, - MediumSmoke=6, - LargeSmoke=7, - HugeSmoke=8, + SmallSmokeAndFire = 1, + MediumSmokeAndFire = 2, + LargeSmokeAndFire = 3, + HugeSmokeAndFire = 4, + SmallSmoke = 5, + MediumSmoke = 6, + LargeSmoke = 7, + HugeSmoke = 8, } --- DCS map as returned by env.mission.theatre. @@ -52,85 +51,84 @@ BIGSMOKEPRESET = { -- @field #string Syria Syria map. -- @field #string MarianaIslands Mariana Islands map. DCSMAP = { - Caucasus="Caucasus", - NTTR="Nevada", - Normandy="Normandy", - PersianGulf="PersianGulf", - TheChannel="TheChannel", - Syria="Syria", - MarianaIslands="MarianaIslands" + Caucasus = "Caucasus", + NTTR = "Nevada", + Normandy = "Normandy", + PersianGulf = "PersianGulf", + TheChannel = "TheChannel", + Syria = "Syria", + MarianaIslands = "MarianaIslands", } - --- See [DCS_enum_callsigns](https://wiki.hoggitworld.com/view/DCS_enum_callsigns) -- @type CALLSIGN -CALLSIGN={ +CALLSIGN = { -- Aircraft - Aircraft={ - Enfield=1, - Springfield=2, - Uzi=3, - Colt=4, - Dodge=5, - Ford=6, - Chevy=7, - Pontiac=8, + Aircraft = { + Enfield = 1, + Springfield = 2, + Uzi = 3, + Colt = 4, + Dodge = 5, + Ford = 6, + Chevy = 7, + Pontiac = 8, -- A-10A or A-10C - Hawg=9, - Boar=10, - Pig=11, - Tusk=12, + Hawg = 9, + Boar = 10, + Pig = 11, + Tusk = 12, }, -- AWACS - AWACS={ - Overlord=1, - Magic=2, - Wizard=3, - Focus=4, - Darkstar=5, + AWACS = { + Overlord = 1, + Magic = 2, + Wizard = 3, + Focus = 4, + Darkstar = 5, }, -- Tanker - Tanker={ - Texaco=1, - Arco=2, - Shell=3, + Tanker = { + Texaco = 1, + Arco = 2, + Shell = 3, }, -- JTAC - JTAC={ - Axeman=1, - Darknight=2, - Warrior=3, - Pointer=4, - Eyeball=5, - Moonbeam=6, - Whiplash=7, - Finger=8, - Pinpoint=9, - Ferret=10, - Shaba=11, - Playboy=12, - Hammer=13, - Jaguar=14, - Deathstar=15, - Anvil=16, - Firefly=17, - Mantis=18, - Badger=19, + JTAC = { + Axeman = 1, + Darknight = 2, + Warrior = 3, + Pointer = 4, + Eyeball = 5, + Moonbeam = 6, + Whiplash = 7, + Finger = 8, + Pinpoint = 9, + Ferret = 10, + Shaba = 11, + Playboy = 12, + Hammer = 13, + Jaguar = 14, + Deathstar = 15, + Anvil = 16, + Firefly = 17, + Mantis = 18, + Badger = 19, }, -- FARP - FARP={ - London=1, - Dallas=2, - Paris=3, - Moscow=4, - Berlin=5, - Rome=6, - Madrid=7, - Warsaw=8, - Dublin=9, - Perth=10, + FARP = { + London = 1, + Dallas = 2, + Paris = 3, + Moscow = 4, + Berlin = 5, + Rome = 6, + Madrid = 7, + Warsaw = 8, + Dublin = 9, + Perth = 10, }, -} --#CALLSIGN +} -- #CALLSIGN --- Utilities static class. -- @type UTILS @@ -170,11 +168,11 @@ UTILS.IsInstanceOf = function( object, className ) -- Get the name of the Moose class as a string className = className.ClassName - -- className is neither a string nor a Moose class, throw an error + -- className is neither a string nor a Moose class, throw an error else -- I'm not sure if this should take advantage of MOOSE logging function, or throw an error for pcall - local err_str = 'className parameter should be a string; parameter received: '..type( className ) + local err_str = 'className parameter should be a string; parameter received: ' .. type( className ) return false -- error( err_str ) @@ -201,17 +199,16 @@ UTILS.IsInstanceOf = function( object, className ) return false end - --- Deep copy a table. See http://lua-users.org/wiki/CopyTable -- @param #table object The input table. -- @return #table Copy of the input table. -UTILS.DeepCopy = function(object) +UTILS.DeepCopy = function( object ) local lookup_table = {} -- Copy function. - local function _copy(object) - if type(object) ~= "table" then + local function _copy( object ) + if type( object ) ~= "table" then return object elseif lookup_table[object] then return lookup_table[object] @@ -221,28 +218,27 @@ UTILS.DeepCopy = function(object) lookup_table[object] = new_table - for index, value in pairs(object) do - new_table[_copy(index)] = _copy(value) + for index, value in pairs( object ) do + new_table[_copy( index )] = _copy( value ) end - return setmetatable(new_table, getmetatable(object)) + return setmetatable( new_table, getmetatable( object ) ) end - local objectreturn = _copy(object) + local objectreturn = _copy( object ) return objectreturn end - --- Porting in Slmod's serialize_slmod2. -- @param #table tbl Input table. -UTILS.OneLineSerialize = function( tbl ) -- serialization of a table all on a single line, no comments, made to replace old get_table_string function +UTILS.OneLineSerialize = function( tbl ) -- serialization of a table all on a single line, no comments, made to replace old get_table_string function lookup_table = {} local function _Serialize( tbl ) - if type(tbl) == 'table' then --function only works for tables! + if type( tbl ) == 'table' then -- function only works for tables! if lookup_table[tbl] then return lookup_table[object] @@ -254,128 +250,127 @@ UTILS.OneLineSerialize = function( tbl ) -- serialization of a table all on a s tbl_str[#tbl_str + 1] = '{' - for ind,val in pairs(tbl) do -- serialize its fields + for ind, val in pairs( tbl ) do -- serialize its fields local ind_str = {} - if type(ind) == "number" then + if type( ind ) == "number" then ind_str[#ind_str + 1] = '[' - ind_str[#ind_str + 1] = tostring(ind) + ind_str[#ind_str + 1] = tostring( ind ) ind_str[#ind_str + 1] = ']=' - else --must be a string + else -- must be a string ind_str[#ind_str + 1] = '[' - ind_str[#ind_str + 1] = routines.utils.basicSerialize(ind) + ind_str[#ind_str + 1] = routines.utils.basicSerialize( ind ) ind_str[#ind_str + 1] = ']=' end local val_str = {} - if ((type(val) == 'number') or (type(val) == 'boolean')) then - val_str[#val_str + 1] = tostring(val) + if ((type( val ) == 'number') or (type( val ) == 'boolean')) then + val_str[#val_str + 1] = tostring( val ) val_str[#val_str + 1] = ',' - tbl_str[#tbl_str + 1] = table.concat(ind_str) - tbl_str[#tbl_str + 1] = table.concat(val_str) - elseif type(val) == 'string' then - val_str[#val_str + 1] = routines.utils.basicSerialize(val) + tbl_str[#tbl_str + 1] = table.concat( ind_str ) + tbl_str[#tbl_str + 1] = table.concat( val_str ) + elseif type( val ) == 'string' then + val_str[#val_str + 1] = routines.utils.basicSerialize( val ) val_str[#val_str + 1] = ',' - tbl_str[#tbl_str + 1] = table.concat(ind_str) - tbl_str[#tbl_str + 1] = table.concat(val_str) - elseif type(val) == 'nil' then -- won't ever happen, right? + tbl_str[#tbl_str + 1] = table.concat( ind_str ) + tbl_str[#tbl_str + 1] = table.concat( val_str ) + elseif type( val ) == 'nil' then -- won't ever happen, right? val_str[#val_str + 1] = 'nil,' - tbl_str[#tbl_str + 1] = table.concat(ind_str) - tbl_str[#tbl_str + 1] = table.concat(val_str) - elseif type(val) == 'table' then + tbl_str[#tbl_str + 1] = table.concat( ind_str ) + tbl_str[#tbl_str + 1] = table.concat( val_str ) + elseif type( val ) == 'table' then if ind == "__index" then - -- tbl_str[#tbl_str + 1] = "__index" - -- tbl_str[#tbl_str + 1] = ',' --I think this is right, I just added it + -- tbl_str[#tbl_str + 1] = "__index" + -- tbl_str[#tbl_str + 1] = ',' --I think this is right, I just added it else - val_str[#val_str + 1] = _Serialize(val) - val_str[#val_str + 1] = ',' --I think this is right, I just added it - tbl_str[#tbl_str + 1] = table.concat(ind_str) - tbl_str[#tbl_str + 1] = table.concat(val_str) + val_str[#val_str + 1] = _Serialize( val ) + val_str[#val_str + 1] = ',' -- I think this is right, I just added it + tbl_str[#tbl_str + 1] = table.concat( ind_str ) + tbl_str[#tbl_str + 1] = table.concat( val_str ) end - elseif type(val) == 'function' then - tbl_str[#tbl_str + 1] = "f() " .. tostring(ind) - tbl_str[#tbl_str + 1] = ',' --I think this is right, I just added it + elseif type( val ) == 'function' then + tbl_str[#tbl_str + 1] = "f() " .. tostring( ind ) + tbl_str[#tbl_str + 1] = ',' -- I think this is right, I just added it else - env.info('unable to serialize value type ' .. routines.utils.basicSerialize(type(val)) .. ' at index ' .. tostring(ind)) + env.info( 'unable to serialize value type ' .. routines.utils.basicSerialize( type( val ) ) .. ' at index ' .. tostring( ind ) ) env.info( debug.traceback() ) end end tbl_str[#tbl_str + 1] = '}' - return table.concat(tbl_str) + return table.concat( tbl_str ) else - return tostring(tbl) + return tostring( tbl ) end end - local objectreturn = _Serialize(tbl) + local objectreturn = _Serialize( tbl ) return objectreturn end ---porting in Slmod's "safestring" basic serialize -UTILS.BasicSerialize = function(s) +-- porting in Slmod's "safestring" basic serialize +UTILS.BasicSerialize = function( s ) if s == nil then return "\"\"" else - if ((type(s) == 'number') or (type(s) == 'boolean') or (type(s) == 'function') or (type(s) == 'table') or (type(s) == 'userdata') ) then - return tostring(s) - elseif type(s) == 'string' then - s = string.format('%q', s) + if ((type( s ) == 'number') or (type( s ) == 'boolean') or (type( s ) == 'function') or (type( s ) == 'table') or (type( s ) == 'userdata')) then + return tostring( s ) + elseif type( s ) == 'string' then + s = string.format( '%q', s ) return s end end end - -UTILS.ToDegree = function(angle) - return angle*180/math.pi +UTILS.ToDegree = function( angle ) + return angle * 180 / math.pi end -UTILS.ToRadian = function(angle) - return angle*math.pi/180 +UTILS.ToRadian = function( angle ) + return angle * math.pi / 180 end -UTILS.MetersToNM = function(meters) - return meters/1852 +UTILS.MetersToNM = function( meters ) + return meters / 1852 end -UTILS.KiloMetersToNM = function(kilometers) - return kilometers/1852*1000 +UTILS.KiloMetersToNM = function( kilometers ) + return kilometers / 1852 * 1000 end -UTILS.MetersToSM = function(meters) - return meters/1609.34 +UTILS.MetersToSM = function( meters ) + return meters / 1609.34 end -UTILS.KiloMetersToSM = function(kilometers) - return kilometers/1609.34*1000 +UTILS.KiloMetersToSM = function( kilometers ) + return kilometers / 1609.34 * 1000 end -UTILS.MetersToFeet = function(meters) - return meters/0.3048 +UTILS.MetersToFeet = function( meters ) + return meters / 0.3048 end -UTILS.KiloMetersToFeet = function(kilometers) - return kilometers/0.3048*1000 +UTILS.KiloMetersToFeet = function( kilometers ) + return kilometers / 0.3048 * 1000 end -UTILS.NMToMeters = function(NM) - return NM*1852 +UTILS.NMToMeters = function( NM ) + return NM * 1852 end -UTILS.NMToKiloMeters = function(NM) - return NM*1852/1000 +UTILS.NMToKiloMeters = function( NM ) + return NM * 1852 / 1000 end -UTILS.FeetToMeters = function(feet) - return feet*0.3048 +UTILS.FeetToMeters = function( feet ) + return feet * 0.3048 end -UTILS.KnotsToKmph = function(knots) +UTILS.KnotsToKmph = function( knots ) return knots * 1.852 end -UTILS.KmphToKnots = function(knots) +UTILS.KmphToKnots = function( knots ) return knots / 1.852 end @@ -402,31 +397,31 @@ end -- @param #number mps Speed in m/s. -- @return #number Speed in knots. UTILS.MpsToKnots = function( mps ) - return mps * 1.94384 --3600 / 1852 + return mps * 1.94384 -- 3600 / 1852 end --- Convert knots to meters per second. -- @param #number knots Speed in knots. -- @return #number Speed in m/s. UTILS.KnotsToMps = function( knots ) - return knots / 1.94384 --* 1852 / 3600 + return knots / 1.94384 -- * 1852 / 3600 end ---- Convert temperature from Celsius to Farenheit. --- @param #number Celcius Temperature in degrees Celsius. --- @return #number Temperature in degrees Farenheit. -UTILS.CelciusToFarenheit = function( Celcius ) - return Celcius * 9/5 + 32 +--- Convert temperature from Celsius to Fahrenheit. +-- @param #number Celsius Temperature in degrees Celsius. +-- @return #number Temperature in degrees Fahrenheit. +UTILS.CelsiusToFahrenheit = function( Celsius ) + return Celsius * 9 / 5 + 32 end ---- Convert pressure from hecto Pascal (hPa) to inches of mercury (inHg). +--- Convert pressure from hectopascal (hPa) to inches of mercury (inHg). -- @param #number hPa Pressure in hPa. -- @return #number Pressure in inHg. UTILS.hPa2inHg = function( hPa ) return hPa * 0.0295299830714 end ---- Convert knots to alitude corrected KIAS, e.g. for tankers. +--- Convert knots to altitude corrected KIAS, e.g. for tankers. -- @param #number knots Speed in knots. -- @param #number altitude Altitude in feet -- @return #number Corrected KIAS @@ -434,14 +429,14 @@ UTILS.KnotsToAltKIAS = function( knots, altitude ) return (knots * 0.018 * (altitude / 1000)) + knots end ---- Convert pressure from hecto Pascal (hPa) to millimeters of mercury (mmHg). +--- Convert pressure from hectopascal (hPa) to millimeters of mercury (mmHg). -- @param #number hPa Pressure in hPa. -- @return #number Pressure in mmHg. UTILS.hPa2mmHg = function( hPa ) return hPa * 0.7500615613030 end ---- Convert kilo gramms (kg) to pounds (lbs). +--- Convert kilograms (kg) to pounds (lbs). -- @param #number kg Mass in kg. -- @return #number Mass in lbs. UTILS.kg2lbs = function( kg ) @@ -455,7 +450,7 @@ position after the decimal of the least significant digit: So: 42.32 - acc of 2. ]] -UTILS.tostringLL = function( lat, lon, acc, DMS) +UTILS.tostringLL = function( lat, lon, acc, DMS ) local latHemi, lonHemi if lat > 0 then @@ -470,23 +465,23 @@ UTILS.tostringLL = function( lat, lon, acc, DMS) lonHemi = 'W' end - lat = math.abs(lat) - lon = math.abs(lon) + lat = math.abs( lat ) + lon = math.abs( lon ) - local latDeg = math.floor(lat) - local latMin = (lat - latDeg)*60 + local latDeg = math.floor( lat ) + local latMin = (lat - latDeg) * 60 - local lonDeg = math.floor(lon) - local lonMin = (lon - lonDeg)*60 + local lonDeg = math.floor( lon ) + local lonMin = (lon - lonDeg) * 60 - if DMS then -- degrees, minutes, and seconds. + if DMS then -- degrees, minutes, and seconds. local oldLatMin = latMin - latMin = math.floor(latMin) - local latSec = UTILS.Round((oldLatMin - latMin)*60, acc) + latMin = math.floor( latMin ) + local latSec = UTILS.Round( (oldLatMin - latMin) * 60, acc ) local oldLonMin = lonMin - lonMin = math.floor(lonMin) - local lonSec = UTILS.Round((oldLonMin - lonMin)*60, acc) + lonMin = math.floor( lonMin ) + local lonSec = UTILS.Round( (oldLonMin - lonMin) * 60, acc ) if latSec == 60 then latSec = 0 @@ -500,20 +495,19 @@ UTILS.tostringLL = function( lat, lon, acc, DMS) local secFrmtStr -- create the formatting string for the seconds place secFrmtStr = '%02d' - if acc <= 0 then -- no decimal place. + if acc <= 0 then -- no decimal place. secFrmtStr = '%02d' else - local width = 3 + acc -- 01.310 - that's a width of 6, for example. Acc is limited to 2 for DMS! + local width = 3 + acc -- 01.310 - that's a width of 6, for example. Acc is limited to 2 for DMS! secFrmtStr = '%0' .. width .. '.' .. acc .. 'f' end -- 024° 23' 12"N or 024° 23' 12.03"N - return string.format('%03d°', latDeg)..string.format('%02d', latMin)..'\''..string.format(secFrmtStr, latSec)..'"'..latHemi..' ' - .. string.format('%03d°', lonDeg)..string.format('%02d', lonMin)..'\''..string.format(secFrmtStr, lonSec)..'"'..lonHemi + return string.format( '%03d°', latDeg ) .. string.format( '%02d', latMin ) .. '\'' .. string.format( secFrmtStr, latSec ) .. '"' .. latHemi .. ' ' .. string.format( '%03d°', lonDeg ) .. string.format( '%02d', lonMin ) .. '\'' .. string.format( secFrmtStr, lonSec ) .. '"' .. lonHemi - else -- degrees, decimal minutes. - latMin = UTILS.Round(latMin, acc) - lonMin = UTILS.Round(lonMin, acc) + else -- degrees, decimal minutes. + latMin = UTILS.Round( latMin, acc ) + lonMin = UTILS.Round( lonMin, acc ) if latMin == 60 then latMin = 0 @@ -526,54 +520,56 @@ UTILS.tostringLL = function( lat, lon, acc, DMS) end local minFrmtStr -- create the formatting string for the minutes place - if acc <= 0 then -- no decimal place. + if acc <= 0 then -- no decimal place. minFrmtStr = '%02d' else - local width = 3 + acc -- 01.310 - that's a width of 6, for example. + local width = 3 + acc -- 01.310 - that's a width of 6, for example. minFrmtStr = '%0' .. width .. '.' .. acc .. 'f' end -- 024 23'N or 024 23.123'N - return string.format('%03d°', latDeg) .. ' ' .. string.format(minFrmtStr, latMin) .. '\'' .. latHemi .. ' ' - .. string.format('%03d°', lonDeg) .. ' ' .. string.format(minFrmtStr, lonMin) .. '\'' .. lonHemi + return string.format( '%03d°', latDeg ) .. ' ' .. string.format( minFrmtStr, latMin ) .. '\'' .. latHemi .. ' ' .. string.format( '%03d°', lonDeg ) .. ' ' .. string.format( minFrmtStr, lonMin ) .. '\'' .. lonHemi end end -- acc- the accuracy of each easting/northing. 0, 1, 2, 3, 4, or 5. -UTILS.tostringMGRS = function(MGRS, acc) --R2.1 +UTILS.tostringMGRS = function( MGRS, acc ) -- R2.1 if acc == 0 then return MGRS.UTMZone .. ' ' .. MGRS.MGRSDigraph else -- Test if Easting/Northing have less than 4 digits. - --MGRS.Easting=123 -- should be 00123 - --MGRS.Northing=5432 -- should be 05432 + -- MGRS.Easting=123 -- should be 00123 + -- MGRS.Northing=5432 -- should be 05432 -- Truncate rather than round MGRS grid! - local Easting=tostring(MGRS.Easting) - local Northing=tostring(MGRS.Northing) + local Easting = tostring( MGRS.Easting ) + local Northing = tostring( MGRS.Northing ) -- Count number of missing digits. Easting/Northing should have 5 digits. However, it is passed as a number. Therefore, any leading zeros would not be displayed by lua. - local nE=5-string.len(Easting) - local nN=5-string.len(Northing) + local nE = 5 - string.len( Easting ) + local nN = 5 - string.len( Northing ) -- Get leading zeros (if any). - for i=1,nE do Easting="0"..Easting end - for i=1,nN do Northing="0"..Northing end + for i = 1, nE do + Easting = "0" .. Easting + end + for i = 1, nN do + Northing = "0" .. Northing + end -- Return MGRS string. - return string.format("%s %s %s %s", MGRS.UTMZone, MGRS.MGRSDigraph, string.sub(Easting, 1, acc), string.sub(Northing, 1, acc)) + return string.format( "%s %s %s %s", MGRS.UTMZone, MGRS.MGRSDigraph, string.sub( Easting, 1, acc ), string.sub( Northing, 1, acc ) ) end end - --- From http://lua-users.org/wiki/SimpleRound -- use negative idp for rounding ahead of decimal place, positive for rounding after decimal place function UTILS.Round( num, idp ) - local mult = 10 ^ ( idp or 0 ) + local mult = 10 ^ (idp or 0) return math.floor( num * mult + 0.5 ) / mult end @@ -589,77 +585,87 @@ end -- Here is a customized version of pairs, which I called spairs because it iterates over the table in a sorted order. function UTILS.spairs( t, order ) - -- collect the keys - local keys = {} - for k in pairs(t) do keys[#keys+1] = k end + -- collect the keys + local keys = {} + for k in pairs( t ) do + keys[#keys + 1] = k + end - -- if order function given, sort by it by passing the table and keys a, b, - -- otherwise just sort the keys - if order then - table.sort(keys, function(a,b) return order(t, a, b) end) - else - table.sort(keys) - end + -- if order function given, sort by it by passing the table and keys a, b, + -- otherwise just sort the keys + if order then + table.sort( keys, function( a, b ) + return order( t, a, b ) + end ) + else + table.sort( keys ) + end - -- return the iterator function - local i = 0 - return function() - i = i + 1 - if keys[i] then - return keys[i], t[keys[i]] - end + -- return the iterator function + local i = 0 + return function() + i = i + 1 + if keys[i] then + return keys[i], t[keys[i]] end + end end - -- Here is a customized version of pairs, which I called kpairs because it iterates over the table in a sorted order, based on a function that will determine the keys as reference first. function UTILS.kpairs( t, getkey, order ) - -- collect the keys - local keys = {} - local keyso = {} - for k, o in pairs(t) do keys[#keys+1] = k keyso[#keyso+1] = getkey( o ) end + -- collect the keys + local keys = {} + local keyso = {} + for k, o in pairs( t ) do + keys[#keys + 1] = k + keyso[#keyso + 1] = getkey( o ) + end - -- if order function given, sort by it by passing the table and keys a, b, - -- otherwise just sort the keys - if order then - table.sort(keys, function(a,b) return order(t, a, b) end) - else - table.sort(keys) - end + -- if order function given, sort by it by passing the table and keys a, b, + -- otherwise just sort the keys + if order then + table.sort( keys, function( a, b ) + return order( t, a, b ) + end ) + else + table.sort( keys ) + end - -- return the iterator function - local i = 0 - return function() - i = i + 1 - if keys[i] then - return keyso[i], t[keys[i]] - end + -- return the iterator function + local i = 0 + return function() + i = i + 1 + if keys[i] then + return keyso[i], t[keys[i]] end + end end -- Here is a customized version of pairs, which I called rpairs because it iterates over the table in a random order. function UTILS.rpairs( t ) - -- collect the keys + -- collect the keys - local keys = {} - for k in pairs(t) do keys[#keys+1] = k end + local keys = {} + for k in pairs( t ) do + keys[#keys + 1] = k + end - local random = {} - local j = #keys - for i = 1, j do - local k = math.random( 1, #keys ) - random[i] = keys[k] - table.remove( keys, k ) - end - - -- return the iterator function - local i = 0 - return function() - i = i + 1 - if random[i] then - return random[i], t[random[i]] - end + local random = {} + local j = #keys + for i = 1, j do + local k = math.random( 1, #keys ) + random[i] = keys[k] + table.remove( keys, k ) + end + + -- return the iterator function + local i = 0 + return function() + i = i + 1 + if random[i] then + return random[i], t[random[i]] end + end end -- get a new mark ID for markings @@ -673,19 +679,18 @@ end --- Remove an object (marker, circle, arrow, text, quad, ...) on the F10 map. -- @param #number MarkID Unique ID of the object. -- @param #number Delay (Optional) Delay in seconds before the mark is removed. -function UTILS.RemoveMark(MarkID, Delay) - if Delay and Delay>0 then - TIMER:New(UTILS.RemoveMark, MarkID):Start(Delay) +function UTILS.RemoveMark( MarkID, Delay ) + if Delay and Delay > 0 then + TIMER:New( UTILS.RemoveMark, MarkID ):Start( Delay ) else - trigger.action.removeMark(MarkID) + trigger.action.removeMark( MarkID ) end end - -- Test if a Vec2 is in a radius of another Vec2 function UTILS.IsInRadius( InVec2, Vec2, Radius ) - local InRadius = ( ( InVec2.x - Vec2.x ) ^2 + ( InVec2.y - Vec2.y ) ^2 ) ^ 0.5 <= Radius + local InRadius = ((InVec2.x - Vec2.x) ^ 2 + (InVec2.y - Vec2.y) ^ 2) ^ 0.5 <= Radius return InRadius end @@ -693,7 +698,7 @@ end -- Test if a Vec3 is in the sphere of another Vec3 function UTILS.IsInSphere( InVec3, Vec3, Radius ) - local InSphere = ( ( InVec3.x - Vec3.x ) ^2 + ( InVec3.y - Vec3.y ) ^2 + ( InVec3.z - Vec3.z ) ^2 ) ^ 0.5 <= Radius + local InSphere = ((InVec3.x - Vec3.x) ^ 2 + (InVec3.y - Vec3.y) ^ 2 + (InVec3.z - Vec3.z) ^ 2) ^ 0.5 <= Radius return InSphere end @@ -702,61 +707,61 @@ end -- @param #number speed Wind speed in m/s. -- @return #number Beaufort number. -- @return #string Beauford wind description. -function UTILS.BeaufortScale(speed) - local bn=nil - local bd=nil - if speed<0.51 then - bn=0 - bd="Calm" - elseif speed<2.06 then - bn=1 - bd="Light Air" - elseif speed<3.60 then - bn=2 - bd="Light Breeze" - elseif speed<5.66 then - bn=3 - bd="Gentle Breeze" - elseif speed<8.23 then - bn=4 - bd="Moderate Breeze" - elseif speed<11.32 then - bn=5 - bd="Fresh Breeze" - elseif speed<14.40 then - bn=6 - bd="Strong Breeze" - elseif speed<17.49 then - bn=7 - bd="Moderate Gale" - elseif speed<21.09 then - bn=8 - bd="Fresh Gale" - elseif speed<24.69 then - bn=9 - bd="Strong Gale" - elseif speed<28.81 then - bn=10 - bd="Storm" - elseif speed<32.92 then - bn=11 - bd="Violent Storm" +function UTILS.BeaufortScale( speed ) + local bn = nil + local bd = nil + if speed < 0.51 then + bn = 0 + bd = "Calm" + elseif speed < 2.06 then + bn = 1 + bd = "Light Air" + elseif speed < 3.60 then + bn = 2 + bd = "Light Breeze" + elseif speed < 5.66 then + bn = 3 + bd = "Gentle Breeze" + elseif speed < 8.23 then + bn = 4 + bd = "Moderate Breeze" + elseif speed < 11.32 then + bn = 5 + bd = "Fresh Breeze" + elseif speed < 14.40 then + bn = 6 + bd = "Strong Breeze" + elseif speed < 17.49 then + bn = 7 + bd = "Moderate Gale" + elseif speed < 21.09 then + bn = 8 + bd = "Fresh Gale" + elseif speed < 24.69 then + bn = 9 + bd = "Strong Gale" + elseif speed < 28.81 then + bn = 10 + bd = "Storm" + elseif speed < 32.92 then + bn = 11 + bd = "Violent Storm" else - bn=12 - bd="Hurricane" + bn = 12 + bd = "Hurricane" end - return bn,bd + return bn, bd end ---- Split string at seperators. C.f. http://stackoverflow.com/questions/1426954/split-string-in-lua +--- Split string at separators. C.f. http://stackoverflow.com/questions/1426954/split-string-in-lua -- @param #string str Sting to split. --- @param #string sep Speparator for split. +-- @param #string sep Separator for split. -- @return #table Split text. -function UTILS.Split(str, sep) +function UTILS.Split( str, sep ) local result = {} - local regex = ("([^%s]+)"):format(sep) - for each in str:gmatch(regex) do - table.insert(result, each) + local regex = ("([^%s]+)"):format( sep ) + for each in str:gmatch( regex ) do + table.insert( result, each ) end return result end @@ -764,13 +769,13 @@ end --- Get a table of all characters in a string. -- @param #string str Sting. -- @return #table Individual characters. -function UTILS.GetCharacters(str) +function UTILS.GetCharacters( str ) - local chars={} + local chars = {} - for i=1,#str do - local c=str:sub(i,i) - table.insert(chars, c) + for i = 1, #str do + local c = str:sub( i, i ) + table.insert( chars, c ) end return chars @@ -780,33 +785,33 @@ end -- @param #number seconds Time in seconds, e.g. from timer.getAbsTime() function. -- @param #boolean short (Optional) If true, use short output, i.e. (HH:)MM:SS without day. -- @return #string Time in format Hours:Minutes:Seconds+Days (HH:MM:SS+D). -function UTILS.SecondsToClock(seconds, short) +function UTILS.SecondsToClock( seconds, short ) -- Nil check. - if seconds==nil then + if seconds == nil then return nil end -- Seconds - local seconds = tonumber(seconds) + local seconds = tonumber( seconds ) -- Seconds of this day. - local _seconds=seconds%(60*60*24) + local _seconds = seconds % (60 * 60 * 24) - if seconds<0 then + 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)) - local clock=hours..":"..mins..":"..secs.."+"..days + 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) ) + local clock = hours .. ":" .. mins .. ":" .. secs .. "+" .. days if short then - if hours=="00" then - --clock=mins..":"..secs - clock=hours..":"..mins..":"..secs + if hours == "00" then + -- clock=mins..":"..secs + clock = hours .. ":" .. mins .. ":" .. secs else - clock=hours..":"..mins..":"..secs + clock = hours .. ":" .. mins .. ":" .. secs end end return clock @@ -817,60 +822,60 @@ end -- @return #number Seconds passed since last midnight. function UTILS.SecondsOfToday() - -- Time in seconds. - local time=timer.getAbsTime() + -- Time in seconds. + local time = timer.getAbsTime() - -- Short format without days since mission start. - local clock=UTILS.SecondsToClock(time, true) + -- Short format without days since mission start. + local clock = UTILS.SecondsToClock( time, true ) - -- Time is now the seconds passed since last midnight. - return UTILS.ClockToSeconds(clock) + -- Time is now the seconds passed since last midnight. + return UTILS.ClockToSeconds( clock ) end ---- Cound seconds until next midnight. +--- Count seconds until next midnight. -- @return #number Seconds to midnight. function UTILS.SecondsToMidnight() - return 24*60*60-UTILS.SecondsOfToday() + return 24 * 60 * 60 - UTILS.SecondsOfToday() 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. -- @return #number Seconds. Corresponds to what you cet from timer.getAbsTime() function. -function UTILS.ClockToSeconds(clock) +function UTILS.ClockToSeconds( clock ) -- Nil check. - if clock==nil then + if clock == nil then return nil end -- Seconds init. - local seconds=0 + local seconds = 0 -- Split additional days. - local dsplit=UTILS.Split(clock, "+") + local dsplit = UTILS.Split( clock, "+" ) -- Convert days to seconds. - if #dsplit>1 then - seconds=seconds+tonumber(dsplit[2])*60*60*24 + if #dsplit > 1 then + seconds = seconds + tonumber( dsplit[2] ) * 60 * 60 * 24 end -- Split hours, minutes, seconds - local tsplit=UTILS.Split(dsplit[1], ":") + local tsplit = UTILS.Split( dsplit[1], ":" ) -- Get time in seconds - local i=1 - for _,time in ipairs(tsplit) do - if i==1 then + local i = 1 + for _, time in ipairs( tsplit ) do + if i == 1 then -- Hours - seconds=seconds+tonumber(time)*60*60 - elseif i==2 then + seconds = seconds + tonumber( time ) * 60 * 60 + elseif i == 2 then -- Minutes - seconds=seconds+tonumber(time)*60 - elseif i==3 then + seconds = seconds + tonumber( time ) * 60 + elseif i == 3 then -- Seconds - seconds=seconds+tonumber(time) + seconds = seconds + tonumber( time ) end - i=i+1 + i = i + 1 end return seconds @@ -878,24 +883,24 @@ 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() +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 --- Replace illegal characters [<>|/?*:\\] in a string. -- @param #string Text Input text. -- @param #string ReplaceBy Replace illegal characters by this character or string. Default underscore "_". -- @return #string The input text with illegal chars replaced. -function UTILS.ReplaceIllegalCharacters(Text, ReplaceBy) - ReplaceBy=ReplaceBy or "_" - local text=Text:gsub("[<>|/?*:\\]", ReplaceBy) +function UTILS.ReplaceIllegalCharacters( Text, ReplaceBy ) + ReplaceBy = ReplaceBy or "_" + local text = Text:gsub( "[<>|/?*:\\]", ReplaceBy ) return text end @@ -906,29 +911,29 @@ end -- @param #number xmax (Optional) Upper cut-off value. -- @param #number imax (Optional) Max number of tries to get a value between xmin and xmax (if specified). Default 100. -- @return #number Gaussian random number. -function UTILS.RandomGaussian(x0, sigma, xmin, xmax, imax) +function UTILS.RandomGaussian( x0, sigma, xmin, xmax, imax ) -- Standard deviation. Default 10 if not given. - sigma=sigma or 10 + sigma = sigma or 10 -- Max attempts. - imax=imax or 100 + imax = imax or 100 local r - local gotit=false - local i=0 + local gotit = false + local i = 0 while not gotit do -- Uniform numbers in [0,1). We need two. - local x1=math.random() - local x2=math.random() + local x1 = math.random() + local x2 = math.random() -- Transform to Gaussian exp(-(x-x0)°/(2*sigma°). - r = math.sqrt(-2*sigma*sigma * math.log(x1)) * math.cos(2*math.pi * x2) + x0 + r = math.sqrt( -2 * sigma * sigma * math.log( x1 ) ) * math.cos( 2 * math.pi * x2 ) + x0 - i=i+1 - if (r>=xmin and r<=xmax) or i>imax then - gotit=true + i = i + 1 + if (r >= xmin and r <= xmax) or i > imax then + gotit = true end end @@ -943,21 +948,21 @@ end -- @return #number Randomized value. -- @usage UTILS.Randomize(100, 0.1) returns a value between 90 and 110, i.e. a plus/minus ten percent variation. -- @usage UTILS.Randomize(100, 0.5, nil, 120) returns a value between 50 and 120, i.e. a plus/minus fivty percent variation with upper bound 120. -function UTILS.Randomize(value, fac, lower, upper) +function UTILS.Randomize( value, fac, lower, upper ) local min if lower then - min=math.max(value-value*fac, lower) + min = math.max( value - value * fac, lower ) else - min=value-value*fac + min = value - value * fac end local max if upper then - max=math.min(value+value*fac, upper) + max = math.min( value + value * fac, upper ) else - max=value+value*fac + max = value + value * fac end - local r=math.random(min, max) + local r = math.random( min, max ) return r end @@ -966,56 +971,54 @@ end -- @param DCS#Vec3 a Vector in 3D with x, y, z components. -- @param DCS#Vec3 b Vector in 3D with x, y, z components. -- @return #number Scalar product of the two vectors a*b. -function UTILS.VecDot(a, b) - return a.x*b.x + a.y*b.y + a.z*b.z +function UTILS.VecDot( a, b ) + return a.x * b.x + a.y * b.y + a.z * b.z end --- Calculate the [dot product](https://en.wikipedia.org/wiki/Dot_product) of two 2D vectors. The result is a number. -- @param DCS#Vec2 a Vector in 2D with x, y components. -- @param DCS#Vec2 b Vector in 2D with x, y components. -- @return #number Scalar product of the two vectors a*b. -function UTILS.Vec2Dot(a, b) - return a.x*b.x + a.y*b.y +function UTILS.Vec2Dot( a, b ) + return a.x * b.x + a.y * b.y end - --- Calculate the [euclidean norm](https://en.wikipedia.org/wiki/Euclidean_distance) (length) of a 3D vector. -- @param DCS#Vec3 a Vector in 3D with x, y, z components. -- @return #number Norm of the vector. -function UTILS.VecNorm(a) - return math.sqrt(UTILS.VecDot(a, a)) +function UTILS.VecNorm( a ) + return math.sqrt( UTILS.VecDot( a, a ) ) end --- Calculate the [euclidean norm](https://en.wikipedia.org/wiki/Euclidean_distance) (length) of a 2D vector. -- @param DCS#Vec2 a Vector in 2D with x, y components. -- @return #number Norm of the vector. -function UTILS.Vec2Norm(a) - return math.sqrt(UTILS.Vec2Dot(a, a)) +function UTILS.Vec2Norm( a ) + return math.sqrt( UTILS.Vec2Dot( a, a ) ) end --- Calculate the distance between two 2D vectors. -- @param DCS#Vec2 a Vector in 3D with x, y components. -- @param DCS#Vec2 b Vector in 3D with x, y components. -- @return #number Distance between the vectors. -function UTILS.VecDist2D(a, b) +function UTILS.VecDist2D( a, b ) - local c={x=b.x-a.x, y=b.y-a.y} + local c = { x = b.x - a.x, y = b.y - a.y } - local d=math.sqrt(c.x*c.x+c.y*c.y) + local d = math.sqrt( c.x * c.x + c.y * c.y ) return d end - --- Calculate the distance between two 3D vectors. -- @param DCS#Vec3 a Vector in 3D with x, y, z components. -- @param DCS#Vec3 b Vector in 3D with x, y, z components. -- @return #number Distance between the vectors. -function UTILS.VecDist3D(a, b) +function UTILS.VecDist3D( a, b ) - local c={x=b.x-a.x, y=b.y-a.y, z=b.z-a.z} + local c = { x = b.x - a.x, y = b.y - a.y, z = b.z - a.z } - local d=math.sqrt(UTILS.VecDot(c, c)) + local d = math.sqrt( UTILS.VecDot( c, c ) ) return d end @@ -1024,53 +1027,53 @@ end -- @param DCS#Vec3 a Vector in 3D with x, y, z components. -- @param DCS#Vec3 b Vector in 3D with x, y, z components. -- @return DCS#Vec3 Vector -function UTILS.VecCross(a, b) - return {x=a.y*b.z - a.z*b.y, y=a.z*b.x - a.x*b.z, z=a.x*b.y - a.y*b.x} +function UTILS.VecCross( a, b ) + return { x = a.y * b.z - a.z * b.y, y = a.z * b.x - a.x * b.z, z = a.x * b.y - a.y * b.x } end --- Calculate the difference between two 3D vectors by substracting the x,y,z components from each other. -- @param DCS#Vec3 a Vector in 3D with x, y, z components. -- @param DCS#Vec3 b Vector in 3D with x, y, z components. -- @return DCS#Vec3 Vector c=a-b with c(i)=a(i)-b(i), i=x,y,z. -function UTILS.VecSubstract(a, b) - return {x=a.x-b.x, y=a.y-b.y, z=a.z-b.z} +function UTILS.VecSubstract( a, b ) + return { x = a.x - b.x, y = a.y - b.y, z = a.z - b.z } end --- Calculate the total vector of two 3D vectors by adding the x,y,z components of each other. -- @param DCS#Vec3 a Vector in 3D with x, y, z components. -- @param DCS#Vec3 b Vector in 3D with x, y, z components. -- @return DCS#Vec3 Vector c=a+b with c(i)=a(i)+b(i), i=x,y,z. -function UTILS.VecAdd(a, b) - return {x=a.x+b.x, y=a.y+b.y, z=a.z+b.z} +function UTILS.VecAdd( a, b ) + return { x = a.x + b.x, y = a.y + b.y, z = a.z + b.z } end --- Calculate the angle between two 3D vectors. -- @param DCS#Vec3 a Vector in 3D with x, y, z components. -- @param DCS#Vec3 b Vector in 3D with x, y, z components. -- @return #number Angle alpha between and b in degrees. alpha=acos(a*b)/(|a||b|), (* denotes the dot product). -function UTILS.VecAngle(a, b) +function UTILS.VecAngle( a, b ) - local cosalpha=UTILS.VecDot(a,b)/(UTILS.VecNorm(a)*UTILS.VecNorm(b)) + local cosalpha = UTILS.VecDot( a, b ) / (UTILS.VecNorm( a ) * UTILS.VecNorm( b )) - local alpha=0 - if cosalpha>=0.9999999999 then --acos(1) is not defined. - alpha=0 - elseif cosalpha<=-0.999999999 then --acos(-1) is not defined. - alpha=math.pi + local alpha = 0 + if cosalpha >= 0.9999999999 then -- acos(1) is not defined. + alpha = 0 + elseif cosalpha <= -0.999999999 then -- acos(-1) is not defined. + alpha = math.pi else - alpha=math.acos(cosalpha) + alpha = math.acos( cosalpha ) end - return math.deg(alpha) + return math.deg( alpha ) end --- Calculate "heading" of a 3D vector in the X-Z plane. -- @param DCS#Vec3 a Vector in 3D with x, y, z components. -- @return #number Heading in degrees in [0,360). -function UTILS.VecHdg(a) - local h=math.deg(math.atan2(a.z, a.x)) - if h<0 then - h=h+360 +function UTILS.VecHdg( a ) + local h = math.deg( math.atan2( a.z, a.x ) ) + if h < 0 then + h = h + 360 end return h end @@ -1078,10 +1081,10 @@ end --- Calculate "heading" of a 2D vector in the X-Y plane. -- @param DCS#Vec2 a Vector in "D with x, y components. -- @return #number Heading in degrees in [0,360). -function UTILS.Vec2Hdg(a) - local h=math.deg(math.atan2(a.y, a.x)) - if h<0 then - h=h+360 +function UTILS.Vec2Hdg( a ) + local h = math.deg( math.atan2( a.y, a.x ) ) + if h < 0 then + h = h + 360 end return h end @@ -1090,36 +1093,35 @@ end -- @param #number h1 Heading one. -- @param #number h2 Heading two. -- @return #number Heading difference in degrees. -function UTILS.HdgDiff(h1, h2) +function UTILS.HdgDiff( h1, h2 ) -- Angle in rad. - local alpha= math.rad(tonumber(h1)) - local beta = math.rad(tonumber(h2)) + local alpha = math.rad( tonumber( h1 ) ) + local beta = math.rad( tonumber( h2 ) ) -- Runway vector. - local v1={x=math.cos(alpha), y=0, z=math.sin(alpha)} - local v2={x=math.cos(beta), y=0, z=math.sin(beta)} + local v1 = { x = math.cos( alpha ), y = 0, z = math.sin( alpha ) } + local v2 = { x = math.cos( beta ), y = 0, z = math.sin( beta ) } - local delta=UTILS.VecAngle(v1, v2) + local delta = UTILS.VecAngle( v1, v2 ) - return math.abs(delta) + return math.abs( delta ) end - --- Translate 3D vector in the 2D (x,z) plane. y-component (usually altitude) unchanged. -- @param DCS#Vec3 a Vector in 3D with x, y, z components. -- @param #number distance The distance to translate. -- @param #number angle Rotation angle in degrees. -- @return DCS#Vec3 Vector rotated in the (x,z) plane. -function UTILS.VecTranslate(a, distance, angle) +function UTILS.VecTranslate( a, distance, angle ) local SX = a.x local SY = a.z - local Radians=math.rad(angle or 0) - local TX=distance*math.cos(Radians)+SX - local TY=distance*math.sin(Radians)+SY + local Radians = math.rad( angle or 0 ) + local TX = distance * math.cos( Radians ) + SX + local TY = distance * math.sin( Radians ) + SY - return {x=TX, y=a.y, z=TY} + return { x = TX, y = a.y, z = TY } end --- Translate 2D vector in the 2D (x,z) plane. @@ -1127,33 +1129,33 @@ end -- @param #number distance The distance to translate. -- @param #number angle Rotation angle in degrees. -- @return DCS#Vec2 Translated vector. -function UTILS.Vec2Translate(a, distance, angle) +function UTILS.Vec2Translate( a, distance, angle ) local SX = a.x local SY = a.y - local Radians=math.rad(angle or 0) - local TX=distance*math.cos(Radians)+SX - local TY=distance*math.sin(Radians)+SY + local Radians = math.rad( angle or 0 ) + local TX = distance * math.cos( Radians ) + SX + local TY = distance * math.sin( Radians ) + SY - return {x=TX, y=TY} + return { x = TX, y = TY } end --- Rotate 3D vector in the 2D (x,z) plane. y-component (usually altitude) unchanged. -- @param DCS#Vec3 a Vector in 3D with x, y, z components. -- @param #number angle Rotation angle in degrees. -- @return DCS#Vec3 Vector rotated in the (x,z) plane. -function UTILS.Rotate2D(a, angle) +function UTILS.Rotate2D( a, angle ) - local phi=math.rad(angle) + local phi = math.rad( angle ) - local x=a.z - local y=a.x + local x = a.z + local y = a.x - local Z=x*math.cos(phi)-y*math.sin(phi) - local X=x*math.sin(phi)+y*math.cos(phi) - local Y=a.y + local Z = x * math.cos( phi ) - y * math.sin( phi ) + local X = x * math.sin( phi ) + y * math.cos( phi ) + local Y = a.y - local A={x=X, y=Y, z=Z} + local A = { x = X, y = Y, z = Z } return A end @@ -1162,39 +1164,38 @@ end -- @param DCS#Vec2 a Vector in 2D with x, y components. -- @param #number angle Rotation angle in degrees. -- @return DCS#Vec2 Vector rotated in the (x,y) plane. -function UTILS.Vec2Rotate2D(a, angle) +function UTILS.Vec2Rotate2D( a, angle ) - local phi=math.rad(angle) + local phi = math.rad( angle ) - local x=a.x - local y=a.y + local x = a.x + local y = a.y - local X=x*math.cos(phi)-y*math.sin(phi) - local Y=x*math.sin(phi)+y*math.cos(phi) + local X = x * math.cos( phi ) - y * math.sin( phi ) + local Y = x * math.sin( phi ) + y * math.cos( phi ) - local A={x=X, y=Y} + local A = { x = X, y = Y } return A end - --- Converts a TACAN Channel/Mode couple into a frequency in Hz. -- @param #number TACANChannel The TACAN channel, i.e. the 10 in "10X". -- @param #string TACANMode The TACAN mode, i.e. the "X" in "10X". -- @return #number Frequency in Hz or #nil if parameters are invalid. -function UTILS.TACANToFrequency(TACANChannel, TACANMode) +function UTILS.TACANToFrequency( TACANChannel, TACANMode ) - if type(TACANChannel) ~= "number" then + if type( TACANChannel ) ~= "number" then return nil -- error in arguments end if TACANMode ~= "X" and TACANMode ~= "Y" then return nil -- error in arguments end --- This code is largely based on ED's code, in DCS World\Scripts\World\Radio\BeaconTypes.lua, line 137. --- I have no idea what it does but it seems to work + -- This code is largely based on ED's code, in DCS World\Scripts\World\Radio\BeaconTypes.lua, line 137. + -- I have no idea what it does but it seems to work local A = 1151 -- 'X', channel >= 64 - local B = 64 -- channel >= 64 + local B = 64 -- channel >= 64 if TACANChannel < 64 then B = 1 @@ -1214,7 +1215,6 @@ function UTILS.TACANToFrequency(TACANChannel, TACANMode) return (A + TACANChannel - B) * 1000000 end - --- Returns the DCS map/theatre as optained by env.mission.theatre -- @return #string DCS map name. function UTILS.GetDCSMap() @@ -1227,22 +1227,22 @@ end -- @return #number The month. -- @return #number The day. function UTILS.GetDCSMissionDate() - local year=tostring(env.mission.date.Year) - local month=tostring(env.mission.date.Month) - local day=tostring(env.mission.date.Day) - return string.format("%s/%s/%s", year, month, day), tonumber(year), tonumber(month), tonumber(day) + local year = tostring( env.mission.date.Year ) + local month = tostring( env.mission.date.Month ) + local day = tostring( env.mission.date.Day ) + return string.format( "%s/%s/%s", year, month, day ), tonumber( year ), tonumber( month ), tonumber( day ) end --- Returns the day of the mission. -- @param #number Time (Optional) Abs. time in seconds. Default now, i.e. the value return from timer.getAbsTime(). -- @return #number Day of the mission. Mission starts on day 0. -function UTILS.GetMissionDay(Time) +function UTILS.GetMissionDay( Time ) - Time=Time or timer.getAbsTime() + Time = Time or timer.getAbsTime() - local clock=UTILS.SecondsToClock(Time, false) + local clock = UTILS.SecondsToClock( Time, false ) - local x=tonumber(UTILS.Split(clock, "+")[2]) + local x = tonumber( UTILS.Split( clock, "+" )[2] ) return x end @@ -1250,13 +1250,13 @@ end --- Returns the current day of the year of the mission. -- @param #number Time (Optional) Abs. time in seconds. Default now, i.e. the value return from timer.getAbsTime(). -- @return #number Current day of year of the mission. For example, January 1st returns 0, January 2nd returns 1 etc. -function UTILS.GetMissionDayOfYear(Time) +function UTILS.GetMissionDayOfYear( Time ) - local Date, Year, Month, Day=UTILS.GetDCSMissionDate() + local Date, Year, Month, Day = UTILS.GetDCSMissionDate() - local d=UTILS.GetMissionDay(Time) + local d = UTILS.GetMissionDay( Time ) - return UTILS.GetDayOfYear(Year, Month, Day)+d + return UTILS.GetDayOfYear( Year, Month, Day ) + d end @@ -1268,15 +1268,15 @@ end function UTILS.GetDate() -- Mission start date - local date, year, month, day=UTILS.GetDCSMissionDate() + local date, year, month, day = UTILS.GetDCSMissionDate() - local time=timer.getAbsTime() + local time = timer.getAbsTime() - local clock=UTILS.SecondsToClock(time, false) + local clock = UTILS.SecondsToClock( time, false ) - local x=tonumber(UTILS.Split(clock, "+")[2]) + local x = tonumber( UTILS.Split( clock, "+" )[2] ) - local day=day+x + local day = day + x end @@ -1292,28 +1292,28 @@ end -- * Mariana Islands +2 (East) -- @param #string map (Optional) Map for which the declination is returned. Default is from env.mission.theatre -- @return #number Declination in degrees. -function UTILS.GetMagneticDeclination(map) +function UTILS.GetMagneticDeclination( map ) -- Map. - map=map or UTILS.GetDCSMap() + map = map or UTILS.GetDCSMap() - local declination=0 - if map==DCSMAP.Caucasus then - declination=6 - elseif map==DCSMAP.NTTR then - declination=12 - elseif map==DCSMAP.Normandy then - declination=-10 - elseif map==DCSMAP.PersianGulf then - declination=2 - elseif map==DCSMAP.TheChannel then - declination=-10 - elseif map==DCSMAP.Syria then - declination=5 - elseif map==DCSMAP.MarianaIslands then - declination=2 + local declination = 0 + if map == DCSMAP.Caucasus then + declination = 6 + elseif map == DCSMAP.NTTR then + declination = 12 + elseif map == DCSMAP.Normandy then + declination = -10 + elseif map == DCSMAP.PersianGulf then + declination = 2 + elseif map == DCSMAP.TheChannel then + declination = -10 + elseif map == DCSMAP.Syria then + declination = 5 + elseif map == DCSMAP.MarianaIslands then + declination = 2 else - declination=0 + declination = 0 end return declination @@ -1322,11 +1322,11 @@ end --- Checks if a file exists or not. This requires **io** to be desanitized. -- @param #string file File that should be checked. -- @return #boolean True if the file exists, false if the file does not exist or nil if the io module is not available and the check could not be performed. -function UTILS.FileExists(file) +function UTILS.FileExists( file ) if io then - local f=io.open(file, "r") - if f~=nil then - io.close(f) + local f = io.open( file, "r" ) + if f ~= nil then + io.close( f ) return true else return false @@ -1339,28 +1339,27 @@ end --- Checks the current memory usage collectgarbage("count"). Info is printed to the DCS log file. Time stamp is the current mission runtime. -- @param #boolean output If true, print to DCS log file. -- @return #number Memory usage in kByte. -function UTILS.CheckMemory(output) - local time=timer.getTime() - local clock=UTILS.SecondsToClock(time) - local mem=collectgarbage("count") +function UTILS.CheckMemory( output ) + local time = timer.getTime() + local clock = UTILS.SecondsToClock( time ) + local mem = collectgarbage( "count" ) if output then - env.info(string.format("T=%s Memory usage %d kByte = %.2f MByte", clock, mem, mem/1024)) + env.info( string.format( "T=%s Memory usage %d kByte = %.2f MByte", clock, mem, mem / 1024 ) ) end return mem end - --- Get the coalition name from its numerical ID, e.g. coaliton.side.RED. -- @param #number Coalition The coalition ID. -- @return #string The coalition name, i.e. "Neutral", "Red" or "Blue" (or "Unknown"). -function UTILS.GetCoalitionName(Coalition) +function UTILS.GetCoalitionName( Coalition ) if Coalition then - if Coalition==coalition.side.BLUE then + if Coalition == coalition.side.BLUE then return "Blue" - elseif Coalition==coalition.side.RED then + elseif Coalition == coalition.side.RED then return "Red" - elseif Coalition==coalition.side.NEUTRAL then + elseif Coalition == coalition.side.NEUTRAL then return "Neutral" else return "Unknown" @@ -1374,12 +1373,12 @@ end --- Get the modulation name from its numerical value. -- @param #number Modulation The modulation enumerator number. Can be either 0 or 1. -- @return #string The modulation name, i.e. "AM"=0 or "FM"=1. Anything else will return "Unknown". -function UTILS.GetModulationName(Modulation) +function UTILS.GetModulationName( Modulation ) if Modulation then - if Modulation==0 then + if Modulation == 0 then return "AM" - elseif Modulation==1 then + elseif Modulation == 1 then return "FM" else return "Unknown" @@ -1393,28 +1392,28 @@ end --- Get the callsign name from its enumerator value -- @param #number Callsign The enumerator callsign. -- @return #string The callsign name or "Ghostrider". -function UTILS.GetCallsignName(Callsign) +function UTILS.GetCallsignName( Callsign ) - for name, value in pairs(CALLSIGN.Aircraft) do - if value==Callsign then + for name, value in pairs( CALLSIGN.Aircraft ) do + if value == Callsign then return name end end - for name, value in pairs(CALLSIGN.AWACS) do - if value==Callsign then + for name, value in pairs( CALLSIGN.AWACS ) do + if value == Callsign then return name end end - for name, value in pairs(CALLSIGN.JTAC) do - if value==Callsign then + for name, value in pairs( CALLSIGN.JTAC ) do + if value == Callsign then return name end end - for name, value in pairs(CALLSIGN.Tanker) do - if value==Callsign then + for name, value in pairs( CALLSIGN.Tanker ) do + if value == Callsign then return name end end @@ -1426,44 +1425,43 @@ end -- @return #number Local time difference in hours compared to GMT. E.g. Dubai is GMT+4 ==> +4 is returned. function UTILS.GMTToLocalTimeDifference() - local theatre=UTILS.GetDCSMap() + local theatre = UTILS.GetDCSMap() - if theatre==DCSMAP.Caucasus then - return 4 -- Caucasus UTC+4 hours - elseif theatre==DCSMAP.PersianGulf then - return 4 -- Abu Dhabi UTC+4 hours - elseif theatre==DCSMAP.NTTR then - return -8 -- Las Vegas UTC-8 hours - elseif theatre==DCSMAP.Normandy then - return 0 -- Calais UTC+1 hour - elseif theatre==DCSMAP.TheChannel then - return 2 -- This map currently needs +2 - elseif theatre==DCSMAP.Syria then - return 3 -- Damascus is UTC+3 hours - elseif theatre==DCSMAP.MarianaIslands then - return 10 -- Guam is UTC+10 hours. + if theatre == DCSMAP.Caucasus then + return 4 -- Caucasus UTC+4 hours + elseif theatre == DCSMAP.PersianGulf then + return 4 -- Abu Dhabi UTC+4 hours + elseif theatre == DCSMAP.NTTR then + return -8 -- Las Vegas UTC-8 hours + elseif theatre == DCSMAP.Normandy then + return 0 -- Calais UTC+1 hour + elseif theatre == DCSMAP.TheChannel then + return 2 -- This map currently needs +2 + elseif theatre == DCSMAP.Syria then + return 3 -- Damascus is UTC+3 hours + elseif theatre == DCSMAP.MarianaIslands then + return 10 -- Guam is UTC+10 hours. else - BASE:E(string.format("ERROR: Unknown Map %s in UTILS.GMTToLocal function. Returning 0", tostring(theatre))) + BASE:E( string.format( "ERROR: Unknown Map %s in UTILS.GMTToLocal function. Returning 0", tostring( theatre ) ) ) return 0 end end - --- Get the day of the year. Counting starts on 1st of January. -- @param #number Year The year. -- @param #number Month The month. -- @param #number Day The day. -- @return #number The day of the year. -function UTILS.GetDayOfYear(Year, Month, Day) +function UTILS.GetDayOfYear( Year, Month, Day ) local floor = math.floor - local n1 = floor(275 * Month / 9) - local n2 = floor((Month + 9) / 12) - local n3 = (1 + floor((Year - 4 * floor(Year / 4) + 2) / 3)) + local n1 = floor( 275 * Month / 9 ) + local n2 = floor( (Month + 9) / 12 ) + local n3 = (1 + floor( (Year - 4 * floor( Year / 4 ) + 2) / 3 )) - return n1 - (n2 * n3) + Day - 30 + return n1 - (n2 * n3) + Day - 30 end --- Get sunrise or sun set of a specific day of the year at a specific location. @@ -1473,100 +1471,113 @@ end -- @param #boolean Rising If true, calc sun rise, or sun set otherwise. -- @param #number Tlocal Local time offset in hours. E.g. +4 for a location which has GMT+4. -- @return #number Sun rise/set in seconds of the day. -function UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, Rising, Tlocal) +function UTILS.GetSunRiseAndSet( DayOfYear, Latitude, Longitude, Rising, Tlocal ) -- Defaults - local zenith=90.83 - local latitude=Latitude - local longitude=Longitude - local rising=Rising - local n=DayOfYear - Tlocal=Tlocal or 0 - + local zenith = 90.83 + local latitude = Latitude + local longitude = Longitude + local rising = Rising + local n = DayOfYear + Tlocal = Tlocal or 0 -- Short cuts. local rad = math.rad local deg = math.deg local floor = math.floor - local frac = function(n) return n - floor(n) end - local cos = function(d) return math.cos(rad(d)) end - local acos = function(d) return deg(math.acos(d)) end - local sin = function(d) return math.sin(rad(d)) end - local asin = function(d) return deg(math.asin(d)) end - local tan = function(d) return math.tan(rad(d)) end - local atan = function(d) return deg(math.atan(d)) end - - local function fit_into_range(val, min, max) - local range = max - min - local count - if val < min then - count = floor((min - val) / range) + 1 - return val + count * range - elseif val >= max then - count = floor((val - max) / range) + 1 - return val - count * range - else - return val - end + local frac = function( n ) + return n - floor( n ) + end + local cos = function( d ) + return math.cos( rad( d ) ) + end + local acos = function( d ) + return deg( math.acos( d ) ) + end + local sin = function( d ) + return math.sin( rad( d ) ) + end + local asin = function( d ) + return deg( math.asin( d ) ) + end + local tan = function( d ) + return math.tan( rad( d ) ) + end + local atan = function( d ) + return deg( math.atan( d ) ) end - -- Convert the longitude to hour value and calculate an approximate time - local lng_hour = longitude / 15 + local function fit_into_range( val, min, max ) + local range = max - min + local count + if val < min then + count = floor( (min - val) / range ) + 1 + return val + count * range + elseif val >= max then + count = floor( (val - max) / range ) + 1 + return val - count * range + else + return val + end + end - local t - if rising then -- Rising time is desired - t = n + ((6 - lng_hour) / 24) - else -- Setting time is desired - t = n + ((18 - lng_hour) / 24) - end + -- Convert the longitude to hour value and calculate an approximate time + local lng_hour = longitude / 15 - -- Calculate the Sun's mean anomaly - local M = (0.9856 * t) - 3.289 + local t + if rising then -- Rising time is desired + t = n + ((6 - lng_hour) / 24) + else -- Setting time is desired + t = n + ((18 - lng_hour) / 24) + end - -- Calculate the Sun's true longitude - local L = fit_into_range(M + (1.916 * sin(M)) + (0.020 * sin(2 * M)) + 282.634, 0, 360) + -- Calculate the Sun's mean anomaly + local M = (0.9856 * t) - 3.289 - -- Calculate the Sun's right ascension - local RA = fit_into_range(atan(0.91764 * tan(L)), 0, 360) + -- Calculate the Sun's true longitude + local L = fit_into_range( M + (1.916 * sin( M )) + (0.020 * sin( 2 * M )) + 282.634, 0, 360 ) - -- Right ascension value needs to be in the same quadrant as L - local Lquadrant = floor(L / 90) * 90 - local RAquadrant = floor(RA / 90) * 90 - RA = RA + Lquadrant - RAquadrant + -- Calculate the Sun's right ascension + local RA = fit_into_range( atan( 0.91764 * tan( L ) ), 0, 360 ) - -- Right ascension value needs to be converted into hours - RA = RA / 15 + -- Right ascension value needs to be in the same quadrant as L + local Lquadrant = floor( L / 90 ) * 90 + local RAquadrant = floor( RA / 90 ) * 90 + RA = RA + Lquadrant - RAquadrant - -- Calculate the Sun's declination - local sinDec = 0.39782 * sin(L) - local cosDec = cos(asin(sinDec)) + -- Right ascension value needs to be converted into hours + RA = RA / 15 - -- Calculate the Sun's local hour angle - local cosH = (cos(zenith) - (sinDec * sin(latitude))) / (cosDec * cos(latitude)) + -- Calculate the Sun's declination + local sinDec = 0.39782 * sin( L ) + local cosDec = cos( asin( sinDec ) ) - if rising and cosH > 1 then - return "N/R" -- The sun never rises on this location on the specified date - elseif cosH < -1 then - return "N/S" -- The sun never sets on this location on the specified date - end + -- Calculate the Sun's local hour angle + local cosH = (cos( zenith ) - (sinDec * sin( latitude ))) / (cosDec * cos( latitude )) - -- Finish calculating H and convert into hours - local H - if rising then - H = 360 - acos(cosH) - else - H = acos(cosH) - end - H = H / 15 + if rising and cosH > 1 then + return "N/R" -- The sun never rises on this location on the specified date + elseif cosH < -1 then + return "N/S" -- The sun never sets on this location on the specified date + end - -- Calculate local mean time of rising/setting - local T = H + RA - (0.06571 * t) - 6.622 + -- Finish calculating H and convert into hours + local H + if rising then + H = 360 - acos( cosH ) + else + H = acos( cosH ) + end + H = H / 15 - -- Adjust back to UTC - local UT = fit_into_range(T - lng_hour +Tlocal, 0, 24) + -- Calculate local mean time of rising/setting + local T = H + RA - (0.06571 * t) - 6.622 - return floor(UT)*60*60+frac(UT)*60*60--+Tlocal*60*60 - end + -- Adjust back to UTC + local UT = fit_into_range( T - lng_hour + Tlocal, 0, 24 ) + + return floor( UT ) * 60 * 60 + frac( UT ) * 60 * 60 -- +Tlocal*60*60 +end --- Get sun rise of a specific day of the year at a specific location. -- @param #number Day Day of the year. @@ -1577,11 +1588,11 @@ function UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, Rising, Tlocal) -- @param #boolean Rising If true, calc sun rise, or sun set otherwise. -- @param #number Tlocal Local time offset in hours. E.g. +4 for a location which has GMT+4. Default 0. -- @return #number Sun rise in seconds of the day. -function UTILS.GetSunrise(Day, Month, Year, Latitude, Longitude, Tlocal) +function UTILS.GetSunrise( Day, Month, Year, Latitude, Longitude, Tlocal ) - local DayOfYear=UTILS.GetDayOfYear(Year, Month, Day) + local DayOfYear = UTILS.GetDayOfYear( Year, Month, Day ) - return UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, true, Tlocal) + return UTILS.GetSunRiseAndSet( DayOfYear, Latitude, Longitude, true, Tlocal ) end --- Get sun set of a specific day of the year at a specific location. @@ -1593,11 +1604,11 @@ end -- @param #boolean Rising If true, calc sun rise, or sun set otherwise. -- @param #number Tlocal Local time offset in hours. E.g. +4 for a location which has GMT+4. Default 0. -- @return #number Sun rise in seconds of the day. -function UTILS.GetSunset(Day, Month, Year, Latitude, Longitude, Tlocal) +function UTILS.GetSunset( Day, Month, Year, Latitude, Longitude, Tlocal ) - local DayOfYear=UTILS.GetDayOfYear(Year, Month, Day) + local DayOfYear = UTILS.GetDayOfYear( Year, Month, Day ) - return UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, false, Tlocal) + return UTILS.GetSunRiseAndSet( DayOfYear, Latitude, Longitude, false, Tlocal ) end --- Get OS time. Needs os to be desanitized! @@ -1611,11 +1622,11 @@ function UTILS.GetOSTime() end --- Shuffle a table accoring to Fisher Yeates algorithm ---@param #table t Table to be shuffled ---@return #table -function UTILS.ShuffleTable(t) - if t == nil or type(t) ~= "table" then - BASE:I("Error in ShuffleTable: Missing or wrong type of Argument") +-- @param #table t Table to be shuffled +-- @return #table +function UTILS.ShuffleTable( t ) + if t == nil or type( t ) ~= "table" then + BASE:I( "Error in ShuffleTable: Missing or wrong type of Argument" ) return end math.random() @@ -1623,67 +1634,67 @@ function UTILS.ShuffleTable(t) math.random() local TempTable = {} for i = 1, #t do - local r = math.random(1,#t) + local r = math.random( 1, #t ) TempTable[i] = t[r] - table.remove(t,r) + table.remove( t, r ) end return TempTable end --- (Helicopter) Check if one loading door is open. ---@param #string unit_name Unit name to be checked ---@return #boolean Outcome - true if a (loading door) is open, false if not, nil if none exists. +-- @param #string unit_name Unit name to be checked +-- @return #boolean Outcome - true if a (loading door) is open, false if not, nil if none exists. function UTILS.IsLoadingDoorOpen( unit_name ) local ret_val = false - local unit = Unit.getByName(unit_name) + local unit = Unit.getByName( unit_name ) if unit ~= nil then - local type_name = unit:getTypeName() + local type_name = unit:getTypeName() - if type_name == "Mi-8MT" and unit:getDrawArgumentValue(38) == 1 or unit:getDrawArgumentValue(86) == 1 or unit:getDrawArgumentValue(250) < 0 then - BASE:T(unit_name .. " Cargo doors are open or cargo door not present") - ret_val = true - end + if type_name == "Mi-8MT" and unit:getDrawArgumentValue( 38 ) == 1 or unit:getDrawArgumentValue( 86 ) == 1 or unit:getDrawArgumentValue( 250 ) < 0 then + BASE:T( unit_name .. " Cargo doors are open or cargo door not present" ) + ret_val = true + end - if type_name == "Mi-24P" and unit:getDrawArgumentValue(38) == 1 or unit:getDrawArgumentValue(86) == 1 then - BASE:T(unit_name .. " a side door is open") - ret_val = true - end + if type_name == "Mi-24P" and unit:getDrawArgumentValue( 38 ) == 1 or unit:getDrawArgumentValue( 86 ) == 1 then + BASE:T( unit_name .. " a side door is open" ) + ret_val = true + end - if type_name == "UH-1H" and unit:getDrawArgumentValue(43) == 1 or unit:getDrawArgumentValue(44) == 1 then - BASE:T(unit_name .. " a side door is open ") - ret_val = true - end + if type_name == "UH-1H" and unit:getDrawArgumentValue( 43 ) == 1 or unit:getDrawArgumentValue( 44 ) == 1 then + BASE:T( unit_name .. " a side door is open " ) + ret_val = true + end - if string.find(type_name, "SA342" ) and unit:getDrawArgumentValue(34) == 1 or unit:getDrawArgumentValue(38) == 1 then - BASE:T(unit_name .. " front door(s) are open") - ret_val = true - end + if string.find( type_name, "SA342" ) and unit:getDrawArgumentValue( 34 ) == 1 or unit:getDrawArgumentValue( 38 ) == 1 then + BASE:T( unit_name .. " front door(s) are open" ) + ret_val = true + end - if string.find(type_name, "Hercules") and unit:getDrawArgumentValue(1215) == 1 and unit:getDrawArgumentValue(1216) == 1 then - BASE:T(unit_name .. " rear doors are open") - ret_val = true - end + if string.find( type_name, "Hercules" ) and unit:getDrawArgumentValue( 1215 ) == 1 and unit:getDrawArgumentValue( 1216 ) == 1 then + BASE:T( unit_name .. " rear doors are open" ) + ret_val = true + end - if string.find(type_name, "Hercules") and (unit:getDrawArgumentValue(1220) == 1 or unit:getDrawArgumentValue(1221) == 1) then - BASE:T(unit_name .. " para doors are open") - ret_val = true - end + if string.find( type_name, "Hercules" ) and (unit:getDrawArgumentValue( 1220 ) == 1 or unit:getDrawArgumentValue( 1221 ) == 1) then + BASE:T( unit_name .. " para doors are open" ) + ret_val = true + end - if string.find(type_name, "Hercules") and unit:getDrawArgumentValue(1217) == 1 then - BASE:T(unit_name .. " side door is open") - ret_val = true - end + if string.find( type_name, "Hercules" ) and unit:getDrawArgumentValue( 1217 ) == 1 then + BASE:T( unit_name .. " side door is open" ) + ret_val = true + end - if string.find(type_name, "Bell-47") then -- bell aint got no doors so always ready to load injured soldiers - BASE:T(unit_name .. " door is open") - ret_val = true - end + if string.find( type_name, "Bell-47" ) then -- bell aint got no doors so always ready to load injured soldiers + BASE:T( unit_name .. " door is open" ) + ret_val = true + end - if ret_val == false then - BASE:T(unit_name .. " all doors are closed") - end - return ret_val + if ret_val == false then + BASE:T( unit_name .. " all doors are closed" ) + end + return ret_val end -- nil @@ -1693,16 +1704,16 @@ end --- Function to generate valid FM frequencies in mHz for radio beacons (FM). -- @return #table Table of frequencies. function UTILS.GenerateFMFrequencies() - local FreeFMFrequencies = {} - for _first = 3, 7 do - for _second = 0, 5 do - for _third = 0, 9 do - local _frequency = ((100 * _first) + (10 * _second) + _third) * 100000 --extra 0 because we didnt bother with 4th digit - table.insert(FreeFMFrequencies, _frequency) - end - end + local FreeFMFrequencies = {} + for _first = 3, 7 do + for _second = 0, 5 do + for _third = 0, 9 do + local _frequency = ((100 * _first) + (10 * _second) + _third) * 100000 -- extra 0 because we didnt bother with 4th digit + table.insert( FreeFMFrequencies, _frequency ) + end end - return FreeFMFrequencies + end + return FreeFMFrequencies end --- Function to generate valid VHF frequencies in kHz for radio beacons (FM). @@ -1711,73 +1722,73 @@ function UTILS.GenerateVHFrequencies() -- known and sorted map-wise NDBs in kHz local _skipFrequencies = { - 214,274,291.5,295,297.5, - 300.5,304,307,309.5,311,312,312.5,316, - 320,324,328,329,330,332,336,337, - 342,343,348,351,352,353,358, - 363,365,368,372.5,374, - 380,381,384,385,389,395,396, - 414,420,430,432,435,440,450,455,462,470,485, - 507,515,520,525,528,540,550,560,570,577,580, - 602,625,641,662,670,680,682,690, - 705,720,722,730,735,740,745,750,770,795, - 822,830,862,866, - 905,907,920,935,942,950,995, - 1000,1025,1030,1050,1065,1116,1175,1182,1210 + 214,274,291.5,295,297.5, + 300.5,304,307,309.5,311,312,312.5,316, + 320,324,328,329,330,332,336,337, + 342,343,348,351,352,353,358, + 363,365,368,372.5,374, + 380,381,384,385,389,395,396, + 414,420,430,432,435,440,450,455,462,470,485, + 507,515,520,525,528,540,550,560,570,577,580, + 602,625,641,662,670,680,682,690, + 705,720,722,730,735,740,745,750,770,795, + 822,830,862,866, + 905,907,920,935,942,950,995, + 1000,1025,1030,1050,1065,1116,1175,1182,1210 } local FreeVHFFrequencies = {} - -- first range + -- first range local _start = 200000 while _start < 400000 do - -- skip existing NDB frequencies# - local _found = false - for _, value in pairs(_skipFrequencies) do - if value * 1000 == _start then - _found = true - break - end + -- skip existing NDB frequencies# + local _found = false + for _, value in pairs( _skipFrequencies ) do + if value * 1000 == _start then + _found = true + break end - if _found == false then - table.insert(FreeVHFFrequencies, _start) - end - _start = _start + 10000 + end + if _found == false then + table.insert( FreeVHFFrequencies, _start ) + end + _start = _start + 10000 end - -- second range + -- second range _start = 400000 while _start < 850000 do - -- skip existing NDB frequencies - local _found = false - for _, value in pairs(_skipFrequencies) do - if value * 1000 == _start then - _found = true - break - end + -- skip existing NDB frequencies + local _found = false + for _, value in pairs( _skipFrequencies ) do + if value * 1000 == _start then + _found = true + break end - if _found == false then - table.insert(FreeVHFFrequencies, _start) - end - _start = _start + 10000 + end + if _found == false then + table.insert( FreeVHFFrequencies, _start ) + end + _start = _start + 10000 end -- third range _start = 850000 while _start <= 999000 do -- adjusted for Gazelle - -- skip existing NDB frequencies - local _found = false - for _, value in pairs(_skipFrequencies) do - if value * 1000 == _start then - _found = true - break - end + -- skip existing NDB frequencies + local _found = false + for _, value in pairs( _skipFrequencies ) do + if value * 1000 == _start then + _found = true + break end - if _found == false then - table.insert(FreeVHFFrequencies, _start) - end - _start = _start + 50000 + end + if _found == false then + table.insert( FreeVHFFrequencies, _start ) + end + _start = _start + 50000 end return FreeVHFFrequencies @@ -1787,52 +1798,50 @@ end -- @return #table UHF Frequencies function UTILS.GenerateUHFrequencies() - local FreeUHFFrequencies = {} - local _start = 220000000 + local FreeUHFFrequencies = {} + local _start = 220000000 - while _start < 399000000 do - table.insert(FreeUHFFrequencies, _start) - _start = _start + 500000 - end + while _start < 399000000 do + table.insert( FreeUHFFrequencies, _start ) + _start = _start + 500000 + end - return FreeUHFFrequencies + return FreeUHFFrequencies end --- Function to generate valid laser codes for JTAC. -- @return #table Laser Codes. function UTILS.GenerateLaserCodes() - local jtacGeneratedLaserCodes = {} + local jtacGeneratedLaserCodes = {} - -- helper function - local function ContainsDigit(_number, _numberToFind) - local _thisNumber = _number - local _thisDigit = 0 - while _thisNumber ~= 0 do - _thisDigit = _thisNumber % 10 - _thisNumber = math.floor(_thisNumber / 10) - if _thisDigit == _numberToFind then - return true - end + -- helper function + local function ContainsDigit( _number, _numberToFind ) + local _thisNumber = _number + local _thisDigit = 0 + while _thisNumber ~= 0 do + _thisDigit = _thisNumber % 10 + _thisNumber = math.floor( _thisNumber / 10 ) + if _thisDigit == _numberToFind then + return true end - return false end + return false + end - -- generate list of laser codes - local _code = 1111 - local _count = 1 - while _code < 1777 and _count < 30 do - while true do - _code = _code + 1 - if not ContainsDigit(_code, 8) - and not ContainsDigit(_code, 9) - and not ContainsDigit(_code, 0) then - table.insert(jtacGeneratedLaserCodes, _code) - break - end - end - _count = _count + 1 + -- generate list of laser codes + local _code = 1111 + local _count = 1 + while _code < 1777 and _count < 30 do + while true do + _code = _code + 1 + if not ContainsDigit( _code, 8 ) and not ContainsDigit( _code, 9 ) and not ContainsDigit( _code, 0 ) then + table.insert( jtacGeneratedLaserCodes, _code ) + break + end end - return jtacGeneratedLaserCodes + _count = _count + 1 + end + return jtacGeneratedLaserCodes end --- Function to save an object to a file @@ -1840,34 +1849,34 @@ end -- @param #string Filename The name of the file. Existing file will be overwritten. -- @param #table Data The LUA data structure to save. This will be e.g. a table of text lines with an \\n at the end of each line. -- @return #boolean outcome True if saving is possible, else false. -function UTILS.SaveToFile(Path,Filename,Data) +function UTILS.SaveToFile( Path, Filename, Data ) -- Thanks to @FunkyFranky -- Check io module is available. if not io then - BASE:E("ERROR: io not desanitized. Can't save current file.") + BASE:E( "ERROR: io not desanitized. Can't save current file." ) return false end - + -- Check default path. - if Path==nil and not lfs then - BASE:E("WARNING: lfs not desanitized. File will be saved in DCS installation root directory rather than your \"Saved Games\\DCS\" folder.") + if Path == nil and not lfs then + BASE:E( "WARNING: lfs not desanitized. File will be saved in DCS installation root directory rather than your \"Saved Games\\DCS\" folder." ) end - + -- Set path or default. local path = nil if lfs then - path=Path or lfs.writedir() + path = Path or lfs.writedir() end - + -- Set file name. - local filename=Filename - if path~=nil then - filename=path.."\\"..filename + local filename = Filename + if path ~= nil then + filename = path .. "\\" .. filename end - + -- write - local f = assert(io.open(filename, "wb")) - f:write(Data) + local f = assert( io.open( filename, "wb" ) ) + f:write( Data ) f:close() return true end @@ -1877,43 +1886,43 @@ end -- @param #string Filename The name of the file. -- @return #boolean outcome True if reading is possible and successful, else false. -- @return #table data The data read from the filesystem (table of lines of text). Each line is one single #string! -function UTILS.LoadFromFile(Path,Filename) +function UTILS.LoadFromFile( Path, Filename ) -- Thanks to @FunkyFranky -- Check io module is available. if not io then - BASE:E("ERROR: io not desanitized. Can't save current state.") + BASE:E( "ERROR: io not desanitized. Can't save current state." ) return false end - + -- Check default path. - if Path==nil and not lfs then - BASE:E("WARNING: lfs not desanitized. Loading will look into your DCS installation root directory rather than your \"Saved Games\\DCS\" folder.") + if Path == nil and not lfs then + BASE:E( "WARNING: lfs not desanitized. Loading will look into your DCS installation root directory rather than your \"Saved Games\\DCS\" folder." ) end - + -- Set path or default. local path = nil if lfs then - path=Path or lfs.writedir() + path = Path or lfs.writedir() end - + -- Set file name. - local filename=Filename - if path~=nil then - filename=path.."\\"..filename + local filename = Filename + if path ~= nil then + filename = path .. "\\" .. filename end - + -- Check if file exists. - local exists=UTILS.CheckFileExists(Path,Filename) + local exists = UTILS.CheckFileExists( Path, Filename ) if not exists then - BASE:E(string.format("ERROR: File %s does not exist!",filename)) + BASE:E( string.format( "ERROR: File %s does not exist!", filename ) ) return false end - + -- read - local file=assert(io.open(filename, "rb")) + local file = assert( io.open( filename, "rb" ) ) local loadeddata = {} for line in file:lines() do - loadeddata[#loadeddata+1] = line + loadeddata[#loadeddata + 1] = line end file:close() return true, loadeddata @@ -1923,46 +1932,46 @@ end -- @param #string Path The path to use. Use double backslashes \\\\ on Windows filesystems. -- @param #string Filename The name of the file. -- @return #boolean outcome True if reading is possible, else false. -function UTILS.CheckFileExists(Path,Filename) +function UTILS.CheckFileExists( Path, Filename ) -- Thanks to @FunkyFranky -- Function that check if a file exists. - local function _fileexists(name) - local f=io.open(name,"r") - if f~=nil then - io.close(f) + local function _fileexists( name ) + local f = io.open( name, "r" ) + if f ~= nil then + io.close( f ) return true else return false end end - + -- Check io module is available. if not io then - BASE:E("ERROR: io not desanitized. Can't save current state.") + BASE:E( "ERROR: io not desanitized. Can't save current state." ) return false end - + -- Check default path. - if Path==nil and not lfs then - BASE:E("WARNING: lfs not desanitized. Loading will look into your DCS installation root directory rather than your \"Saved Games\\DCS\" folder.") + if Path == nil and not lfs then + BASE:E( "WARNING: lfs not desanitized. Loading will look into your DCS installation root directory rather than your \"Saved Games\\DCS\" folder." ) end - + -- Set path or default. local path = nil if lfs then - path=Path or lfs.writedir() + path = Path or lfs.writedir() end - + -- Set file name. - local filename=Filename - if path~=nil then - filename=path.."\\"..filename + local filename = Filename + if path ~= nil then + filename = path .. "\\" .. filename end - + -- Check if file exists. - local exists=_fileexists(filename) + local exists = _fileexists( filename ) if not exists then - BASE:E(string.format("ERROR: File %s does not exist!",filename)) + BASE:E( string.format( "ERROR: File %s does not exist!", filename ) ) return false else return true @@ -1980,21 +1989,21 @@ end -- Position is still saved for your usage. -- The idea is to reduce the number of units when reloading the data again to restart the saved mission. -- The data will be a simple comma separated list of groupname and size, with one header line. -function UTILS.SaveStationaryListOfGroups(List,Path,Filename) +function UTILS.SaveStationaryListOfGroups( List, Path, Filename ) local filename = Filename or "StateListofGroups" - local data = "--Save Stationary List of Groups: "..Filename .."\n" - for _,_group in pairs (List) do - local group = GROUP:FindByName(_group) -- Wrapper.Group#GROUP + local data = "--Save Stationary List of Groups: " .. Filename .. "\n" + for _, _group in pairs( List ) do + local group = GROUP:FindByName( _group ) -- Wrapper.Group#GROUP if group and group:IsAlive() then local units = group:CountAliveUnits() local position = group:GetVec3() - data = string.format("%s%s,%d,%d,%d,%d\n",data,_group,units,position.x,position.y,position.z) + data = string.format( "%s%s,%d,%d,%d,%d\n", data, _group, units, position.x, position.y, position.z ) else - data = string.format("%s%s,0,0,0,0\n",data,_group) + data = string.format( "%s%s,0,0,0,0\n", data, _group ) end end -- save the data - local outcome = UTILS.SaveToFile(Path,Filename,data) + local outcome = UTILS.SaveToFile( Path, Filename, data ) return outcome end @@ -2011,25 +2020,25 @@ end -- **Note** Do NOT use dashes or hashes in group template names (-,#)! -- The data will be a simple comma separated list of groupname and size, with one header line. -- The current task/waypoint/etc cannot be restored. -function UTILS.SaveSetOfGroups(Set,Path,Filename) +function UTILS.SaveSetOfGroups( Set, Path, Filename ) local filename = Filename or "SetOfGroups" - local data = "--Save SET of groups: "..Filename .."\n" + local data = "--Save SET of groups: " .. Filename .. "\n" local List = Set:GetSetObjects() - for _,_group in pairs (List) do + for _, _group in pairs( List ) do local group = _group -- Wrapper.Group#GROUP if group and group:IsAlive() then local name = group:GetName() - local template = string.gsub(name,"-(.+)$","") - if string.find(template,"#") then - template = string.gsub(name,"#(%d+)$","") - end + local template = string.gsub( name, "-(.+)$", "" ) + if string.find( template, "#" ) then + template = string.gsub( name, "#(%d+)$", "" ) + end local units = group:CountAliveUnits() local position = group:GetVec3() - data = string.format("%s%s,%s,%d,%d,%d,%d\n",data,name,template,units,position.x,position.y,position.z) + data = string.format( "%s%s,%s,%d,%d,%d,%d\n", data, name, template, units, position.x, position.y, position.z ) end end -- save the data - local outcome = UTILS.SaveToFile(Path,Filename,data) + local outcome = UTILS.SaveToFile( Path, Filename, data ) return outcome end @@ -2041,20 +2050,20 @@ end -- @usage -- We will go through the set and find the corresponding static and save the current name and postion when alive. -- The data will be a simple comma separated list of name and state etc, with one header line. -function UTILS.SaveSetOfStatics(Set,Path,Filename) +function UTILS.SaveSetOfStatics( Set, Path, Filename ) local filename = Filename or "SetOfStatics" - local data = "--Save SET of statics: "..Filename .."\n" + local data = "--Save SET of statics: " .. Filename .. "\n" local List = Set:GetSetObjects() - for _,_group in pairs (List) do + for _, _group in pairs( List ) do local group = _group -- Wrapper.Static#STATIC if group and group:IsAlive() then local name = group:GetName() local position = group:GetVec3() - data = string.format("%s%s,%d,%d,%d\n",data,name,position.x,position.y,position.z) + data = string.format( "%s%s,%d,%d,%d\n", data, name, position.x, position.y, position.z ) end end -- save the data - local outcome = UTILS.SaveToFile(Path,Filename,data) + local outcome = UTILS.SaveToFile( Path, Filename, data ) return outcome end @@ -2068,20 +2077,20 @@ end -- Position is saved for your usage. **Note** this works on UNIT-name level. -- The idea is to reduce the number of units when reloading the data again to restart the saved mission. -- The data will be a simple comma separated list of name and state etc, with one header line. -function UTILS.SaveStationaryListOfStatics(List,Path,Filename) +function UTILS.SaveStationaryListOfStatics( List, Path, Filename ) local filename = Filename or "StateListofStatics" - local data = "--Save Stationary List of Statics: "..Filename .."\n" - for _,_group in pairs (List) do - local group = STATIC:FindByName(_group,false) -- Wrapper.Static#STATIC + local data = "--Save Stationary List of Statics: " .. Filename .. "\n" + for _, _group in pairs( List ) do + local group = STATIC:FindByName( _group, false ) -- Wrapper.Static#STATIC if group and group:IsAlive() then local position = group:GetVec3() - data = string.format("%s%s,1,%d,%d,%d\n",data,_group,position.x,position.y,position.z) + data = string.format( "%s%s,1,%d,%d,%d\n", data, _group, position.x, position.y, position.z ) else - data = string.format("%s%s,0,0,0,0\n",data,_group) + data = string.format( "%s%s,0,0,0,0\n", data, _group ) end end -- save the data - local outcome = UTILS.SaveToFile(Path,Filename,data) + local outcome = UTILS.SaveToFile( Path, Filename, data ) return outcome end @@ -2090,41 +2099,43 @@ end -- @param #string Filename The name of the file. -- @param #boolean Reduce If false, existing loaded groups will not be reduced to fit the saved number. -- @return #table Table of data objects (tables) containing groupname, coordinate and group object. Returns nil when file cannot be read. -function UTILS.LoadStationaryListOfGroups(Path,Filename,Reduce) +function UTILS.LoadStationaryListOfGroups( Path, Filename, Reduce ) local reduce = true - if Reduce == false then reduce = false end + if Reduce == false then + reduce = false + end local filename = Filename or "StateListofGroups" local datatable = {} - if UTILS.CheckFileExists(Path,filename) then - local outcome,loadeddata = UTILS.LoadFromFile(Path,Filename) + if UTILS.CheckFileExists( Path, filename ) then + local outcome, loadeddata = UTILS.LoadFromFile( Path, Filename ) -- remove header - table.remove(loadeddata, 1) - for _id,_entry in pairs (loadeddata) do - local dataset = UTILS.Split(_entry,",") + table.remove( loadeddata, 1 ) + for _id, _entry in pairs( loadeddata ) do + local dataset = UTILS.Split( _entry, "," ) -- groupname,units,position.x,position.y,position.z local groupname = dataset[1] - local size = tonumber(dataset[2]) - local posx = tonumber(dataset[3]) - local posy = tonumber(dataset[4]) - local posz = tonumber(dataset[5]) - local coordinate = COORDINATE:NewFromVec3({x=posx, y=posy, z=posz}) - local data = { groupname=groupname, size=size, coordinate=coordinate, group=GROUP:FindByName(groupname) } + local size = tonumber( dataset[2] ) + local posx = tonumber( dataset[3] ) + local posy = tonumber( dataset[4] ) + local posz = tonumber( dataset[5] ) + local coordinate = COORDINATE:NewFromVec3( { x = posx, y = posy, z = posz } ) + local data = { groupname = groupname, size = size, coordinate = coordinate, group = GROUP:FindByName( groupname ) } if reduce then - local actualgroup = GROUP:FindByName(groupname) + local actualgroup = GROUP:FindByName( groupname ) local actualsize = actualgroup:CountAliveUnits() if actualsize > size then - local reduction = actualsize-size - BASE:I("Reducing groupsize by ".. reduction .. " units!") + local reduction = actualsize - size + BASE:I( "Reducing groupsize by " .. reduction .. " units!" ) -- reduce existing group local units = actualgroup:GetUnits() - local units2 = UTILS.ShuffleTable(units) -- randomize table - for i=1,reduction do - units2[i]:Destroy(false) + local units2 = UTILS.ShuffleTable( units ) -- randomize table + for i = 1, reduction do + units2[i]:Destroy( false ) end end end - table.insert(datatable,data) - end + table.insert( datatable, data ) + end else return nil end @@ -2137,58 +2148,55 @@ end -- @param #boolean Spawn If set to false, do not re-spawn the groups loaded in location and reduce to size. -- @return Core.Set#SET_GROUP Set of GROUP objects. -- Returns nil when file cannot be read. Returns a table of data entries if Spawn is false: `{ groupname=groupname, size=size, coordinate=coordinate }` -function UTILS.LoadSetOfGroups(Path,Filename,Spawn) +function UTILS.LoadSetOfGroups( Path, Filename, Spawn ) local spawn = true - if Spawn == false then spawn = false end - BASE:I("Spawn = "..tostring(spawn)) + if Spawn == false then + spawn = false + end + BASE:I( "Spawn = " .. tostring( spawn ) ) local filename = Filename or "SetOfGroups" local setdata = SET_GROUP:New() local datatable = {} - if UTILS.CheckFileExists(Path,filename) then - local outcome,loadeddata = UTILS.LoadFromFile(Path,Filename) + if UTILS.CheckFileExists( Path, filename ) then + local outcome, loadeddata = UTILS.LoadFromFile( Path, Filename ) -- remove header - table.remove(loadeddata, 1) - for _id,_entry in pairs (loadeddata) do - local dataset = UTILS.Split(_entry,",") + table.remove( loadeddata, 1 ) + for _id, _entry in pairs( loadeddata ) do + local dataset = UTILS.Split( _entry, "," ) -- groupname,template,units,position.x,position.y,position.z local groupname = dataset[1] local template = dataset[2] - local size = tonumber(dataset[3]) - local posx = tonumber(dataset[4]) - local posy = tonumber(dataset[5]) - local posz = tonumber(dataset[6]) - local coordinate = COORDINATE:NewFromVec3({x=posx, y=posy, z=posz}) - local group=nil - local data = { groupname=groupname, size=size, coordinate=coordinate } - table.insert(datatable,data) + local size = tonumber( dataset[3] ) + local posx = tonumber( dataset[4] ) + local posy = tonumber( dataset[5] ) + local posz = tonumber( dataset[6] ) + local coordinate = COORDINATE:NewFromVec3( { x = posx, y = posy, z = posz } ) + local group = nil + local data = { groupname = groupname, size = size, coordinate = coordinate } + table.insert( datatable, data ) if spawn then - local group = SPAWN:New(groupname) - :InitDelayOff() - :OnSpawnGroup( - function(spwndgrp) - setdata:AddObject(spwndgrp) - local actualsize = spwndgrp:CountAliveUnits() - if actualsize > size then - local reduction = actualsize-size - -- reduce existing group - local units = spwndgrp:GetUnits() - local units2 = UTILS.ShuffleTable(units) -- randomize table - for i=1,reduction do - units2[i]:Destroy(false) - end - end + local group = SPAWN:New( groupname ):InitDelayOff():OnSpawnGroup( function( spwndgrp ) + setdata:AddObject( spwndgrp ) + local actualsize = spwndgrp:CountAliveUnits() + if actualsize > size then + local reduction = actualsize - size + -- reduce existing group + local units = spwndgrp:GetUnits() + local units2 = UTILS.ShuffleTable( units ) -- randomize table + for i = 1, reduction do + units2[i]:Destroy( false ) end - ) - :SpawnFromCoordinate(coordinate) + end + end ):SpawnFromCoordinate( coordinate ) end - end + end else return nil end if spawn then return setdata else - return datatable + return datatable end end @@ -2196,23 +2204,23 @@ end -- @param #string Path The path to use. Use double backslashes \\\\ on Windows filesystems. -- @param #string Filename The name of the file. -- @return Core.Set#SET_STATIC Set SET_STATIC containing the static objects. -function UTILS.LoadSetOfStatics(Path,Filename) +function UTILS.LoadSetOfStatics( Path, Filename ) local filename = Filename or "SetOfStatics" local datatable = SET_STATIC:New() - if UTILS.CheckFileExists(Path,filename) then - local outcome,loadeddata = UTILS.LoadFromFile(Path,Filename) + if UTILS.CheckFileExists( Path, filename ) then + local outcome, loadeddata = UTILS.LoadFromFile( Path, Filename ) -- remove header - table.remove(loadeddata, 1) - for _id,_entry in pairs (loadeddata) do - local dataset = UTILS.Split(_entry,",") + table.remove( loadeddata, 1 ) + for _id, _entry in pairs( loadeddata ) do + local dataset = UTILS.Split( _entry, "," ) -- staticname,position.x,position.y,position.z local staticname = dataset[1] - local posx = tonumber(dataset[2]) - local posy = tonumber(dataset[3]) - local posz = tonumber(dataset[4]) - local coordinate = COORDINATE:NewFromVec3({x=posx, y=posy, z=posz}) - datatable:AddObject(STATIC:FindByName(staticname,false)) - end + local posx = tonumber( dataset[2] ) + local posy = tonumber( dataset[3] ) + local posz = tonumber( dataset[4] ) + local coordinate = COORDINATE:NewFromVec3( { x = posx, y = posy, z = posz } ) + datatable:AddObject( STATIC:FindByName( staticname, false ) ) + end else return nil end @@ -2225,33 +2233,35 @@ end -- @param #boolean Reduce If false, do not destroy the units with size=0. -- @return #table Table of data objects (tables) containing staticname, size (0=dead else 1), coordinate and the static object. -- Returns nil when file cannot be read. -function UTILS.LoadStationaryListOfStatics(Path,Filename,Reduce) +function UTILS.LoadStationaryListOfStatics( Path, Filename, Reduce ) local reduce = true - if Reduce == false then reduce = false end + if Reduce == false then + reduce = false + end local filename = Filename or "StateListofStatics" local datatable = {} - if UTILS.CheckFileExists(Path,filename) then - local outcome,loadeddata = UTILS.LoadFromFile(Path,Filename) + if UTILS.CheckFileExists( Path, filename ) then + local outcome, loadeddata = UTILS.LoadFromFile( Path, Filename ) -- remove header - table.remove(loadeddata, 1) - for _id,_entry in pairs (loadeddata) do - local dataset = UTILS.Split(_entry,",") + table.remove( loadeddata, 1 ) + for _id, _entry in pairs( loadeddata ) do + local dataset = UTILS.Split( _entry, "," ) -- staticname,units(1/0),position.x,position.y,position.z) local staticname = dataset[1] - local size = tonumber(dataset[2]) - local posx = tonumber(dataset[3]) - local posy = tonumber(dataset[4]) - local posz = tonumber(dataset[5]) - local coordinate = COORDINATE:NewFromVec3({x=posx, y=posy, z=posz}) - local data = { staticname=staticname, size=size, coordinate=coordinate, static=STATIC:FindByName(staticname,false) } - table.insert(datatable,data) - if size==0 and reduce then - local static = STATIC:FindByName(staticname,false) + local size = tonumber( dataset[2] ) + local posx = tonumber( dataset[3] ) + local posy = tonumber( dataset[4] ) + local posz = tonumber( dataset[5] ) + local coordinate = COORDINATE:NewFromVec3( { x = posx, y = posy, z = posz } ) + local data = { staticname = staticname, size = size, coordinate = coordinate, static = STATIC:FindByName( staticname, false ) } + table.insert( datatable, data ) + if size == 0 and reduce then + local static = STATIC:FindByName( staticname, false ) if static then - static:Destroy(false) + static:Destroy( false ) end end - end + end else return nil end