mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-08-15 10:47:21 +00:00
Improve the consistency of the module intros to the most commonly used version (single dash). Add missing module information (abbreviated where none existed previously). Fix broken documentation links Make module names correspond to filenames (and fix links). Fix typos.
445 lines
16 KiB
Lua
445 lines
16 KiB
Lua
--- **Functional** - Keep airbases clean of crashing or colliding airplanes, and kill missiles when being fired at airbases.
|
|
--
|
|
-- ===
|
|
--
|
|
-- ## Features:
|
|
--
|
|
--
|
|
-- * Try to keep the airbase clean and operational.
|
|
-- * Prevent airplanes from crashing.
|
|
-- * Clean up obstructing airplanes from the runway that are standing still for a period of time.
|
|
-- * Prevent airplanes firing missiles within the airbase zone.
|
|
--
|
|
-- ===
|
|
--
|
|
-- ## Missions:
|
|
--
|
|
-- [CLA - CleanUp Airbase](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/CLA%20-%20CleanUp%20Airbase)
|
|
--
|
|
-- ===
|
|
--
|
|
-- Specific airbases need to be provided that need to be guarded. Each airbase registered, will be guarded within a zone of 8 km around the airbase.
|
|
-- Any unit that fires a missile, or shoots within the zone of an airbase, will be monitored by CLEANUP_AIRBASE.
|
|
-- Within the 8km zone, units cannot fire any missile, which prevents the airbase runway to receive missile or bomb hits.
|
|
-- Any airborne or ground unit that is on the runway below 30 meters (default value) will be automatically removed if it is damaged.
|
|
--
|
|
-- This is not a full 100% secure implementation. It is still possible that CLEANUP_AIRBASE cannot prevent (in-time) to keep the airbase clean.
|
|
-- The following situations may happen that will still stop the runway of an airbase:
|
|
--
|
|
-- * A damaged unit is not removed on time when above the runway, and crashes on the runway.
|
|
-- * A bomb or missile is still able to dropped on the runway.
|
|
-- * Units collide on the airbase, and could not be removed on time.
|
|
--
|
|
-- When a unit is within the airbase zone and needs to be monitored,
|
|
-- its status will be checked every 0.25 seconds! This is required to ensure that the airbase is kept clean.
|
|
-- But as a result, there is more CPU overload.
|
|
--
|
|
-- So as an advise, I suggest you use the CLEANUP_AIRBASE class with care:
|
|
--
|
|
-- * Only monitor airbases that really need to be monitored!
|
|
-- * Try not to monitor airbases that are likely to be invaded by enemy troops.
|
|
-- For these airbases, there is little use to keep them clean, as they will be invaded anyway...
|
|
--
|
|
-- By following the above guidelines, you can add airbase cleanup with acceptable CPU overhead.
|
|
--
|
|
-- ===
|
|
--
|
|
-- ### Author: **FlightControl**
|
|
-- ### Contributions:
|
|
--
|
|
-- ===
|
|
--
|
|
-- @module Functional.CleanUp
|
|
-- @image CleanUp_Airbases.JPG
|
|
|
|
--- @type CLEANUP_AIRBASE.__ Methods which are not intended for mission designers, but which are used interally by the moose designer :-)
|
|
-- @field #map<#string,Wrapper.Airbase#AIRBASE> Airbases Map of Airbases.
|
|
-- @extends Core.Base#BASE
|
|
|
|
--- @type CLEANUP_AIRBASE
|
|
-- @extends #CLEANUP_AIRBASE.__
|
|
|
|
--- Keeps airbases clean, and tries to guarantee continuous airbase operations, even under combat.
|
|
--
|
|
-- # 1. CLEANUP_AIRBASE Constructor
|
|
--
|
|
-- Creates the main object which is preventing the airbase to get polluted with debris on the runway, which halts the airbase.
|
|
--
|
|
-- -- Clean these Zones.
|
|
-- CleanUpAirports = CLEANUP_AIRBASE:New( { AIRBASE.Caucasus.Tbilisi, AIRBASE.Caucasus.Kutaisi } )
|
|
--
|
|
-- -- or
|
|
-- CleanUpTbilisi = CLEANUP_AIRBASE:New( AIRBASE.Caucasus.Tbilisi )
|
|
-- CleanUpKutaisi = CLEANUP_AIRBASE:New( AIRBASE.Caucasus.Kutaisi )
|
|
--
|
|
-- # 2. Add or Remove airbases
|
|
--
|
|
-- The method @{#CLEANUP_AIRBASE.AddAirbase}() to add an airbase to the cleanup validation process.
|
|
-- The method @{#CLEANUP_AIRBASE.RemoveAirbase}() removes an airbase from the cleanup validation process.
|
|
--
|
|
-- # 3. Clean missiles and bombs within the airbase zone.
|
|
--
|
|
-- When missiles or bombs hit the runway, the airbase operations stop.
|
|
-- Use the method @{#CLEANUP_AIRBASE.SetCleanMissiles}() to control the cleaning of missiles, which will prevent airbases to stop.
|
|
-- Note that this method will not allow anymore airbases to be attacked, so there is a trade-off here to do.
|
|
--
|
|
-- @field #CLEANUP_AIRBASE
|
|
CLEANUP_AIRBASE = {
|
|
ClassName = "CLEANUP_AIRBASE",
|
|
TimeInterval = 0.2,
|
|
CleanUpList = {},
|
|
}
|
|
|
|
-- @field #CLEANUP_AIRBASE.__
|
|
CLEANUP_AIRBASE.__ = {}
|
|
|
|
--- @field #CLEANUP_AIRBASE.__.Airbases
|
|
CLEANUP_AIRBASE.__.Airbases = {}
|
|
|
|
--- Creates the main object which is handling the cleaning of the debris within the given Zone Names.
|
|
-- @param #CLEANUP_AIRBASE self
|
|
-- @param #list<#string> AirbaseNames Is a table of airbase names where the debris should be cleaned. Also a single string can be passed with one airbase name.
|
|
-- @return #CLEANUP_AIRBASE
|
|
-- @usage
|
|
-- -- Clean these Zones.
|
|
-- CleanUpAirports = CLEANUP_AIRBASE:New( { AIRBASE.Caucasus.Tbilisi, AIRBASE.Caucasus.Kutaisi )
|
|
-- or
|
|
-- CleanUpTbilisi = CLEANUP_AIRBASE:New( AIRBASE.Caucasus.Tbilisi )
|
|
-- CleanUpKutaisi = CLEANUP_AIRBASE:New( AIRBASE.Caucasus.Kutaisi )
|
|
function CLEANUP_AIRBASE:New( AirbaseNames )
|
|
|
|
local self = BASE:Inherit( self, BASE:New() ) -- #CLEANUP_AIRBASE
|
|
self:F( { AirbaseNames } )
|
|
|
|
if type( AirbaseNames ) == 'table' then
|
|
for AirbaseID, AirbaseName in pairs( AirbaseNames ) do
|
|
self:AddAirbase( AirbaseName )
|
|
end
|
|
else
|
|
local AirbaseName = AirbaseNames
|
|
self:AddAirbase( AirbaseName )
|
|
end
|
|
|
|
self:HandleEvent( EVENTS.Birth, self.__.OnEventBirth )
|
|
|
|
self.__.CleanUpScheduler = SCHEDULER:New( self, self.__.CleanUpSchedule, {}, 1, self.TimeInterval )
|
|
|
|
self:HandleEvent( EVENTS.EngineShutdown , self.__.EventAddForCleanUp )
|
|
self:HandleEvent( EVENTS.EngineStartup, self.__.EventAddForCleanUp )
|
|
self:HandleEvent( EVENTS.Hit, self.__.EventAddForCleanUp )
|
|
self:HandleEvent( EVENTS.PilotDead, self.__.OnEventCrash )
|
|
self:HandleEvent( EVENTS.Dead, self.__.OnEventCrash )
|
|
self:HandleEvent( EVENTS.Crash, self.__.OnEventCrash )
|
|
|
|
for UnitName, Unit in pairs( _DATABASE.UNITS ) do
|
|
local Unit = Unit -- Wrapper.Unit#UNIT
|
|
if Unit:IsAlive() ~= nil then
|
|
if self:IsInAirbase( Unit:GetVec2() ) then
|
|
self:F( { UnitName = UnitName } )
|
|
self.CleanUpList[UnitName] = {}
|
|
self.CleanUpList[UnitName].CleanUpUnit = Unit
|
|
self.CleanUpList[UnitName].CleanUpGroup = Unit:GetGroup()
|
|
self.CleanUpList[UnitName].CleanUpGroupName = Unit:GetGroup():GetName()
|
|
self.CleanUpList[UnitName].CleanUpUnitName = Unit:GetName()
|
|
end
|
|
end
|
|
end
|
|
|
|
return self
|
|
end
|
|
|
|
--- Adds an airbase to the airbase validation list.
|
|
-- @param #CLEANUP_AIRBASE self
|
|
-- @param #string AirbaseName
|
|
-- @return #CLEANUP_AIRBASE
|
|
function CLEANUP_AIRBASE:AddAirbase( AirbaseName )
|
|
self.__.Airbases[AirbaseName] = AIRBASE:FindByName( AirbaseName )
|
|
self:F({"Airbase:", AirbaseName, self.__.Airbases[AirbaseName]:GetDesc()})
|
|
|
|
return self
|
|
end
|
|
|
|
--- Removes an airbase from the airbase validation list.
|
|
-- @param #CLEANUP_AIRBASE self
|
|
-- @param #string AirbaseName
|
|
-- @return #CLEANUP_AIRBASE
|
|
function CLEANUP_AIRBASE:RemoveAirbase( AirbaseName )
|
|
self.__.Airbases[AirbaseName] = nil
|
|
return self
|
|
end
|
|
|
|
--- Enables or disables the cleaning of missiles within the airbase zones.
|
|
-- Airbase operations stop when a missile or bomb is dropped at a runway.
|
|
-- Note that when this method is used, the airbase operations won't stop if
|
|
-- the missile or bomb was cleaned within the airbase zone, which is 8km from the center of the airbase.
|
|
-- However, there is a trade-off to make. Attacks on airbases won't be possible anymore if this method is used.
|
|
-- Note, one can also use the method @{#CLEANUP_AIRBASE.RemoveAirbase}() to remove the airbase from the control process as a whole,
|
|
-- when an enemy unit is near. That is also an option...
|
|
-- @param #CLEANUP_AIRBASE self
|
|
-- @param #string CleanMissiles (Default=true) If true, missiles fired are immediately destroyed. If false missiles are not controlled.
|
|
-- @return #CLEANUP_AIRBASE
|
|
function CLEANUP_AIRBASE:SetCleanMissiles( CleanMissiles )
|
|
|
|
if CleanMissiles then
|
|
self:HandleEvent( EVENTS.Shot, self.__.OnEventShot )
|
|
else
|
|
self:UnHandleEvent( EVENTS.Shot )
|
|
end
|
|
end
|
|
|
|
function CLEANUP_AIRBASE.__:IsInAirbase( Vec2 )
|
|
|
|
local InAirbase = false
|
|
for AirbaseName, Airbase in pairs( self.__.Airbases ) do
|
|
local Airbase = Airbase -- Wrapper.Airbase#AIRBASE
|
|
if Airbase:GetZone():IsVec2InZone( Vec2 ) then
|
|
InAirbase = true
|
|
break;
|
|
end
|
|
end
|
|
|
|
return InAirbase
|
|
end
|
|
|
|
|
|
|
|
--- Destroys a @{Wrapper.Unit} from the simulator, but checks first if it is still existing!
|
|
-- @param #CLEANUP_AIRBASE self
|
|
-- @param Wrapper.Unit#UNIT CleanUpUnit The object to be destroyed.
|
|
function CLEANUP_AIRBASE.__:DestroyUnit( CleanUpUnit )
|
|
self:F( { CleanUpUnit } )
|
|
|
|
if CleanUpUnit then
|
|
local CleanUpUnitName = CleanUpUnit:GetName()
|
|
local CleanUpGroup = CleanUpUnit:GetGroup()
|
|
-- TODO DCS BUG - Client bug in 1.5.3
|
|
if CleanUpGroup:IsAlive() then
|
|
local CleanUpGroupUnits = CleanUpGroup:GetUnits()
|
|
if #CleanUpGroupUnits == 1 then
|
|
local CleanUpGroupName = CleanUpGroup:GetName()
|
|
CleanUpGroup:Destroy()
|
|
else
|
|
CleanUpUnit:Destroy()
|
|
end
|
|
self.CleanUpList[CleanUpUnitName] = nil
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
|
|
--- Destroys a missile from the simulator, but checks first if it is still existing!
|
|
-- @param #CLEANUP_AIRBASE self
|
|
-- @param DCS#Weapon MissileObject
|
|
function CLEANUP_AIRBASE.__:DestroyMissile( MissileObject )
|
|
self:F( { MissileObject } )
|
|
|
|
if MissileObject and MissileObject:isExist() then
|
|
MissileObject:destroy()
|
|
self:T( "MissileObject Destroyed")
|
|
end
|
|
end
|
|
|
|
--- @param #CLEANUP_AIRBASE self
|
|
-- @param Core.Event#EVENTDATA EventData
|
|
function CLEANUP_AIRBASE.__:OnEventBirth( EventData )
|
|
self:F( { EventData } )
|
|
|
|
if EventData and EventData.IniUnit and EventData.IniUnit:IsAlive() ~= nil then
|
|
if self:IsInAirbase( EventData.IniUnit:GetVec2() ) then
|
|
self.CleanUpList[EventData.IniDCSUnitName] = {}
|
|
self.CleanUpList[EventData.IniDCSUnitName].CleanUpUnit = EventData.IniUnit
|
|
self.CleanUpList[EventData.IniDCSUnitName].CleanUpGroup = EventData.IniGroup
|
|
self.CleanUpList[EventData.IniDCSUnitName].CleanUpGroupName = EventData.IniDCSGroupName
|
|
self.CleanUpList[EventData.IniDCSUnitName].CleanUpUnitName = EventData.IniDCSUnitName
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
|
|
--- Detects if a crash event occurs.
|
|
-- Crashed units go into a CleanUpList for removal.
|
|
-- @param #CLEANUP_AIRBASE self
|
|
-- @param Core.Event#EVENTDATA Event
|
|
function CLEANUP_AIRBASE.__:OnEventCrash( Event )
|
|
self:F( { Event } )
|
|
|
|
--TODO: DCS BUG - This stuff is not working due to a DCS bug. Burning units cannot be destroyed.
|
|
-- self:T("before getGroup")
|
|
-- local _grp = Unit.getGroup(event.initiator)-- Identify the group that fired
|
|
-- self:T("after getGroup")
|
|
-- _grp:destroy()
|
|
-- self:T("after deactivateGroup")
|
|
-- event.initiator:destroy()
|
|
|
|
if Event.IniDCSUnitName and Event.IniCategory == Object.Category.UNIT then
|
|
self.CleanUpList[Event.IniDCSUnitName] = {}
|
|
self.CleanUpList[Event.IniDCSUnitName].CleanUpUnit = Event.IniUnit
|
|
self.CleanUpList[Event.IniDCSUnitName].CleanUpGroup = Event.IniGroup
|
|
self.CleanUpList[Event.IniDCSUnitName].CleanUpGroupName = Event.IniDCSGroupName
|
|
self.CleanUpList[Event.IniDCSUnitName].CleanUpUnitName = Event.IniDCSUnitName
|
|
end
|
|
|
|
end
|
|
|
|
--- Detects if a unit shoots a missile.
|
|
-- If this occurs within one of the airbases, then the weapon used must be destroyed.
|
|
-- @param #CLEANUP_AIRBASE self
|
|
-- @param Core.Event#EVENTDATA Event
|
|
function CLEANUP_AIRBASE.__:OnEventShot( Event )
|
|
self:F( { Event } )
|
|
|
|
-- Test if the missile was fired within one of the CLEANUP_AIRBASE.AirbaseNames.
|
|
if self:IsInAirbase( Event.IniUnit:GetVec2() ) then
|
|
-- Okay, the missile was fired within the CLEANUP_AIRBASE.AirbaseNames, destroy the fired weapon.
|
|
self:DestroyMissile( Event.Weapon )
|
|
end
|
|
end
|
|
|
|
--- Detects if the Unit has an S_EVENT_HIT within the given AirbaseNames. If this is the case, destroy the unit.
|
|
-- @param #CLEANUP_AIRBASE self
|
|
-- @param Core.Event#EVENTDATA Event
|
|
function CLEANUP_AIRBASE.__:OnEventHit( Event )
|
|
self:F( { Event } )
|
|
|
|
if Event.IniUnit then
|
|
if self:IsInAirbase( Event.IniUnit:GetVec2() ) then
|
|
self:T( { "Life: ", Event.IniDCSUnitName, ' = ', Event.IniUnit:GetLife(), "/", Event.IniUnit:GetLife0() } )
|
|
if Event.IniUnit:GetLife() < Event.IniUnit:GetLife0() then
|
|
self:T( "CleanUp: Destroy: " .. Event.IniDCSUnitName )
|
|
CLEANUP_AIRBASE.__:DestroyUnit( Event.IniUnit )
|
|
end
|
|
end
|
|
end
|
|
|
|
if Event.TgtUnit then
|
|
if self:IsInAirbase( Event.TgtUnit:GetVec2() ) then
|
|
self:T( { "Life: ", Event.TgtDCSUnitName, ' = ', Event.TgtUnit:GetLife(), "/", Event.TgtUnit:GetLife0() } )
|
|
if Event.TgtUnit:GetLife() < Event.TgtUnit:GetLife0() then
|
|
self:T( "CleanUp: Destroy: " .. Event.TgtDCSUnitName )
|
|
CLEANUP_AIRBASE.__:DestroyUnit( Event.TgtUnit )
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
--- Add the @{DCS#Unit} to the CleanUpList for CleanUp.
|
|
-- @param #CLEANUP_AIRBASE self
|
|
-- @param DCS#UNIT CleanUpUnit
|
|
-- @oaram #string CleanUpUnitName
|
|
function CLEANUP_AIRBASE.__:AddForCleanUp( CleanUpUnit, CleanUpUnitName )
|
|
self:F( { CleanUpUnit, CleanUpUnitName } )
|
|
|
|
self.CleanUpList[CleanUpUnitName] = {}
|
|
self.CleanUpList[CleanUpUnitName].CleanUpUnit = CleanUpUnit
|
|
self.CleanUpList[CleanUpUnitName].CleanUpUnitName = CleanUpUnitName
|
|
|
|
local CleanUpGroup = CleanUpUnit:GetGroup()
|
|
|
|
self.CleanUpList[CleanUpUnitName].CleanUpGroup = CleanUpGroup
|
|
self.CleanUpList[CleanUpUnitName].CleanUpGroupName = CleanUpGroup:GetName()
|
|
self.CleanUpList[CleanUpUnitName].CleanUpTime = timer.getTime()
|
|
self.CleanUpList[CleanUpUnitName].CleanUpMoved = false
|
|
|
|
self:T( { "CleanUp: Add to CleanUpList: ", CleanUpGroup:GetName(), CleanUpUnitName } )
|
|
|
|
end
|
|
|
|
--- Detects if the Unit has an S_EVENT_ENGINE_SHUTDOWN or an S_EVENT_HIT within the given AirbaseNames. If this is the case, add the Group to the CLEANUP_AIRBASE List.
|
|
-- @param #CLEANUP_AIRBASE.__ self
|
|
-- @param Core.Event#EVENTDATA Event
|
|
function CLEANUP_AIRBASE.__:EventAddForCleanUp( Event )
|
|
|
|
self:F({Event})
|
|
|
|
|
|
if Event.IniDCSUnit and Event.IniCategory == Object.Category.UNIT then
|
|
if self.CleanUpList[Event.IniDCSUnitName] == nil then
|
|
if self:IsInAirbase( Event.IniUnit:GetVec2() ) then
|
|
self:AddForCleanUp( Event.IniUnit, Event.IniDCSUnitName )
|
|
end
|
|
end
|
|
end
|
|
|
|
if Event.TgtDCSUnit and Event.TgtCategory == Object.Category.UNIT then
|
|
if self.CleanUpList[Event.TgtDCSUnitName] == nil then
|
|
if self:IsInAirbase( Event.TgtUnit:GetVec2() ) then
|
|
self:AddForCleanUp( Event.TgtUnit, Event.TgtDCSUnitName )
|
|
end
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
|
|
--- At the defined time interval, CleanUp the Groups within the CleanUpList.
|
|
-- @param #CLEANUP_AIRBASE self
|
|
function CLEANUP_AIRBASE.__:CleanUpSchedule()
|
|
|
|
local CleanUpCount = 0
|
|
for CleanUpUnitName, CleanUpListData in pairs( self.CleanUpList ) do
|
|
CleanUpCount = CleanUpCount + 1
|
|
|
|
local CleanUpUnit = CleanUpListData.CleanUpUnit -- Wrapper.Unit#UNIT
|
|
local CleanUpGroupName = CleanUpListData.CleanUpGroupName
|
|
|
|
if CleanUpUnit:IsAlive() ~= nil then
|
|
|
|
if self:IsInAirbase( CleanUpUnit:GetVec2() ) then
|
|
|
|
if _DATABASE:GetStatusGroup( CleanUpGroupName ) ~= "ReSpawn" then
|
|
|
|
local CleanUpCoordinate = CleanUpUnit:GetCoordinate()
|
|
|
|
self:T( { "CleanUp Scheduler", CleanUpUnitName } )
|
|
if CleanUpUnit:GetLife() <= CleanUpUnit:GetLife0() * 0.95 then
|
|
if CleanUpUnit:IsAboveRunway() then
|
|
if CleanUpUnit:InAir() then
|
|
|
|
local CleanUpLandHeight = CleanUpCoordinate:GetLandHeight()
|
|
local CleanUpUnitHeight = CleanUpCoordinate.y - CleanUpLandHeight
|
|
|
|
if CleanUpUnitHeight < 100 then
|
|
self:T( { "CleanUp Scheduler", "Destroy " .. CleanUpUnitName .. " because below safe height and damaged." } )
|
|
self:DestroyUnit( CleanUpUnit )
|
|
end
|
|
else
|
|
self:T( { "CleanUp Scheduler", "Destroy " .. CleanUpUnitName .. " because on runway and damaged." } )
|
|
self:DestroyUnit( CleanUpUnit )
|
|
end
|
|
end
|
|
end
|
|
-- Clean Units which are waiting for a very long time in the CleanUpZone.
|
|
if CleanUpUnit and not CleanUpUnit:GetPlayerName() then
|
|
local CleanUpUnitVelocity = CleanUpUnit:GetVelocityKMH()
|
|
if CleanUpUnitVelocity < 1 then
|
|
if CleanUpListData.CleanUpMoved then
|
|
if CleanUpListData.CleanUpTime + 180 <= timer.getTime() then
|
|
self:T( { "CleanUp Scheduler", "Destroy due to not moving anymore " .. CleanUpUnitName } )
|
|
self:DestroyUnit( CleanUpUnit )
|
|
end
|
|
end
|
|
else
|
|
CleanUpListData.CleanUpTime = timer.getTime()
|
|
CleanUpListData.CleanUpMoved = true
|
|
end
|
|
end
|
|
else
|
|
-- not anymore in an airbase zone, remove from cleanup list.
|
|
self.CleanUpList[CleanUpUnitName] = nil
|
|
end
|
|
else
|
|
-- Do nothing ...
|
|
self.CleanUpList[CleanUpUnitName] = nil
|
|
end
|
|
else
|
|
self:T( "CleanUp: Group " .. CleanUpUnitName .. " cannot be found in DCS RTE, removing ..." )
|
|
self.CleanUpList[CleanUpUnitName] = nil
|
|
end
|
|
end
|
|
self:T(CleanUpCount)
|
|
|
|
return true
|
|
end
|