diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index 182133a1f..36f467284 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -194,7 +194,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.ToStringBRA}(): Generates a Bearing, Range & Altitude text. + -- * @{#COORDINATE.ToStringBRAANATO}(): Generates a Generates a Bearing, Range, Aspect & Altitude text in NATOPS. + -- * @{#COORDINATE.ToStringLL}(): Generates a Latutide & Longitude text. + -- * @{#COORDINATE.ToStringLLDMS}(): Generates a Lat, Lon, Degree, Minute, Second text. + -- * @{#COORDINATE.ToStringLLDDM}(): Generates a Lat, Lon, Degree, decimal Minute text. + -- * @{#COORDINATE.ToStringMGRS}(): Generates a MGRS grid coordinate text. -- -- ## 10) Drawings on F10 map -- @@ -1112,25 +1117,28 @@ do -- COORDINATE -- @param #COORDINATE self -- @param #number Distance The distance in meters. -- @param Core.Settings#SETTINGS Settings + -- @param #string Language (optional) "EN" or "RU" + -- @param #number Precision (optional) round to this many decimal places -- @return #string The distance text expressed in the units of measurement. - function COORDINATE:GetDistanceText( Distance, Settings, Language ) + function COORDINATE:GetDistanceText( Distance, Settings, Language, Precision ) local Settings = Settings or _SETTINGS -- Core.Settings#SETTINGS local Language = Language or "EN" - + local Precision = Precision or 0 + local DistanceText if Settings:IsMetric() then if Language == "EN" then - DistanceText = " for " .. UTILS.Round( Distance / 1000, 2 ) .. " km" + DistanceText = " for " .. UTILS.Round( Distance / 1000, Precision ) .. " km" elseif Language == "RU" then - DistanceText = " за " .. UTILS.Round( Distance / 1000, 2 ) .. " километров" + DistanceText = " за " .. UTILS.Round( Distance / 1000, Precision ) .. " километров" end else if Language == "EN" then - DistanceText = " for " .. UTILS.Round( UTILS.MetersToNM( Distance ), 2 ) .. " miles" + DistanceText = " for " .. UTILS.Round( UTILS.MetersToNM( Distance ), Precision ) .. " miles" elseif Language == "RU" then - DistanceText = " за " .. UTILS.Round( UTILS.MetersToNM( Distance ), 2 ) .. " миль" + DistanceText = " за " .. UTILS.Round( UTILS.MetersToNM( Distance ), Precision ) .. " миль" end end @@ -1208,7 +1216,7 @@ 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 DistanceText = self:GetDistanceText( Distance, Settings, Language, 0 ) local BRText = BearingText .. DistanceText @@ -1226,7 +1234,7 @@ 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 DistanceText = self:GetDistanceText( Distance, Settings, Language, 0 ) local AltitudeText = self:GetAltitudeText( Settings, Language ) local BRAText = BearingText .. DistanceText .. AltitudeText -- When the POINT is a VEC2, there will be no altitude shown. @@ -2164,14 +2172,21 @@ do -- COORDINATE 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=FillColor or UTILS.DeepCopy(Color) FillColor[4]=FillAlpha or 0.15 + trigger.action.circleToAll(Coalition, MarkID, vec3, Radius, Color, FillColor, LineType, ReadOnly, Text or "") return MarkID end @@ -2196,13 +2211,19 @@ do -- COORDINATE 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=FillColor or UTILS.DeepCopy(Color) FillColor[4]=FillAlpha or 0.15 + trigger.action.rectToAll(Coalition, MarkID, self:GetVec3(), vec3, Color, FillColor, LineType, ReadOnly, Text or "") return MarkID end @@ -2226,17 +2247,23 @@ do -- COORDINATE 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=FillColor or UTILS.DeepCopy(Color) FillColor[4]=FillAlpha or 0.15 - trigger.action.quadToAll(Coalition, MarkID, self:GetVec3(), point2, point3, point4, Color, FillColor, LineType, ReadOnly, Text or "") + + trigger.action.quadToAll(Coalition, MarkID, point1, point2, point3, point4, Color, FillColor, LineType, ReadOnly, Text or "") return MarkID end @@ -2320,11 +2347,15 @@ do -- COORDINATE ReadOnly=false end Coalition=Coalition or -1 + Color=Color or {1,0,0} Color[4]=Alpha or 1.0 - FillColor=FillColor or Color + + FillColor=FillColor or UTILS.DeepCopy(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 @@ -2346,13 +2377,19 @@ do -- COORDINATE 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=FillColor or UTILS.DeepCopy(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 diff --git a/Moose Development/Moose/Core/Zone.lua b/Moose Development/Moose/Core/Zone.lua index 7f4828df6..5d88d833e 100644 --- a/Moose Development/Moose/Core/Zone.lua +++ b/Moose Development/Moose/Core/Zone.lua @@ -1989,6 +1989,18 @@ function ZONE_POLYGON_BASE:IsVec2InZone( Vec2 ) return InPolygon end +--- Returns if a point is within the zone. +-- @param #ZONE_POLYGON_BASE self +-- @param DCS#Vec3 Vec3 The point to test. +-- @return #boolean true if the point is within the zone. +function ZONE_POLYGON_BASE:IsVec3InZone( Vec3 ) + self:F2( Vec3 ) + + local InZone = self:IsVec2InZone( { x = Vec3.x, y = Vec3.z } ) + + return InZone +end + --- Define a random @{DCS#Vec2} within the zone. -- @param #ZONE_POLYGON_BASE self -- @return DCS#Vec2 The Vec2 coordinate. diff --git a/Moose Development/Moose/Modules.lua b/Moose Development/Moose/Modules.lua index ad27b6b84..29c10ad0c 100644 --- a/Moose Development/Moose/Modules.lua +++ b/Moose Development/Moose/Modules.lua @@ -4,6 +4,7 @@ __Moose.Include( 'Scripts/Moose/Utilities/Utils.lua' ) __Moose.Include( 'Scripts/Moose/Utilities/Profiler.lua' ) __Moose.Include( 'Scripts/Moose/Utilities/Templates.lua' ) __Moose.Include( 'Scripts/Moose/Utilities/STTS.lua' ) +__Moose.Include( 'Scripts/Moose/Utilities/FiFo.lua' ) __Moose.Include( 'Scripts/Moose/Core/Base.lua' ) __Moose.Include( 'Scripts/Moose/Core/Beacon.lua' ) diff --git a/Moose Development/Moose/Sound/SRS.lua b/Moose Development/Moose/Sound/SRS.lua index 2c4411ac1..3ec73c6f1 100644 --- a/Moose Development/Moose/Sound/SRS.lua +++ b/Moose Development/Moose/Sound/SRS.lua @@ -45,6 +45,7 @@ -- @field Core.Point#COORDINATE coordinate Coordinate from where the transmission is send. -- @field #string path Path to the SRS exe. This includes the final slash "/". -- @field #string google Full path google credentials JSON file, e.g. "C:\Users\username\Downloads\service-account-file.json". +-- @field #string Label Label showing up on the SRS radio overlay. Default is "ROBOT". No spaces allowed. -- @extends Core.Base#BASE --- *It is a very sad thing that nowadays there is so little useless information.* - Oscar Wilde @@ -125,11 +126,12 @@ MSRS = { volume = 1, speed = 1, coordinate = nil, + Label = "ROBOT", } --- MSRS class version. -- @field #string version -MSRS.version="0.0.3" +MSRS.version="0.0.4" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO list @@ -164,6 +166,7 @@ function MSRS:New(PathToSRS, Frequency, Modulation) self:SetModulations(Modulation) self:SetGender() self:SetCoalition() + self:SetLabel() return self end @@ -206,6 +209,22 @@ function MSRS:GetPath() return self.path end +--- Set label. +-- @param #MSRS self +-- @param #number Label. Default "ROBOT" +-- @return #MSRS self +function MSRS:SetLabel(Label) + self.Label=Label or "ROBOT" + return self +end + +--- Get label. +-- @param #MSRS self +-- @return #number Label. +function MSRS:GetLabel() + return self.Label +end + --- Set port. -- @param #MSRS self -- @param #number Port Port. Default 5002. @@ -640,8 +659,9 @@ end -- @param #number volume Volume. -- @param #number speed Speed. -- @param #number port Port. +-- @param #string label Label, defaults to "ROBOT" (displayed sender name in the radio overlay of SRS) - No spaces allowed! -- @return #string Command. -function MSRS:_GetCommand(freqs, modus, coal, gender, voice, culture, volume, speed, port) +function MSRS:_GetCommand(freqs, modus, coal, gender, voice, culture, volume, speed, port,label) local path=self:GetPath() or STTS.DIRECTORY local exe=STTS.EXECUTABLE or "DCS-SR-ExternalAudio.exe" @@ -654,6 +674,7 @@ function MSRS:_GetCommand(freqs, modus, coal, gender, voice, culture, volume, sp volume=volume or self.volume speed=speed or self.speed port=port or self.port + label=label or self.Label -- Replace modulation modus=modus:gsub("0", "AM") @@ -668,7 +689,7 @@ function MSRS:_GetCommand(freqs, modus, coal, gender, voice, culture, volume, sp --local command=string.format('start /b "" /d "%s" "%s" -f %s -m %s -c %s -p %s -n "%s" > bla.txt', path, exe, freqs, modus, coal, port, "ROBOT") -- Command. - local command=string.format('"%s\\%s" -f %s -m %s -c %s -p %s -n "%s"', path, exe, freqs, modus, coal, port, "ROBOT") + local command=string.format('"%s\\%s" -f %s -m %s -c %s -p %s -n "%s"', path, exe, freqs, modus, coal, port, label) -- Set voice or gender/culture. if voice then diff --git a/Moose Development/Moose/Utilities/Enums.lua b/Moose Development/Moose/Utilities/Enums.lua index f4de6e4d7..423bd85e9 100644 --- a/Moose Development/Moose/Utilities/Enums.lua +++ b/Moose Development/Moose/Utilities/Enums.lua @@ -1,18 +1,18 @@ --- **Utilities** Enumerators. --- +-- -- An enumerator is a variable that holds a constant value. Enumerators are very useful because they make the code easier to read and to change in general. --- +-- -- For example, instead of using the same value at multiple different places in your code, you should use a variable set to that value. -- If, for whatever reason, the value needs to be changed, you only have to change the variable once and do not have to search through you code and reset -- every value by hand. --- +-- -- Another big advantage is that the LDT intellisense "knows" the enumerators. So you can use the autocompletion feature and do not have to keep all the --- values in your head or look them up in the docs. --- +-- values in your head or look them up in the docs. +-- -- DCS itself provides a lot of enumerators for various things. See [Enumerators](https://wiki.hoggitworld.com/view/Category:Enumerators) on Hoggit. --- +-- -- Other Moose classes also have enumerators. For example, the AIRBASE class has enumerators for airbase names. --- +-- -- @module ENUMS -- @image MOOSE.JPG @@ -20,7 +20,7 @@ -- @type ENUMS --- Because ENUMS are just better practice. --- +-- -- The ENUMS class adds some handy variables, which help you to make your code better and more general. -- -- @field #ENUMS @@ -30,16 +30,16 @@ ENUMS = {} -- @type ENUMS.ROE -- @field #number WeaponFree AI will engage any enemy group it detects. Target prioritization is based based on the threat of the target. -- @field #number OpenFireWeaponFree AI will engage any enemy group it detects, but will prioritize targets specified in the groups tasking. --- @field #number OpenFire AI will engage only targets specified in its tasking. +-- @field #number OpenFire AI will engage only targets specified in its taskings. -- @field #number ReturnFire AI will only engage threats that shoot first. -- @field #number WeaponHold AI will hold fire under all circumstances. ENUMS.ROE = { - WeaponFree = 0, - OpenFireWeaponFree = 1, - OpenFire = 2, - ReturnFire = 3, - WeaponHold = 4, -} + WeaponFree=0, + OpenFireWeaponFree=1, + OpenFire=2, + ReturnFire=3, + WeaponHold=4, + } --- Reaction On Threat. -- @type ENUMS.ROT @@ -49,11 +49,11 @@ ENUMS.ROE = { -- @field #number BypassAndEscape AI will attempt to avoid enemy threat zones all together. This includes attempting to fly above or around threats. -- @field #number AllowAbortMission If a threat is deemed severe enough the AI will abort its mission and return to base. ENUMS.ROT = { - NoReaction = 0, - PassiveDefense = 1, - EvadeFire = 2, - BypassAndEscape = 3, - AllowAbortMission = 4, + NoReaction=0, + PassiveDefense=1, + EvadeFire=2, + BypassAndEscape=3, + AllowAbortMission=4, } --- Alarm state. @@ -62,12 +62,12 @@ ENUMS.ROT = { -- @field #number Green Group is not combat ready. Sensors are stowed if possible. -- @field #number Red Group is combat ready and actively searching for targets. Some groups like infantry will not move in this state. ENUMS.AlarmState = { - Auto = 0, - Green = 1, - Red = 2, + Auto=0, + Green=1, + Red=2, } ---- Weapon types. See the [Weapon Flag](https://wiki.hoggitworld.com/view/DCS_enum_weapon_flag) enumerator on Hoggit wiki. +--- Weapon types. See the [Weapon Flag](https://wiki.hoggitworld.com/view/DCS_enum_weapon_flag) enumerotor on hoggit wiki. -- @type ENUMS.WeaponFlag ENUMS.WeaponFlag={ -- Bombs @@ -111,7 +111,7 @@ ENUMS.WeaponFlag={ -- -- Bombs GuidedBomb = 14, -- (LGB + TvGB + SNSGB) - AnyUnguidedBomb = 2147485680, -- (HeBomb + Penetrator + NapalmBomb + FAEBomb + ClusterBomb + Dispenser + CandleBomb + ParachuteBomb) + AnyUnguidedBomb = 2147485680, -- (HeBomb + Penetrator + NapalmBomb + FAEBomb + ClusterBomb + Dispencer + CandleBomb + ParachuteBomb) AnyBomb = 2147485694, -- (GuidedBomb + AnyUnguidedBomb) --- Rockets AnyRocket = 30720, -- LightRocket + MarkerRocket + CandleRocket + HeavyRocket @@ -123,9 +123,11 @@ ENUMS.WeaponFlag={ --- Air-To-Air Missiles AnyAAM = 264241152, -- IR_AAM + SAR_AAM + AR_AAM + SRAAM + MRAAM + LRAAM AnyAutonomousMissile = 36012032, -- IR_AAM + AntiRadarMissile + AntiShipMissile + FireAndForgetASM + CruiseMissile - AnyMissile = 268402688, -- AnyASM + AnyAAM + AnyMissile = 268402688, -- AnyASM + AnyAAM --- Guns Cannons = 805306368, -- GUN_POD + BuiltInCannon + --- Torpedo + Torpedo = 4294967296, --- -- Even More Genral Auto = 3221225470, -- Any Weapon (AnyBomb + AnyRocket + AnyMissile + Cannons) @@ -133,9 +135,96 @@ ENUMS.WeaponFlag={ AnyAG = 2956984318, -- Any Air-To-Ground Weapon AnyAA = 264241152, -- Any Air-To-Air Weapon AnyUnguided = 2952822768, -- Any Unguided Weapon - AnyGuided = 268402702, -- Any Guided Weapon + AnyGuided = 268402702, -- Any Guided Weapon } +--- Weapon types by category. See the [Weapon Flag](https://wiki.hoggitworld.com/view/DCS_enum_weapon_flag) enumerator on hoggit wiki. +-- @type ENUMS.WeaponType +-- @field #table Bomb Bombs. +-- @field #table Rocket Rocket. +-- @field #table Gun Guns. +-- @field #table Missile Missiles. +-- @field #table AAM Air-to-Air missiles. +-- @field #table Torpedo Torpedos. +-- @field #table Any Combinations. +ENUMS.WeaponType={} +ENUMS.WeaponType.Bomb={ + -- Bombs + LGB = 2, + TvGB = 4, + SNSGB = 8, + HEBomb = 16, + Penetrator = 32, + NapalmBomb = 64, + FAEBomb = 128, + ClusterBomb = 256, + Dispencer = 512, + CandleBomb = 1024, + ParachuteBomb = 2147483648, + -- Combinations + GuidedBomb = 14, -- (LGB + TvGB + SNSGB) + AnyUnguidedBomb = 2147485680, -- (HeBomb + Penetrator + NapalmBomb + FAEBomb + ClusterBomb + Dispencer + CandleBomb + ParachuteBomb) + AnyBomb = 2147485694, -- (GuidedBomb + AnyUnguidedBomb) +} +ENUMS.WeaponType.Rocket={ + -- Rockets + LightRocket = 2048, + MarkerRocket = 4096, + CandleRocket = 8192, + HeavyRocket = 16384, + -- Combinations + AnyRocket = 30720, -- LightRocket + MarkerRocket + CandleRocket + HeavyRocket +} +ENUMS.WeaponType.Gun={ + -- Guns + GunPod = 268435456, + BuiltInCannon = 536870912, + -- Combinations + Cannons = 805306368, -- GUN_POD + BuiltInCannon +} +ENUMS.WeaponType.Missile={ + -- Missiles + AntiRadarMissile = 32768, + AntiShipMissile = 65536, + AntiTankMissile = 131072, + FireAndForgetASM = 262144, + LaserASM = 524288, + TeleASM = 1048576, + CruiseMissile = 2097152, + AntiRadarMissile2 = 1073741824, + -- Combinations + GuidedASM = 1572864, -- (LaserASM + TeleASM) + TacticalASM = 1835008, -- (GuidedASM + FireAndForgetASM) + AnyASM = 4161536, -- (AntiRadarMissile + AntiShipMissile + AntiTankMissile + FireAndForgetASM + GuidedASM + CruiseMissile) + AnyASM2 = 1077903360, -- 4161536+1073741824, + AnyAutonomousMissile = 36012032, -- IR_AAM + AntiRadarMissile + AntiShipMissile + FireAndForgetASM + CruiseMissile + AnyMissile = 268402688, -- AnyASM + AnyAAM +} +ENUMS.WeaponType.AAM={ + -- Air-To-Air Missiles + SRAM = 4194304, + MRAAM = 8388608, + LRAAM = 16777216, + IR_AAM = 33554432, + SAR_AAM = 67108864, + AR_AAM = 134217728, + -- Combinations + AnyAAM = 264241152, -- IR_AAM + SAR_AAM + AR_AAM + SRAAM + MRAAM + LRAAM +} +ENUMS.WeaponType.Torpedo={ + -- Torpedo + Torpedo = 4294967296, +} +ENUMS.WeaponType.Any={ + -- General combinations + Weapon = 3221225470, -- Any Weapon (AnyBomb + AnyRocket + AnyMissile + Cannons) + AG = 2956984318, -- Any Air-To-Ground Weapon + AA = 264241152, -- Any Air-To-Air Weapon + Unguided = 2952822768, -- Any Unguided Weapon + Guided = 268402702, -- Any Guided Weapon +} + + --- Mission tasks. -- @type ENUMS.MissionTask -- @field #string NOTHING No special task. Group can perform the minimal tasks: Orbit, Refuelling, Follow and Aerobatics. @@ -173,7 +262,7 @@ ENUMS.MissionTask={ TRANSPORT="Transport", } ---- Formations (new). See the [Formations](https://wiki.hoggitworld.com/view/DCS_enum_formation) on Hoggit wiki. +--- Formations (new). See the [Formations](https://wiki.hoggitworld.com/view/DCS_enum_formation) on hoggit wiki. -- @type ENUMS.Formation ENUMS.Formation={} ENUMS.Formation.FixedWing={} @@ -216,23 +305,23 @@ ENUMS.Formation.FixedWing.FighterVic.Close = 917505 ENUMS.Formation.FixedWing.FighterVic.Open = 917506 ENUMS.Formation.RotaryWing={} ENUMS.Formation.RotaryWing.Column={} -ENUMS.Formation.RotaryWing.Column.D70 = 720896 +ENUMS.Formation.RotaryWing.Column.D70=720896 ENUMS.Formation.RotaryWing.Wedge={} -ENUMS.Formation.RotaryWing.Wedge.D70 = 8 +ENUMS.Formation.RotaryWing.Wedge.D70=8 ENUMS.Formation.RotaryWing.FrontRight={} -ENUMS.Formation.RotaryWing.FrontRight.D300 = 655361 -ENUMS.Formation.RotaryWing.FrontRight.D600 = 655362 +ENUMS.Formation.RotaryWing.FrontRight.D300=655361 +ENUMS.Formation.RotaryWing.FrontRight.D600=655362 ENUMS.Formation.RotaryWing.FrontLeft={} -ENUMS.Formation.RotaryWing.FrontLeft.D300 = 655617 -ENUMS.Formation.RotaryWing.FrontLeft.D600 = 655618 +ENUMS.Formation.RotaryWing.FrontLeft.D300=655617 +ENUMS.Formation.RotaryWing.FrontLeft.D600=655618 ENUMS.Formation.RotaryWing.EchelonRight={} -ENUMS.Formation.RotaryWing.EchelonRight.D70 = 589825 -ENUMS.Formation.RotaryWing.EchelonRight.D300 = 589826 -ENUMS.Formation.RotaryWing.EchelonRight.D600 = 589827 +ENUMS.Formation.RotaryWing.EchelonRight.D70 =589825 +ENUMS.Formation.RotaryWing.EchelonRight.D300=589826 +ENUMS.Formation.RotaryWing.EchelonRight.D600=589827 ENUMS.Formation.RotaryWing.EchelonLeft={} -ENUMS.Formation.RotaryWing.EchelonLeft.D70 = 590081 -ENUMS.Formation.RotaryWing.EchelonLeft.D300 = 590082 -ENUMS.Formation.RotaryWing.EchelonLeft.D600 = 590083 +ENUMS.Formation.RotaryWing.EchelonLeft.D70 =590081 +ENUMS.Formation.RotaryWing.EchelonLeft.D300=590082 +ENUMS.Formation.RotaryWing.EchelonLeft.D600=590083 ENUMS.Formation.Vehicle={} ENUMS.Formation.Vehicle.Vee="Vee" ENUMS.Formation.Vehicle.EchelonRight="EchelonR" @@ -244,34 +333,34 @@ ENUMS.Formation.Vehicle.Cone="Cone" ENUMS.Formation.Vehicle.Diamond="Diamond" --- Formations (old). The old format is a simplified version of the new formation enums, which allow more sophisticated settings. --- See the [Formations](https://wiki.hoggitworld.com/view/DCS_enum_formation) on Hoggit wiki. +-- See the [Formations](https://wiki.hoggitworld.com/view/DCS_enum_formation) on hoggit wiki. -- @type ENUMS.FormationOld ENUMS.FormationOld={} ENUMS.FormationOld.FixedWing={} -ENUMS.FormationOld.FixedWing.LineAbreast = 1 -ENUMS.FormationOld.FixedWing.Trail = 2 -ENUMS.FormationOld.FixedWing.Wedge = 3 -ENUMS.FormationOld.FixedWing.EchelonRight = 4 -ENUMS.FormationOld.FixedWing.EchelonLeft = 5 -ENUMS.FormationOld.FixedWing.FingerFour = 6 -ENUMS.FormationOld.FixedWing.SpreadFour = 7 -ENUMS.FormationOld.FixedWing.BomberElement = 12 -ENUMS.FormationOld.FixedWing.BomberElementHeight = 13 -ENUMS.FormationOld.FixedWing.FighterVic = 14 +ENUMS.FormationOld.FixedWing.LineAbreast=1 +ENUMS.FormationOld.FixedWing.Trail=2 +ENUMS.FormationOld.FixedWing.Wedge=3 +ENUMS.FormationOld.FixedWing.EchelonRight=4 +ENUMS.FormationOld.FixedWing.EchelonLeft=5 +ENUMS.FormationOld.FixedWing.FingerFour=6 +ENUMS.FormationOld.FixedWing.SpreadFour=7 +ENUMS.FormationOld.FixedWing.BomberElement=12 +ENUMS.FormationOld.FixedWing.BomberElementHeight=13 +ENUMS.FormationOld.FixedWing.FighterVic=14 ENUMS.FormationOld.RotaryWing={} -ENUMS.FormationOld.RotaryWing.Wedge = 8 -ENUMS.FormationOld.RotaryWing.Echelon = 9 -ENUMS.FormationOld.RotaryWing.Front = 10 -ENUMS.FormationOld.RotaryWing.Column = 11 +ENUMS.FormationOld.RotaryWing.Wedge=8 +ENUMS.FormationOld.RotaryWing.Echelon=9 +ENUMS.FormationOld.RotaryWing.Front=10 +ENUMS.FormationOld.RotaryWing.Column=11 --- Morse Code. See the [Wikipedia](https://en.wikipedia.org/wiki/Morse_code). --- +-- -- * Short pulse "*" -- * Long pulse "-" --- +-- -- Pulses are separated by a blank character " ". --- +-- -- @type ENUMS.Morse ENUMS.Morse={} ENUMS.Morse.A="* -" @@ -313,9 +402,9 @@ ENUMS.Morse.N0="- - - - -" ENUMS.Morse[" "]=" " --- ISO (639-1) 2-letter Language Codes. See the [Wikipedia](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes). --- +-- -- @type ENUMS.ISOLang -ENUMS.ISOLang = +ENUMS.ISOLang = { Arabic = 'AR', Chinese = 'ZH', @@ -329,7 +418,7 @@ ENUMS.ISOLang = } --- Phonetic Alphabet (NATO). See the [Wikipedia](https://en.wikipedia.org/wiki/NATO_phonetic_alphabet). --- +-- -- @type ENUMS.Phonetic ENUMS.Phonetic = { @@ -359,4 +448,50 @@ ENUMS.Phonetic = X = 'Xray', Y = 'Yankee', Z = 'Zulu', -} \ No newline at end of file +} + +--- Reporting Names (NATO). See the [Wikipedia](https://en.wikipedia.org/wiki/List_of_NATO_reporting_names_for_fighter_aircraft). +-- DCS known aircraft types +-- +-- @type ENUMS.ReportingName +ENUMS.ReportingName = +{ + NATO = { + -- Fighters + Dragon = "JF-17", -- China, correct? + Fagot = "MiG-15", + Farmer = "MiG-19", -- Shenyang J-6 and Mikoyan-Gurevich MiG-19 + Felon = "Su-57", + Fencer = "Su-24", + Fishbed = "MiG-21", + Fitter = "Su-17", -- Sukhoi Su-7 and Su-17/Su-20/Su-22 + Flogger = "MiG-23", --and MiG-27 + Flogger_D = "MiG-27", --and MiG-23 + Flagon = "Su-15", + Foxbat = "MiG-25", + Fulcrum = "MiG-29", + Foxhound = "MiG-31", + Flanker = "Su-27", -- Sukhoi Su-27/Su-30/Su-33/Su-35/Su-37 and Shenyang J-11/J-15/J-16 + Flanker_C = "Su-30", + Flanker_E = "Su-35", + Flanker_F = "Su-37", + Flanker_Dragon = "J-11A", + Sea_Flanker = "Su-33", + Fullback = "Su-32", -- also Su-34 + Frogfoot = "Su-25", + Tomcat = "F-14", -- Iran + Mirage = "Mirage", -- various non-NATO + -- Bomber + H6J = "H6-J", + Sea_Bear = "Tu-142", -- also Tu-95 + Bear = "Tu-95", -- also Tu-142 + Blinder = "Tu-22", + Blackjack = "Tu-160", + -- AIC / Transport / Other + Clank = "An-30", + Curl = "An-26", + Candid = "IL-76", + Midas = "IL-78", + Mainstay = "A-50", -- KJ-2000 China + } +} diff --git a/Moose Development/Moose/Utilities/FiFo.lua b/Moose Development/Moose/Utilities/FiFo.lua new file mode 100644 index 000000000..38b318a2d --- /dev/null +++ b/Moose Development/Moose/Utilities/FiFo.lua @@ -0,0 +1,769 @@ +--- **UTILS** - ClassicFiFo Stack. +-- +-- === +-- +-- ## Main Features: +-- +-- * Build a simple multi-purpose FiFo (First-In, First-Out) stack for generic data. +-- * [Wikipedia](https://en.wikipedia.org/wiki/FIFO_(computing_and_electronics) +-- +-- === +-- +-- ### Author: **applevangelist** +-- @module Utils.FiFo +-- @image MOOSE.JPG + +-- Date: April 2022 + +do +--- FIFO class. +-- @type FIFO +-- @field #string ClassName Name of the class. +-- @field #string lid Class id string for output to DCS log file. +-- @field #string version Version of FiFo +-- @field #number counter +-- @field #number pointer +-- @field #table stackbypointer +-- @field #table stackbyid +-- @extends Core.Base#BASE + +--- +-- @type FIFO.IDEntry +-- @field #number pointer +-- @field #table data +-- @field #table uniqueID + +--- +-- @field #FIFO +FIFO = { + ClassName = "FIFO", + lid = "", + version = "0.0.5", + counter = 0, + pointer = 0, + stackbypointer = {}, + stackbyid = {} +} + +--- Instantiate a new FIFO Stack +-- @param #FIFO self +-- @return #FIFO self +function FIFO:New() + -- Inherit everything from BASE class. + local self=BASE:Inherit(self, BASE:New()) + self.pointer = 0 + self.counter = 0 + self.stackbypointer = {} + self.stackbyid = {} + self.uniquecounter = 0 + -- Set some string id for output to DCS.log file. + self.lid=string.format("%s (%s) | ", "FiFo", self.version) + self:T(self.lid .."Created.") + return self +end + +--- Empty FIFO Stack +-- @param #FIFO self +-- @return #FIFO self +function FIFO:Clear() + self:T(self.lid.."Clear") + self.pointer = 0 + self.counter = 0 + self.stackbypointer = nil + self.stackbyid = nil + self.stackbypointer = {} + self.stackbyid = {} + self.uniquecounter = 0 + return self +end + +--- FIFO Push Object to Stack +-- @param #FIFO self +-- @param #table Object +-- @param #string UniqueID (optional) - will default to current pointer + 1. Note - if you intend to use `FIFO:GetIDStackSorted()` keep the UniqueID numerical! +-- @return #FIFO self +function FIFO:Push(Object,UniqueID) + self:T(self.lid.."Push") + self:T({Object,UniqueID}) + self.pointer = self.pointer + 1 + self.counter = self.counter + 1 + local uniID = UniqueID + if not UniqueID then + self.uniquecounter = self.uniquecounter + 1 + uniID = self.uniquecounter + end + self.stackbyid[uniID] = { pointer = self.pointer, data = Object, uniqueID = uniID } + self.stackbypointer[self.pointer] = { pointer = self.pointer, data = Object, uniqueID = uniID } + return self +end + +--- FIFO Pull Object from Stack +-- @param #FIFO self +-- @return #table Object or nil if stack is empty +function FIFO:Pull() + self:T(self.lid.."Pull") + if self.counter == 0 then return nil end + --local object = self.stackbypointer[self.pointer].data + --self.stackbypointer[self.pointer] = nil + local object = self.stackbypointer[1].data + self.stackbypointer[1] = nil + self.counter = self.counter - 1 + --self.pointer = self.pointer - 1 + self:Flatten() + return object +end + +--- FIFO Pull Object from Stack by Pointer +-- @param #FIFO self +-- @param #number Pointer +-- @return #table Object or nil if stack is empty +function FIFO:PullByPointer(Pointer) + self:T(self.lid.."PullByPointer " .. tostring(Pointer)) + if self.counter == 0 then return nil end + local object = self.stackbypointer[Pointer] -- #FIFO.IDEntry + self.stackbypointer[Pointer] = nil + if object then self.stackbyid[object.uniqueID] = nil end + self.counter = self.counter - 1 + self:Flatten() + if object then + return object.data + else + return nil + end +end + + +--- FIFO Read, not Pull, Object from Stack by Pointer +-- @param #FIFO self +-- @param #number Pointer +-- @return #table Object or nil if stack is empty or pointer does not exist +function FIFO:ReadByPointer(Pointer) + self:T(self.lid.."ReadByPointer " .. tostring(Pointer)) + if self.counter == 0 or not Pointer or not self.stackbypointer[Pointer] then return nil end + local object = self.stackbypointer[Pointer] -- #FIFO.IDEntry + if object then + return object.data + else + return nil + end +end + +--- FIFO Read, not Pull, Object from Stack by UniqueID +-- @param #FIFO self +-- @param #number UniqueID +-- @return #table Object data or nil if stack is empty or ID does not exist +function FIFO:ReadByID(UniqueID) + self:T(self.lid.."ReadByID " .. tostring(UniqueID)) + if self.counter == 0 or not UniqueID or not self.stackbyid[UniqueID] then return nil end + local object = self.stackbyid[UniqueID] -- #FIFO.IDEntry + if object then + return object.data + else + return nil + end +end + +--- FIFO Pull Object from Stack by UniqueID +-- @param #FIFO self +-- @param #tableUniqueID +-- @return #table Object or nil if stack is empty +function FIFO:PullByID(UniqueID) + self:T(self.lid.."PullByID " .. tostring(UniqueID)) + if self.counter == 0 then return nil end + local object = self.stackbyid[UniqueID] -- #FIFO.IDEntry + --self.stackbyid[UniqueID] = nil + if object then + return self:PullByPointer(object.pointer) + else + return nil + end +end + +--- FIFO Housekeeping +-- @param #FIFO self +-- @return #FIFO self +function FIFO:Flatten() + self:T(self.lid.."Flatten") + -- rebuild stacks + local pointerstack = {} + local idstack = {} + local counter = 0 + for _ID,_entry in pairs(self.stackbypointer) do + counter = counter + 1 + pointerstack[counter] = { pointer = counter, data = _entry.data, uniqueID = _entry.uniqueID} + end + for _ID,_entry in pairs(pointerstack) do + idstack[_entry.uniqueID] = { pointer = _entry.pointer , data = _entry.data, uniqueID = _entry.uniqueID} + end + self.stackbypointer = nil + self.stackbypointer = pointerstack + self.stackbyid = nil + self.stackbyid = idstack + self.counter = counter + self.pointer = counter + return self +end + +--- FIFO Check Stack is empty +-- @param #FIFO self +-- @return #boolean empty +function FIFO:IsEmpty() + self:T(self.lid.."IsEmpty") + return self.counter == 0 and true or false +end + +--- FIFO Get stack size +-- @param #FIFO self +-- @return #number size +function FIFO:GetSize() + self:T(self.lid.."GetSize") + return self.counter +end + +--- FIFO Get stack size +-- @param #FIFO self +-- @return #number size +function FIFO:Count() + self:T(self.lid.."Count") + return self.counter +end + +--- FIFO Check Stack is NOT empty +-- @param #FIFO self +-- @return #boolean notempty +function FIFO:IsNotEmpty() + self:T(self.lid.."IsNotEmpty") + return not self:IsEmpty() +end + +--- FIFO Get the data stack by pointer +-- @param #FIFO self +-- @return #table Table of #FIFO.IDEntry entries +function FIFO:GetPointerStack() + self:T(self.lid.."GetPointerStack") + return self.stackbypointer +end + +--- FIFO Check if a certain UniqeID exists +-- @param #FIFO self +-- @return #boolean exists +function FIFO:HasUniqueID(UniqueID) + self:T(self.lid.."HasUniqueID") + return self.stackbyid[UniqueID] and true or false +end + +--- FIFO Get the data stack by UniqueID +-- @param #FIFO self +-- @return #table Table of #FIFO.IDEntry entries +function FIFO:GetIDStack() + self:T(self.lid.."GetIDStack") + return self.stackbyid +end + +--- FIFO Get table of UniqueIDs sorted smallest to largest +-- @param #FIFO self +-- @return #table Table with index [1] to [n] of UniqueID entries +function FIFO:GetIDStackSorted() + self:T(self.lid.."GetIDStackSorted") + + local stack = self:GetIDStack() + local idstack = {} + for _id,_entry in pairs(stack) do + idstack[#idstack+1] = _id + + self:T({"pre",_id}) + end + + local function sortID(a, b) + return a < b + end + + table.sort(idstack) + + return idstack +end + +--- FIFO Get table of data entries +-- @param #FIFO self +-- @return #table Raw table indexed [1] to [n] of object entries - might be empty! +function FIFO:GetDataTable() + self:T(self.lid.."GetDataTable") + local datatable = {} + for _,_entry in pairs(self.stackbypointer) do + datatable[#datatable+1] = _entry.data + end + return datatable +end + +--- FIFO Get sorted table of data entries by UniqueIDs (must be numerical UniqueIDs only!) +-- @param #FIFO self +-- @return #table Table indexed [1] to [n] of sorted object entries - might be empty! +function FIFO:GetSortedDataTable() + self:T(self.lid.."GetSortedDataTable") + local datatable = {} + local idtablesorted = self:GetIDStackSorted() + for _,_entry in pairs(idtablesorted) do + datatable[#datatable+1] = self:ReadByID(_entry) + end + return datatable +end + +--- Iterate the FIFO and call an iterator function for the given FIFO data, providing the object for each element of the stack and optional parameters. +-- @param #FIFO self +-- @param #function IteratorFunction The function that will be called. +-- @param #table Arg (Optional) Further Arguments of the IteratorFunction. +-- @param #function Function (Optional) A function returning a #boolean true/false. Only if true, the IteratorFunction is called. +-- @param #table FunctionArguments (Optional) Function arguments. +-- @return #FIFO self +function FIFO:ForEach( IteratorFunction, Arg, Function, FunctionArguments ) + self:T(self.lid.."ForEach") + + local Set = self:GetPointerStack() or {} + Arg = Arg or {} + + local function CoRoutine() + local Count = 0 + for ObjectID, ObjectData in pairs( Set ) do + local Object = ObjectData.data + self:T( {Object} ) + if Function then + if Function( unpack( FunctionArguments or {} ), Object ) == true then + IteratorFunction( Object, unpack( Arg ) ) + end + else + IteratorFunction( Object, unpack( Arg ) ) + end + Count = Count + 1 + end + return true + end + + local co = CoRoutine + + local function Schedule() + + local status, res = co() + self:T( { status, res } ) + + if status == false then + error( res ) + end + if res == false then + return true -- resume next time the loop + end + + return false + end + + Schedule() + + return self +end + +--- FIFO Print stacks to dcs.log +-- @param #FIFO self +-- @return #FIFO self +function FIFO:Flush() + self:T(self.lid.."FiFo Flush") + self:I("FIFO Flushing Stack by Pointer") + for _id,_data in pairs (self.stackbypointer) do + local data = _data -- #FIFO.IDEntry + self:I(string.format("Pointer: %s | Entry: Number = %s Data = %s UniqueID = %s",tostring(_id),tostring(data.pointer),tostring(data.data),tostring(data.uniqueID))) + end + self:I("FIFO Flushing Stack by ID") + for _id,_data in pairs (self.stackbyid) do + local data = _data -- #FIFO.IDEntry + self:I(string.format("ID: %s | Entry: Number = %s Data = %s UniqueID = %s",tostring(_id),tostring(data.pointer),tostring(data.data),tostring(data.uniqueID))) + end + self:I("Counter = " .. self.counter) + self:I("Pointer = ".. self.pointer) + return self +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- End FIFO +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- LIFO +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +do +--- **UTILS** - LiFo Stack. +-- +-- **Main Features:** +-- +-- * Build a simple multi-purpose LiFo (Last-In, First-Out) stack for generic data. +-- +-- === +-- +-- ### Author: **applevangelist** + +--- LIFO class. +-- @type LIFO +-- @field #string ClassName Name of the class. +-- @field #string lid Class id string for output to DCS log file. +-- @field #string version Version of LiFo +-- @field #number counter +-- @field #number pointer +-- @field #table stackbypointer +-- @field #table stackbyid +-- @extends Core.Base#BASE + +--- +-- @type LIFO.IDEntry +-- @field #number pointer +-- @field #table data +-- @field #table uniqueID + +--- +-- @field #LIFO +LIFO = { + ClassName = "LIFO", + lid = "", + version = "0.0.5", + counter = 0, + pointer = 0, + stackbypointer = {}, + stackbyid = {} +} + +--- Instantiate a new LIFO Stack +-- @param #LIFO self +-- @return #LIFO self +function LIFO:New() + -- Inherit everything from BASE class. + local self=BASE:Inherit(self, BASE:New()) + self.pointer = 0 + self.counter = 0 + self.uniquecounter = 0 + self.stackbypointer = {} + self.stackbyid = {} + -- Set some string id for output to DCS.log file. + self.lid=string.format("%s (%s) | ", "LiFo", self.version) + self:T(self.lid .."Created.") + return self +end + +--- Empty LIFO Stack +-- @param #LIFO self +-- @return #LIFO self +function LIFO:Clear() + self:T(self.lid.."Clear") + self.pointer = 0 + self.counter = 0 + self.stackbypointer = nil + self.stackbyid = nil + self.stackbypointer = {} + self.stackbyid = {} + self.uniquecounter = 0 + return self +end + +--- LIFO Push Object to Stack +-- @param #LIFO self +-- @param #table Object +-- @param #string UniqueID (optional) - will default to current pointer + 1 +-- @return #LIFO self +function LIFO:Push(Object,UniqueID) + self:T(self.lid.."Push") + self:T({Object,UniqueID}) + self.pointer = self.pointer + 1 + self.counter = self.counter + 1 + local uniID = UniqueID + if not UniqueID then + self.uniquecounter = self.uniquecounter + 1 + uniID = self.uniquecounter + end + self.stackbyid[uniID] = { pointer = self.pointer, data = Object, uniqueID = uniID } + self.stackbypointer[self.pointer] = { pointer = self.pointer, data = Object, uniqueID = uniID } + return self +end + +--- LIFO Pull Object from Stack +-- @param #LIFO self +-- @return #table Object or nil if stack is empty +function LIFO:Pull() + self:T(self.lid.."Pull") + if self.counter == 0 then return nil end + local object = self.stackbypointer[self.pointer].data + self.stackbypointer[self.pointer] = nil + --local object = self.stackbypointer[1].data + --self.stackbypointer[1] = nil + self.counter = self.counter - 1 + self.pointer = self.pointer - 1 + self:Flatten() + return object +end + +--- LIFO Pull Object from Stack by Pointer +-- @param #LIFO self +-- @param #number Pointer +-- @return #table Object or nil if stack is empty +function LIFO:PullByPointer(Pointer) + self:T(self.lid.."PullByPointer " .. tostring(Pointer)) + if self.counter == 0 then return nil end + local object = self.stackbypointer[Pointer] -- #FIFO.IDEntry + self.stackbypointer[Pointer] = nil + if object then self.stackbyid[object.uniqueID] = nil end + self.counter = self.counter - 1 + self:Flatten() + if object then + return object.data + else + return nil + end +end + +--- LIFO Read, not Pull, Object from Stack by Pointer +-- @param #LIFO self +-- @param #number Pointer +-- @return #table Object or nil if stack is empty or pointer does not exist +function LIFO:ReadByPointer(Pointer) + self:T(self.lid.."ReadByPointer " .. tostring(Pointer)) + if self.counter == 0 or not Pointer or not self.stackbypointer[Pointer] then return nil end + local object = self.stackbypointer[Pointer] -- #LIFO.IDEntry + if object then + return object.data + else + return nil + end +end + +--- LIFO Read, not Pull, Object from Stack by UniqueID +-- @param #LIFO self +-- @param #number UniqueID +-- @return #table Object or nil if stack is empty or ID does not exist +function LIFO:ReadByID(UniqueID) + self:T(self.lid.."ReadByID " .. tostring(UniqueID)) + if self.counter == 0 or not UniqueID or not self.stackbyid[UniqueID] then return nil end + local object = self.stackbyid[UniqueID] -- #LIFO.IDEntry + if object then + return object.data + else + return nil + end +end + +--- LIFO Pull Object from Stack by UniqueID +-- @param #LIFO self +-- @param #tableUniqueID +-- @return #table Object or nil if stack is empty +function LIFO:PullByID(UniqueID) + self:T(self.lid.."PullByID " .. tostring(UniqueID)) + if self.counter == 0 then return nil end + local object = self.stackbyid[UniqueID] -- #LIFO.IDEntry + --self.stackbyid[UniqueID] = nil + if object then + return self:PullByPointer(object.pointer) + else + return nil + end +end + +--- LIFO Housekeeping +-- @param #LIFO self +-- @return #LIFO self +function LIFO:Flatten() + self:T(self.lid.."Flatten") + -- rebuild stacks + local pointerstack = {} + local idstack = {} + local counter = 0 + for _ID,_entry in pairs(self.stackbypointer) do + counter = counter + 1 + pointerstack[counter] = { pointer = counter, data = _entry.data, uniqueID = _entry.uniqueID} + end + for _ID,_entry in pairs(pointerstack) do + idstack[_entry.uniqueID] = { pointer = _entry.pointer , data = _entry.data, uniqueID = _entry.uniqueID} + end + self.stackbypointer = nil + self.stackbypointer = pointerstack + self.stackbyid = nil + self.stackbyid = idstack + self.counter = counter + self.pointer = counter + return self +end + +--- LIFO Check Stack is empty +-- @param #LIFO self +-- @return #boolean empty +function LIFO:IsEmpty() + self:T(self.lid.."IsEmpty") + return self.counter == 0 and true or false +end + +--- LIFO Get stack size +-- @param #LIFO self +-- @return #number size +function LIFO:GetSize() + self:T(self.lid.."GetSize") + return self.counter +end + +--- LIFO Get stack size +-- @param #LIFO self +-- @return #number size +function LIFO:Count() + self:T(self.lid.."Count") + return self.counter +end + +--- LIFO Check Stack is NOT empty +-- @param #LIFO self +-- @return #boolean notempty +function LIFO:IsNotEmpty() + self:T(self.lid.."IsNotEmpty") + return not self:IsEmpty() +end + +--- LIFO Get the data stack by pointer +-- @param #LIFO self +-- @return #table Table of #LIFO.IDEntry entries +function LIFO:GetPointerStack() + self:T(self.lid.."GetPointerStack") + return self.stackbypointer +end + +--- LIFO Get the data stack by UniqueID +-- @param #LIFO self +-- @return #table Table of #LIFO.IDEntry entries +function LIFO:GetIDStack() + self:T(self.lid.."GetIDStack") + return self.stackbyid +end + +--- LIFO Get table of UniqueIDs sorted smallest to largest +-- @param #LIFO self +-- @return #table Table of #LIFO.IDEntry entries +function LIFO:GetIDStackSorted() + self:T(self.lid.."GetIDStackSorted") + + local stack = self:GetIDStack() + local idstack = {} + for _id,_entry in pairs(stack) do + idstack[#idstack+1] = _id + + self:T({"pre",_id}) + end + + local function sortID(a, b) + return a < b + end + + table.sort(idstack) + + return idstack +end + +--- LIFO Check if a certain UniqeID exists +-- @param #LIFO self +-- @return #boolean exists +function LIFO:HasUniqueID(UniqueID) + self:T(self.lid.."HasUniqueID") + return self.stackbyid[UniqueID] and true or false +end + +--- LIFO Print stacks to dcs.log +-- @param #LIFO self +-- @return #LIFO self +function LIFO:Flush() + self:T(self.lid.."FiFo Flush") + self:I("LIFO Flushing Stack by Pointer") + for _id,_data in pairs (self.stackbypointer) do + local data = _data -- #LIFO.IDEntry + self:I(string.format("Pointer: %s | Entry: Number = %s Data = %s UniqueID = %s",tostring(_id),tostring(data.pointer),tostring(data.data),tostring(data.uniqueID))) + end + self:I("LIFO Flushing Stack by ID") + for _id,_data in pairs (self.stackbyid) do + local data = _data -- #LIFO.IDEntry + self:I(string.format("ID: %s | Entry: Number = %s Data = %s UniqueID = %s",tostring(_id),tostring(data.pointer),tostring(data.data),tostring(data.uniqueID))) + end + self:I("Counter = " .. self.counter) + self:I("Pointer = ".. self.pointer) + return self +end + +--- LIFO Get table of data entries +-- @param #LIFO self +-- @return #table Raw table indexed [1] to [n] of object entries - might be empty! +function LIFO:GetDataTable() + self:T(self.lid.."GetDataTable") + local datatable = {} + for _,_entry in pairs(self.stackbypointer) do + datatable[#datatable+1] = _entry.data + end + return datatable +end + +--- LIFO Get sorted table of data entries by UniqueIDs (must be numerical UniqueIDs only!) +-- @param #LIFO self +-- @return #table Table indexed [1] to [n] of sorted object entries - might be empty! +function LIFO:GetSortedDataTable() + self:T(self.lid.."GetSortedDataTable") + local datatable = {} + local idtablesorted = self:GetIDStackSorted() + for _,_entry in pairs(idtablesorted) do + datatable[#datatable+1] = self:ReadByID(_entry) + end + return datatable +end + +--- Iterate the LIFO and call an iterator function for the given LIFO data, providing the object for each element of the stack and optional parameters. +-- @param #LIFO self +-- @param #function IteratorFunction The function that will be called. +-- @param #table Arg (Optional) Further Arguments of the IteratorFunction. +-- @param #function Function (Optional) A function returning a #boolean true/false. Only if true, the IteratorFunction is called. +-- @param #table FunctionArguments (Optional) Function arguments. +-- @return #LIFO self +function LIFO:ForEach( IteratorFunction, Arg, Function, FunctionArguments ) + self:T(self.lid.."ForEach") + + local Set = self:GetPointerStack() or {} + Arg = Arg or {} + + local function CoRoutine() + local Count = 0 + for ObjectID, ObjectData in pairs( Set ) do + local Object = ObjectData.data + self:T( {Object} ) + if Function then + if Function( unpack( FunctionArguments or {} ), Object ) == true then + IteratorFunction( Object, unpack( Arg ) ) + end + else + IteratorFunction( Object, unpack( Arg ) ) + end + Count = Count + 1 + end + return true + end + + local co = CoRoutine + + local function Schedule() + + local status, res = co() + self:T( { status, res } ) + + if status == false then + error( res ) + end + if res == false then + return true -- resume next time the loop + end + + return false + end + + Schedule() + + return self +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- End LIFO +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +end \ No newline at end of file diff --git a/Moose Development/Moose/Utilities/Utils.lua b/Moose Development/Moose/Utilities/Utils.lua index 46805e997..5e7a411e5 100644 --- a/Moose Development/Moose/Utilities/Utils.lua +++ b/Moose Development/Moose/Utilities/Utils.lua @@ -809,7 +809,7 @@ function UTILS.BeaufortScale(speed) return bn,bd end ---- Split string at seperators. C.f. http://stackoverflow.com/questions/1426954/split-string-in-lua +--- Split string at seperators. C.f. [split-string-in-lua](http://stackoverflow.com/questions/1426954/split-string-in-lua). -- @param #string str Sting to split. -- @param #string sep Speparator for split. -- @return #table Split text. @@ -1447,6 +1447,23 @@ function UTILS.GetModulationName(Modulation) end +--- Get the NATO reporting name of a unit type name +-- @param #number Typename The type name. +-- @return #string The Reporting name or "Bogey". +function UTILS.GetReportingName(Typename) + + local typename = string.lower(Typename) + + for name, value in pairs(ENUMS.ReportingName.NATO) do + local svalue = string.lower(value) + if string.find(typename,svalue,1,true) then + return name + end + end + + return "Bogey" +end + --- Get the callsign name from its enumerator value -- @param #number Callsign The enumerator callsign. -- @return #string The callsign name or "Ghostrider". @@ -1475,7 +1492,49 @@ function UTILS.GetCallsignName(Callsign) return name end end - + + for name, value in pairs(CALLSIGN.B1B) do + if value==Callsign then + return name + end + end + + for name, value in pairs(CALLSIGN.B52) do + if value==Callsign then + return name + end + end + + for name, value in pairs(CALLSIGN.F15E) do + if value==Callsign then + return name + end + end + + for name, value in pairs(CALLSIGN.F16) do + if value==Callsign then + return name + end + end + + for name, value in pairs(CALLSIGN.F18) do + if value==Callsign then + return name + end + end + + for name, value in pairs(CALLSIGN.FARP) do + if value==Callsign then + return name + end + end + + for name, value in pairs(CALLSIGN.TransportAircraft) do + if value==Callsign then + return name + end + end + return "Ghostrider" end @@ -2402,493 +2461,3 @@ function UTILS.ToStringBRAANATO(FromGrp,ToGrp) end return BRAANATO end - -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- FIFO -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - -do ---- **UTILS** - FiFo Stack. --- --- **Main Features:** --- --- * Build a simple multi-purpose FiFo (First-In, First-Out) stack for generic data. --- --- === --- --- ### Author: **applevangelist** - ---- FIFO class. --- @type FIFO --- @field #string ClassName Name of the class. --- @field #string lid Class id string for output to DCS log file. --- @field #string version Version of FiFo --- @field #number counter --- @field #number pointer --- @field #table stackbypointer --- @field #table stackbyid --- @extends Core.Base#BASE - ---- --- @type FIFO.IDEntry --- @field #number pointer --- @field #table data --- @field #table uniqueID - ---- --- @field #FIFO -FIFO = { - ClassName = "FIFO", - lid = "", - version = "0.0.1", - counter = 0, - pointer = 0, - stackbypointer = {}, - stackbyid = {} -} - ---- Instantiate a new FIFO Stack --- @param #FIFO self --- @return #FIFO self -function FIFO:New() - -- Inherit everything from BASE class. - local self=BASE:Inherit(self, BASE:New()) - self.pointer = 0 - self.counter = 0 - self.stackbypointer = {} - self.stackbyid = {} - self.uniquecounter = 0 - -- Set some string id for output to DCS.log file. - self.lid=string.format("%s (%s) | ", "FiFo", self.version) - self:I(self.lid .."Created.") - return self -end - ---- FIFO Push Object to Stack --- @param #FIFO self --- @param #table Object --- @param #string UniqueID (optional) - will default to current pointer + 1 --- @return #FIFO self -function FIFO:Push(Object,UniqueID) - self:T(self.lid.."Push") - self:T({Object,UniqueID}) - self.pointer = self.pointer + 1 - self.counter = self.counter + 1 - local uniID = UniqueID - if not UniqueID then - self.uniquecounter = self.uniquecounter + 1 - uniID = self.uniquecounter - end - self.stackbyid[uniID] = { pointer = self.pointer, data = Object, uniqueID = uniID } - self.stackbypointer[self.pointer] = { pointer = self.pointer, data = Object, uniqueID = uniID } - return self -end - ---- FIFO Pull Object from Stack --- @param #FIFO self --- @return #table Object or nil if stack is empty -function FIFO:Pull() - self:T(self.lid.."Pull") - if self.counter == 0 then return nil end - --local object = self.stackbypointer[self.pointer].data - --self.stackbypointer[self.pointer] = nil - local object = self.stackbypointer[1].data - self.stackbypointer[1] = nil - self.counter = self.counter - 1 - --self.pointer = self.pointer - 1 - self:Flatten() - return object -end - ---- FIFO Pull Object from Stack by Pointer --- @param #FIFO self --- @param #number Pointer --- @return #table Object or nil if stack is empty -function FIFO:PullByPointer(Pointer) - self:T(self.lid.."PullByPointer " .. tostring(Pointer)) - if self.counter == 0 then return nil end - local object = self.stackbypointer[Pointer] -- #FIFO.IDEntry - self.stackbypointer[Pointer] = nil - self.stackbyid[object.uniqueID] = nil - self.counter = self.counter - 1 - self:Flatten() - return object.data -end - ---- FIFO Pull Object from Stack by UniqueID --- @param #FIFO self --- @param #tableUniqueID --- @return #table Object or nil if stack is empty -function FIFO:PullByID(UniqueID) - self:T(self.lid.."PullByID " .. tostring(UniqueID)) - if self.counter == 0 then return nil end - local object = self.stackbyid[UniqueID] -- #FIFO.IDEntry - --self.stackbyid[UniqueID] = nil - return self:PullByPointer(object.pointer) -end - ---- FIFO Housekeeping --- @param #FIFO self --- @return #FIFO self -function FIFO:Flatten() - self:T(self.lid.."Flatten") - -- rebuild stacks - local pointerstack = {} - local idstack = {} - local counter = 0 - for _ID,_entry in pairs(self.stackbypointer) do - counter = counter + 1 - pointerstack[counter] = { pointer = counter, data = _entry.data, uniqueID = _entry.uniqueID} - end - for _ID,_entry in pairs(pointerstack) do - idstack[_entry.uniqueID] = { pointer = _entry.pointer , data = _entry.data, uniqueID = _entry.uniqueID} - end - self.stackbypointer = nil - self.stackbypointer = pointerstack - self.stackbyid = nil - self.stackbyid = idstack - self.counter = counter - self.pointer = counter - return self -end - ---- FIFO Check Stack is empty --- @param #FIFO self --- @return #boolean empty -function FIFO:IsEmpty() - self:T(self.lid.."IsEmpty") - return self.counter == 0 and true or false -end - ---- FIFO Get stack size --- @param #FIFO self --- @return #number size -function FIFO:GetSize() - self:T(self.lid.."GetSize") - return self.counter -end - ---- FIFO Check Stack is NOT empty --- @param #FIFO self --- @return #boolean notempty -function FIFO:IsNotEmpty() - self:T(self.lid.."IsNotEmpty") - return not self:IsEmpty() -end - ---- FIFO Get the data stack by pointer --- @param #FIFO self --- @return #table Table of #FIFO.IDEntry entries -function FIFO:GetPointerStack() - self:T(self.lid.."GetPointerStack") - return self.stackbypointer -end - ---- FIFO Check if a certain UniqeID exists --- @param #FIFO self --- @return #boolean exists -function FIFO:HasUniqueID(UniqueID) - self:T(self.lid.."HasUniqueID") - return self.stackbyid[UniqueID] and true or false -end - ---- FIFO Get the data stack by UniqueID --- @param #FIFO self --- @return #table Table of #FIFO.IDEntry entries -function FIFO:GetIDStack() - self:T(self.lid.."GetIDStack") - return self.stackbyid -end - ---- FIFO Get table of UniqueIDs sorthed smallest to largest --- @param #FIFO self --- @return #table Table of #FIFO.IDEntry entries -function FIFO:GetIDStackSorted() - self:T(self.lid.."GetIDStackSorted") - - local stack = self:GetIDStack() - local idstack = {} - for _id,_entry in pairs(stack) do - idstack[#idstack+1] = _id - - self:T({"pre",_id}) - end - - local function sortID(a, b) - return a < b - end - - table.sort(idstack) - - return idstack -end - ---- FIFO Print stacks to dcs.log --- @param #FIFO self --- @return #FIFO self -function FIFO:Flush() - self:T(self.lid.."FiFo Flush") - self:I("FIFO Flushing Stack by Pointer") - for _id,_data in pairs (self.stackbypointer) do - local data = _data -- #FIFO.IDEntry - self:I(string.format("Pointer: %s | Entry: Number = %s Data = %s UniqueID = %s",tostring(_id),tostring(data.pointer),tostring(data.data),tostring(data.uniqueID))) - end - self:I("FIFO Flushing Stack by ID") - for _id,_data in pairs (self.stackbyid) do - local data = _data -- #FIFO.IDEntry - self:I(string.format("ID: %s | Entry: Number = %s Data = %s UniqueID = %s",tostring(_id),tostring(data.pointer),tostring(data.data),tostring(data.uniqueID))) - end - self:I("Counter = " .. self.counter) - self:I("Pointer = ".. self.pointer) - return self -end - -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- End FIFO -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -end - -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- LIFO -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - -do ---- **UTILS** - LiFo Stack. --- --- **Main Features:** --- --- * Build a simple multi-purpose LiFo (Last-In, First-Out) stack for generic data. --- --- === --- --- ### Author: **applevangelist** - ---- LIFO class. --- @type LIFO --- @field #string ClassName Name of the class. --- @field #string lid Class id string for output to DCS log file. --- @field #string version Version of LiFo --- @field #number counter --- @field #number pointer --- @field #table stackbypointer --- @field #table stackbyid --- @extends Core.Base#BASE - ---- --- @type LIFO.IDEntry --- @field #number pointer --- @field #table data --- @field #table uniqueID - ---- --- @field #LIFO -LIFO = { - ClassName = "LIFO", - lid = "", - version = "0.0.1", - counter = 0, - pointer = 0, - stackbypointer = {}, - stackbyid = {} -} - ---- Instantiate a new LIFO Stack --- @param #LIFO self --- @return #LIFO self -function LIFO:New() - -- Inherit everything from BASE class. - local self=BASE:Inherit(self, BASE:New()) - self.pointer = 0 - self.counter = 0 - self.uniquecounter = 0 - self.stackbypointer = {} - self.stackbyid = {} - -- Set some string id for output to DCS.log file. - self.lid=string.format("%s (%s) | ", "LiFo", self.version) - self:I(self.lid .."Created.") - return self -end - ---- LIFO Push Object to Stack --- @param #LIFO self --- @param #table Object --- @param #string UniqueID (optional) - will default to current pointer + 1 --- @return #LIFO self -function LIFO:Push(Object,UniqueID) - self:T(self.lid.."Push") - self:T({Object,UniqueID}) - self.pointer = self.pointer + 1 - self.counter = self.counter + 1 - local uniID = UniqueID - if not UniqueID then - self.uniquecounter = self.uniquecounter + 1 - uniID = self.uniquecounter - end - self.stackbyid[uniID] = { pointer = self.pointer, data = Object, uniqueID = uniID } - self.stackbypointer[self.pointer] = { pointer = self.pointer, data = Object, uniqueID = uniID } - return self -end - ---- LIFO Pull Object from Stack --- @param #LIFO self --- @return #table Object or nil if stack is empty -function LIFO:Pull() - self:T(self.lid.."Pull") - if self.counter == 0 then return nil end - local object = self.stackbypointer[self.pointer].data - self.stackbypointer[self.pointer] = nil - --local object = self.stackbypointer[1].data - --self.stackbypointer[1] = nil - self.counter = self.counter - 1 - self.pointer = self.pointer - 1 - self:Flatten() - return object -end - ---- LIFO Pull Object from Stack by Pointer --- @param #LIFO self --- @param #number Pointer --- @return #table Object or nil if stack is empty -function LIFO:PullByPointer(Pointer) - self:T(self.lid.."PullByPointer " .. tostring(Pointer)) - if self.counter == 0 then return nil end - local object = self.stackbypointer[Pointer] -- #LIFO.IDEntry - self.stackbypointer[Pointer] = nil - self.stackbyid[object.uniqueID] = nil - self.counter = self.counter - 1 - self:Flatten() - return object.data -end - ---- LIFO Pull Object from Stack by UniqueID --- @param #LIFO self --- @param #tableUniqueID --- @return #table Object or nil if stack is empty -function LIFO:PullByID(UniqueID) - self:T(self.lid.."PullByID " .. tostring(UniqueID)) - if self.counter == 0 then return nil end - local object = self.stackbyid[UniqueID] -- #LIFO.IDEntry - --self.stackbyid[UniqueID] = nil - return self:PullByPointer(object.pointer) -end - ---- LIFO Housekeeping --- @param #LIFO self --- @return #LIFO self -function LIFO:Flatten() - self:T(self.lid.."Flatten") - -- rebuild stacks - local pointerstack = {} - local idstack = {} - local counter = 0 - for _ID,_entry in pairs(self.stackbypointer) do - counter = counter + 1 - pointerstack[counter] = { pointer = counter, data = _entry.data, uniqueID = _entry.uniqueID} - end - for _ID,_entry in pairs(pointerstack) do - idstack[_entry.uniqueID] = { pointer = _entry.pointer , data = _entry.data, uniqueID = _entry.uniqueID} - end - self.stackbypointer = nil - self.stackbypointer = pointerstack - self.stackbyid = nil - self.stackbyid = idstack - self.counter = counter - self.pointer = counter - return self -end - ---- LIFO Check Stack is empty --- @param #LIFO self --- @return #boolean empty -function LIFO:IsEmpty() - self:T(self.lid.."IsEmpty") - return self.counter == 0 and true or false -end - ---- LIFO Get stack size --- @param #LIFO self --- @return #number size -function LIFO:GetSize() - self:T(self.lid.."GetSize") - return self.counter -end - ---- LIFO Check Stack is NOT empty --- @param #LIFO self --- @return #boolean notempty -function LIFO:IsNotEmpty() - self:T(self.lid.."IsNotEmpty") - return not self:IsEmpty() -end - ---- LIFO Get the data stack by pointer --- @param #LIFO self --- @return #table Table of #LIFO.IDEntry entries -function LIFO:GetPointerStack() - self:T(self.lid.."GetPointerStack") - return self.stackbypointer -end - ---- LIFO Get the data stack by UniqueID --- @param #LIFO self --- @return #table Table of #LIFO.IDEntry entries -function LIFO:GetIDStack() - self:T(self.lid.."GetIDStack") - return self.stackbyid -end - ---- LIFO Get table of UniqueIDs sorthed smallest to largest --- @param #LIFO self --- @return #table Table of #LIFO.IDEntry entries -function LIFO:GetIDStackSorted() - self:T(self.lid.."GetIDStackSorted") - - local stack = self:GetIDStack() - local idstack = {} - for _id,_entry in pairs(stack) do - idstack[#idstack+1] = _id - - self:T({"pre",_id}) - end - - local function sortID(a, b) - return a < b - end - - table.sort(idstack) - - return idstack -end - ---- LIFO Check if a certain UniqeID exists --- @param #LIFO self --- @return #boolean exists -function LIFO:HasUniqueID(UniqueID) - self:T(self.lid.."HasUniqueID") - return self.stackbyid[UniqueID] and true or false -end - ---- LIFO Print stacks to dcs.log --- @param #LIFO self --- @return #LIFO self -function LIFO:Flush() - self:T(self.lid.."FiFo Flush") - self:I("LIFO Flushing Stack by Pointer") - for _id,_data in pairs (self.stackbypointer) do - local data = _data -- #LIFO.IDEntry - self:I(string.format("Pointer: %s | Entry: Number = %s Data = %s UniqueID = %s",tostring(_id),tostring(data.pointer),tostring(data.data),tostring(data.uniqueID))) - end - self:I("LIFO Flushing Stack by ID") - for _id,_data in pairs (self.stackbyid) do - local data = _data -- #LIFO.IDEntry - self:I(string.format("ID: %s | Entry: Number = %s Data = %s UniqueID = %s",tostring(_id),tostring(data.pointer),tostring(data.data),tostring(data.uniqueID))) - end - self:I("Counter = " .. self.counter) - self:I("Pointer = ".. self.pointer) - return self -end - -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- End LIFO -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -end \ No newline at end of file diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index 5773a12a2..8127ffba9 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -384,7 +384,7 @@ end -- So all event listeners will catch the destroy event of this group for each unit in the group. -- To raise these events, provide the `GenerateEvent` parameter. -- @param #GROUP self --- @param #boolean GenerateEvent If true, a crash or dead event for each unit is generated. If false, if no event is triggered. If nil, a RemoveUnit event is triggered. +-- @param #boolean GenerateEvent If true, a crash [AIR] or dead [GROUND] event for each unit is generated. If false, if no event is triggered. If nil, a RemoveUnit event is triggered. -- @param #number delay Delay in seconds before despawning the group. -- @usage -- -- Air unit example: destroy the Helicopter and generate a S_EVENT_CRASH for each unit in the Helicopter group. @@ -765,8 +765,7 @@ end --- Returns the average velocity Vec3 vector. -- @param Wrapper.Group#GROUP self --- @return DCS#Vec3 The velocity Vec3 vector --- @return #nil The GROUP is not existing or alive. +-- @return DCS#Vec3 The velocity Vec3 vector or `#nil` if the GROUP is not existing or alive. function GROUP:GetVelocityVec3() self:F2( self.GroupName ) @@ -909,6 +908,24 @@ function GROUP:GetTypeName() return nil end +--- [AIRPLANE] Get the NATO reporting name (platform, e.g. "Flanker") of a GROUP (note - first unit the group). "Bogey" if not found. Currently airplanes only! +--@param #GROUP self +--@return #string NatoReportingName or "Bogey" if unknown. +function GROUP:GetNatoReportingName() + self:F2( self.GroupName ) + + local DCSGroup = self:GetDCSObject() + + if DCSGroup then + local GroupTypeName = DCSGroup:getUnit(1):getTypeName() + self:T3( GroupTypeName ) + return UTILS.GetReportingName(GroupTypeName) + end + + return "Bogey" + +end + --- Gets the player name of the group. -- @param #GROUP self -- @return #string The player name of the group. @@ -1006,6 +1023,8 @@ function GROUP:GetCoordinate() if FirstUnit then local FirstUnitCoordinate = FirstUnit:GetCoordinate() + local Heading = self:GetHeading() + FirstUnitCoordinate.Heading = Heading return FirstUnitCoordinate end @@ -1017,9 +1036,8 @@ end --- Returns a random @{DCS#Vec3} vector (point in 3D of the UNIT within the mission) within a range around the first UNIT of the GROUP. -- @param #GROUP self --- @param #number Radius --- @return DCS#Vec3 The random 3D point vector around the first UNIT of the GROUP. --- @return #nil The GROUP is invalid or empty +-- @param #number Radius Radius in meters. +-- @return DCS#Vec3 The random 3D point vector around the first UNIT of the GROUP or #nil The GROUP is invalid or empty. -- @usage -- -- If Radius is ignored, returns the DCS#Vec3 of first UNIT of the GROUP function GROUP:GetRandomVec3(Radius) @@ -1040,8 +1058,7 @@ end --- Returns the mean heading of every UNIT in the GROUP in degrees -- @param #GROUP self --- @return #number mean heading of the GROUP --- @return #nil The first UNIT is not existing or alive. +-- @return #number Mean heading of the GROUP in degrees or #nil The first UNIT is not existing or alive. function GROUP:GetHeading() self:F2(self.GroupName) @@ -1069,8 +1086,8 @@ end --- Return the fuel state and unit reference for the unit with the least -- amount of fuel in the group. -- @param #GROUP self --- @return #number The fuel state of the unit with the least amount of fuel --- @return #Unit reference to #Unit object for further processing +-- @return #number The fuel state of the unit with the least amount of fuel. +-- @return Wrapper.Unit#UNIT reference to #Unit object for further processing. function GROUP:GetFuelMin() self:F3(self.ControllableName) @@ -2617,6 +2634,7 @@ function GROUP:GetSkill() return skill end + --- Get the unit in the group with the highest threat level, which is still alive. -- @param #GROUP self -- @return Wrapper.Unit#UNIT The most dangerous unit in the group. diff --git a/Moose Development/Moose/Wrapper/Positionable.lua b/Moose Development/Moose/Wrapper/Positionable.lua index dc5955d3d..ff5563023 100644 --- a/Moose Development/Moose/Wrapper/Positionable.lua +++ b/Moose Development/Moose/Wrapper/Positionable.lua @@ -382,7 +382,8 @@ function POSITIONABLE:GetCoordinate() local PositionableVec3 = self:GetVec3() local coord = COORDINATE:NewFromVec3( PositionableVec3 ) - + local heading = self:GetHeading() + coord.Heading = heading -- Return a new coordinate object. return coord diff --git a/Moose Development/Moose/Wrapper/Unit.lua b/Moose Development/Moose/Wrapper/Unit.lua index ad2ddc433..bb6b61551 100644 --- a/Moose Development/Moose/Wrapper/Unit.lua +++ b/Moose Development/Moose/Wrapper/Unit.lua @@ -88,8 +88,8 @@ -- -- @field #UNIT UNIT UNIT = { - ClassName="UNIT", - UnitName=nil, + ClassName="UNIT", + UnitName=nil, } @@ -102,7 +102,7 @@ UNIT = { -- Registration. - + --- Create a new UNIT from DCSUnit. -- @param #UNIT self -- @param #string UnitName The name of the DCS unit. @@ -168,6 +168,9 @@ function UNIT:GetDCSObject() return nil end + + + --- Respawn the @{Wrapper.Unit} using a (tweaked) template of the parent Group. -- -- This function will: @@ -260,6 +263,8 @@ function UNIT:ReSpawnAt( Coordinate, Heading ) _DATABASE:Spawn( SpawnGroupTemplate ) end + + --- Returns if the unit is activated. -- @param #UNIT self -- @return #boolean `true` if Unit is activated. `nil` The DCS Unit is not existing or alive. @@ -296,6 +301,8 @@ function UNIT:IsAlive() return nil end + + --- Returns the Unit's callsign - the localized string. -- @param #UNIT self -- @return #string The Callsign of the Unit. @@ -401,6 +408,17 @@ function UNIT:GetClient() return nil end +--- [AIRPLANE] Get the NATO reporting name of a UNIT. Currently airplanes only! +--@param #UNIT self +--@return #string NatoReportingName or "Bogey" if unknown. +function UNIT:GetNatoReportingName() + + local typename = self:GetTypeName() + return UTILS.GetReportingName(typename) + +end + + --- Returns the unit's number in the group. -- The number is the same number the unit has in ME. -- It may not be changed during the mission. @@ -517,6 +535,63 @@ function UNIT:IsTanker() return tanker, system end +--- Check if the unit can supply ammo. Currently, we have +-- +-- * M 818 +-- * Ural-375 +-- * ZIL-135 +-- +-- This list needs to be extended, if DCS adds other units capable of supplying ammo. +-- +-- @param #UNIT self +-- @return #boolean If `true`, unit can supply ammo. +function UNIT:IsAmmoSupply() + + -- Type name is the only thing we can check. There is no attribute (Sep. 2021) which would tell us. + local typename=self:GetTypeName() + + if typename=="M 818" then + -- Blue ammo truck. + return true + elseif typename=="Ural-375" then + -- Red ammo truck. + return true + elseif typename=="ZIL-135" then + -- Red ammo truck. Checked that it can also provide ammo. + return true + end + + return false +end + +--- Check if the unit can supply fuel. Currently, we have +-- +-- * M978 HEMTT Tanker +-- * ATMZ-5 +-- * ATMZ-10 +-- * ATZ-5 +-- +-- This list needs to be extended, if DCS adds other units capable of supplying fuel. +-- +-- @param #UNIT self +-- @return #boolean If `true`, unit can supply fuel. +function UNIT:IsFuelSupply() + + -- Type name is the only thing we can check. There is no attribute (Sep. 2021) which would tell us. + local typename=self:GetTypeName() + + if typename=="M978 HEMTT Tanker" then + return true + elseif typename=="ATMZ-5" then + return true + elseif typename=="ATMZ-10" then + return true + elseif typename=="ATZ-5" then + return true + end + + return false +end --- Returns the unit's group if it exist and nil otherwise. -- @param Wrapper.Unit#UNIT self @@ -544,14 +619,14 @@ end -- @return #string The name of the DCS Unit. -- @return #nil The DCS Unit is not existing or alive. function UNIT:GetPrefix() - self:F2( self.UnitName ) + self:F2( self.UnitName ) local DCSUnit = self:GetDCSObject() - + if DCSUnit then - local UnitPrefix = string.match( self.UnitName, ".*#" ):sub( 1, -2 ) - self:T3( UnitPrefix ) - return UnitPrefix + local UnitPrefix = string.match( self.UnitName, ".*#" ):sub( 1, -2 ) + self:T3( UnitPrefix ) + return UnitPrefix end return nil @@ -676,8 +751,6 @@ function UNIT:GetAmmunition() return nammo, nshells, nrockets, nbombs, nmissiles end - - --- Returns the unit sensors. -- @param #UNIT self -- @return DCS#Unit.Sensors Table of sensors. @@ -954,6 +1027,7 @@ end -- @return #string Some text. function UNIT:GetThreatLevel() + local ThreatLevel = 0 local ThreatText = "" @@ -979,6 +1053,7 @@ function UNIT:GetThreatLevel() "LR SAMs" } + if Attributes["LR SAM"] then ThreatLevel = 10 elseif Attributes["MR SAM"] then ThreatLevel = 9 elseif Attributes["SR SAM"] and @@ -992,7 +1067,7 @@ function UNIT:GetThreatLevel() elseif ( Attributes["Tanks"] or Attributes["IFV"] ) and not Attributes["ATGM"] then ThreatLevel = 3 elseif Attributes["Old Tanks"] or Attributes["APC"] or Attributes["Artillery"] then ThreatLevel = 2 - elseif Attributes["Infantry"] then ThreatLevel = 1 + elseif Attributes["Infantry"] or Attributes["EWR"] then ThreatLevel = 1 end ThreatText = ThreatLevels[ThreatLevel+1] @@ -1014,6 +1089,7 @@ function UNIT:GetThreatLevel() "Fighter" } + if Attributes["Fighters"] then ThreatLevel = 10 elseif Attributes["Multirole fighters"] then ThreatLevel = 9 elseif Attributes["Battleplanes"] then ThreatLevel = 8 @@ -1111,26 +1187,32 @@ end -- @return true If the other DCS Unit is within the radius of the 2D point of the DCS Unit. -- @return #nil The DCS Unit is not existing or alive. function UNIT:OtherUnitInRadius( AwaitUnit, Radius ) - self:F2( { self.UnitName, AwaitUnit.UnitName, Radius } ) + self:F2( { self.UnitName, AwaitUnit.UnitName, Radius } ) local DCSUnit = self:GetDCSObject() if DCSUnit then - local UnitVec3 = self:GetVec3() - local AwaitUnitVec3 = AwaitUnit:GetVec3() + local UnitVec3 = self:GetVec3() + local AwaitUnitVec3 = AwaitUnit:GetVec3() - if (((UnitVec3.x - AwaitUnitVec3.x)^2 + (UnitVec3.z - AwaitUnitVec3.z)^2)^0.5 <= Radius) then - self:T3( "true" ) - return true - else - self:T3( "false" ) - return false - end + if (((UnitVec3.x - AwaitUnitVec3.x)^2 + (UnitVec3.z - AwaitUnitVec3.z)^2)^0.5 <= Radius) then + self:T3( "true" ) + return true + else + self:T3( "false" ) + return false + end end - return nil + return nil end + + + + + + --- Returns if the unit is a friendly unit. -- @param #UNIT self -- @return #boolean IsFriendly evaluation result.