diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua index 311a07b59..424a0f814 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua @@ -1151,6 +1151,10 @@ function AI_CARGO_DISPATCHER:onafterMonitor() self.PickupCargo[Carrier] = CargoCoordinate PickupCargo = Cargo break + else + local text=string.format("WARNING: Cargo %s is too heavy to be loaded into transport. Cargo weight %.1f > %.1f load capacity of carrier %s.", + tostring(Cargo:GetName()), Cargo:GetWeight(), LargestLoadCapacity, tostring(Carrier:GetName())) + self:I(text) end end end diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua index 149d22d23..58cb5c386 100644 --- a/Moose Development/Moose/Core/Set.lua +++ b/Moose Development/Moose/Core/Set.lua @@ -1576,8 +1576,8 @@ do -- SET_GROUP --- Iterate the SET_GROUP and count how many GROUPs and UNITs are alive. -- @param #SET_GROUP self - -- @return #number The number of GROUPs completely in the Zone - -- @return #number The number of UNITS alive. + -- @return #number The number of GROUPs alive. + -- @return #number The number of UNITs alive. function SET_GROUP:CountAlive() local CountG = 0 local CountU = 0 @@ -2186,20 +2186,6 @@ do -- SET_UNIT return IsNotInZone end - - --- Check if minimal one element of the SET_UNIT is in the Zone. - -- @param #SET_UNIT self - -- @param #function IteratorFunction The function that will be called when there is an alive UNIT in the SET_UNIT. The function needs to accept a UNIT parameter. - -- @return #SET_UNIT self - function SET_UNIT:ForEachUnitInZone( IteratorFunction, ... ) - self:F2( arg ) - - self:ForEach( IteratorFunction, arg, self:GetSet() ) - - return self - end - - end diff --git a/Moose Development/Moose/Core/Spawn.lua b/Moose Development/Moose/Core/Spawn.lua index 4865754ca..200d8a7a0 100644 --- a/Moose Development/Moose/Core/Spawn.lua +++ b/Moose Development/Moose/Core/Spawn.lua @@ -214,9 +214,8 @@ -- ### **Scheduled** spawning methods -- -- * @{#SPAWN.SpawnScheduled}(): Spawn groups at scheduled but randomized intervals. --- * @{#SPAWN.SpawnScheduledStart}(): Start or continue to spawn groups at scheduled time intervals. --- * @{#SPAWN.SpawnScheduledStop}(): Stop the spawning of groups at scheduled time intervals. --- +--- * @{#SPAWN.SpawnScheduleStart}(): Start or continue to spawn groups at scheduled time intervals. +-- * @{#SPAWN.SpawnScheduleStop}(): Stop the spawning of groups at scheduled time intervals. -- -- -- ## Retrieve alive GROUPs spawned by the SPAWN object @@ -260,7 +259,7 @@ -- immediately when :SpawnScheduled() is initiated. The methods @{#SPAWN.InitDelayOnOff}() and @{#SPAWN.InitDelayOn}() can be used to -- activate a delay before the first @{Wrapper.Group} is spawned. For completeness, a method @{#SPAWN.InitDelayOff}() is also available, that -- can be used to switch off the initial delay. Because there is no delay by default, this method would only be used when a --- @{#SPAWN.SpawnScheduledStop}() ; @{#SPAWN.SpawnScheduledStart}() sequence would have been used. +-- @{#SPAWN.SpawnScheduleStop}() ; @{#SPAWN.SpawnScheduleStart}() sequence would have been used. -- -- -- @field #SPAWN SPAWN diff --git a/Moose Development/Moose/Core/Zone.lua b/Moose Development/Moose/Core/Zone.lua index a1db93d70..802656890 100644 --- a/Moose Development/Moose/Core/Zone.lua +++ b/Moose Development/Moose/Core/Zone.lua @@ -949,7 +949,7 @@ function ZONE_RADIUS:SearchZone( EvaluateFunction, ObjectCategories ) local function EvaluateZone( ZoneDCSUnit ) - env.info( ZoneDCSUnit:getName() ) + --env.info( ZoneDCSUnit:getName() ) local ZoneUnit = UNIT:Find( ZoneDCSUnit ) diff --git a/Moose Development/Moose/Functional/Suppression.lua b/Moose Development/Moose/Functional/Suppression.lua index 073c009bd..1698f0c0a 100644 --- a/Moose Development/Moose/Functional/Suppression.lua +++ b/Moose Development/Moose/Functional/Suppression.lua @@ -22,7 +22,7 @@ -- -- The implementation is based on an idea and script by MBot. See the [DCS forum threat](https://forums.eagle.ru/showthread.php?t=107635) for details. -- --- In addition to suppressing the fire, conditions can be specified which let the group retreat to a defined zone, move away from the attacker +-- In addition to suppressing the fire, conditions can be specified, which let the group retreat to a defined zone, move away from the attacker -- or hide at a nearby scenery object. -- -- ==== @@ -83,6 +83,8 @@ -- @field #string DefaultAlarmState Alarm state the group will go to when it is changed back from another state. Default is "Auto". -- @field #string DefaultROE ROE the group will get once suppression is over. Default is "Free". -- @field #boolean eventmoose If true, events are handled by MOOSE. If false, events are handled directly by DCS eventhandler. Default true. +-- @field Core.Zone#ZONE BattleZone +-- @field #boolean AutoEngage -- @extends Core.Fsm#FSM_CONTROLLABLE -- @@ -266,7 +268,10 @@ SUPPRESSION={ } --- Enumerator of possible rules of engagement. --- @field #list ROE +-- @type SUPPRESSION.ROE +-- @field #string Hold Hold fire. +-- @field #string Free Weapon fire. +-- @field #string Return Return fire. SUPPRESSION.ROE={ Hold="Weapon Hold", Free="Weapon Free", @@ -274,7 +279,10 @@ SUPPRESSION.ROE={ } --- Enumerator of possible alarm states. --- @field #list AlarmState +-- @type SUPPRESSION.AlarmState +-- @field #string Auto Automatic. +-- @field #string Green Green. +-- @field #string Red Red. SUPPRESSION.AlarmState={ Auto="Auto", Green="Green", @@ -287,7 +295,7 @@ SUPPRESSION.MenuF10=nil --- PSEUDOATC version. -- @field #number version -SUPPRESSION.version="0.9.2" +SUPPRESSION.version="0.9.3" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -301,8 +309,7 @@ SUPPRESSION.version="0.9.2" --- Creates a new AI_suppression object. -- @param #SUPPRESSION self -- @param Wrapper.Group#GROUP group The GROUP object for which suppression should be applied. --- @return #SUPPRESSION SUPPRESSION object. --- @return nil If group does not exist or is not a ground group. +-- @return #SUPPRESSION SUPPRESSION object or *nil* if group does not exist or is not a ground group. function SUPPRESSION:New(group) -- Inherits from FSM_CONTROLLABLE @@ -327,18 +334,16 @@ function SUPPRESSION:New(group) self:SetControllable(group) -- Get DCS descriptors of group. - local DCSgroup=Group.getByName(group:GetName()) - local DCSunit=DCSgroup:getUnit(1) - self.DCSdesc=DCSunit:getDesc() + self.DCSdesc=group:GetDCSDesc(1) -- Get max speed the group can do and convert to km/h. - self.SpeedMax=self.DCSdesc.speedMaxOffRoad*3.6 + self.SpeedMax=group:GetSpeedMax() -- Set speed to maximum. self.Speed=self.SpeedMax -- Is this infantry or not. - self.IsInfantry=DCSunit:hasAttribute("Infantry") + self.IsInfantry=group:GetUnit(1):HasAttribute("Infantry") -- Type of group. self.Type=group:GetTypeName() @@ -362,6 +367,7 @@ function SUPPRESSION:New(group) self:AddTransition("TakingCover", "FightBack", "CombatReady") self:AddTransition("FallingBack", "FightBack", "CombatReady") self:AddTransition("Retreating", "Retreated", "Retreated") + self:AddTransition("*", "OutOfAmmo", "*") self:AddTransition("*", "Dead", "*") self:AddTransition("*", "Stop", "Stopped") @@ -592,6 +598,24 @@ function SUPPRESSION:New(group) -- @param #string To To state. + --- Trigger "OutOfAmmo" event. + -- @function [parent=#SUPPRESSION] OutOfAmmo + -- @param #SUPPRESSION self + + --- Trigger "OutOfAmmo" event after a delay. + -- @function [parent=#SUPPRESSION] __OutOfAmmo + -- @param #SUPPRESSION self + -- @param #number Delay Delay in seconds. + + --- User function for OnAfter "OutOfAmmo" event. + -- @function [parent=#SUPPRESSION] OnAfterOutOfAmmo + -- @param #SUPPRESSION self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + + --- Trigger "Dead" event. -- @function [parent=#SUPPRESSION] Dead -- @param #SUPPRESSION self @@ -876,10 +900,11 @@ function SUPPRESSION:StatusReport(message) local state=self.CurrentAlarmState local life_min, life_max, life_ave, life_ave0, groupstrength=self:_GetLife() local ammotot=group:GetAmmunition() + local detectedG=group:GetDetectedGroupSet():CountAlive() + local detectedU=group:GetDetectedUnitSet():Count() - - local text=string.format("State %s, Units=%d/%d, ROE=%s, AlarmState=%s, Hits=%d, Life(min/max/ave/ave0)=%d/%d/%d/%d, Total Ammo=%d", - self:GetState(), nunits, self.IniGroupStrength, self.CurrentROE, self.CurrentAlarmState, self.Nhit, life_min, life_max, life_ave, life_ave0, ammotot) + local text=string.format("State %s, Units=%d/%d, ROE=%s, AlarmState=%s, Hits=%d, Life(min/max/ave/ave0)=%d/%d/%d/%d, Total Ammo=%d, Detected=%d/%d", + self:GetState(), nunits, self.IniGroupStrength, self.CurrentROE, self.CurrentAlarmState, self.Nhit, life_min, life_max, life_ave, life_ave0, ammotot, detectedG, detectedU) MESSAGE:New(text, 10):ToAllIf(message or self.Debug) self:I(self.lid..text) @@ -991,12 +1016,12 @@ function SUPPRESSION:onafterStatus(Controllable, From, Event, To) local nunits=group:CountAliveUnits() -- Check if there are units. - if nunits>0 then + if nunits>0 then -- Retreat if completely out of ammo and retreat zone defined. local nammo=group:GetAmmunition() - if nammo==0 and self.RetreatZone then - self:Retreat() + if nammo==0 then + self:OutOfAmmo() end -- Status report. @@ -1008,34 +1033,18 @@ function SUPPRESSION:onafterStatus(Controllable, From, Event, To) end else + -- Stop FSM as there are no units left. self:Stop() end else + -- Stop FSM as there group object does not exist. self:Stop() end end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---- Before "Hit" event. (Of course, this is not really before the group got hit.) --- @param #SUPPRESSION self --- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. --- @param #string From From state. --- @param #string Event Event. --- @param #string To To state. --- @param Wrapper.Unit#UNIT Unit Unit that was hit. --- @param Wrapper.Unit#UNIT AttackUnit Unit that attacked. --- @return boolean -function SUPPRESSION:onbeforeHit(Controllable, From, Event, To, Unit, AttackUnit) - self:_EventFromTo("onbeforeHit", Event, From, To) - - --local Tnow=timer.getTime() - --env.info(self.lid..string.format("Last hit = %s %s", tostring(self.LastHit), tostring(Tnow))) - - return true -end - --- After "Hit" event. -- @param #SUPPRESSION self -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. @@ -1306,6 +1315,25 @@ function SUPPRESSION:onafterTakeCover(Controllable, From, Event, To, Hideout) end +--- After "OutOfAmmo" event. Triggered when group is completely out of ammo. +-- @param #SUPPRESSION self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +function SUPPRESSION:onafterOutOfAmmo(Controllable, From, Event, To) + self:_EventFromTo("onafterOutOfAmmo", Event, From, To) + + -- Info to log. + self:I(self.lid..string.format("Out of ammo!")) + + -- Order retreat if retreat zone was specified. + if self.RetreatZone then + self:Retreat() + end + +end + ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- Before "Retreat" event. We check that the group is not already retreating. diff --git a/Moose Development/Moose/Functional/ZoneCaptureCoalition.lua b/Moose Development/Moose/Functional/ZoneCaptureCoalition.lua index 81c2aefd1..4b0801681 100644 --- a/Moose Development/Moose/Functional/ZoneCaptureCoalition.lua +++ b/Moose Development/Moose/Functional/ZoneCaptureCoalition.lua @@ -874,8 +874,16 @@ do -- ZONE_CAPTURE_COALITION self:Capture() end + -- Get red and blue unit sets. + local unitsetRed=self:GetScannedSetUnit():FilterCoalitions(coalition.side.RED):FilterActive(true):FilterOnce() + local unitsetBlu=self:GetScannedSetUnit():FilterCoalitions(coalition.side.BLUE):FilterActive(true):FilterOnce() + + -- Count number of units. + local nRed=unitsetRed:Count() + local nBlu=unitsetBlu:Count() + -- Status text. - local text=string.format("CAPTURE ZONE %s: Owner=%s (Previous=%s): Status %s", self:GetZoneName(), self:GetCoalitionName(), UTILS.GetCoalitionName(self:GetPreviousCoalition()), State) + local text=string.format("CAPTURE ZONE %s: Owner=%s (Previous=%s): #blue=%d, #red=%d, Status %s", self:GetZoneName(), self:GetCoalitionName(), UTILS.GetCoalitionName(self:GetPreviousCoalition()), nBlu, nRed, State) local NewState = self:GetState() if NewState~=State then text=text..string.format(" --> %s", NewState) diff --git a/Moose Development/Moose/Ops/ATIS.lua b/Moose Development/Moose/Ops/ATIS.lua index 6d7a939bd..a1b5f4866 100644 --- a/Moose Development/Moose/Ops/ATIS.lua +++ b/Moose Development/Moose/Ops/ATIS.lua @@ -515,7 +515,7 @@ _ATIS={} --- ATIS class version. -- @field #string version -ATIS.version="0.6.0" +ATIS.version="0.6.1" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO list @@ -996,9 +996,15 @@ function ATIS:onafterStatus(From, Event, To) -- Get FSM state. local fsmstate=self:GetState() + + local relayunitstatus="N/A" + if self.relayunitname then + local ru=UNIT:FindByName(self.relayunitname) + relayunitstatus=tostring(ru:IsAlive()) + end -- Info text. - local text=string.format("State %s", fsmstate) + local text=string.format("State %s: Freq=%.3f MHz %s, Relay unit=%s (alive=%s)", fsmstate, self.frequency, UTILS.GetModulationName(self.modulation), tostring(self.relayunitname), relayunitstatus) self:I(self.lid..text) self:__Status(-60) diff --git a/Moose Development/Moose/Ops/Airboss.lua b/Moose Development/Moose/Ops/Airboss.lua index da53af408..83502fa80 100644 --- a/Moose Development/Moose/Ops/Airboss.lua +++ b/Moose Development/Moose/Ops/Airboss.lua @@ -1691,7 +1691,7 @@ AIRBOSS.MenuF10Root=nil --- Airboss class version. -- @field #string version -AIRBOSS.version="1.1.0" +AIRBOSS.version="1.1.1" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO list @@ -2081,6 +2081,7 @@ function AIRBOSS:New(carriername, alias) self:AddTransition("*", "RecoveryCase", "*") -- Switch to another case recovery. self:AddTransition("*", "PassingWaypoint", "*") -- Carrier is passing a waypoint. self:AddTransition("*", "LSOGrade", "*") -- LSO grade. + self:AddTransition("*", "Marshal", "*") -- A flight was send into the marshal stack. self:AddTransition("*", "Save", "*") -- Save player scores to file. self:AddTransition("*", "Stop", "Stopped") -- Stop AIRBOSS FMS. @@ -2254,29 +2255,6 @@ function AIRBOSS:New(carriername, alias) -- @param #string filename (Optional) File name. Default is AIRBOSS-*ALIAS*_LSOgrades.csv. - --- Triggers the FSM event "LSOgrade". Called when the LSO grades a player - -- @function [parent=#AIRBOSS] LSOgrade - -- @param #AIRBOSS self - -- @param #AIRBOSS.PlayerData playerData Player Data. - -- @param #AIRBOSS.LSOgrade grade LSO grade. - - --- Triggers the FSM event "LSOgrade". Delayed called when the LSO grades a player. - -- @function [parent=#AIRBOSS] __LSOgrade - -- @param #AIRBOSS self - -- @param #number delay Delay in seconds. - -- @param #AIRBOSS.PlayerData playerData Player Data. - -- @param #AIRBOSS.LSOgrade grade LSO grade. - - --- On after "LSOgrade" user function. Called when the carrier passes a waypoint of its route. - -- @function [parent=#AIRBOSS] OnAfterLSOgrade - -- @param #AIRBOSS self - -- @param #string From From state. - -- @param #string Event Event. - -- @param #string To To state. - -- @param #AIRBOSS.PlayerData playerData Player Data. - -- @param #AIRBOSS.LSOgrade grade LSO grade. - - --- Triggers the FSM event "LSOGrade". Called when the LSO grades a player -- @function [parent=#AIRBOSS] LSOGrade -- @param #AIRBOSS self @@ -2300,27 +2278,24 @@ function AIRBOSS:New(carriername, alias) -- @param #AIRBOSS.LSOgrade grade LSO grade. - --- Triggers the FSM event "LSOGrade". Called when the LSO grades a player - -- @function [parent=#AIRBOSS] LSOGrade + --- Triggers the FSM event "Marshal". Called when a flight is send to the Marshal stack. + -- @function [parent=#AIRBOSS] Marshal -- @param #AIRBOSS self - -- @param #AIRBOSS.PlayerData playerData Player Data. - -- @param #AIRBOSS.LSOgrade grade LSO grade. + -- @param #AIRBOSS.FlightGroup flight The flight group data. - --- Triggers the FSM event "LSOGrade". Delayed called when the LSO grades a player. - -- @function [parent=#AIRBOSS] __LSOGrade + --- Triggers the FSM event "Marshal". Delayed call when a flight is send to the Marshal stack. + -- @function [parent=#AIRBOSS] __Marshal -- @param #AIRBOSS self -- @param #number delay Delay in seconds. - -- @param #AIRBOSS.PlayerData playerData Player Data. - -- @param #AIRBOSS.LSOgrade grade LSO grade. + -- @param #AIRBOSS.FlightGroup flight The flight group data. - --- On after "LSOGrade" user function. Called when the carrier passes a waypoint of its route. - -- @function [parent=#AIRBOSS] OnAfterLSOGrade + --- On after "Marshal" user function. Called when a flight is send to the Marshal stack. + -- @function [parent=#AIRBOSS] OnAfterMarshal -- @param #AIRBOSS self -- @param #string From From state. -- @param #string Event Event. -- @param #string To To state. - -- @param #AIRBOSS.PlayerData playerData Player Data. - -- @param #AIRBOSS.LSOgrade grade LSO grade. + -- @param #AIRBOSS.FlightGroup flight The flight group data. --- Triggers the FSM event "Stop" that stops the airboss. Event handlers are stopped. @@ -6187,6 +6162,9 @@ function AIRBOSS:_MarshalPlayer(playerData, stack) -- Set stack flag. flight.flag=stack + + -- Trigger Marshal event. + self:Marshal(flight) end else @@ -6443,6 +6421,9 @@ function AIRBOSS:_MarshalAI(flight, nstack, respawn) -- Route group. flight.group:Route(wp, 1) + + -- Trigger Marshal event. + self:Marshal(flight) end diff --git a/Moose Development/Moose/Ops/RecoveryTanker.lua b/Moose Development/Moose/Ops/RecoveryTanker.lua index b779f8efc..e43cd9cc7 100644 --- a/Moose Development/Moose/Ops/RecoveryTanker.lua +++ b/Moose Development/Moose/Ops/RecoveryTanker.lua @@ -629,7 +629,7 @@ function RECOVERYTANKER:SetHomeBase(airbase, terminaltype) if not self.airbase then self:E(self.lid.."ERROR: Airbase is nil!") end - if termialtype then + if terminaltype then self.terminaltype=terminaltype end return self diff --git a/Moose Development/Moose/Utilities/Utils.lua b/Moose Development/Moose/Utilities/Utils.lua index acfc30323..766b8de47 100644 --- a/Moose Development/Moose/Utilities/Utils.lua +++ b/Moose Development/Moose/Utilities/Utils.lua @@ -78,7 +78,7 @@ CALLSIGN={ }, -- AWACS AWACS={ - Overloard=1, + Overlord=1, Magic=2, Wizard=3, Focus=4, @@ -1060,3 +1060,23 @@ function UTILS.GetCoalitionName(Coalition) 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) + + if Modulation then + if Modulation==0 then + return "AM" + elseif Modulation==1 then + return "FM" + else + return "Unknown" + end + else + return "Unknown" + end + +end + + diff --git a/Moose Development/Moose/Wrapper/Controllable.lua b/Moose Development/Moose/Wrapper/Controllable.lua index b42085516..28eaff805 100644 --- a/Moose Development/Moose/Wrapper/Controllable.lua +++ b/Moose Development/Moose/Wrapper/Controllable.lua @@ -2802,7 +2802,9 @@ function CONTROLLABLE:GetDetectedTargets( DetectVisual, DetectOptical, DetectRad self:F2( self.ControllableName ) local DCSControllable = self:GetDCSObject() + if DCSControllable then + local DetectionVisual = ( DetectVisual and DetectVisual == true ) and Controller.Detection.VISUAL or nil local DetectionOptical = ( DetectOptical and DetectOptical == true ) and Controller.Detection.OPTICAL or nil local DetectionRadar = ( DetectRadar and DetectRadar == true ) and Controller.Detection.RADAR or nil @@ -2841,7 +2843,25 @@ function CONTROLLABLE:GetDetectedTargets( DetectVisual, DetectOptical, DetectRad end --- Check if a target is detected. +-- The optional parametes specify the detection methods that can be applied. +-- If **no** detection method is given, the detection will use **all** the available methods by default. +-- If **at least one** detection method is specified, only the methods set to *true* will be used. -- @param Wrapper.Controllable#CONTROLLABLE self +-- @param DCS#Object DCSObject The DCS object that is checked. +-- @param Wrapper.Controllable#CONTROLLABLE self +-- @param #boolean DetectVisual (Optional) If *false*, do not include visually detected targets. +-- @param #boolean DetectOptical (Optional) If *false*, do not include optically detected targets. +-- @param #boolean DetectRadar (Optional) If *false*, do not include targets detected by radar. +-- @param #boolean DetectIRST (Optional) If *false*, do not include targets detected by IRST. +-- @param #boolean DetectRWR (Optional) If *false*, do not include targets detected by RWR. +-- @param #boolean DetectDLINK (Optional) If *false*, do not include targets detected by data link. +-- @return #boolean True if target is detected. +-- @return #boolean True if target is visible by line of sight. +-- @return #number Mission time when target was detected. +-- @return #boolean True if target type is known. +-- @return #boolean True if distance to target is known. +-- @return DCS#Vec3 Last known position vector of the target. +-- @return DCS#Vec3 Last known velocity vector of the target. function CONTROLLABLE:IsTargetDetected( DCSObject, DetectVisual, DetectOptical, DetectRadar, DetectIRST, DetectRWR, DetectDLINK ) self:F2( self.ControllableName ) @@ -2867,6 +2887,147 @@ function CONTROLLABLE:IsTargetDetected( DCSObject, DetectVisual, DetectOptical, return nil end +--- Check if a certain UNIT is detected by the controllable. +-- The optional parametes specify the detection methods that can be applied. +-- If **no** detection method is given, the detection will use **all** the available methods by default. +-- If **at least one** detection method is specified, only the methods set to *true* will be used. +-- @param #CONTROLLABLE self +-- @param Wrapper.Unit#UNIT Unit The unit that is supposed to be detected. +-- @param #boolean DetectVisual (Optional) If *false*, do not include visually detected targets. +-- @param #boolean DetectOptical (Optional) If *false*, do not include optically detected targets. +-- @param #boolean DetectRadar (Optional) If *false*, do not include targets detected by radar. +-- @param #boolean DetectIRST (Optional) If *false*, do not include targets detected by IRST. +-- @param #boolean DetectRWR (Optional) If *false*, do not include targets detected by RWR. +-- @param #boolean DetectDLINK (Optional) If *false*, do not include targets detected by data link. +-- @return #boolean True if target is detected. +-- @return #boolean True if target is visible by line of sight. +-- @return #number Mission time when target was detected. +-- @return #boolean True if target type is known. +-- @return #boolean True if distance to target is known. +-- @return DCS#Vec3 Last known position vector of the target. +-- @return DCS#Vec3 Last known velocity vector of the target. +function CONTROLLABLE:IsUnitDetected( Unit, DetectVisual, DetectOptical, DetectRadar, DetectIRST, DetectRWR, DetectDLINK ) + self:F2( self.ControllableName ) + + if Unit and Unit:IsAlive() then + return self:IsTargetDetected(Unit:GetDCSObject(), DetectVisual, DetectOptical, DetectRadar, DetectIRST, DetectRWR, DetectDLINK) + end + + return nil +end + +--- Check if a certain GROUP is detected by the controllable. +-- The optional parametes specify the detection methods that can be applied. +-- If **no** detection method is given, the detection will use **all** the available methods by default. +-- If **at least one** detection method is specified, only the methods set to *true* will be used. +-- @param #CONTROLLABLE self +-- @param Wrapper.Group#GROUP Group The group that is supposed to be detected. +-- @param #boolean DetectVisual (Optional) If *false*, do not include visually detected targets. +-- @param #boolean DetectOptical (Optional) If *false*, do not include optically detected targets. +-- @param #boolean DetectRadar (Optional) If *false*, do not include targets detected by radar. +-- @param #boolean DetectIRST (Optional) If *false*, do not include targets detected by IRST. +-- @param #boolean DetectRWR (Optional) If *false*, do not include targets detected by RWR. +-- @param #boolean DetectDLINK (Optional) If *false*, do not include targets detected by data link. +-- @return #boolean True if any unit of the group is detected. +function CONTROLLABLE:IsGroupDetected( Group, DetectVisual, DetectOptical, DetectRadar, DetectIRST, DetectRWR, DetectDLINK ) + self:F2( self.ControllableName ) + + if Group and Group:IsAlive() then + for _,_unit in pairs(Group:GetUnits()) do + local unit=_unit --Wrapper.Unit#UNIT + if unit and unit:IsAlive() then + + local isdetected=self:IsUnitDetected(unit, DetectVisual, DetectOptical, DetectRadar, DetectIRST, DetectRWR, DetectDLINK) + + if isdetected then + return true + end + end + end + return false + end + + return nil +end + + +--- Return the detected targets of the controllable. +-- The optional parametes specify the detection methods that can be applied. +-- If **no** detection method is given, the detection will use **all** the available methods by default. +-- If **at least one** detection method is specified, only the methods set to *true* will be used. +-- @param Wrapper.Controllable#CONTROLLABLE self +-- @param #boolean DetectVisual (Optional) If *false*, do not include visually detected targets. +-- @param #boolean DetectOptical (Optional) If *false*, do not include optically detected targets. +-- @param #boolean DetectRadar (Optional) If *false*, do not include targets detected by radar. +-- @param #boolean DetectIRST (Optional) If *false*, do not include targets detected by IRST. +-- @param #boolean DetectRWR (Optional) If *false*, do not include targets detected by RWR. +-- @param #boolean DetectDLINK (Optional) If *false*, do not include targets detected by data link. +-- @return Core.Set#SET_UNIT Set of detected units. +function CONTROLLABLE:GetDetectedUnitSet(DetectVisual, DetectOptical, DetectRadar, DetectIRST, DetectRWR, DetectDLINK) + + -- Get detected DCS units. + local detectedtargets=self:GetDetectedTargets(DetectVisual, DetectOptical, DetectRadar, DetectIRST, DetectRWR, DetectDLINK) + + local unitset=SET_UNIT:New() + + for DetectionObjectID, Detection in pairs(detectedtargets or {}) do + local DetectedObject=Detection.object -- DCS#Object + + if DetectedObject and DetectedObject:isExist() and DetectedObject.id_<50000000 then + local unit=UNIT:Find(DetectedObject) + + if unit and unit:IsAlive() then + + if not unitset:FindUnit(unit:GetName()) then + unitset:AddUnit(unit) + end + + end + end + end + + return unitset +end + +--- Return the detected target groups of the controllable as a @{SET_GROUP}. +-- The optional parametes specify the detection methods that can be applied. +-- If no detection method is given, the detection will use all the available methods by default. +-- @param Wrapper.Controllable#CONTROLLABLE self +-- @param #boolean DetectVisual (Optional) If *false*, do not include visually detected targets. +-- @param #boolean DetectOptical (Optional) If *false*, do not include optically detected targets. +-- @param #boolean DetectRadar (Optional) If *false*, do not include targets detected by radar. +-- @param #boolean DetectIRST (Optional) If *false*, do not include targets detected by IRST. +-- @param #boolean DetectRWR (Optional) If *false*, do not include targets detected by RWR. +-- @param #boolean DetectDLINK (Optional) If *false*, do not include targets detected by data link. +-- @return Core.Set#SET_GROUP Set of detected groups. +function CONTROLLABLE:GetDetectedGroupSet(DetectVisual, DetectOptical, DetectRadar, DetectIRST, DetectRWR, DetectDLINK) + + -- Get detected DCS units. + local detectedtargets=self:GetDetectedTargets(DetectVisual, DetectOptical, DetectRadar, DetectIRST, DetectRWR, DetectDLINK) + + local groupset=SET_GROUP:New() + + for DetectionObjectID, Detection in pairs(detectedtargets or {}) do + local DetectedObject=Detection.object -- DCS#Object + + if DetectedObject and DetectedObject:isExist() and DetectedObject.id_<50000000 then + local unit=UNIT:Find(DetectedObject) + + if unit and unit:IsAlive() then + local group=unit:GetGroup() + + if group and not groupset:FindGroup(group:GetName()) then + groupset:AddGroup(group) + end + + end + end + end + + return groupset +end + + -- Options --- Can the CONTROLLABLE hold their weapons? diff --git a/Moose Development/Moose/Wrapper/Unit.lua b/Moose Development/Moose/Wrapper/Unit.lua index 7f974be19..c747bc92e 100644 --- a/Moose Development/Moose/Wrapper/Unit.lua +++ b/Moose Development/Moose/Wrapper/Unit.lua @@ -1165,6 +1165,45 @@ do -- Detection return IsLOS end + + --- Forces the unit to become aware of the specified target, without the unit manually detecting the other unit itself. + -- Applies only to a Unit Controller. Cannot be used at the group level. + -- @param #UNIT self + -- @param #UNIT TargetUnit The unit to be known. + -- @param #boolean TypeKnown The target type is known. If *false*, the type is not known. + -- @param #boolean DistanceKnown The distance to the target is known. If *false*, distance is unknown. + function UNIT:KnowUnit(TargetUnit, TypeKnown, DistanceKnown) + + -- Defaults. + if TypeKnown~=false then + TypeKnown=true + end + if DistanceKnown~=false then + DistanceKnown=true + end + local DCSControllable = self:GetDCSObject() + + if DCSControllable then + + local Controller = DCSControllable:getController() --self:_GetController() + + if Controller then + + local object=TargetUnit:GetDCSObject() + + if object then + + self:I(string.format("Unit %s now knows target unit %s. Type known=%s, distance known=%s", self:GetName(), TargetUnit:GetName(), tostring(TypeKnown), tostring(DistanceKnown))) + + Controller:knowTarget(object, TypeKnown, DistanceKnown) + + end + + end + + end + + end end \ No newline at end of file