FlightControl ccfcca8f9a Tweaks for the settings system
- Player settings are located at the group level. Only the first player
that joins the group will be able to configure the settings.
- Default system settings are located at the group of the commend
center. Thus, the COMMANDCENTER class will contain the default system
settings menu. You need to join the command center unit (ALT-J) as a
game master to be able to configure these settings.
2017-07-04 10:55:45 +02:00

407 lines
15 KiB
Lua

--- **Functional** -- The CLEANUP class keeps an area clean of crashing or colliding airplanes. It also prevents airplanes from firing within this area.
--
-- ===
--
-- ### Author: **Sven Van de Velde (FlightControl)**
-- ### Contributions:
--
-- ====
--
-- @module CleanUp
--- @type CLEANUP.__ 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
-- @extends #CLEANUP.__
--- # CLEANUP, extends @{Base#BASE}
--
-- ![Banner Image](..\Presentations\CLEANUP\Dia1.JPG)
--
-- The CLEANUP class keeps airbases clean, and tries to guarantee continuous airbase operations, even under combat.
-- 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.
-- 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 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 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.
--
-- ## 1. CLEANUP 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:New( { AIRBASE.Caucasus.Tbilisi, AIRBASE.Caucasus.Kutaisi )
--
-- -- or
-- CleanUpTbilisi = CLEANUP:New( AIRBASE.Caucasus.Tbilisi )
-- CleanUpKutaisi = CLEANUP:New( AIRBASE.Caucasus.Kutaisi )
--
-- ## 2. Add or Remove airbases
--
-- The method @{#CLEANUP.AddAirbase}() to add an airbase to the cleanup validation process.
-- The method @{#CLEANUP.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.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
CLEANUP = {
ClassName = "CLEANUP",
TimeInterval = 0.2,
CleanUpList = {},
}
-- @field #CLEANUP.__
CLEANUP.__ = {}
--- @field #CLEANUP.__.Airbases
CLEANUP.__.Airbases = {}
--- Creates the main object which is handling the cleaning of the debris within the given Zone Names.
-- @param #CLEANUP 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
-- @usage
-- -- Clean these Zones.
-- CleanUpAirports = CLEANUP:New( { AIRBASE.Caucasus.Tbilisi, AIRBASE.Caucasus.Kutaisi )
-- or
-- CleanUpTbilisi = CLEANUP:New( AIRBASE.Caucasus.Tbilisi )
-- CleanUpKutaisi = CLEANUP:New( AIRBASE.Caucasus.Kutaisi )
function CLEANUP:New( AirbaseNames )
local self = BASE:Inherit( self, BASE:New() ) -- #CLEANUP
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 )
return self
end
--- Adds an airbase to the airbase validation list.
-- @param #CLEANUP self
-- @param #string AirbaseName
-- @return #CLEANUP
function CLEANUP: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 self
-- @param #string AirbaseName
-- @return #CLEANUP
function CLEANUP: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.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 self
-- @param #string CleanMissiles (Default=true) If true, missiles fired are immediately destroyed. If false missiles are not controlled.
-- @return #CLEANUP
function CLEANUP:SetCleanMissiles( CleanMissiles )
if CleanMissiles or true then
self:HandleEvent( EVENTS.Shot, self.__.OnEventShot )
else
self:UnHandleEvent( EVENTS.Shot )
end
end
function CLEANUP.__: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 @{Unit} from the simulator, but checks first if it is still existing!
-- @param #CLEANUP self
-- @param Wrapper.Unit#UNIT CleanUpUnit The object to be destroyed.
function CLEANUP.__:DestroyUnit( CleanUpUnit )
self:F( { CleanUpUnit } )
if CleanUpUnit then
local CleanUpUnitName = CleanUpUnit:GetName()
local CleanUpGroup = CleanUpUnit:GetGroup()
-- TODO 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 self
-- @param Dcs.DCSTypes#Weapon MissileObject
function CLEANUP.__:DestroyMissile( MissileObject )
self:F( { MissileObject } )
if MissileObject and MissileObject:isExist() then
MissileObject:destroy()
self:T( "MissileObject Destroyed")
end
end
--- @param #CLEANUP self
-- @param Core.Event#EVENTDATA EventData
function CLEANUP.__:OnEventBirth( EventData )
self:F( { EventData } )
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
--- Detects if a crash event occurs.
-- Crashed units go into a CleanUpList for removal.
-- @param #CLEANUP self
-- @param Core.Event#EVENTDATA Event
function CLEANUP.__:OnEventCrash( Event )
self:F( { Event } )
--TODO: 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 self
-- @param Core.Event#EVENTDATA Event
function CLEANUP.__:OnEventShot( Event )
self:F( { Event } )
-- Test if the missile was fired within one of the CLEANUP.AirbaseNames.
if self:IsInAirbase( Event.IniUnit:GetVec2() ) then
-- Okay, the missile was fired within the CLEANUP.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 self
-- @param Core.Event#EVENTDATA Event
function CLEANUP.__: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.__: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.__:DestroyUnit( Event.TgtUnit )
end
end
end
end
--- Add the @{DCSWrapper.Unit#Unit} to the CleanUpList for CleanUp.
-- @param #CLEANUP self
-- @param Wrapper.Unit#UNIT CleanUpUnit
-- @oaram #string CleanUpUnitName
function CLEANUP.__: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 List.
-- @param #CLEANUP.__ self
-- @param Core.Event#EVENTDATA Event
function CLEANUP.__: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 self
function CLEANUP.__: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 _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 < 30 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 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
-- 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