MOOSE/Moose/CleanUp.lua
2015-12-04 13:41:41 +01:00

387 lines
16 KiB
Lua

--- 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_ENGINE_STARTUP, 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 Group " .. CleanUpGroupName, CleanUpGroupName, 1, 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( CleanUpUnit, CleanUpUnitName )
trace.f( self.ClassName )
if CleanUpUnit then
MESSAGE:New( "Destroy " .. CleanUpUnitName, CleanUpUnitName, 1, CleanUpUnitName ):ToAll()
local CleanUpGroup = Unit.getGroup(CleanUpUnit)
if CleanUpGroup then
local CleanUpGroupUnits = CleanUpGroup:getUnits()
if #CleanUpGroupUnits == 1 then
local CleanUpGroupName = CleanUpGroup:getName()
local Event = {["initiator"]=CleanUpUnit,["id"]=8}
world.onEvent(Event)
trigger.action.deactivateGroup(CleanUpGroup)
trace.i(self.ClassName, "Destroyed Group " .. CleanUpGroupName )
else
CleanUpUnit:destroy()
trace.i(self.ClassName, "Destroyed Unit " .. CleanUpUnitName )
end
self.CleanUpList[CleanUpUnitName] = nil -- Cleaning from the list
CleanUpUnit = nil
end
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
function CLEANUP:_AddForCleanUp( CleanUpUnit, CleanUpUnitName )
self.CleanUpList[CleanUpUnitName] = {}
self.CleanUpList[CleanUpUnitName].CleanUpUnit = CleanUpUnit
self.CleanUpList[CleanUpUnitName].CleanUpUnitName = CleanUpUnitName
self.CleanUpList[CleanUpUnitName].CleanUpGroup = Unit.getGroup(CleanUpUnit)
self.CleanUpList[CleanUpUnitName].CleanUpGroupName = Unit.getGroup(CleanUpUnit):getName()
self.CleanUpList[CleanUpUnitName].CleanUpTime = timer.getTime()
self.CleanUpList[CleanUpUnitName].CleanUpMoved = false
trace.i( self.ClassName, "CleanUp: Add to CleanUpList: " .. Unit.getGroup(CleanUpUnit):getName() .. " / " .. CleanUpUnitName )
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 )
local CleanUpUnit = event.initiator -- the Unit
if CleanUpUnit and Object.getCategory(CleanUpUnit) == Object.Category.UNIT then
local CleanUpUnitName = CleanUpUnit:getName() -- return the name of the Unit
if self.CleanUpList[CleanUpUnitName] == nil then
if routines.IsUnitInZones( CleanUpUnit, self.ZoneNames ) ~= nil then
self:_AddForCleanUp( CleanUpUnit, CleanUpUnitName )
end
end
end
local CleanUpTgtUnit = event.target -- the target Unit
if CleanUpTgtUnit and Object.getCategory(CleanUpTgtUnit) == Object.Category.UNIT then
local CleanUpTgtUnitName = CleanUpTgtUnit:getName() -- return the name of the target Unit
if self.CleanUpList[CleanUpTgtUnitName] == nil then
if routines.IsUnitInZones( CleanUpTgtUnit, self.ZoneNames ) ~= nil then
self:_AddForCleanUp( CleanUpTgtUnit, CleanUpTgtUnitName )
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
trace.i( self.ClassName, { CleanUpUnitName, UnitData } )
local CleanUpGroup = Group.getByName(UnitData.CleanUpGroupName)
local CleanUpUnit = Unit.getByName(UnitData.CleanUpUnitName)
local CleanUpGroupName = UnitData.CleanUpGroupName
local CleanUpUnitName = UnitData.CleanUpUnitName
if CleanUpUnit then
trace.i( self.ClassName, "Checking " .. CleanUpUnitName )
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 and CleanUpUnit:getLife() <= CleanUpUnit:getLife0() * 0.95 then
if CleanUpSurfaceType == land.SurfaceType.RUNWAY then
if CleanUpUnit:inAir() then
local CleanUpLandHeight = land.getHeight(CleanUpUnitVec2)
local CleanUpUnitHeight = CleanUpUnitVec3.y - CleanUpLandHeight
trace.i( self.ClassName, "Height = " .. CleanUpUnitHeight )
if CleanUpUnitHeight < 30 then
trace.i( self.ClassName, "Destroy " .. CleanUpUnitName .. " because below safe height and damaged." )
self:_DestroyUnit(CleanUpUnit, CleanUpUnitName)
end
else
trace.i( self.ClassName, "Destroy " .. CleanUpUnitName .. " because on runway and damaged." )
self:_DestroyUnit(CleanUpUnit, CleanUpUnitName)
end
end
end
-- Clean Units which are waiting for a very long time in the CleanUpZone.
if CleanUpUnit then
local CleanUpUnitVelocity = CleanUpUnit:getVelocity()
local CleanUpUnitVelocityTotal = math.abs(CleanUpUnitVelocity.x) + math.abs(CleanUpUnitVelocity.y) + math.abs(CleanUpUnitVelocity.z)
if CleanUpUnitVelocityTotal < 1 then
if UnitData.CleanUpMoved then
if UnitData.CleanUpTime + 180 <= timer.getTime() then
trace.i( self.ClassName, "Destroy due to not moving anymore " .. CleanUpUnitName )
self:_DestroyUnit(CleanUpUnit, CleanUpUnitName)
end
end
else
UnitData.CleanUpTime = timer.getTime()
UnitData.CleanUpMoved = true
MESSAGE:New( "Moved " .. CleanUpUnitName, CleanUpUnitName, 10, CleanUpUnitName ):ToAll()
end
end
else
-- Do nothing ...
self.CleanUpList[CleanUpUnitName] = nil -- Not anymore in the DCSRTE
end
else
trace.i( self.ClassName, "CleanUp: Group " .. CleanUpUnitName .. " cannot be found in DCS RTE, removing ..." )
self.CleanUpList[CleanUpUnitName] = nil -- Not anymore in the DCSRTE
end
end
end