--- CLEANUP Classes -- @classmod CLEANUP -- @author Flightcontrol Include.File( "Routines" ) Include.File( "Base" ) Include.File( "Mission" ) Include.File( "Client" ) Include.File( "Task" ) CLEANUP = { ClassName = "CLEANUP", ZoneNames = {}, TimeInterval = 300, CleanUpList = {}, } --- Creates the main object which is handling the cleaning of the debris within the given Zone Names. -- @tparam table{string,...}|string ZoneNames which is a table of zone names where the debris should be cleaned. Also a single string can be passed with one zone name. -- @tparam ?number TimeInterval is the interval in seconds when the clean activity takes place. The default is 300 seconds, thus every 5 minutes. -- @treturn CLEANUP -- @usage -- -- Clean these Zones. -- CleanUpAirports = CLEANUP:New( { 'CLEAN Tbilisi', 'CLEAN Kutaisi' }, 150 ) -- or -- CleanUpTbilisi = CLEANUP:New( 'CLEAN Tbilisi', 150 ) -- CleanUpKutaisi = CLEANUP:New( 'CLEAN Kutaisi', 600 ) function CLEANUP:New( ZoneNames, TimeInterval ) trace.f( self.ClassName, { ZoneNames, TimeInterval } ) -- Arrange meta tables local self = BASE:Inherit( self, BASE:New() ) if type( ZoneNames ) == 'table' then self.ZoneNames = ZoneNames else self.ZoneNames = { ZoneNames } end if TimeInterval then self.TimeInterval = TimeInterval end self:AddEvent( world.event.S_EVENT_ENGINE_SHUTDOWN, self._EventAddForCleanUp ) self:AddEvent( world.event.S_EVENT_HIT, self._EventAddForCleanUp ) -- , self._EventHitCleanUp ) self:AddEvent( world.event.S_EVENT_CRASH, self._EventCrash ) -- , self._EventHitCleanUp ) --self:AddEvent( world.event.S_EVENT_DEAD, self._EventCrash ) self:AddEvent( world.event.S_EVENT_SHOT, self._EventShot ) self:EnableEvents() self.CleanUpFunction = routines.scheduleFunction( self._Scheduler, { self }, timer.getTime() + 1, TimeInterval ) return self end --- Destroys a group from the simulator, but checks first if it is still existing! -- @see CLEANUP function CLEANUP:_DestroyGroup( GroupObject, CleanUpGroupName ) trace.f( self.ClassName ) if GroupObject then -- and GroupObject:isExist() then MESSAGE:New( "Destroy " .. CleanUpGroupName, CleanUpGroupName, 10, CleanUpGroupName ):ToAll() trigger.action.deactivateGroup(GroupObject) trace.i(self.ClassName, "GroupObject Destroyed") end end --- Destroys a unit from the simulator, but checks first if it is still existing! -- @see CLEANUP function CLEANUP:_DestroyUnit( CleanUpUnitObject, CleanUpUnitName ) trace.f( self.ClassName ) if CleanUpUnitObject then MESSAGE:New( "Destroy " .. CleanUpUnitName, CleanUpUnitName, 10, CleanUpUnitName ):ToAll() CleanUpUnitObject:destroy() trace.i(self.ClassName, "UnitObject Destroyed") end end --- Destroys a missile from the simulator, but checks first if it is still existing! -- @see CLEANUP function CLEANUP:_DestroyMissile( MissileObject ) trace.f( self.ClassName ) if MissileObject and MissileObject:isExist() then MissileObject:destroy() trace.i(self.ClassName, "MissileObject Destroyed") end end --- Detects if an SA site was shot with an anti radiation missile. In this case, take evasive actions based on the skill level set within the ME. -- @see CLEANUP function CLEANUP:_EventCrash( event ) trace.f( self.ClassName ) MESSAGE:New( "Crash ", "Crash", 10, "Crash" ):ToAll() -- trace.i(self.ClassName,"before getGroup") -- local _grp = Unit.getGroup(event.initiator)-- Identify the group that fired -- trace.i(self.ClassName,"after getGroup") -- _grp:destroy() -- trace.i(self.ClassName,"after deactivateGroup") -- event.initiator:destroy() local CleanUpUnit = event.initiator -- the Unit local CleanUpUnitName = CleanUpUnit:getName() -- return the name of the Unit local CleanUpGroup = Unit.getGroup(CleanUpUnit)-- Identify the Group local CleanUpGroupName = CleanUpGroup:getName() -- return the name of the Group self.CleanUpList[CleanUpUnitName] = {} self.CleanUpList[CleanUpUnitName].CleanUpUnit = CleanUpUnit self.CleanUpList[CleanUpUnitName].CleanUpGroup = CleanUpGroup self.CleanUpList[CleanUpUnitName].CleanUpGroupName = CleanUpGroupName self.CleanUpList[CleanUpUnitName].CleanUpUnitName = CleanUpUnitName end --- Detects if an SA site was shot with an anti radiation missile. In this case, take evasive actions based on the skill level set within the ME. -- @see CLEANUP function CLEANUP:_EventShot( event ) trace.f( self.ClassName ) local _grp = Unit.getGroup(event.initiator)-- Identify the group that fired local _groupname = _grp:getName() -- return the name of the group local _unittable = {event.initiator:getName()} -- return the name of the units in the group local _SEADmissile = event.weapon -- Identify the weapon fired --local _SEADmissileName = _SEADmissile:getTypeName() -- return weapon type --trigger.action.outText( string.format("Alerte, depart missile " ..string.format(_SEADmissileName)), 20) --debug message -- Start of the 2nd loop --trace.i( self.ClassName, "Missile Launched = " .. _SEADmissileName ) -- Test if the missile was fired within one of the CLEANUP.ZoneNames. local CurrentLandingZoneID = 0 CurrentLandingZoneID = routines.IsUnitInZones( event.initiator, self.ZoneNames ) if ( CurrentLandingZoneID ) then -- Okay, the missile was fired within the CLEANUP.ZoneNames, destroy the fired weapon. --_SEADmissile:destroy() routines.scheduleFunction( CLEANUP._DestroyMissile, {self, _SEADmissile}, timer.getTime() + 0.1) end --[[ if _SEADmissileName == "KH-58" or _SEADmissileName == "KH-25MPU" or _SEADmissileName == "AGM-88" or _SEADmissileName == "KH-31A" or _SEADmissileName == "KH-31P" then -- Check if the missile is a SEAD local _evade = math.random (1,100) -- random number for chance of evading action local _targetMim = Weapon.getTarget(_SEADmissile) -- Identify target local _targetMimname = Unit.getName(_targetMim) local _targetMimgroup = Unit.getGroup(Weapon.getTarget(_SEADmissile)) local _targetMimgroupName = _targetMimgroup:getName() local _targetMimcont= _targetMimgroup:getController() local _targetskill = _Database.Units[_targetMimname].Template.skill trace.i( self.ClassName, self.SEADGroupPrefixes ) trace.i( self.ClassName, _targetMimgroupName ) local SEADGroupFound = false for SEADGroupPrefixID, SEADGroupPrefix in pairs( self.SEADGroupPrefixes ) do if string.find( _targetMimgroupName, SEADGroupPrefix, 1, true ) then SEADGroupFound = true trace.i( self.ClassName, 'Group Found' ) break end end if SEADGroupFound == true then if _targetskill == "Random" then -- when skill is random, choose a skill local Skills = { "Average", "Good", "High", "Excellent" } _targetskill = Skills[ math.random(1,4) ] end trace.i( self.ClassName, _targetskill ) -- debug message for skill check if self.TargetSkill[_targetskill] then if (_evade > self.TargetSkill[_targetskill].Evade) then trace.i( self.ClassName, string.format("Evading, target skill " ..string.format(_targetskill)) ) --debug message local _targetMim = Weapon.getTarget(_SEADmissile) local _targetMimname = Unit.getName(_targetMim) local _targetMimgroup = Unit.getGroup(Weapon.getTarget(_SEADmissile)) local _targetMimcont= _targetMimgroup:getController() routines.groupRandomDistSelf(_targetMimgroup,300,'Rank',250,20) -- move randomly local SuppressedGroups1 = {} -- unit suppressed radar off for a random time local function SuppressionEnd1(id) id.ctrl:setOption(AI.Option.Ground.id.ALARM_STATE,AI.Option.Ground.val.ALARM_STATE.GREEN) SuppressedGroups1[id.groupName] = nil end local id = { groupName = _targetMimgroup, ctrl = _targetMimcont } local delay1 = math.random(self.TargetSkill[_targetskill].DelayOff[1], self.TargetSkill[_targetskill].DelayOff[2]) if SuppressedGroups1[id.groupName] == nil then SuppressedGroups1[id.groupName] = { SuppressionEndTime1 = timer.getTime() + delay1, SuppressionEndN1 = SuppressionEndCounter1 --Store instance of SuppressionEnd() scheduled function } Controller.setOption(_targetMimcont, AI.Option.Ground.id.ALARM_STATE,AI.Option.Ground.val.ALARM_STATE.GREEN) timer.scheduleFunction(SuppressionEnd1, id, SuppressedGroups1[id.groupName].SuppressionEndTime1) --Schedule the SuppressionEnd() function --trigger.action.outText( string.format("Radar Off " ..string.format(delay1)), 20) end local SuppressedGroups = {} local function SuppressionEnd(id) id.ctrl:setOption(AI.Option.Ground.id.ALARM_STATE,AI.Option.Ground.val.ALARM_STATE.RED) SuppressedGroups[id.groupName] = nil end local id = { groupName = _targetMimgroup, ctrl = _targetMimcont } local delay = math.random(self.TargetSkill[_targetskill].DelayOn[1], self.TargetSkill[_targetskill].DelayOn[2]) if SuppressedGroups[id.groupName] == nil then SuppressedGroups[id.groupName] = { SuppressionEndTime = timer.getTime() + delay, SuppressionEndN = SuppressionEndCounter --Store instance of SuppressionEnd() scheduled function } timer.scheduleFunction(SuppressionEnd, id, SuppressedGroups[id.groupName].SuppressionEndTime) --Schedule the SuppressionEnd() function --trigger.action.outText( string.format("Radar On " ..string.format(delay)), 20) end end end end end --]] end --- Detects if the Unit has an S_EVENT_HIT within the given ZoneNames. If this is the case, destroy the unit. function CLEANUP:_EventHitCleanUp( event ) trace.f( self.ClassName ) local CleanUpUnit = event.initiator -- the Unit if CleanUpUnit and CleanUpUnit:isExist() and Object.getCategory(CleanUpUnit) == Object.Category.UNIT then local CleanUpUnitName = event.initiator:getName() -- return the name of the Unit local CleanUpGroup = Unit.getGroup(event.initiator)-- Identify the Group local CleanUpGroupName = CleanUpGroup:getName() -- return the name of the Group if routines.IsUnitInZones( CleanUpUnit, self.ZoneNames ) ~= nil then trace.i( self.ClassName, "Life: " .. CleanUpUnitName .. ' = ' .. CleanUpUnit:getLife() .. "/" .. CleanUpUnit:getLife0() ) if CleanUpUnit:getLife() < CleanUpUnit:getLife0() then trace.i( self.ClassName, "CleanUp: Destroy: " .. CleanUpUnitName ) routines.scheduleFunction( CLEANUP._DestroyUnit, {self, CleanUpUnit}, timer.getTime() + 0.1) end end end local CleanUpTgtUnit = event.target -- the target Unit if CleanUpTgtUnit and CleanUpTgtUnit:isExist() and Object.getCategory(CleanUpTgtUnit) == Object.Category.UNIT then local CleanUpTgtUnitName = event.target:getName() -- return the name of the target Unit local CleanUpTgtGroup = Unit.getGroup(event.target)-- Identify the target Group local CleanUpTgtGroupName = CleanUpTgtGroup:getName() -- return the name of the target Group if routines.IsUnitInZones( CleanUpTgtUnit, self.ZoneNames ) ~= nil then trace.i( self.ClassName, "Life: " .. CleanUpTgtUnitName .. ' = ' .. CleanUpTgtUnit:getLife() .. "/" .. CleanUpTgtUnit:getLife0() ) if CleanUpTgtUnit:getLife() < CleanUpTgtUnit:getLife0() then trace.i( self.ClassName, "CleanUp: Destroy: " .. CleanUpTgtUnitName ) routines.scheduleFunction( CLEANUP._DestroyUnit, {self, CleanUpTgtUnit}, timer.getTime() + 0.1) end end end end --- Detects if the Unit has an S_EVENT_ENGINE_SHUTDOWN or an S_EVENT_HIT within the given ZoneNames. If this is the case, add the Group to the CLEANUP List. function CLEANUP:_EventAddForCleanUp( event ) trace.f( self.ClassName, { event } ) if event.initiator and Object.getCategory(event.initiator) == Object.Category.UNIT then local CleanUpUnit = event.initiator -- the Unit local CleanUpUnitName = event.initiator:getName() -- return the name of the Unit local CleanUpGroup = Unit.getGroup(event.initiator)-- Identify the Group local CleanUpGroupName = CleanUpGroup:getName() -- return the name of the Group if not self.CleanUpList[CleanUpGroupName] then local AddForCleanUp = false if routines.IsUnitInZones( CleanUpUnit, self.ZoneNames ) ~= nil then AddForCleanUp = true end if AddForCleanUp == true then trace.i( self.ClassName, "CleanUp: Add for CleanUp: " .. CleanUpGroupName .. "/" .. CleanUpUnitName ) end end end if event.target and Object.getCategory(event.target) == Object.Category.UNIT then local CleanUpTgtUnit = event.target -- the target Unit if CleanUpTgtUnit then local CleanUpTgtUnitName = event.target:getName() -- return the name of the target Unit local CleanUpTgtGroup = Unit.getGroup(event.target)-- Identify the target Group local CleanUpTgtGroupName = CleanUpTgtGroup:getName() -- return the name of the target Group if not self.CleanUpList[CleanUpTgtUnitName] then local AddForCleanUp = false if routines.IsUnitInZones( CleanUpTgtUnit, self.ZoneNames ) ~= nil then AddForCleanUp = true --env.info( "CleanUp:" .. CleanUpTgtGroupName .. "/" .. CleanUpTgtUnitName ) end if AddForCleanUp == true then trace.i( self.ClassName, "CleanUp: Add for CleanUp: " .. CleanUpTgtGroupName .. "/" .. CleanUpTgtUnitName ) self.CleanUpList[CleanUpTgtUnitName] = {} self.CleanUpList[CleanUpTgtUnitName].CleanUpUnit = CleanUpTgtUnit self.CleanUpList[CleanUpTgtUnitName].CleanUpGroup = CleanUpTgtGroup self.CleanUpList[CleanUpTgtUnitName].CleanUpGroupName = CleanUpTgtGroupName self.CleanUpList[CleanUpTgtUnitName].CleanUpUnitName = CleanUpTgtUnitName end end end end end CleanUpSurfaceTypeText = { "LAND", "SHALLOW_WATER", "WATER", "ROAD", "RUNWAY" } --- At the defined time interval, CleanUp the Groups within the CleanUpList. function CLEANUP:_Scheduler() for CleanUpUnitName, UnitData in pairs( self.CleanUpList ) do --env.info( "CleanUp: GroupName = " .. GroupName .. " UnitName = " .. ListData ) local CleanUpGroup = Group.getByName(UnitData.CleanUpGroupName) local CleanUpUnit = Unit.getByName(UnitData.CleanUpUnitName) local CleanUpGroupName = UnitData.CleanUpGroupName local CleanUpUnitName = UnitData.CleanUpUnitName if CleanUpGroup and CleanUpUnit then trace.i( self.ClassName, "CleanUp: " .. CleanUpGroupName ) if CleanUpGroup:isExist() and CleanUpUnit:isExist() then if _Database:GetStatusGroup( CleanUpGroupName ) ~= "ReSpawn" then local CleanUpUnitVec3 = CleanUpUnit:getPoint() trace.i( self.ClassName, CleanUpUnitVec3 ) local CleanUpUnitVec2 = {} CleanUpUnitVec2.x = CleanUpUnitVec3.x CleanUpUnitVec2.y = CleanUpUnitVec3.z trace.i( self.ClassName, CleanUpUnitVec2 ) local CleanUpSurfaceType = land.getSurfaceType(CleanUpUnitVec2) trace.i( self.ClassName, CleanUpSurfaceType ) MESSAGE:New( "Surface " .. CleanUpUnitName .. " = " .. CleanUpSurfaceTypeText[CleanUpSurfaceType], CleanUpUnitName, 10, CleanUpUnitName ):ToAll() if CleanUpUnit:getLife() <= CleanUpUnit:getLife0() * 0.95 then if CleanUpSurfaceType == land.SurfaceType.RUNWAY then trace.i( self.ClassName, "CleanUp: Destroy " .. CleanUpGroupName .. " because above runway and damaged." ) self:_DestroyUnit(CleanUpUnit, CleanUpUnitName) UnitData = nil end if CleanUpUnit:inAir() then if CleanUpUnit.getHeight(CleanUpUnitVec2) < 20 then trace.i( self.ClassName, "CleanUp: Destroy " .. CleanUpGroupName .. " because below safe height and damaged." ) self:_DestroyUnit(CleanUpUnit, CleanUpUnitName) UnitData = nil end end end local CleanUpUnitVelocity = CleanUpUnit:getVelocity() local CleanUpUnitVelocityTotal = math.abs(CleanUpUnitVelocity.x) + math.abs(CleanUpUnitVelocity.y) + math.abs(CleanUpUnitVelocity.z) if CleanUpUnitVelocityTotal < 1 then trace.i( self.ClassName, "CleanUp: Destroy: " .. CleanUpGroupName ) self:_DestroyUnit(CleanUpUnit, CleanUpUnitName) UnitData = nil end else -- Do nothing ... UnitData = nil end else trace.i( self.ClassName, "CleanUp: Group " .. CleanUpGroupName .. " does not exist anymore in CleanUpList, Removing ..." ) UnitData = nil end else trace.i( self.ClassName, "CleanUp: Group " .. CleanUpGroupName .. " cannot be found in DCS RTE, removing ..." ) UnitData = nil -- Not anymore in the DCSRTE end end end