From 57eeefcf06a56e49b0a738753b25811642edbd1a Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Thu, 28 Sep 2017 19:54:44 +0200 Subject: [PATCH] Progress --- Moose Development/Moose/Core/Set.lua | 2412 +- Moose Development/Moose/Core/Zone.lua | 33 + .../Moose/Functional/Protect.lua | 63 +- Moose Mission Setup/Moose.lua | 26454 +--------------- 4 files changed, 1746 insertions(+), 27216 deletions(-) diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua index c7dda4192..5eae5b712 100644 --- a/Moose Development/Moose/Core/Set.lua +++ b/Moose Development/Moose/Core/Set.lua @@ -1271,872 +1271,1616 @@ function SET_GROUP:IsIncludeObject( MooseGroup ) return MooseGroupInclude end ---- @type SET_UNIT --- @extends Core.Set#SET_BASE ---- # 3) SET_UNIT class, extends @{Set#SET_BASE} --- --- Mission designers can use the SET_UNIT class to build sets of units belonging to certain: --- --- * Coalitions --- * Categories --- * Countries --- * Unit types --- * Starting with certain prefix strings. --- --- ## 3.1) SET_UNIT constructor --- --- Create a new SET_UNIT object with the @{#SET_UNIT.New} method: --- --- * @{#SET_UNIT.New}: Creates a new SET_UNIT object. --- --- ## 3.2) Add or Remove UNIT(s) from SET_UNIT --- --- UNITs can be added and removed using the @{Set#SET_UNIT.AddUnitsByName} and @{Set#SET_UNIT.RemoveUnitsByName} respectively. --- These methods take a single UNIT name or an array of UNIT names to be added or removed from SET_UNIT. --- --- ## 3.3) SET_UNIT filter criteria --- --- You can set filter criteria to define the set of units within the SET_UNIT. --- Filter criteria are defined by: --- --- * @{#SET_UNIT.FilterCoalitions}: Builds the SET_UNIT with the units belonging to the coalition(s). --- * @{#SET_UNIT.FilterCategories}: Builds the SET_UNIT with the units belonging to the category(ies). --- * @{#SET_UNIT.FilterTypes}: Builds the SET_UNIT with the units belonging to the unit type(s). --- * @{#SET_UNIT.FilterCountries}: Builds the SET_UNIT with the units belonging to the country(ies). --- * @{#SET_UNIT.FilterPrefixes}: Builds the SET_UNIT with the units starting with the same prefix string(s). --- --- Once the filter criteria have been set for the SET_UNIT, you can start filtering using: --- --- * @{#SET_UNIT.FilterStart}: Starts the filtering of the units within the SET_UNIT. --- --- Planned filter criteria within development are (so these are not yet available): --- --- * @{#SET_UNIT.FilterZones}: Builds the SET_UNIT with the units within a @{Zone#ZONE}. --- --- ## 3.4) SET_UNIT iterators --- --- Once the filters have been defined and the SET_UNIT has been built, you can iterate the SET_UNIT with the available iterator methods. --- The iterator methods will walk the SET_UNIT set, and call for each element within the set a function that you provide. --- The following iterator methods are currently available within the SET_UNIT: --- --- * @{#SET_UNIT.ForEachUnit}: Calls a function for each alive unit it finds within the SET_UNIT. --- * @{#SET_GROUP.ForEachGroupCompletelyInZone}: Iterate the SET_GROUP and call an iterator function for each **alive** GROUP presence completely in a @{Zone}, providing the GROUP and optional parameters to the called function. --- * @{#SET_GROUP.ForEachGroupNotInZone}: Iterate the SET_GROUP and call an iterator function for each **alive** GROUP presence not in a @{Zone}, providing the GROUP and optional parameters to the called function. --- --- Planned iterators methods in development are (so these are not yet available): --- --- * @{#SET_UNIT.ForEachUnitInUnit}: Calls a function for each unit contained within the SET_UNIT. --- * @{#SET_UNIT.ForEachUnitCompletelyInZone}: Iterate and call an iterator function for each **alive** UNIT presence completely in a @{Zone}, providing the UNIT and optional parameters to the called function. --- * @{#SET_UNIT.ForEachUnitNotInZone}: Iterate and call an iterator function for each **alive** UNIT presence not in a @{Zone}, providing the UNIT and optional parameters to the called function. --- --- ## 3.5 ) SET_UNIT atomic methods --- --- Various methods exist for a SET_UNIT to perform actions or calculations and retrieve results from the SET_UNIT: --- --- * @{#SET_UNIT.GetTypeNames}(): Retrieve the type names of the @{Unit}s in the SET, delimited by a comma. --- --- === --- @field #SET_UNIT SET_UNIT -SET_UNIT = { - ClassName = "SET_UNIT", - Units = {}, - Filter = { - Coalitions = nil, - Categories = nil, - Types = nil, - Countries = nil, - UnitPrefixes = nil, - }, - FilterMeta = { - Coalitions = { - red = coalition.side.RED, - blue = coalition.side.BLUE, - neutral = coalition.side.NEUTRAL, - }, - Categories = { - plane = Unit.Category.AIRPLANE, - helicopter = Unit.Category.HELICOPTER, - ground = Unit.Category.GROUND_UNIT, - ship = Unit.Category.SHIP, - structure = Unit.Category.STRUCTURE, - }, - }, -} +do -- SET_UNIT - ---- Get the first unit from the set. --- @function [parent=#SET_UNIT] GetFirst --- @param #SET_UNIT self --- @return Wrapper.Unit#UNIT The UNIT object. - ---- Creates a new SET_UNIT object, building a set of units belonging to a coalitions, categories, countries, types or with defined prefix names. --- @param #SET_UNIT self --- @return #SET_UNIT --- @usage --- -- Define a new SET_UNIT Object. This DBObject will contain a reference to all alive Units. --- DBObject = SET_UNIT:New() -function SET_UNIT:New() - - -- Inherits from BASE - local self = BASE:Inherit( self, SET_BASE:New( _DATABASE.UNITS ) ) -- Core.Set#SET_UNIT - - return self -end - ---- Add UNIT(s) to SET_UNIT. --- @param #SET_UNIT self --- @param #string AddUnit A single UNIT. --- @return #SET_UNIT self -function SET_UNIT:AddUnit( AddUnit ) - self:F2( AddUnit:GetName() ) - - self:Add( AddUnit:GetName(), AddUnit ) - - return self -end - - ---- Add UNIT(s) to SET_UNIT. --- @param #SET_UNIT self --- @param #string AddUnitNames A single name or an array of UNIT names. --- @return #SET_UNIT self -function SET_UNIT:AddUnitsByName( AddUnitNames ) - - local AddUnitNamesArray = ( type( AddUnitNames ) == "table" ) and AddUnitNames or { AddUnitNames } + --- @type SET_UNIT + -- @extends Core.Set#SET_BASE - self:T( AddUnitNamesArray ) - for AddUnitID, AddUnitName in pairs( AddUnitNamesArray ) do - self:Add( AddUnitName, UNIT:FindByName( AddUnitName ) ) - end - - return self -end - ---- Remove UNIT(s) from SET_UNIT. --- @param Core.Set#SET_UNIT self --- @param Wrapper.Unit#UNIT RemoveUnitNames A single name or an array of UNIT names. --- @return self -function SET_UNIT:RemoveUnitsByName( RemoveUnitNames ) - - local RemoveUnitNamesArray = ( type( RemoveUnitNames ) == "table" ) and RemoveUnitNames or { RemoveUnitNames } + --- # 3) SET_UNIT class, extends @{Set#SET_BASE} + -- + -- Mission designers can use the SET_UNIT class to build sets of units belonging to certain: + -- + -- * Coalitions + -- * Categories + -- * Countries + -- * Unit types + -- * Starting with certain prefix strings. + -- + -- ## 3.1) SET_UNIT constructor + -- + -- Create a new SET_UNIT object with the @{#SET_UNIT.New} method: + -- + -- * @{#SET_UNIT.New}: Creates a new SET_UNIT object. + -- + -- ## 3.2) Add or Remove UNIT(s) from SET_UNIT + -- + -- UNITs can be added and removed using the @{Set#SET_UNIT.AddUnitsByName} and @{Set#SET_UNIT.RemoveUnitsByName} respectively. + -- These methods take a single UNIT name or an array of UNIT names to be added or removed from SET_UNIT. + -- + -- ## 3.3) SET_UNIT filter criteria + -- + -- You can set filter criteria to define the set of units within the SET_UNIT. + -- Filter criteria are defined by: + -- + -- * @{#SET_UNIT.FilterCoalitions}: Builds the SET_UNIT with the units belonging to the coalition(s). + -- * @{#SET_UNIT.FilterCategories}: Builds the SET_UNIT with the units belonging to the category(ies). + -- * @{#SET_UNIT.FilterTypes}: Builds the SET_UNIT with the units belonging to the unit type(s). + -- * @{#SET_UNIT.FilterCountries}: Builds the SET_UNIT with the units belonging to the country(ies). + -- * @{#SET_UNIT.FilterPrefixes}: Builds the SET_UNIT with the units starting with the same prefix string(s). + -- + -- Once the filter criteria have been set for the SET_UNIT, you can start filtering using: + -- + -- * @{#SET_UNIT.FilterStart}: Starts the filtering of the units within the SET_UNIT. + -- + -- Planned filter criteria within development are (so these are not yet available): + -- + -- * @{#SET_UNIT.FilterZones}: Builds the SET_UNIT with the units within a @{Zone#ZONE}. + -- + -- ## 3.4) SET_UNIT iterators + -- + -- Once the filters have been defined and the SET_UNIT has been built, you can iterate the SET_UNIT with the available iterator methods. + -- The iterator methods will walk the SET_UNIT set, and call for each element within the set a function that you provide. + -- The following iterator methods are currently available within the SET_UNIT: + -- + -- * @{#SET_UNIT.ForEachUnit}: Calls a function for each alive unit it finds within the SET_UNIT. + -- * @{#SET_GROUP.ForEachGroupCompletelyInZone}: Iterate the SET_GROUP and call an iterator function for each **alive** GROUP presence completely in a @{Zone}, providing the GROUP and optional parameters to the called function. + -- * @{#SET_GROUP.ForEachGroupNotInZone}: Iterate the SET_GROUP and call an iterator function for each **alive** GROUP presence not in a @{Zone}, providing the GROUP and optional parameters to the called function. + -- + -- Planned iterators methods in development are (so these are not yet available): + -- + -- * @{#SET_UNIT.ForEachUnitInUnit}: Calls a function for each unit contained within the SET_UNIT. + -- * @{#SET_UNIT.ForEachUnitCompletelyInZone}: Iterate and call an iterator function for each **alive** UNIT presence completely in a @{Zone}, providing the UNIT and optional parameters to the called function. + -- * @{#SET_UNIT.ForEachUnitNotInZone}: Iterate and call an iterator function for each **alive** UNIT presence not in a @{Zone}, providing the UNIT and optional parameters to the called function. + -- + -- ## 3.5 ) SET_UNIT atomic methods + -- + -- Various methods exist for a SET_UNIT to perform actions or calculations and retrieve results from the SET_UNIT: + -- + -- * @{#SET_UNIT.GetTypeNames}(): Retrieve the type names of the @{Unit}s in the SET, delimited by a comma. + -- + -- === + -- @field #SET_UNIT SET_UNIT + SET_UNIT = { + ClassName = "SET_UNIT", + Units = {}, + Filter = { + Coalitions = nil, + Categories = nil, + Types = nil, + Countries = nil, + UnitPrefixes = nil, + }, + FilterMeta = { + Coalitions = { + red = coalition.side.RED, + blue = coalition.side.BLUE, + neutral = coalition.side.NEUTRAL, + }, + Categories = { + plane = Unit.Category.AIRPLANE, + helicopter = Unit.Category.HELICOPTER, + ground = Unit.Category.GROUND_UNIT, + ship = Unit.Category.SHIP, + structure = Unit.Category.STRUCTURE, + }, + }, + } - for RemoveUnitID, RemoveUnitName in pairs( RemoveUnitNamesArray ) do - self:Remove( RemoveUnitName ) + + --- Get the first unit from the set. + -- @function [parent=#SET_UNIT] GetFirst + -- @param #SET_UNIT self + -- @return Wrapper.Unit#UNIT The UNIT object. + + --- Creates a new SET_UNIT object, building a set of units belonging to a coalitions, categories, countries, types or with defined prefix names. + -- @param #SET_UNIT self + -- @return #SET_UNIT + -- @usage + -- -- Define a new SET_UNIT Object. This DBObject will contain a reference to all alive Units. + -- DBObject = SET_UNIT:New() + function SET_UNIT:New() + + -- Inherits from BASE + local self = BASE:Inherit( self, SET_BASE:New( _DATABASE.UNITS ) ) -- Core.Set#SET_UNIT + + return self end + + --- Add UNIT(s) to SET_UNIT. + -- @param #SET_UNIT self + -- @param #string AddUnit A single UNIT. + -- @return #SET_UNIT self + function SET_UNIT:AddUnit( AddUnit ) + self:F2( AddUnit:GetName() ) + + self:Add( AddUnit:GetName(), AddUnit ) + + return self + end + + + --- Add UNIT(s) to SET_UNIT. + -- @param #SET_UNIT self + -- @param #string AddUnitNames A single name or an array of UNIT names. + -- @return #SET_UNIT self + function SET_UNIT:AddUnitsByName( AddUnitNames ) + + local AddUnitNamesArray = ( type( AddUnitNames ) == "table" ) and AddUnitNames or { AddUnitNames } - return self -end + self:T( AddUnitNamesArray ) + for AddUnitID, AddUnitName in pairs( AddUnitNamesArray ) do + self:Add( AddUnitName, UNIT:FindByName( AddUnitName ) ) + end + + return self + end + + --- Remove UNIT(s) from SET_UNIT. + -- @param Core.Set#SET_UNIT self + -- @param Wrapper.Unit#UNIT RemoveUnitNames A single name or an array of UNIT names. + -- @return self + function SET_UNIT:RemoveUnitsByName( RemoveUnitNames ) + + local RemoveUnitNamesArray = ( type( RemoveUnitNames ) == "table" ) and RemoveUnitNames or { RemoveUnitNames } + + for RemoveUnitID, RemoveUnitName in pairs( RemoveUnitNamesArray ) do + self:Remove( RemoveUnitName ) + end + + return self + end + + + --- Finds a Unit based on the Unit Name. + -- @param #SET_UNIT self + -- @param #string UnitName + -- @return Wrapper.Unit#UNIT The found Unit. + function SET_UNIT:FindUnit( UnitName ) + + local UnitFound = self.Set[UnitName] + return UnitFound + end + + + + --- Builds a set of units of coalitions. + -- Possible current coalitions are red, blue and neutral. + -- @param #SET_UNIT self + -- @param #string Coalitions Can take the following values: "red", "blue", "neutral". + -- @return #SET_UNIT self + function SET_UNIT:FilterCoalitions( Coalitions ) - ---- Finds a Unit based on the Unit Name. --- @param #SET_UNIT self --- @param #string UnitName --- @return Wrapper.Unit#UNIT The found Unit. -function SET_UNIT:FindUnit( UnitName ) - - local UnitFound = self.Set[UnitName] - return UnitFound -end - - - ---- Builds a set of units of coalitions. --- Possible current coalitions are red, blue and neutral. --- @param #SET_UNIT self --- @param #string Coalitions Can take the following values: "red", "blue", "neutral". --- @return #SET_UNIT self -function SET_UNIT:FilterCoalitions( Coalitions ) - if not self.Filter.Coalitions then self.Filter.Coalitions = {} - end - if type( Coalitions ) ~= "table" then - Coalitions = { Coalitions } - end - for CoalitionID, Coalition in pairs( Coalitions ) do - self.Filter.Coalitions[Coalition] = Coalition - end - return self -end - - ---- Builds a set of units out of categories. --- Possible current categories are plane, helicopter, ground, ship. --- @param #SET_UNIT self --- @param #string Categories Can take the following values: "plane", "helicopter", "ground", "ship". --- @return #SET_UNIT self -function SET_UNIT:FilterCategories( Categories ) - if not self.Filter.Categories then - self.Filter.Categories = {} - end - if type( Categories ) ~= "table" then - Categories = { Categories } - end - for CategoryID, Category in pairs( Categories ) do - self.Filter.Categories[Category] = Category - end - return self -end - - ---- Builds a set of units of defined unit types. --- Possible current types are those types known within DCS world. --- @param #SET_UNIT self --- @param #string Types Can take those type strings known within DCS world. --- @return #SET_UNIT self -function SET_UNIT:FilterTypes( Types ) - if not self.Filter.Types then - self.Filter.Types = {} - end - if type( Types ) ~= "table" then - Types = { Types } - end - for TypeID, Type in pairs( Types ) do - self.Filter.Types[Type] = Type - end - return self -end - - ---- Builds a set of units of defined countries. --- Possible current countries are those known within DCS world. --- @param #SET_UNIT self --- @param #string Countries Can take those country strings known within DCS world. --- @return #SET_UNIT self -function SET_UNIT:FilterCountries( Countries ) - if not self.Filter.Countries then - self.Filter.Countries = {} - end - if type( Countries ) ~= "table" then - Countries = { Countries } - end - for CountryID, Country in pairs( Countries ) do - self.Filter.Countries[Country] = Country - end - return self -end - - ---- Builds a set of units of defined unit prefixes. --- All the units starting with the given prefixes will be included within the set. --- @param #SET_UNIT self --- @param #string Prefixes The prefix of which the unit name starts with. --- @return #SET_UNIT self -function SET_UNIT:FilterPrefixes( Prefixes ) - if not self.Filter.UnitPrefixes then - self.Filter.UnitPrefixes = {} - end - if type( Prefixes ) ~= "table" then - Prefixes = { Prefixes } - end - for PrefixID, Prefix in pairs( Prefixes ) do - self.Filter.UnitPrefixes[Prefix] = Prefix - end - return self -end - ---- Builds a set of units having a radar of give types. --- All the units having a radar of a given type will be included within the set. --- @param #SET_UNIT self --- @param #table RadarTypes The radar types. --- @return #SET_UNIT self -function SET_UNIT:FilterHasRadar( RadarTypes ) - - self.Filter.RadarTypes = self.Filter.RadarTypes or {} - if type( RadarTypes ) ~= "table" then - RadarTypes = { RadarTypes } - end - for RadarTypeID, RadarType in pairs( RadarTypes ) do - self.Filter.RadarTypes[RadarType] = RadarType - end - return self -end - ---- Builds a set of SEADable units. --- @param #SET_UNIT self --- @return #SET_UNIT self -function SET_UNIT:FilterHasSEAD() - - self.Filter.SEAD = true - return self -end - - - ---- Starts the filtering. --- @param #SET_UNIT self --- @return #SET_UNIT self -function SET_UNIT:FilterStart() - - if _DATABASE then - self:_FilterStart() - end - - return self -end - ---- Handles the Database to check on an event (birth) that the Object was added in the Database. --- This is required, because sometimes the _DATABASE birth event gets called later than the SET_BASE birth event! --- @param #SET_UNIT self --- @param Core.Event#EVENTDATA Event --- @return #string The name of the UNIT --- @return #table The UNIT -function SET_UNIT:AddInDatabase( Event ) - self:F3( { Event } ) - - if Event.IniObjectCategory == 1 then - if not self.Database[Event.IniDCSUnitName] then - self.Database[Event.IniDCSUnitName] = UNIT:Register( Event.IniDCSUnitName ) - self:T3( self.Database[Event.IniDCSUnitName] ) + if type( Coalitions ) ~= "table" then + Coalitions = { Coalitions } end + for CoalitionID, Coalition in pairs( Coalitions ) do + self.Filter.Coalitions[Coalition] = Coalition + end + return self end - return Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName] -end - ---- Handles the Database to check on any event that Object exists in the Database. --- This is required, because sometimes the _DATABASE event gets called later than the SET_BASE event or vise versa! --- @param #SET_UNIT self --- @param Core.Event#EVENTDATA Event --- @return #string The name of the UNIT --- @return #table The UNIT -function SET_UNIT:FindInDatabase( Event ) - self:F2( { Event.IniDCSUnitName, self.Set[Event.IniDCSUnitName], Event } ) - - - return Event.IniDCSUnitName, self.Set[Event.IniDCSUnitName] -end - ---- Iterate the SET_UNIT and call an interator function for each **alive** UNIT, providing the UNIT and optional parameters. --- @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:ForEachUnit( IteratorFunction, ... ) - self:F2( arg ) - self:ForEach( IteratorFunction, arg, self.Set ) - - return self -end - ---- Iterate the SET_UNIT **sorted *per Threat Level** and call an interator function for each **alive** UNIT, providing the UNIT and optional parameters. --- --- @param #SET_UNIT self --- @param #number FromThreatLevel The TreatLevel to start the evaluation **From** (this must be a value between 0 and 10). --- @param #number ToThreatLevel The TreatLevel to stop the evaluation **To** (this must be a value between 0 and 10). --- @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 --- @usage --- --- UnitSet:ForEachUnitPerThreatLevel( 10, 0, --- -- @param Wrapper.Unit#UNIT UnitObject The UNIT object in the UnitSet, that will be passed to the local function for evaluation. --- function( UnitObject ) --- .. logic .. --- end --- ) --- -function SET_UNIT:ForEachUnitPerThreatLevel( FromThreatLevel, ToThreatLevel, IteratorFunction, ... ) --R2.1 Threat Level implementation - self:F2( arg ) + --- Builds a set of units out of categories. + -- Possible current categories are plane, helicopter, ground, ship. + -- @param #SET_UNIT self + -- @param #string Categories Can take the following values: "plane", "helicopter", "ground", "ship". + -- @return #SET_UNIT self + function SET_UNIT:FilterCategories( Categories ) + if not self.Filter.Categories then + self.Filter.Categories = {} + end + if type( Categories ) ~= "table" then + Categories = { Categories } + end + for CategoryID, Category in pairs( Categories ) do + self.Filter.Categories[Category] = Category + end + return self + end - local ThreatLevelSet = {} - if self:Count() ~= 0 then - for UnitName, UnitObject in pairs( self.Set ) do - local Unit = UnitObject -- Wrapper.Unit#UNIT - - local ThreatLevel = Unit:GetThreatLevel() - ThreatLevelSet[ThreatLevel] = ThreatLevelSet[ThreatLevel] or {} - ThreatLevelSet[ThreatLevel].Set = ThreatLevelSet[ThreatLevel].Set or {} - ThreatLevelSet[ThreatLevel].Set[UnitName] = UnitObject - self:E( { ThreatLevel = ThreatLevel, ThreatLevelSet = ThreatLevelSet[ThreatLevel].Set } ) + --- Builds a set of units of defined unit types. + -- Possible current types are those types known within DCS world. + -- @param #SET_UNIT self + -- @param #string Types Can take those type strings known within DCS world. + -- @return #SET_UNIT self + function SET_UNIT:FilterTypes( Types ) + if not self.Filter.Types then + self.Filter.Types = {} + end + if type( Types ) ~= "table" then + Types = { Types } + end + for TypeID, Type in pairs( Types ) do + self.Filter.Types[Type] = Type + end + return self + end + + + --- Builds a set of units of defined countries. + -- Possible current countries are those known within DCS world. + -- @param #SET_UNIT self + -- @param #string Countries Can take those country strings known within DCS world. + -- @return #SET_UNIT self + function SET_UNIT:FilterCountries( Countries ) + if not self.Filter.Countries then + self.Filter.Countries = {} + end + if type( Countries ) ~= "table" then + Countries = { Countries } + end + for CountryID, Country in pairs( Countries ) do + self.Filter.Countries[Country] = Country + end + return self + end + + + --- Builds a set of units of defined unit prefixes. + -- All the units starting with the given prefixes will be included within the set. + -- @param #SET_UNIT self + -- @param #string Prefixes The prefix of which the unit name starts with. + -- @return #SET_UNIT self + function SET_UNIT:FilterPrefixes( Prefixes ) + if not self.Filter.UnitPrefixes then + self.Filter.UnitPrefixes = {} + end + if type( Prefixes ) ~= "table" then + Prefixes = { Prefixes } + end + for PrefixID, Prefix in pairs( Prefixes ) do + self.Filter.UnitPrefixes[Prefix] = Prefix + end + return self + end + + --- Builds a set of units having a radar of give types. + -- All the units having a radar of a given type will be included within the set. + -- @param #SET_UNIT self + -- @param #table RadarTypes The radar types. + -- @return #SET_UNIT self + function SET_UNIT:FilterHasRadar( RadarTypes ) + + self.Filter.RadarTypes = self.Filter.RadarTypes or {} + if type( RadarTypes ) ~= "table" then + RadarTypes = { RadarTypes } + end + for RadarTypeID, RadarType in pairs( RadarTypes ) do + self.Filter.RadarTypes[RadarType] = RadarType + end + return self + end + + --- Builds a set of SEADable units. + -- @param #SET_UNIT self + -- @return #SET_UNIT self + function SET_UNIT:FilterHasSEAD() + + self.Filter.SEAD = true + return self + end + + + + --- Starts the filtering. + -- @param #SET_UNIT self + -- @return #SET_UNIT self + function SET_UNIT:FilterStart() + + if _DATABASE then + self:_FilterStart() end - local ThreatLevelIncrement = FromThreatLevel <= ToThreatLevel and 1 or -1 + return self + end + + --- Handles the Database to check on an event (birth) that the Object was added in the Database. + -- This is required, because sometimes the _DATABASE birth event gets called later than the SET_BASE birth event! + -- @param #SET_UNIT self + -- @param Core.Event#EVENTDATA Event + -- @return #string The name of the UNIT + -- @return #table The UNIT + function SET_UNIT:AddInDatabase( Event ) + self:F3( { Event } ) + + if Event.IniObjectCategory == 1 then + if not self.Database[Event.IniDCSUnitName] then + self.Database[Event.IniDCSUnitName] = UNIT:Register( Event.IniDCSUnitName ) + self:T3( self.Database[Event.IniDCSUnitName] ) + end + end - for ThreatLevel = FromThreatLevel, ToThreatLevel, ThreatLevelIncrement do - self:E( { ThreatLevel = ThreatLevel } ) - local ThreatLevelItem = ThreatLevelSet[ThreatLevel] - if ThreatLevelItem then - self:ForEach( IteratorFunction, arg, ThreatLevelItem.Set ) - end - end + return Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName] end - return self -end - - - ---- Iterate the SET_UNIT and call an iterator function for each **alive** UNIT presence completely in a @{Zone}, providing the UNIT and optional parameters to the called function. --- @param #SET_UNIT self --- @param Core.Zone#ZONE ZoneObject The Zone to be tested for. --- @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:ForEachUnitCompletelyInZone( ZoneObject, IteratorFunction, ... ) - self:F2( arg ) + --- Handles the Database to check on any event that Object exists in the Database. + -- This is required, because sometimes the _DATABASE event gets called later than the SET_BASE event or vise versa! + -- @param #SET_UNIT self + -- @param Core.Event#EVENTDATA Event + -- @return #string The name of the UNIT + -- @return #table The UNIT + function SET_UNIT:FindInDatabase( Event ) + self:F2( { Event.IniDCSUnitName, self.Set[Event.IniDCSUnitName], Event } ) - self:ForEach( IteratorFunction, arg, self.Set, - --- @param Core.Zone#ZONE_BASE ZoneObject - -- @param Wrapper.Unit#UNIT UnitObject - function( ZoneObject, UnitObject ) - if UnitObject:IsInZone( ZoneObject ) then - return true - else - return false - end - end, { ZoneObject } ) - - return self -end - ---- Iterate the SET_UNIT and call an iterator function for each **alive** UNIT presence not in a @{Zone}, providing the UNIT and optional parameters to the called function. --- @param #SET_UNIT self --- @param Core.Zone#ZONE ZoneObject The Zone to be tested for. --- @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:ForEachUnitNotInZone( ZoneObject, IteratorFunction, ... ) - self:F2( arg ) - self:ForEach( IteratorFunction, arg, self.Set, - --- @param Core.Zone#ZONE_BASE ZoneObject - -- @param Wrapper.Unit#UNIT UnitObject - function( ZoneObject, UnitObject ) - if UnitObject:IsNotInZone( ZoneObject ) then - return true - else - return false - end - end, { ZoneObject } ) - - return self -end - ---- Returns map of unit types. --- @param #SET_UNIT self --- @return #map<#string,#number> A map of the unit types found. The key is the UnitTypeName and the value is the amount of unit types found. -function SET_UNIT:GetUnitTypes() - self:F2() - - local MT = {} -- Message Text - local UnitTypes = {} - - for UnitID, UnitData in pairs( self:GetSet() ) do - local TextUnit = UnitData -- Wrapper.Unit#UNIT - if TextUnit:IsAlive() then - local UnitType = TextUnit:GetTypeName() - - if not UnitTypes[UnitType] then - UnitTypes[UnitType] = 1 - else - UnitTypes[UnitType] = UnitTypes[UnitType] + 1 - end - end + return Event.IniDCSUnitName, self.Set[Event.IniDCSUnitName] end - - for UnitTypeID, UnitType in pairs( UnitTypes ) do - MT[#MT+1] = UnitType .. " of " .. UnitTypeID - end - - return UnitTypes -end - - ---- Returns a comma separated string of the unit types with a count in the @{Set}. --- @param #SET_UNIT self --- @return #string The unit types string -function SET_UNIT:GetUnitTypesText() - self:F2() - - local MT = {} -- Message Text - local UnitTypes = self:GetUnitTypes() - for UnitTypeID, UnitType in pairs( UnitTypes ) do - MT[#MT+1] = UnitType .. " of " .. UnitTypeID - end - - return table.concat( MT, ", " ) -end - ---- Returns map of unit threat levels. --- @param #SET_UNIT self --- @return #table. -function SET_UNIT:GetUnitThreatLevels() - self:F2() - - local UnitThreatLevels = {} - for UnitID, UnitData in pairs( self:GetSet() ) do - local ThreatUnit = UnitData -- Wrapper.Unit#UNIT - if ThreatUnit:IsAlive() then - local UnitThreatLevel, UnitThreatLevelText = ThreatUnit:GetThreatLevel() - local ThreatUnitName = ThreatUnit:GetName() + do -- Is Zone methods - UnitThreatLevels[UnitThreatLevel] = UnitThreatLevels[UnitThreatLevel] or {} - UnitThreatLevels[UnitThreatLevel].UnitThreatLevelText = UnitThreatLevelText - UnitThreatLevels[UnitThreatLevel].Units = UnitThreatLevels[UnitThreatLevel].Units or {} - UnitThreatLevels[UnitThreatLevel].Units[ThreatUnitName] = ThreatUnit - end - end - - return UnitThreatLevels -end - ---- Calculate the maxium A2G threat level of the SET_UNIT. --- @param #SET_UNIT self --- @return #number The maximum threatlevel -function SET_UNIT:CalculateThreatLevelA2G() - - local MaxThreatLevelA2G = 0 - local MaxThreatText = "" - for UnitName, UnitData in pairs( self:GetSet() ) do - local ThreatUnit = UnitData -- Wrapper.Unit#UNIT - local ThreatLevelA2G, ThreatText = ThreatUnit:GetThreatLevel() - if ThreatLevelA2G > MaxThreatLevelA2G then - MaxThreatLevelA2G = ThreatLevelA2G - MaxThreatText = ThreatText - end - end - - self:F( { MaxThreatLevelA2G = MaxThreatLevelA2G, MaxThreatText = MaxThreatText } ) - return MaxThreatLevelA2G, MaxThreatText - -end - ---- Get the center coordinate of the SET_UNIT. --- @param #SET_UNIT self --- @return Core.Point#COORDINATE The center coordinate of all the units in the set, including heading in degrees and speed in mps in case of moving units. -function SET_UNIT:GetCoordinate() - - local Coordinate = self:GetFirst():GetCoordinate() - - local x1 = Coordinate.x - local x2 = Coordinate.x - local y1 = Coordinate.y - local y2 = Coordinate.y - local z1 = Coordinate.z - local z2 = Coordinate.z - local MaxVelocity = 0 - local AvgHeading = nil - local MovingCount = 0 - - for UnitName, UnitData in pairs( self:GetSet() ) do - - local Unit = UnitData -- Wrapper.Unit#UNIT - local Coordinate = Unit:GetCoordinate() - - x1 = ( Coordinate.x < x1 ) and Coordinate.x or x1 - x2 = ( Coordinate.x > x2 ) and Coordinate.x or x2 - y1 = ( Coordinate.y < y1 ) and Coordinate.y or y1 - y2 = ( Coordinate.y > y2 ) and Coordinate.y or y2 - z1 = ( Coordinate.y < z1 ) and Coordinate.z or z1 - z2 = ( Coordinate.y > z2 ) and Coordinate.z or z2 - - local Velocity = Coordinate:GetVelocity() - if Velocity ~= 0 then - MaxVelocity = ( MaxVelocity < Velocity ) and Velocity or MaxVelocity - local Heading = Coordinate:GetHeading() - AvgHeading = AvgHeading and ( AvgHeading + Heading ) or Heading - MovingCount = MovingCount + 1 - end - end - - AvgHeading = AvgHeading and ( AvgHeading / MovingCount ) - - Coordinate.x = ( x2 - x1 ) / 2 + x1 - Coordinate.y = ( y2 - y1 ) / 2 + y1 - Coordinate.z = ( z2 - z1 ) / 2 + z1 - Coordinate:SetHeading( AvgHeading ) - Coordinate:SetVelocity( MaxVelocity ) - - self:F( { Coordinate = Coordinate } ) - return Coordinate - -end - ---- Get the maximum velocity of the SET_UNIT. --- @param #SET_UNIT self --- @return #number The speed in mps in case of moving units. -function SET_UNIT:GetVelocity() - - local Coordinate = self:GetFirst():GetCoordinate() - - local MaxVelocity = 0 - - for UnitName, UnitData in pairs( self:GetSet() ) do - - local Unit = UnitData -- Wrapper.Unit#UNIT - local Coordinate = Unit:GetCoordinate() - - local Velocity = Coordinate:GetVelocity() - if Velocity ~= 0 then - MaxVelocity = ( MaxVelocity < Velocity ) and Velocity or MaxVelocity - end - end - - self:F( { MaxVelocity = MaxVelocity } ) - return MaxVelocity - -end - ---- Get the average heading of the SET_UNIT. --- @param #SET_UNIT self --- @return #number Heading Heading in degrees and speed in mps in case of moving units. -function SET_UNIT:GetHeading() - - local HeadingSet = nil - local MovingCount = 0 - - for UnitName, UnitData in pairs( self:GetSet() ) do - - local Unit = UnitData -- Wrapper.Unit#UNIT - local Coordinate = Unit:GetCoordinate() - - local Velocity = Coordinate:GetVelocity() - if Velocity ~= 0 then - local Heading = Coordinate:GetHeading() - if HeadingSet == nil then - HeadingSet = Heading - else - local HeadingDiff = ( HeadingSet - Heading + 180 + 360 ) % 360 - 180 - HeadingDiff = math.abs( HeadingDiff ) - if HeadingDiff > 5 then - HeadingSet = nil - break + --- Check if minimal one element of the SET_UNIT is in the Zone. + -- @param #SET_UNIT self + -- @param Core.Zone#ZONE ZoneTest The Zone to be tested for. + -- @return #boolean + function SET_UNIT:IsPartiallyInZone( ZoneTest ) + + local IsPartiallyInZone = false + + local function EvaluateZone( ZoneUnit ) + + local ZoneUnitName = ZoneUnit:GetName() + self:E( { ZoneUnitName = ZoneUnitName } ) + if self:FindUnit( ZoneUnitName ) then + IsPartiallyInZone = true + self:E( { Found = true } ) + return false end - end - end - end - - return HeadingSet - -end - - - ---- Returns if the @{Set} has targets having a radar (of a given type). --- @param #SET_UNIT self --- @param Dcs.DCSWrapper.Unit#Unit.RadarType RadarType --- @return #number The amount of radars in the Set with the given type -function SET_UNIT:HasRadar( RadarType ) - self:F2( RadarType ) - - local RadarCount = 0 - for UnitID, UnitData in pairs( self:GetSet()) do - local UnitSensorTest = UnitData -- Wrapper.Unit#UNIT - local HasSensors - if RadarType then - HasSensors = UnitSensorTest:HasSensors( Unit.SensorType.RADAR, RadarType ) - else - HasSensors = UnitSensorTest:HasSensors( Unit.SensorType.RADAR ) - end - self:T3(HasSensors) - if HasSensors then - RadarCount = RadarCount + 1 - end - end - - return RadarCount -end - ---- Returns if the @{Set} has targets that can be SEADed. --- @param #SET_UNIT self --- @return #number The amount of SEADable units in the Set -function SET_UNIT:HasSEAD() - self:F2() - - local SEADCount = 0 - for UnitID, UnitData in pairs( self:GetSet()) do - local UnitSEAD = UnitData -- Wrapper.Unit#UNIT - if UnitSEAD:IsAlive() then - local UnitSEADAttributes = UnitSEAD:GetDesc().attributes - - local HasSEAD = UnitSEAD:HasSEAD() - - self:T3(HasSEAD) - if HasSEAD then - SEADCount = SEADCount + 1 + + return true end + + ZoneTest:SearchZone( EvaluateZone ) + + return IsPartiallyInZone end - end - - return SEADCount -end - ---- Returns if the @{Set} has ground targets. --- @param #SET_UNIT self --- @return #number The amount of ground targets in the Set. -function SET_UNIT:HasGroundUnits() - self:F2() - - local GroundUnitCount = 0 - for UnitID, UnitData in pairs( self:GetSet()) do - local UnitTest = UnitData -- Wrapper.Unit#UNIT - if UnitTest:IsGround() then - GroundUnitCount = GroundUnitCount + 1 - end - end - - return GroundUnitCount -end - ---- Returns if the @{Set} has friendly ground units. --- @param #SET_UNIT self --- @return #number The amount of ground targets in the Set. -function SET_UNIT:HasFriendlyUnits( FriendlyCoalition ) - self:F2() - - local FriendlyUnitCount = 0 - for UnitID, UnitData in pairs( self:GetSet()) do - local UnitTest = UnitData -- Wrapper.Unit#UNIT - if UnitTest:IsFriendly( FriendlyCoalition ) then - FriendlyUnitCount = FriendlyUnitCount + 1 - end - end - - return FriendlyUnitCount -end - - - ------ Iterate the SET_UNIT and call an interator function for each **alive** player, providing the Unit of the player and optional parameters. ----- @param #SET_UNIT self ----- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_UNIT. The function needs to accept a UNIT parameter. ----- @return #SET_UNIT self ---function SET_UNIT:ForEachPlayer( IteratorFunction, ... ) --- self:F2( arg ) --- --- self:ForEach( IteratorFunction, arg, self.PlayersAlive ) --- --- return self ---end --- --- ------ Iterate the SET_UNIT and call an interator function for each client, providing the Client to the function and optional parameters. ----- @param #SET_UNIT self ----- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_UNIT. The function needs to accept a CLIENT parameter. ----- @return #SET_UNIT self ---function SET_UNIT:ForEachClient( IteratorFunction, ... ) --- self:F2( arg ) --- --- self:ForEach( IteratorFunction, arg, self.Clients ) --- --- return self ---end - - ---- --- @param #SET_UNIT self --- @param Wrapper.Unit#UNIT MUnit --- @return #SET_UNIT self -function SET_UNIT:IsIncludeObject( MUnit ) - self:F2( MUnit ) - local MUnitInclude = true - - if self.Filter.Coalitions then - local MUnitCoalition = false - for CoalitionID, CoalitionName in pairs( self.Filter.Coalitions ) do - self:T3( { "Coalition:", MUnit:GetCoalition(), self.FilterMeta.Coalitions[CoalitionName], CoalitionName } ) - if self.FilterMeta.Coalitions[CoalitionName] and self.FilterMeta.Coalitions[CoalitionName] == MUnit:GetCoalition() then - MUnitCoalition = true - end - end - MUnitInclude = MUnitInclude and MUnitCoalition - end - - if self.Filter.Categories then - local MUnitCategory = false - for CategoryID, CategoryName in pairs( self.Filter.Categories ) do - self:T3( { "Category:", MUnit:GetDesc().category, self.FilterMeta.Categories[CategoryName], CategoryName } ) - if self.FilterMeta.Categories[CategoryName] and self.FilterMeta.Categories[CategoryName] == MUnit:GetDesc().category then - MUnitCategory = true - end - end - MUnitInclude = MUnitInclude and MUnitCategory - end - - if self.Filter.Types then - local MUnitType = false - for TypeID, TypeName in pairs( self.Filter.Types ) do - self:T3( { "Type:", MUnit:GetTypeName(), TypeName } ) - if TypeName == MUnit:GetTypeName() then - MUnitType = true - end - end - MUnitInclude = MUnitInclude and MUnitType - end - - if self.Filter.Countries then - local MUnitCountry = false - for CountryID, CountryName in pairs( self.Filter.Countries ) do - self:T3( { "Country:", MUnit:GetCountry(), CountryName } ) - if country.id[CountryName] == MUnit:GetCountry() then - MUnitCountry = true - end - end - MUnitInclude = MUnitInclude and MUnitCountry - end - - if self.Filter.UnitPrefixes then - local MUnitPrefix = false - for UnitPrefixId, UnitPrefix in pairs( self.Filter.UnitPrefixes ) do - self:T3( { "Prefix:", string.find( MUnit:GetName(), UnitPrefix, 1 ), UnitPrefix } ) - if string.find( MUnit:GetName(), UnitPrefix, 1 ) then - MUnitPrefix = true - end - end - MUnitInclude = MUnitInclude and MUnitPrefix - end - - if self.Filter.RadarTypes then - local MUnitRadar = false - for RadarTypeID, RadarType in pairs( self.Filter.RadarTypes ) do - self:T3( { "Radar:", RadarType } ) - if MUnit:HasSensors( Unit.SensorType.RADAR, RadarType ) == true then - if MUnit:GetRadar() == true then -- This call is necessary to evaluate the SEAD capability. - self:T3( "RADAR Found" ) - end - MUnitRadar = true - end - end - MUnitInclude = MUnitInclude and MUnitRadar - end - - if self.Filter.SEAD then - local MUnitSEAD = false - if MUnit:HasSEAD() == true then - self:T3( "SEAD Found" ) - MUnitSEAD = true - end - MUnitInclude = MUnitInclude and MUnitSEAD - end - - self:T2( MUnitInclude ) - return MUnitInclude -end - - ---- Retrieve the type names of the @{Unit}s in the SET, delimited by an optional delimiter. --- @param #SET_UNIT self --- @param #string Delimiter (optional) The delimiter, which is default a comma. --- @return #string The types of the @{Unit}s delimited. -function SET_UNIT:GetTypeNames( Delimiter ) - - Delimiter = Delimiter or ", " - local TypeReport = REPORT:New() - local Types = {} - - for UnitName, UnitData in pairs( self:GetSet() ) do - - local Unit = UnitData -- Wrapper.Unit#UNIT - local UnitTypeName = Unit:GetTypeName() - if not Types[UnitTypeName] then - Types[UnitTypeName] = UnitTypeName - TypeReport:Add( UnitTypeName ) + + --- Check if no element of the SET_UNIT is in the Zone. + -- @param #SET_UNIT self + -- @param Core.Zone#ZONE ZoneObject The Zone to be tested for. + -- @return #boolean + function SET_UNIT:IsNotInZone( Zone ) + + local IsNotInZone = true + + local function EvaluateZone( ZoneUnit ) + + local ZoneUnitName = ZoneUnit:GetName() + if self:FindUnit( ZoneUnitName ) then + IsNotInZone = false + return false + end + + return true + end + + Zone:SearchZone( EvaluateZone ) + + 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.Set ) + + return self + end + + + end + + + --- Iterate the SET_UNIT and call an interator function for each **alive** UNIT, providing the UNIT and optional parameters. + -- @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:ForEachUnit( IteratorFunction, ... ) + self:F2( arg ) + + self:ForEach( IteratorFunction, arg, self.Set ) + + return self + end + + --- Iterate the SET_UNIT **sorted *per Threat Level** and call an interator function for each **alive** UNIT, providing the UNIT and optional parameters. + -- + -- @param #SET_UNIT self + -- @param #number FromThreatLevel The TreatLevel to start the evaluation **From** (this must be a value between 0 and 10). + -- @param #number ToThreatLevel The TreatLevel to stop the evaluation **To** (this must be a value between 0 and 10). + -- @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 + -- @usage + -- + -- UnitSet:ForEachUnitPerThreatLevel( 10, 0, + -- -- @param Wrapper.Unit#UNIT UnitObject The UNIT object in the UnitSet, that will be passed to the local function for evaluation. + -- function( UnitObject ) + -- .. logic .. + -- end + -- ) + -- + function SET_UNIT:ForEachUnitPerThreatLevel( FromThreatLevel, ToThreatLevel, IteratorFunction, ... ) --R2.1 Threat Level implementation + self:F2( arg ) + + local ThreatLevelSet = {} + + if self:Count() ~= 0 then + for UnitName, UnitObject in pairs( self.Set ) do + local Unit = UnitObject -- Wrapper.Unit#UNIT + + local ThreatLevel = Unit:GetThreatLevel() + ThreatLevelSet[ThreatLevel] = ThreatLevelSet[ThreatLevel] or {} + ThreatLevelSet[ThreatLevel].Set = ThreatLevelSet[ThreatLevel].Set or {} + ThreatLevelSet[ThreatLevel].Set[UnitName] = UnitObject + self:E( { ThreatLevel = ThreatLevel, ThreatLevelSet = ThreatLevelSet[ThreatLevel].Set } ) + end + + local ThreatLevelIncrement = FromThreatLevel <= ToThreatLevel and 1 or -1 + + for ThreatLevel = FromThreatLevel, ToThreatLevel, ThreatLevelIncrement do + self:E( { ThreatLevel = ThreatLevel } ) + local ThreatLevelItem = ThreatLevelSet[ThreatLevel] + if ThreatLevelItem then + self:ForEach( IteratorFunction, arg, ThreatLevelItem.Set ) + end + end + end + + return self + end + + + + --- Iterate the SET_UNIT and call an iterator function for each **alive** UNIT presence completely in a @{Zone}, providing the UNIT and optional parameters to the called function. + -- @param #SET_UNIT self + -- @param Core.Zone#ZONE ZoneObject The Zone to be tested for. + -- @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:ForEachUnitCompletelyInZone( ZoneObject, IteratorFunction, ... ) + self:F2( arg ) + + self:ForEach( IteratorFunction, arg, self.Set, + --- @param Core.Zone#ZONE_BASE ZoneObject + -- @param Wrapper.Unit#UNIT UnitObject + function( ZoneObject, UnitObject ) + if UnitObject:IsInZone( ZoneObject ) then + return true + else + return false + end + end, { ZoneObject } ) + + return self + end + + --- Iterate the SET_UNIT and call an iterator function for each **alive** UNIT presence not in a @{Zone}, providing the UNIT and optional parameters to the called function. + -- @param #SET_UNIT self + -- @param Core.Zone#ZONE ZoneObject The Zone to be tested for. + -- @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:ForEachUnitNotInZone( ZoneObject, IteratorFunction, ... ) + self:F2( arg ) + + self:ForEach( IteratorFunction, arg, self.Set, + --- @param Core.Zone#ZONE_BASE ZoneObject + -- @param Wrapper.Unit#UNIT UnitObject + function( ZoneObject, UnitObject ) + if UnitObject:IsNotInZone( ZoneObject ) then + return true + else + return false + end + end, { ZoneObject } ) + + return self + end + + --- Returns map of unit types. + -- @param #SET_UNIT self + -- @return #map<#string,#number> A map of the unit types found. The key is the UnitTypeName and the value is the amount of unit types found. + function SET_UNIT:GetUnitTypes() + self:F2() + + local MT = {} -- Message Text + local UnitTypes = {} + + for UnitID, UnitData in pairs( self:GetSet() ) do + local TextUnit = UnitData -- Wrapper.Unit#UNIT + if TextUnit:IsAlive() then + local UnitType = TextUnit:GetTypeName() + + if not UnitTypes[UnitType] then + UnitTypes[UnitType] = 1 + else + UnitTypes[UnitType] = UnitTypes[UnitType] + 1 + end + end + end + + for UnitTypeID, UnitType in pairs( UnitTypes ) do + MT[#MT+1] = UnitType .. " of " .. UnitTypeID + end + + return UnitTypes + end + + + --- Returns a comma separated string of the unit types with a count in the @{Set}. + -- @param #SET_UNIT self + -- @return #string The unit types string + function SET_UNIT:GetUnitTypesText() + self:F2() + + local MT = {} -- Message Text + local UnitTypes = self:GetUnitTypes() + + for UnitTypeID, UnitType in pairs( UnitTypes ) do + MT[#MT+1] = UnitType .. " of " .. UnitTypeID + end + + return table.concat( MT, ", " ) + end + + --- Returns map of unit threat levels. + -- @param #SET_UNIT self + -- @return #table. + function SET_UNIT:GetUnitThreatLevels() + self:F2() + + local UnitThreatLevels = {} + + for UnitID, UnitData in pairs( self:GetSet() ) do + local ThreatUnit = UnitData -- Wrapper.Unit#UNIT + if ThreatUnit:IsAlive() then + local UnitThreatLevel, UnitThreatLevelText = ThreatUnit:GetThreatLevel() + local ThreatUnitName = ThreatUnit:GetName() + + UnitThreatLevels[UnitThreatLevel] = UnitThreatLevels[UnitThreatLevel] or {} + UnitThreatLevels[UnitThreatLevel].UnitThreatLevelText = UnitThreatLevelText + UnitThreatLevels[UnitThreatLevel].Units = UnitThreatLevels[UnitThreatLevel].Units or {} + UnitThreatLevels[UnitThreatLevel].Units[ThreatUnitName] = ThreatUnit + end + end + + return UnitThreatLevels + end + + --- Calculate the maxium A2G threat level of the SET_UNIT. + -- @param #SET_UNIT self + -- @return #number The maximum threatlevel + function SET_UNIT:CalculateThreatLevelA2G() + + local MaxThreatLevelA2G = 0 + local MaxThreatText = "" + for UnitName, UnitData in pairs( self:GetSet() ) do + local ThreatUnit = UnitData -- Wrapper.Unit#UNIT + local ThreatLevelA2G, ThreatText = ThreatUnit:GetThreatLevel() + if ThreatLevelA2G > MaxThreatLevelA2G then + MaxThreatLevelA2G = ThreatLevelA2G + MaxThreatText = ThreatText + end + end + + self:F( { MaxThreatLevelA2G = MaxThreatLevelA2G, MaxThreatText = MaxThreatText } ) + return MaxThreatLevelA2G, MaxThreatText + + end + + --- Get the center coordinate of the SET_UNIT. + -- @param #SET_UNIT self + -- @return Core.Point#COORDINATE The center coordinate of all the units in the set, including heading in degrees and speed in mps in case of moving units. + function SET_UNIT:GetCoordinate() + + local Coordinate = self:GetFirst():GetCoordinate() + + local x1 = Coordinate.x + local x2 = Coordinate.x + local y1 = Coordinate.y + local y2 = Coordinate.y + local z1 = Coordinate.z + local z2 = Coordinate.z + local MaxVelocity = 0 + local AvgHeading = nil + local MovingCount = 0 + + for UnitName, UnitData in pairs( self:GetSet() ) do + + local Unit = UnitData -- Wrapper.Unit#UNIT + local Coordinate = Unit:GetCoordinate() + + x1 = ( Coordinate.x < x1 ) and Coordinate.x or x1 + x2 = ( Coordinate.x > x2 ) and Coordinate.x or x2 + y1 = ( Coordinate.y < y1 ) and Coordinate.y or y1 + y2 = ( Coordinate.y > y2 ) and Coordinate.y or y2 + z1 = ( Coordinate.y < z1 ) and Coordinate.z or z1 + z2 = ( Coordinate.y > z2 ) and Coordinate.z or z2 + + local Velocity = Coordinate:GetVelocity() + if Velocity ~= 0 then + MaxVelocity = ( MaxVelocity < Velocity ) and Velocity or MaxVelocity + local Heading = Coordinate:GetHeading() + AvgHeading = AvgHeading and ( AvgHeading + Heading ) or Heading + MovingCount = MovingCount + 1 + end + end + + AvgHeading = AvgHeading and ( AvgHeading / MovingCount ) + + Coordinate.x = ( x2 - x1 ) / 2 + x1 + Coordinate.y = ( y2 - y1 ) / 2 + y1 + Coordinate.z = ( z2 - z1 ) / 2 + z1 + Coordinate:SetHeading( AvgHeading ) + Coordinate:SetVelocity( MaxVelocity ) + + self:F( { Coordinate = Coordinate } ) + return Coordinate + + end + + --- Get the maximum velocity of the SET_UNIT. + -- @param #SET_UNIT self + -- @return #number The speed in mps in case of moving units. + function SET_UNIT:GetVelocity() + + local Coordinate = self:GetFirst():GetCoordinate() + + local MaxVelocity = 0 + + for UnitName, UnitData in pairs( self:GetSet() ) do + + local Unit = UnitData -- Wrapper.Unit#UNIT + local Coordinate = Unit:GetCoordinate() + + local Velocity = Coordinate:GetVelocity() + if Velocity ~= 0 then + MaxVelocity = ( MaxVelocity < Velocity ) and Velocity or MaxVelocity + end + end + + self:F( { MaxVelocity = MaxVelocity } ) + return MaxVelocity + + end + + --- Get the average heading of the SET_UNIT. + -- @param #SET_UNIT self + -- @return #number Heading Heading in degrees and speed in mps in case of moving units. + function SET_UNIT:GetHeading() + + local HeadingSet = nil + local MovingCount = 0 + + for UnitName, UnitData in pairs( self:GetSet() ) do + + local Unit = UnitData -- Wrapper.Unit#UNIT + local Coordinate = Unit:GetCoordinate() + + local Velocity = Coordinate:GetVelocity() + if Velocity ~= 0 then + local Heading = Coordinate:GetHeading() + if HeadingSet == nil then + HeadingSet = Heading + else + local HeadingDiff = ( HeadingSet - Heading + 180 + 360 ) % 360 - 180 + HeadingDiff = math.abs( HeadingDiff ) + if HeadingDiff > 5 then + HeadingSet = nil + break + end + end + end + end + + return HeadingSet + + end + + + + --- Returns if the @{Set} has targets having a radar (of a given type). + -- @param #SET_UNIT self + -- @param Dcs.DCSWrapper.Unit#Unit.RadarType RadarType + -- @return #number The amount of radars in the Set with the given type + function SET_UNIT:HasRadar( RadarType ) + self:F2( RadarType ) + + local RadarCount = 0 + for UnitID, UnitData in pairs( self:GetSet()) do + local UnitSensorTest = UnitData -- Wrapper.Unit#UNIT + local HasSensors + if RadarType then + HasSensors = UnitSensorTest:HasSensors( Unit.SensorType.RADAR, RadarType ) + else + HasSensors = UnitSensorTest:HasSensors( Unit.SensorType.RADAR ) + end + self:T3(HasSensors) + if HasSensors then + RadarCount = RadarCount + 1 + end + end + + return RadarCount + end + + --- Returns if the @{Set} has targets that can be SEADed. + -- @param #SET_UNIT self + -- @return #number The amount of SEADable units in the Set + function SET_UNIT:HasSEAD() + self:F2() + + local SEADCount = 0 + for UnitID, UnitData in pairs( self:GetSet()) do + local UnitSEAD = UnitData -- Wrapper.Unit#UNIT + if UnitSEAD:IsAlive() then + local UnitSEADAttributes = UnitSEAD:GetDesc().attributes + + local HasSEAD = UnitSEAD:HasSEAD() + + self:T3(HasSEAD) + if HasSEAD then + SEADCount = SEADCount + 1 + end + end + end + + return SEADCount + end + + --- Returns if the @{Set} has ground targets. + -- @param #SET_UNIT self + -- @return #number The amount of ground targets in the Set. + function SET_UNIT:HasGroundUnits() + self:F2() + + local GroundUnitCount = 0 + for UnitID, UnitData in pairs( self:GetSet()) do + local UnitTest = UnitData -- Wrapper.Unit#UNIT + if UnitTest:IsGround() then + GroundUnitCount = GroundUnitCount + 1 + end + end + + return GroundUnitCount + end + + --- Returns if the @{Set} has friendly ground units. + -- @param #SET_UNIT self + -- @return #number The amount of ground targets in the Set. + function SET_UNIT:HasFriendlyUnits( FriendlyCoalition ) + self:F2() + + local FriendlyUnitCount = 0 + for UnitID, UnitData in pairs( self:GetSet()) do + local UnitTest = UnitData -- Wrapper.Unit#UNIT + if UnitTest:IsFriendly( FriendlyCoalition ) then + FriendlyUnitCount = FriendlyUnitCount + 1 + end + end + + return FriendlyUnitCount + end + + + + ----- Iterate the SET_UNIT and call an interator function for each **alive** player, providing the Unit of the player and optional parameters. + ---- @param #SET_UNIT self + ---- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_UNIT. The function needs to accept a UNIT parameter. + ---- @return #SET_UNIT self + --function SET_UNIT:ForEachPlayer( IteratorFunction, ... ) + -- self:F2( arg ) + -- + -- self:ForEach( IteratorFunction, arg, self.PlayersAlive ) + -- + -- return self + --end + -- + -- + ----- Iterate the SET_UNIT and call an interator function for each client, providing the Client to the function and optional parameters. + ---- @param #SET_UNIT self + ---- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_UNIT. The function needs to accept a CLIENT parameter. + ---- @return #SET_UNIT self + --function SET_UNIT:ForEachClient( IteratorFunction, ... ) + -- self:F2( arg ) + -- + -- self:ForEach( IteratorFunction, arg, self.Clients ) + -- + -- return self + --end + + + --- + -- @param #SET_UNIT self + -- @param Wrapper.Unit#UNIT MUnit + -- @return #SET_UNIT self + function SET_UNIT:IsIncludeObject( MUnit ) + self:F2( MUnit ) + local MUnitInclude = true + + if self.Filter.Coalitions then + local MUnitCoalition = false + for CoalitionID, CoalitionName in pairs( self.Filter.Coalitions ) do + self:E( { "Coalition:", MUnit:GetCoalition(), self.FilterMeta.Coalitions[CoalitionName], CoalitionName } ) + if self.FilterMeta.Coalitions[CoalitionName] and self.FilterMeta.Coalitions[CoalitionName] == MUnit:GetCoalition() then + MUnitCoalition = true + end + end + MUnitInclude = MUnitInclude and MUnitCoalition + end + + if self.Filter.Categories then + local MUnitCategory = false + for CategoryID, CategoryName in pairs( self.Filter.Categories ) do + self:T3( { "Category:", MUnit:GetDesc().category, self.FilterMeta.Categories[CategoryName], CategoryName } ) + if self.FilterMeta.Categories[CategoryName] and self.FilterMeta.Categories[CategoryName] == MUnit:GetDesc().category then + MUnitCategory = true + end + end + MUnitInclude = MUnitInclude and MUnitCategory + end + + if self.Filter.Types then + local MUnitType = false + for TypeID, TypeName in pairs( self.Filter.Types ) do + self:T3( { "Type:", MUnit:GetTypeName(), TypeName } ) + if TypeName == MUnit:GetTypeName() then + MUnitType = true + end + end + MUnitInclude = MUnitInclude and MUnitType + end + + if self.Filter.Countries then + local MUnitCountry = false + for CountryID, CountryName in pairs( self.Filter.Countries ) do + self:T3( { "Country:", MUnit:GetCountry(), CountryName } ) + if country.id[CountryName] == MUnit:GetCountry() then + MUnitCountry = true + end + end + MUnitInclude = MUnitInclude and MUnitCountry + end + + if self.Filter.UnitPrefixes then + local MUnitPrefix = false + for UnitPrefixId, UnitPrefix in pairs( self.Filter.UnitPrefixes ) do + self:T3( { "Prefix:", string.find( MUnit:GetName(), UnitPrefix, 1 ), UnitPrefix } ) + if string.find( MUnit:GetName(), UnitPrefix, 1 ) then + MUnitPrefix = true + end + end + MUnitInclude = MUnitInclude and MUnitPrefix + end + + if self.Filter.RadarTypes then + local MUnitRadar = false + for RadarTypeID, RadarType in pairs( self.Filter.RadarTypes ) do + self:T3( { "Radar:", RadarType } ) + if MUnit:HasSensors( Unit.SensorType.RADAR, RadarType ) == true then + if MUnit:GetRadar() == true then -- This call is necessary to evaluate the SEAD capability. + self:T3( "RADAR Found" ) + end + MUnitRadar = true + end + end + MUnitInclude = MUnitInclude and MUnitRadar + end + + if self.Filter.SEAD then + local MUnitSEAD = false + if MUnit:HasSEAD() == true then + self:T3( "SEAD Found" ) + MUnitSEAD = true + end + MUnitInclude = MUnitInclude and MUnitSEAD + end + + self:T2( MUnitInclude ) + return MUnitInclude + end + + + --- Retrieve the type names of the @{Unit}s in the SET, delimited by an optional delimiter. + -- @param #SET_UNIT self + -- @param #string Delimiter (optional) The delimiter, which is default a comma. + -- @return #string The types of the @{Unit}s delimited. + function SET_UNIT:GetTypeNames( Delimiter ) + + Delimiter = Delimiter or ", " + local TypeReport = REPORT:New() + local Types = {} + + for UnitName, UnitData in pairs( self:GetSet() ) do + + local Unit = UnitData -- Wrapper.Unit#UNIT + local UnitTypeName = Unit:GetTypeName() + + if not Types[UnitTypeName] then + Types[UnitTypeName] = UnitTypeName + TypeReport:Add( UnitTypeName ) + end + end + + return TypeReport:Text( Delimiter ) + end + +end + +do -- SET_STATIC + + --- @type SET_STATIC + -- @extends Core.Set#SET_BASE + + --- # 3) SET_STATIC class, extends @{Set#SET_BASE} + -- + -- Mission designers can use the SET_STATIC class to build sets of Statics belonging to certain: + -- + -- * Coalitions + -- * Categories + -- * Countries + -- * Static types + -- * Starting with certain prefix strings. + -- + -- ## 3.1) SET_STATIC constructor + -- + -- Create a new SET_STATIC object with the @{#SET_STATIC.New} method: + -- + -- * @{#SET_STATIC.New}: Creates a new SET_STATIC object. + -- + -- ## 3.2) Add or Remove STATIC(s) from SET_STATIC + -- + -- STATICs can be added and removed using the @{Set#SET_STATIC.AddStaticsByName} and @{Set#SET_STATIC.RemoveStaticsByName} respectively. + -- These methods take a single STATIC name or an array of STATIC names to be added or removed from SET_STATIC. + -- + -- ## 3.3) SET_STATIC filter criteria + -- + -- You can set filter criteria to define the set of units within the SET_STATIC. + -- Filter criteria are defined by: + -- + -- * @{#SET_STATIC.FilterCoalitions}: Builds the SET_STATIC with the units belonging to the coalition(s). + -- * @{#SET_STATIC.FilterCategories}: Builds the SET_STATIC with the units belonging to the category(ies). + -- * @{#SET_STATIC.FilterTypes}: Builds the SET_STATIC with the units belonging to the unit type(s). + -- * @{#SET_STATIC.FilterCountries}: Builds the SET_STATIC with the units belonging to the country(ies). + -- * @{#SET_STATIC.FilterPrefixes}: Builds the SET_STATIC with the units starting with the same prefix string(s). + -- + -- Once the filter criteria have been set for the SET_STATIC, you can start filtering using: + -- + -- * @{#SET_STATIC.FilterStart}: Starts the filtering of the units within the SET_STATIC. + -- + -- Planned filter criteria within development are (so these are not yet available): + -- + -- * @{#SET_STATIC.FilterZones}: Builds the SET_STATIC with the units within a @{Zone#ZONE}. + -- + -- ## 3.4) SET_STATIC iterators + -- + -- Once the filters have been defined and the SET_STATIC has been built, you can iterate the SET_STATIC with the available iterator methods. + -- The iterator methods will walk the SET_STATIC set, and call for each element within the set a function that you provide. + -- The following iterator methods are currently available within the SET_STATIC: + -- + -- * @{#SET_STATIC.ForEachStatic}: Calls a function for each alive unit it finds within the SET_STATIC. + -- * @{#SET_GROUP.ForEachGroupCompletelyInZone}: Iterate the SET_GROUP and call an iterator function for each **alive** GROUP presence completely in a @{Zone}, providing the GROUP and optional parameters to the called function. + -- * @{#SET_GROUP.ForEachGroupNotInZone}: Iterate the SET_GROUP and call an iterator function for each **alive** GROUP presence not in a @{Zone}, providing the GROUP and optional parameters to the called function. + -- + -- Planned iterators methods in development are (so these are not yet available): + -- + -- * @{#SET_STATIC.ForEachStaticInZone}: Calls a function for each unit contained within the SET_STATIC. + -- * @{#SET_STATIC.ForEachStaticCompletelyInZone}: Iterate and call an iterator function for each **alive** STATIC presence completely in a @{Zone}, providing the STATIC and optional parameters to the called function. + -- * @{#SET_STATIC.ForEachStaticNotInZone}: Iterate and call an iterator function for each **alive** STATIC presence not in a @{Zone}, providing the STATIC and optional parameters to the called function. + -- + -- ## 3.5 ) SET_STATIC atomic methods + -- + -- Various methods exist for a SET_STATIC to perform actions or calculations and retrieve results from the SET_STATIC: + -- + -- * @{#SET_STATIC.GetTypeNames}(): Retrieve the type names of the @{Static}s in the SET, delimited by a comma. + -- + -- === + -- @field #SET_STATIC SET_STATIC + SET_STATIC = { + ClassName = "SET_STATIC", + Statics = {}, + Filter = { + Coalitions = nil, + Categories = nil, + Types = nil, + Countries = nil, + StaticPrefixes = nil, + }, + FilterMeta = { + Coalitions = { + red = coalition.side.RED, + blue = coalition.side.BLUE, + neutral = coalition.side.NEUTRAL, + }, + Categories = { + plane = Unit.Category.AIRPLANE, + helicopter = Unit.Category.HELICOPTER, + ground = Unit.Category.GROUND_STATIC, + ship = Unit.Category.SHIP, + structure = Unit.Category.STRUCTURE, + }, + }, + } + + + --- Get the first unit from the set. + -- @function [parent=#SET_STATIC] GetFirst + -- @param #SET_STATIC self + -- @return Wrapper.Static#STATIC The STATIC object. + + --- Creates a new SET_STATIC object, building a set of units belonging to a coalitions, categories, countries, types or with defined prefix names. + -- @param #SET_STATIC self + -- @return #SET_STATIC + -- @usage + -- -- Define a new SET_STATIC Object. This DBObject will contain a reference to all alive Statics. + -- DBObject = SET_STATIC:New() + function SET_STATIC:New() + + -- Inherits from BASE + local self = BASE:Inherit( self, SET_BASE:New( _DATABASE.STATICS ) ) -- Core.Set#SET_STATIC + + return self + end + + --- Add STATIC(s) to SET_STATIC. + -- @param #SET_STATIC self + -- @param #string AddStatic A single STATIC. + -- @return #SET_STATIC self + function SET_STATIC:AddStatic( AddStatic ) + self:F2( AddStatic:GetName() ) + + self:Add( AddStatic:GetName(), AddStatic ) + + return self + end + + + --- Add STATIC(s) to SET_STATIC. + -- @param #SET_STATIC self + -- @param #string AddStaticNames A single name or an array of STATIC names. + -- @return #SET_STATIC self + function SET_STATIC:AddStaticsByName( AddStaticNames ) + + local AddStaticNamesArray = ( type( AddStaticNames ) == "table" ) and AddStaticNames or { AddStaticNames } + + self:T( AddStaticNamesArray ) + for AddStaticID, AddStaticName in pairs( AddStaticNamesArray ) do + self:Add( AddStaticName, STATIC:FindByName( AddStaticName ) ) + end + + return self + end + + --- Remove STATIC(s) from SET_STATIC. + -- @param Core.Set#SET_STATIC self + -- @param Wrapper.Static#STATIC RemoveStaticNames A single name or an array of STATIC names. + -- @return self + function SET_STATIC:RemoveStaticsByName( RemoveStaticNames ) + + local RemoveStaticNamesArray = ( type( RemoveStaticNames ) == "table" ) and RemoveStaticNames or { RemoveStaticNames } + + for RemoveStaticID, RemoveStaticName in pairs( RemoveStaticNamesArray ) do + self:Remove( RemoveStaticName ) + end + + return self + end + + + --- Finds a Static based on the Static Name. + -- @param #SET_STATIC self + -- @param #string StaticName + -- @return Wrapper.Static#STATIC The found Static. + function SET_STATIC:FindStatic( StaticName ) + + local StaticFound = self.Set[StaticName] + return StaticFound + end + + + + --- Builds a set of units of coalitions. + -- Possible current coalitions are red, blue and neutral. + -- @param #SET_STATIC self + -- @param #string Coalitions Can take the following values: "red", "blue", "neutral". + -- @return #SET_STATIC self + function SET_STATIC:FilterCoalitions( Coalitions ) + if not self.Filter.Coalitions then + self.Filter.Coalitions = {} + end + if type( Coalitions ) ~= "table" then + Coalitions = { Coalitions } + end + for CoalitionID, Coalition in pairs( Coalitions ) do + self.Filter.Coalitions[Coalition] = Coalition + end + return self + end + + + --- Builds a set of units out of categories. + -- Possible current categories are plane, helicopter, ground, ship. + -- @param #SET_STATIC self + -- @param #string Categories Can take the following values: "plane", "helicopter", "ground", "ship". + -- @return #SET_STATIC self + function SET_STATIC:FilterCategories( Categories ) + if not self.Filter.Categories then + self.Filter.Categories = {} + end + if type( Categories ) ~= "table" then + Categories = { Categories } + end + for CategoryID, Category in pairs( Categories ) do + self.Filter.Categories[Category] = Category + end + return self + end + + + --- Builds a set of units of defined unit types. + -- Possible current types are those types known within DCS world. + -- @param #SET_STATIC self + -- @param #string Types Can take those type strings known within DCS world. + -- @return #SET_STATIC self + function SET_STATIC:FilterTypes( Types ) + if not self.Filter.Types then + self.Filter.Types = {} + end + if type( Types ) ~= "table" then + Types = { Types } + end + for TypeID, Type in pairs( Types ) do + self.Filter.Types[Type] = Type + end + return self + end + + + --- Builds a set of units of defined countries. + -- Possible current countries are those known within DCS world. + -- @param #SET_STATIC self + -- @param #string Countries Can take those country strings known within DCS world. + -- @return #SET_STATIC self + function SET_STATIC:FilterCountries( Countries ) + if not self.Filter.Countries then + self.Filter.Countries = {} + end + if type( Countries ) ~= "table" then + Countries = { Countries } + end + for CountryID, Country in pairs( Countries ) do + self.Filter.Countries[Country] = Country + end + return self + end + + + --- Builds a set of units of defined unit prefixes. + -- All the units starting with the given prefixes will be included within the set. + -- @param #SET_STATIC self + -- @param #string Prefixes The prefix of which the unit name starts with. + -- @return #SET_STATIC self + function SET_STATIC:FilterPrefixes( Prefixes ) + if not self.Filter.StaticPrefixes then + self.Filter.StaticPrefixes = {} + end + if type( Prefixes ) ~= "table" then + Prefixes = { Prefixes } + end + for PrefixID, Prefix in pairs( Prefixes ) do + self.Filter.StaticPrefixes[Prefix] = Prefix + end + return self + end + + + --- Starts the filtering. + -- @param #SET_STATIC self + -- @return #SET_STATIC self + function SET_STATIC:FilterStart() + + if _DATABASE then + self:_FilterStart() + end + + return self + end + + --- Handles the Database to check on an event (birth) that the Object was added in the Database. + -- This is required, because sometimes the _DATABASE birth event gets called later than the SET_BASE birth event! + -- @param #SET_STATIC self + -- @param Core.Event#EVENTDATA Event + -- @return #string The name of the STATIC + -- @return #table The STATIC + function SET_STATIC:AddInDatabase( Event ) + self:F3( { Event } ) + + if Event.IniObjectCategory == 1 then + if not self.Database[Event.IniDCSStaticName] then + self.Database[Event.IniDCSStaticName] = STATIC:Register( Event.IniDCSStaticName ) + self:T3( self.Database[Event.IniDCSStaticName] ) + end + end + + return Event.IniDCSStaticName, self.Database[Event.IniDCSStaticName] + end + + --- Handles the Database to check on any event that Object exists in the Database. + -- This is required, because sometimes the _DATABASE event gets called later than the SET_BASE event or vise versa! + -- @param #SET_STATIC self + -- @param Core.Event#EVENTDATA Event + -- @return #string The name of the STATIC + -- @return #table The STATIC + function SET_STATIC:FindInDatabase( Event ) + self:F2( { Event.IniDCSStaticName, self.Set[Event.IniDCSStaticName], Event } ) + + + return Event.IniDCSStaticName, self.Set[Event.IniDCSStaticName] + end + + + do -- Is Zone methods + + --- Check if minimal one element of the SET_STATIC is in the Zone. + -- @param #SET_STATIC self + -- @param Core.Zone#ZONE Zone The Zone to be tested for. + -- @return #boolean + function SET_STATIC:IsPatriallyInZone( Zone ) + + local IsPartiallyInZone = false + + local function EvaluateZone( ZoneStatic ) + + local ZoneStaticName = ZoneStatic:GetName() + if self:FindStatic( ZoneStaticName ) then + IsPartiallyInZone = true + return false + end + + return true + end + + return IsPartiallyInZone + end + + + --- Check if no element of the SET_STATIC is in the Zone. + -- @param #SET_STATIC self + -- @param Core.Zone#ZONE ZoneObject The Zone to be tested for. + -- @return #boolean + function SET_STATIC:IsNotInZone( Zone ) + + local IsNotInZone = true + + local function EvaluateZone( ZoneStatic ) + + local ZoneStaticName = ZoneStatic:GetName() + if self:FindStatic( ZoneStaticName ) then + IsNotInZone = false + return false + end + + return true + end + + Zone:Search( EvaluateZone ) + + return IsNotInZone + end + + + --- Check if minimal one element of the SET_STATIC is in the Zone. + -- @param #SET_STATIC self + -- @param #function IteratorFunction The function that will be called when there is an alive STATIC in the SET_STATIC. The function needs to accept a STATIC parameter. + -- @return #SET_STATIC self + function SET_STATIC:ForEachStaticInZone( IteratorFunction, ... ) + self:F2( arg ) + + self:ForEach( IteratorFunction, arg, self.Set ) + + return self + end + + + end + + + --- Iterate the SET_STATIC and call an interator function for each **alive** STATIC, providing the STATIC and optional parameters. + -- @param #SET_STATIC self + -- @param #function IteratorFunction The function that will be called when there is an alive STATIC in the SET_STATIC. The function needs to accept a STATIC parameter. + -- @return #SET_STATIC self + function SET_STATIC:ForEachStatic( IteratorFunction, ... ) + self:F2( arg ) + + self:ForEach( IteratorFunction, arg, self.Set ) + + return self + end + + + --- Iterate the SET_STATIC and call an iterator function for each **alive** STATIC presence completely in a @{Zone}, providing the STATIC and optional parameters to the called function. + -- @param #SET_STATIC self + -- @param Core.Zone#ZONE ZoneObject The Zone to be tested for. + -- @param #function IteratorFunction The function that will be called when there is an alive STATIC in the SET_STATIC. The function needs to accept a STATIC parameter. + -- @return #SET_STATIC self + function SET_STATIC:ForEachStaticCompletelyInZone( ZoneObject, IteratorFunction, ... ) + self:F2( arg ) + + self:ForEach( IteratorFunction, arg, self.Set, + --- @param Core.Zone#ZONE_BASE ZoneObject + -- @param Wrapper.Static#STATIC StaticObject + function( ZoneObject, StaticObject ) + if StaticObject:IsInZone( ZoneObject ) then + return true + else + return false + end + end, { ZoneObject } ) + + return self + end + + --- Iterate the SET_STATIC and call an iterator function for each **alive** STATIC presence not in a @{Zone}, providing the STATIC and optional parameters to the called function. + -- @param #SET_STATIC self + -- @param Core.Zone#ZONE ZoneObject The Zone to be tested for. + -- @param #function IteratorFunction The function that will be called when there is an alive STATIC in the SET_STATIC. The function needs to accept a STATIC parameter. + -- @return #SET_STATIC self + function SET_STATIC:ForEachStaticNotInZone( ZoneObject, IteratorFunction, ... ) + self:F2( arg ) + + self:ForEach( IteratorFunction, arg, self.Set, + --- @param Core.Zone#ZONE_BASE ZoneObject + -- @param Wrapper.Static#STATIC StaticObject + function( ZoneObject, StaticObject ) + if StaticObject:IsNotInZone( ZoneObject ) then + return true + else + return false + end + end, { ZoneObject } ) + + return self + end + + --- Returns map of unit types. + -- @param #SET_STATIC self + -- @return #map<#string,#number> A map of the unit types found. The key is the StaticTypeName and the value is the amount of unit types found. + function SET_STATIC:GetStaticTypes() + self:F2() + + local MT = {} -- Message Text + local StaticTypes = {} + + for StaticID, StaticData in pairs( self:GetSet() ) do + local TextStatic = StaticData -- Wrapper.Static#STATIC + if TextStatic:IsAlive() then + local StaticType = TextStatic:GetTypeName() + + if not StaticTypes[StaticType] then + StaticTypes[StaticType] = 1 + else + StaticTypes[StaticType] = StaticTypes[StaticType] + 1 + end + end + end + + for StaticTypeID, StaticType in pairs( StaticTypes ) do + MT[#MT+1] = StaticType .. " of " .. StaticTypeID + end + + return StaticTypes + end + + + --- Returns a comma separated string of the unit types with a count in the @{Set}. + -- @param #SET_STATIC self + -- @return #string The unit types string + function SET_STATIC:GetStaticTypesText() + self:F2() + + local MT = {} -- Message Text + local StaticTypes = self:GetStaticTypes() + + for StaticTypeID, StaticType in pairs( StaticTypes ) do + MT[#MT+1] = StaticType .. " of " .. StaticTypeID + end + + return table.concat( MT, ", " ) + end + + --- Get the center coordinate of the SET_STATIC. + -- @param #SET_STATIC self + -- @return Core.Point#COORDINATE The center coordinate of all the units in the set, including heading in degrees and speed in mps in case of moving units. + function SET_STATIC:GetCoordinate() + + local Coordinate = self:GetFirst():GetCoordinate() + + local x1 = Coordinate.x + local x2 = Coordinate.x + local y1 = Coordinate.y + local y2 = Coordinate.y + local z1 = Coordinate.z + local z2 = Coordinate.z + local MaxVelocity = 0 + local AvgHeading = nil + local MovingCount = 0 + + for StaticName, StaticData in pairs( self:GetSet() ) do + + local Static = StaticData -- Wrapper.Static#STATIC + local Coordinate = Static:GetCoordinate() + + x1 = ( Coordinate.x < x1 ) and Coordinate.x or x1 + x2 = ( Coordinate.x > x2 ) and Coordinate.x or x2 + y1 = ( Coordinate.y < y1 ) and Coordinate.y or y1 + y2 = ( Coordinate.y > y2 ) and Coordinate.y or y2 + z1 = ( Coordinate.y < z1 ) and Coordinate.z or z1 + z2 = ( Coordinate.y > z2 ) and Coordinate.z or z2 + + local Velocity = Coordinate:GetVelocity() + if Velocity ~= 0 then + MaxVelocity = ( MaxVelocity < Velocity ) and Velocity or MaxVelocity + local Heading = Coordinate:GetHeading() + AvgHeading = AvgHeading and ( AvgHeading + Heading ) or Heading + MovingCount = MovingCount + 1 + end + end + + AvgHeading = AvgHeading and ( AvgHeading / MovingCount ) + + Coordinate.x = ( x2 - x1 ) / 2 + x1 + Coordinate.y = ( y2 - y1 ) / 2 + y1 + Coordinate.z = ( z2 - z1 ) / 2 + z1 + Coordinate:SetHeading( AvgHeading ) + Coordinate:SetVelocity( MaxVelocity ) + + self:F( { Coordinate = Coordinate } ) + return Coordinate + + end + + --- Get the maximum velocity of the SET_STATIC. + -- @param #SET_STATIC self + -- @return #number The speed in mps in case of moving units. + function SET_STATIC:GetVelocity() + + return 0 + + end + + --- Get the average heading of the SET_STATIC. + -- @param #SET_STATIC self + -- @return #number Heading Heading in degrees and speed in mps in case of moving units. + function SET_STATIC:GetHeading() + + local HeadingSet = nil + local MovingCount = 0 + + for StaticName, StaticData in pairs( self:GetSet() ) do + + local Static = StaticData -- Wrapper.Static#STATIC + local Coordinate = Static:GetCoordinate() + + local Velocity = Coordinate:GetVelocity() + if Velocity ~= 0 then + local Heading = Coordinate:GetHeading() + if HeadingSet == nil then + HeadingSet = Heading + else + local HeadingDiff = ( HeadingSet - Heading + 180 + 360 ) % 360 - 180 + HeadingDiff = math.abs( HeadingDiff ) + if HeadingDiff > 5 then + HeadingSet = nil + break + end + end + end + end + + return HeadingSet + + end + + + --- + -- @param #SET_STATIC self + -- @param Wrapper.Static#STATIC MStatic + -- @return #SET_STATIC self + function SET_STATIC:IsIncludeObject( MStatic ) + self:F2( MStatic ) + local MStaticInclude = true + + if self.Filter.Coalitions then + local MStaticCoalition = false + for CoalitionID, CoalitionName in pairs( self.Filter.Coalitions ) do + self:T3( { "Coalition:", MStatic:GetCoalition(), self.FilterMeta.Coalitions[CoalitionName], CoalitionName } ) + if self.FilterMeta.Coalitions[CoalitionName] and self.FilterMeta.Coalitions[CoalitionName] == MStatic:GetCoalition() then + MStaticCoalition = true + end + end + MStaticInclude = MStaticInclude and MStaticCoalition + end + + if self.Filter.Categories then + local MStaticCategory = false + for CategoryID, CategoryName in pairs( self.Filter.Categories ) do + self:T3( { "Category:", MStatic:GetDesc().category, self.FilterMeta.Categories[CategoryName], CategoryName } ) + if self.FilterMeta.Categories[CategoryName] and self.FilterMeta.Categories[CategoryName] == MStatic:GetDesc().category then + MStaticCategory = true + end + end + MStaticInclude = MStaticInclude and MStaticCategory + end + + if self.Filter.Types then + local MStaticType = false + for TypeID, TypeName in pairs( self.Filter.Types ) do + self:T3( { "Type:", MStatic:GetTypeName(), TypeName } ) + if TypeName == MStatic:GetTypeName() then + MStaticType = true + end + end + MStaticInclude = MStaticInclude and MStaticType + end + + if self.Filter.Countries then + local MStaticCountry = false + for CountryID, CountryName in pairs( self.Filter.Countries ) do + self:T3( { "Country:", MStatic:GetCountry(), CountryName } ) + if country.id[CountryName] == MStatic:GetCountry() then + MStaticCountry = true + end + end + MStaticInclude = MStaticInclude and MStaticCountry + end + + if self.Filter.StaticPrefixes then + local MStaticPrefix = false + for StaticPrefixId, StaticPrefix in pairs( self.Filter.StaticPrefixes ) do + self:T3( { "Prefix:", string.find( MStatic:GetName(), StaticPrefix, 1 ), StaticPrefix } ) + if string.find( MStatic:GetName(), StaticPrefix, 1 ) then + MStaticPrefix = true + end + end + MStaticInclude = MStaticInclude and MStaticPrefix + end + + self:T2( MStaticInclude ) + return MStaticInclude + end + + + --- Retrieve the type names of the @{Static}s in the SET, delimited by an optional delimiter. + -- @param #SET_STATIC self + -- @param #string Delimiter (optional) The delimiter, which is default a comma. + -- @return #string The types of the @{Static}s delimited. + function SET_STATIC:GetTypeNames( Delimiter ) + + Delimiter = Delimiter or ", " + local TypeReport = REPORT:New() + local Types = {} + + for StaticName, StaticData in pairs( self:GetSet() ) do + + local Static = StaticData -- Wrapper.Static#STATIC + local StaticTypeName = Static:GetTypeName() + + if not Types[StaticTypeName] then + Types[StaticTypeName] = StaticTypeName + TypeReport:Add( StaticTypeName ) + end + end + + return TypeReport:Text( Delimiter ) end - return TypeReport:Text( Delimiter ) end diff --git a/Moose Development/Moose/Core/Zone.lua b/Moose Development/Moose/Core/Zone.lua index 19f3cbc12..b1c672c10 100644 --- a/Moose Development/Moose/Core/Zone.lua +++ b/Moose Development/Moose/Core/Zone.lua @@ -562,6 +562,39 @@ function ZONE_RADIUS:GetVec3( Height ) end +--- Searches the zone +-- @param #ZONE_RADIUS self +-- @param EvaluateFunction +function ZONE_RADIUS:SearchZone( EvaluateFunction ) + + local SearchZoneResult = true + + local ZoneCoord = self:GetCoordinate() + local ZoneRadius = self:GetRadius() + + self:E({ZoneCoord = ZoneCoord, ZoneRadius = ZoneRadius, ZoneCoordLL = ZoneCoord:ToStringLLDMS()}) + + local SphereSearch = { + id = world.VolumeType.SPHERE, + params = { + point = ZoneCoord:GetVec3(), + radius = ZoneRadius / 2, + } + } + + local function EvaluateZone( DCSZoneUnit ) + + env.info( DCSZoneUnit:getName() ) + + local ZoneUnit = UNIT:Find( DCSZoneUnit ) + + return EvaluateFunction( ZoneUnit ) + end + + world.searchObjects( Object.Category.UNIT, SphereSearch, EvaluateZone ) + +end + --- Returns if a location is within the zone. -- @param #ZONE_RADIUS self -- @param Dcs.DCSTypes#Vec2 Vec2 The location to test. diff --git a/Moose Development/Moose/Functional/Protect.lua b/Moose Development/Moose/Functional/Protect.lua index 151260dbd..a601a3004 100644 --- a/Moose Development/Moose/Functional/Protect.lua +++ b/Moose Development/Moose/Functional/Protect.lua @@ -36,6 +36,7 @@ function PROTECT:New( ProtectZone ) self.ProtectZone = ProtectZone self.ProtectUnitSet = SET_UNIT:New() + self.ProtectStaticSet = SET_STATIC:New() self.CaptureUnitSet = SET_UNIT:New() self:SetStartState( "Idle" ) @@ -62,6 +63,27 @@ function PROTECT:AddProtectUnit( ProtectUnit ) self.ProtectUnitSet:AddUnit( ProtectUnit ) end +--- Get the Protect unit Set. +-- @param #PROTECT self +-- @return Wrapper.Unit#UNIT The Set of capture units. +function PROTECT:GetProtectUnitSet() + return self.ProtectUnitSet +end + +--- Add a static to the protection. +-- @param #PROTECT self +-- @param Wrapper.Unit#UNIT ProtectStatic A @{Static} object to protect. +function PROTECT:AddProtectStatic( ProtectStatic ) + self.ProtectStaticSet:AddStatic( ProtectStatic ) +end + +--- Get the Protect static Set. +-- @param #PROTECT self +-- @return Wrapper.Unit#UNIT The Set of capture statics. +function PROTECT:GetProtectStaticSet() + return self.ProtectStaticSet +end + --- Add a Capture unit to allow to capture the zone. -- @param #PROTECT self -- @param Wrapper.Unit#UNIT CaptureUnit A @{Unit} object to allow a capturing. @@ -98,25 +120,38 @@ function PROTECT:AreProtectUnitsAlive() return IsAlive end +--- Check if the statics are still alive. +-- @param #PROTECT self +function PROTECT:AreProtectStaticsAlive() + + local IsAlive = false + + local StaticSet = self.ProtectStaticSet + StaticSet:Flush() + local StaticList = StaticSet:GetSet() + + for UnitID, ProtectStatic in pairs( StaticList ) do + local IsStaticAlive = ProtectStatic:IsAlive() + if IsStaticAlive == true then + IsAlive = true + break + end + end + + return IsAlive +end + + --- Check if there is a capture unit in the zone. -- @param #PROTECT self function PROTECT:IsCaptureUnitInZone() - local IsInZone = false - local CaptureUnitSet = self.CaptureUnitSet CaptureUnitSet:Flush() - local CaptureUnitList = CaptureUnitSet:GetSet() + + local IsInZone = self.CaptureUnitSet:IsPartiallyInZone( self.ProtectZone ) - for UnitID, CaptureUnit in pairs( CaptureUnitList ) do - local IsUnitAlive = CaptureUnit:IsAlive() - if IsUnitAlive == true then - if CaptureUnit:IsInZone( self.ProtectZone ) then - IsInZone = true - break - end - end - end + self:E({IsInZone = IsInZone}) return IsInZone end @@ -136,7 +171,9 @@ end function PROTECT:onafterCheck() - if self:AreProtectUnitsAlive() or not self:IsCaptureUnitInZone() then + if ( self.ProtectUnitSet and self:AreProtectUnitsAlive() ) or + ( self.ProtectStaticSet and self:AreProtectStaticsAlive() ) or + self:IsCaptureUnitInZone() == false then self:__Check( -1 ) else self:Capture() diff --git a/Moose Mission Setup/Moose.lua b/Moose Mission Setup/Moose.lua index 1a8f63557..640d3276c 100644 --- a/Moose Mission Setup/Moose.lua +++ b/Moose Mission Setup/Moose.lua @@ -1,26370 +1,86 @@ -env.info('*** MOOSE STATIC INCLUDE START *** ') -env.info('Moose Generation Timestamp: 20170928_1256') -env.setErrorMessageBoxEnabled(false) -routines={} -routines.majorVersion=3 -routines.minorVersion=3 -routines.build=22 -routines.utils={} -routines.utils.deepCopy=function(object) -local lookup_table={} -local function _copy(object) -if type(object)~="table"then -return object -elseif lookup_table[object]then -return lookup_table[object] -end -local new_table={} -lookup_table[object]=new_table -for index,value in pairs(object)do -new_table[_copy(index)]=_copy(value) -end -return setmetatable(new_table,getmetatable(object)) -end -local objectreturn=_copy(object) -return objectreturn -end -routines.utils.oneLineSerialize=function(tbl) -lookup_table={} -local function _Serialize(tbl) -if type(tbl)=='table'then -if lookup_table[tbl]then -return lookup_table[object] -end -local tbl_str={} -lookup_table[tbl]=tbl_str -tbl_str[#tbl_str+1]='{' -for ind,val in pairs(tbl)do -local ind_str={} -if type(ind)=="number"then -ind_str[#ind_str+1]='[' -ind_str[#ind_str+1]=tostring(ind) -ind_str[#ind_str+1]=']=' -else -ind_str[#ind_str+1]='[' -ind_str[#ind_str+1]=routines.utils.basicSerialize(ind) -ind_str[#ind_str+1]=']=' -end -local val_str={} -if((type(val)=='number')or(type(val)=='boolean'))then -val_str[#val_str+1]=tostring(val) -val_str[#val_str+1]=',' -tbl_str[#tbl_str+1]=table.concat(ind_str) -tbl_str[#tbl_str+1]=table.concat(val_str) -elseif type(val)=='string'then -val_str[#val_str+1]=routines.utils.basicSerialize(val) -val_str[#val_str+1]=',' -tbl_str[#tbl_str+1]=table.concat(ind_str) -tbl_str[#tbl_str+1]=table.concat(val_str) -elseif type(val)=='nil'then -val_str[#val_str+1]='nil,' -tbl_str[#tbl_str+1]=table.concat(ind_str) -tbl_str[#tbl_str+1]=table.concat(val_str) -elseif type(val)=='table'then -if ind=="__index"then -else -val_str[#val_str+1]=_Serialize(val) -val_str[#val_str+1]=',' -tbl_str[#tbl_str+1]=table.concat(ind_str) -tbl_str[#tbl_str+1]=table.concat(val_str) -end -elseif type(val)=='function'then -else -end -end -tbl_str[#tbl_str+1]='}' -return table.concat(tbl_str) -else -return tostring(tbl) -end -end -local objectreturn=_Serialize(tbl) -return objectreturn -end -routines.utils.basicSerialize=function(s) -if s==nil then -return"\"\"" -else -if((type(s)=='number')or(type(s)=='boolean')or(type(s)=='function')or(type(s)=='table')or(type(s)=='userdata'))then -return tostring(s) -elseif type(s)=='string'then -s=string.format('%q',s) -return s -end -end -end -routines.utils.toDegree=function(angle) -return angle*180/math.pi -end -routines.utils.toRadian=function(angle) -return angle*math.pi/180 -end -routines.utils.metersToNM=function(meters) -return meters/1852 -end -routines.utils.metersToFeet=function(meters) -return meters/0.3048 -end -routines.utils.NMToMeters=function(NM) -return NM*1852 -end -routines.utils.feetToMeters=function(feet) -return feet*0.3048 -end -routines.utils.mpsToKnots=function(mps) -return mps*3600/1852 -end -routines.utils.mpsToKmph=function(mps) -return mps*3.6 -end -routines.utils.knotsToMps=function(knots) -return knots*1852/3600 -end -routines.utils.kmphToMps=function(kmph) -return kmph/3.6 -end -function routines.utils.makeVec2(Vec3) -if Vec3.z then -return{x=Vec3.x,y=Vec3.z} -else -return{x=Vec3.x,y=Vec3.y} -end -end -function routines.utils.makeVec3(Vec2,y) -if not Vec2.z then -if not y then -y=0 -end -return{x=Vec2.x,y=y,z=Vec2.y} -else -return{x=Vec2.x,y=Vec2.y,z=Vec2.z} -end -end -function routines.utils.makeVec3GL(Vec2,offset) -local adj=offset or 0 -if not Vec2.z then -return{x=Vec2.x,y=(land.getHeight(Vec2)+adj),z=Vec2.y} -else -return{x=Vec2.x,y=(land.getHeight({x=Vec2.x,y=Vec2.z})+adj),z=Vec2.z} -end -end -routines.utils.zoneToVec3=function(zone) -local new={} -if type(zone)=='table'and zone.point then -new.x=zone.point.x -new.y=zone.point.y -new.z=zone.point.z -return new -elseif type(zone)=='string'then -zone=trigger.misc.getZone(zone) -if zone then -new.x=zone.point.x -new.y=zone.point.y -new.z=zone.point.z -return new -end -end -end -function routines.utils.getDir(vec,point) -local dir=math.atan2(vec.z,vec.x) -dir=dir+routines.getNorthCorrection(point) -if dir<0 then -dir=dir+2*math.pi -end -return dir -end -function routines.utils.get2DDist(point1,point2) -point1=routines.utils.makeVec3(point1) -point2=routines.utils.makeVec3(point2) -return routines.vec.mag({x=point1.x-point2.x,y=0,z=point1.z-point2.z}) -end -function routines.utils.get3DDist(point1,point2) -return routines.vec.mag({x=point1.x-point2.x,y=point1.y-point2.y,z=point1.z-point2.z}) -end -routines.vec={} -routines.vec.add=function(vec1,vec2) -return{x=vec1.x+vec2.x,y=vec1.y+vec2.y,z=vec1.z+vec2.z} -end -routines.vec.sub=function(vec1,vec2) -return{x=vec1.x-vec2.x,y=vec1.y-vec2.y,z=vec1.z-vec2.z} -end -routines.vec.scalarMult=function(vec,mult) -return{x=vec.x*mult,y=vec.y*mult,z=vec.z*mult} -end -routines.vec.scalar_mult=routines.vec.scalarMult -routines.vec.dp=function(vec1,vec2) -return vec1.x*vec2.x+vec1.y*vec2.y+vec1.z*vec2.z -end -routines.vec.cp=function(vec1,vec2) -return{x=vec1.y*vec2.z-vec1.z*vec2.y,y=vec1.z*vec2.x-vec1.x*vec2.z,z=vec1.x*vec2.y-vec1.y*vec2.x} -end -routines.vec.mag=function(vec) -return(vec.x^2+vec.y^2+vec.z^2)^0.5 -end -routines.vec.getUnitVec=function(vec) -local mag=routines.vec.mag(vec) -return{x=vec.x/mag,y=vec.y/mag,z=vec.z/mag} -end -routines.vec.rotateVec2=function(vec2,theta) -return{x=vec2.x*math.cos(theta)-vec2.y*math.sin(theta),y=vec2.x*math.sin(theta)+vec2.y*math.cos(theta)} -end -routines.tostringMGRS=function(MGRS,acc) -if acc==0 then -return MGRS.UTMZone..' '..MGRS.MGRSDigraph -else -return MGRS.UTMZone..' '..MGRS.MGRSDigraph..' '..string.format('%0'..acc..'d',routines.utils.round(MGRS.Easting/(10^(5-acc)),0)) -..' '..string.format('%0'..acc..'d',routines.utils.round(MGRS.Northing/(10^(5-acc)),0)) -end -end -routines.tostringLL=function(lat,lon,acc,DMS) -local latHemi,lonHemi -if lat>0 then -latHemi='N' -else -latHemi='S' -end -if lon>0 then -lonHemi='E' -else -lonHemi='W' -end -lat=math.abs(lat) -lon=math.abs(lon) -local latDeg=math.floor(lat) -local latMin=(lat-latDeg)*60 -local lonDeg=math.floor(lon) -local lonMin=(lon-lonDeg)*60 -if DMS then -local oldLatMin=latMin -latMin=math.floor(latMin) -local latSec=routines.utils.round((oldLatMin-latMin)*60,acc) -local oldLonMin=lonMin -lonMin=math.floor(lonMin) -local lonSec=routines.utils.round((oldLonMin-lonMin)*60,acc) -if latSec==60 then -latSec=0 -latMin=latMin+1 -end -if lonSec==60 then -lonSec=0 -lonMin=lonMin+1 -end -local secFrmtStr -if acc<=0 then -secFrmtStr='%02d' -else -local width=3+acc -secFrmtStr='%0'..width..'.'..acc..'f' -end -return string.format('%02d',latDeg)..' '..string.format('%02d',latMin)..'\' '..string.format(secFrmtStr,latSec)..'"'..latHemi..' ' -..string.format('%02d',lonDeg)..' '..string.format('%02d',lonMin)..'\' '..string.format(secFrmtStr,lonSec)..'"'..lonHemi -else -latMin=routines.utils.round(latMin,acc) -lonMin=routines.utils.round(lonMin,acc) -if latMin==60 then -latMin=0 -latDeg=latDeg+1 -end -if lonMin==60 then -lonMin=0 -lonDeg=lonDeg+1 -end -local minFrmtStr -if acc<=0 then -minFrmtStr='%02d' -else -local width=3+acc -minFrmtStr='%0'..width..'.'..acc..'f' -end -return string.format('%02d',latDeg)..' '..string.format(minFrmtStr,latMin)..'\''..latHemi..' ' -..string.format('%02d',lonDeg)..' '..string.format(minFrmtStr,lonMin)..'\''..lonHemi -end -end -routines.tostringBR=function(az,dist,alt,metric) -az=routines.utils.round(routines.utils.toDegree(az),0) -if metric then -dist=routines.utils.round(dist/1000,2) -else -dist=routines.utils.round(routines.utils.metersToNM(dist),2) -end -local s=string.format('%03d',az)..' for '..dist -if alt then -if metric then -s=s..' at '..routines.utils.round(alt,0) -else -s=s..' at '..routines.utils.round(routines.utils.metersToFeet(alt),0) -end -end -return s -end -routines.getNorthCorrection=function(point) -if not point.z then -point.z=point.y -point.y=0 -end -local lat,lon=coord.LOtoLL(point) -local north_posit=coord.LLtoLO(lat+1,lon) -return math.atan2(north_posit.z-point.z,north_posit.x-point.x) -end -do -local idNum=0 -routines.addEventHandler=function(f) -local handler={} -idNum=idNum+1 -handler.id=idNum -handler.f=f -handler.onEvent=function(self,event) -self.f(event) -end -world.addEventHandler(handler) -end -routines.removeEventHandler=function(id) -for key,handler in pairs(world.eventHandlers)do -if handler.id and handler.id==id then -world.eventHandlers[key]=nil -return true -end -end -return false -end -end -function routines.getRandPointInCircle(point,radius,innerRadius) -local theta=2*math.pi*math.random() -local rad=math.random()+math.random() -if rad>1 then -rad=2-rad -end -local radMult -if innerRadius and innerRadius<=radius then -radMult=(radius-innerRadius)*rad+innerRadius -else -radMult=radius*rad -end -if not point.z then -point.z=point.y -end -local rndCoord -if radius>0 then -rndCoord={x=math.cos(theta)*radMult+point.x,y=math.sin(theta)*radMult+point.z} -else -rndCoord={x=point.x,y=point.z} -end -return rndCoord -end -routines.goRoute=function(group,path) -local misTask={ -id='Mission', -params={ -route={ -points=routines.utils.deepCopy(path), -}, -}, -} -if type(group)=='string'then -group=Group.getByName(group) -end -local groupCon=group:getController() -if groupCon then -groupCon:setTask(misTask) -return true -end -Controller.setTask(groupCon,misTask) -return false -end -routines.ground={} -routines.fixedWing={} -routines.heli={} -routines.ground.buildWP=function(point,overRideForm,overRideSpeed) -local wp={} -wp.x=point.x -if point.z then -wp.y=point.z -else -wp.y=point.y -end -local form,speed -if point.speed and not overRideSpeed then -wp.speed=point.speed -elseif type(overRideSpeed)=='number'then -wp.speed=overRideSpeed -else -wp.speed=routines.utils.kmphToMps(20) -end -if point.form and not overRideForm then -form=point.form -else -form=overRideForm -end -if not form then -wp.action='Cone' -else -form=string.lower(form) -if form=='off_road'or form=='off road'then -wp.action='Off Road' -elseif form=='on_road'or form=='on road'then -wp.action='On Road' -elseif form=='rank'or form=='line_abrest'or form=='line abrest'or form=='lineabrest'then -wp.action='Rank' -elseif form=='cone'then -wp.action='Cone' -elseif form=='diamond'then -wp.action='Diamond' -elseif form=='vee'then -wp.action='Vee' -elseif form=='echelon_left'or form=='echelon left'or form=='echelonl'then -wp.action='EchelonL' -elseif form=='echelon_right'or form=='echelon right'or form=='echelonr'then -wp.action='EchelonR' -else -wp.action='Cone' -end -end -wp.type='Turning Point' -return wp -end -routines.fixedWing.buildWP=function(point,WPtype,speed,alt,altType) -local wp={} -wp.x=point.x -if point.z then -wp.y=point.z -else -wp.y=point.y -end -if alt and type(alt)=='number'then -wp.alt=alt -else -wp.alt=2000 -end -if altType then -altType=string.lower(altType) -if altType=='radio'or'agl'then -wp.alt_type='RADIO' -elseif altType=='baro'or'asl'then -wp.alt_type='BARO' -end -else -wp.alt_type='RADIO' -end -if point.speed then -speed=point.speed -end -if point.type then -WPtype=point.type -end -if not speed then -wp.speed=routines.utils.kmphToMps(500) -else -wp.speed=speed -end -if not WPtype then -wp.action='Turning Point' -else -WPtype=string.lower(WPtype) -if WPtype=='flyover'or WPtype=='fly over'or WPtype=='fly_over'then -wp.action='Fly Over Point' -elseif WPtype=='turningpoint'or WPtype=='turning point'or WPtype=='turning_point'then -wp.action='Turning Point' -else -wp.action='Turning Point' -end -end -wp.type='Turning Point' -return wp -end -routines.heli.buildWP=function(point,WPtype,speed,alt,altType) -local wp={} -wp.x=point.x -if point.z then -wp.y=point.z -else -wp.y=point.y -end -if alt and type(alt)=='number'then -wp.alt=alt -else -wp.alt=500 -end -if altType then -altType=string.lower(altType) -if altType=='radio'or'agl'then -wp.alt_type='RADIO' -elseif altType=='baro'or'asl'then -wp.alt_type='BARO' -end -else -wp.alt_type='RADIO' -end -if point.speed then -speed=point.speed -end -if point.type then -WPtype=point.type -end -if not speed then -wp.speed=routines.utils.kmphToMps(200) -else -wp.speed=speed -end -if not WPtype then -wp.action='Turning Point' -else -WPtype=string.lower(WPtype) -if WPtype=='flyover'or WPtype=='fly over'or WPtype=='fly_over'then -wp.action='Fly Over Point' -elseif WPtype=='turningpoint'or WPtype=='turning point'or WPtype=='turning_point'then -wp.action='Turning Point' -else -wp.action='Turning Point' -end -end -wp.type='Turning Point' -return wp -end -routines.groupToRandomPoint=function(vars) -local group=vars.group -local point=vars.point -local radius=vars.radius or 0 -local innerRadius=vars.innerRadius -local form=vars.form or'Cone' -local heading=vars.heading or math.random()*2*math.pi -local headingDegrees=vars.headingDegrees -local speed=vars.speed or routines.utils.kmphToMps(20) -local useRoads -if not vars.disableRoads then -useRoads=true -else -useRoads=false -end -local path={} -if headingDegrees then -heading=headingDegrees*math.pi/180 -end -if heading>=2*math.pi then -heading=heading-2*math.pi -end -local rndCoord=routines.getRandPointInCircle(point,radius,innerRadius) -local offset={} -local posStart=routines.getLeadPos(group) -offset.x=routines.utils.round(math.sin(heading-(math.pi/2))*50+rndCoord.x,3) -offset.z=routines.utils.round(math.cos(heading+(math.pi/2))*50+rndCoord.y,3) -path[#path+1]=routines.ground.buildWP(posStart,form,speed) -if useRoads==true and((point.x-posStart.x)^2+(point.z-posStart.z)^2)^0.5>radius*1.3 then -path[#path+1]=routines.ground.buildWP({['x']=posStart.x+11,['z']=posStart.z+11},'off_road',speed) -path[#path+1]=routines.ground.buildWP(posStart,'on_road',speed) -path[#path+1]=routines.ground.buildWP(offset,'on_road',speed) -else -path[#path+1]=routines.ground.buildWP({['x']=posStart.x+25,['z']=posStart.z+25},form,speed) -end -path[#path+1]=routines.ground.buildWP(offset,form,speed) -path[#path+1]=routines.ground.buildWP(rndCoord,form,speed) -routines.goRoute(group,path) -return -end -routines.groupRandomDistSelf=function(gpData,dist,form,heading,speed) -local pos=routines.getLeadPos(gpData) -local fakeZone={} -fakeZone.radius=dist or math.random(300,1000) -fakeZone.point={x=pos.x,y,pos.y,z=pos.z} -routines.groupToRandomZone(gpData,fakeZone,form,heading,speed) -return -end -routines.groupToRandomZone=function(gpData,zone,form,heading,speed) -if type(gpData)=='string'then -gpData=Group.getByName(gpData) -end -if type(zone)=='string'then -zone=trigger.misc.getZone(zone) -elseif type(zone)=='table'and not zone.radius then -zone=trigger.misc.getZone(zone[math.random(1,#zone)]) -end -if speed then -speed=routines.utils.kmphToMps(speed) -end -local vars={} -vars.group=gpData -vars.radius=zone.radius -vars.form=form -vars.headingDegrees=heading -vars.speed=speed -vars.point=routines.utils.zoneToVec3(zone) -routines.groupToRandomPoint(vars) -return -end -routines.isTerrainValid=function(coord,terrainTypes) -if coord.z then -coord.y=coord.z -end -local typeConverted={} -if type(terrainTypes)=='string'then -for constId,constData in pairs(land.SurfaceType)do -if string.lower(constId)==string.lower(terrainTypes)or string.lower(constData)==string.lower(terrainTypes)then -table.insert(typeConverted,constId) -end -end -elseif type(terrainTypes)=='table'then -for typeId,typeData in pairs(terrainTypes)do -for constId,constData in pairs(land.SurfaceType)do -if string.lower(constId)==string.lower(typeData)or string.lower(constData)==string.lower(typeId)then -table.insert(typeConverted,constId) -end -end -end -end -for validIndex,validData in pairs(typeConverted)do -if land.getSurfaceType(coord)==land.SurfaceType[validData]then -return true -end -end -return false -end -routines.groupToPoint=function(gpData,point,form,heading,speed,useRoads) -if type(point)=='string'then -point=trigger.misc.getZone(point) -end -if speed then -speed=routines.utils.kmphToMps(speed) -end -local vars={} -vars.group=gpData -vars.form=form -vars.headingDegrees=heading -vars.speed=speed -vars.disableRoads=useRoads -vars.point=routines.utils.zoneToVec3(point) -routines.groupToRandomPoint(vars) -return -end -routines.getLeadPos=function(group) -if type(group)=='string'then -group=Group.getByName(group) -end -local units=group:getUnits() -local leader=units[1] -if not leader then -local lowestInd=math.huge -for ind,unit in pairs(units)do -if ind0 then -local maxPos=-math.huge -local maxPosInd -for i=1,#unitPosTbl do -local rotatedVec2=routines.vec.rotateVec2(routines.utils.makeVec2(unitPosTbl[i]),heading) -if(not maxPos)or maxPos=1.0 then -CurrentZoneID=routines.IsUnitInZones(CargoUnit,LandingZones) -if CurrentZoneID then -break -end -end -end -end -return CurrentZoneID -end -function routines.IsUnitInZones(TransportUnit,LandingZones) -local TransportZoneResult=nil -local TransportZonePos=nil -local TransportZone=nil -if TransportUnit then -local TransportUnitPos=TransportUnit:getPosition().p -if type(LandingZones)=="table"then -for LandingZoneID,LandingZoneName in pairs(LandingZones)do -TransportZone=trigger.misc.getZone(LandingZoneName) -if TransportZone then -TransportZonePos={radius=TransportZone.radius,x=TransportZone.point.x,y=TransportZone.point.y,z=TransportZone.point.z} -if(((TransportUnitPos.x-TransportZonePos.x)^2+(TransportUnitPos.z-TransportZonePos.z)^2)^0.5<=TransportZonePos.radius)then -TransportZoneResult=LandingZoneID -break -end -end -end -else -TransportZone=trigger.misc.getZone(LandingZones) -TransportZonePos={radius=TransportZone.radius,x=TransportZone.point.x,y=TransportZone.point.y,z=TransportZone.point.z} -if(((TransportUnitPos.x-TransportZonePos.x)^2+(TransportUnitPos.z-TransportZonePos.z)^2)^0.5<=TransportZonePos.radius)then -TransportZoneResult=1 -end -end -if TransportZoneResult then -else -end -return TransportZoneResult -else -return nil -end -end -function routines.IsUnitNearZonesRadius(TransportUnit,LandingZones,ZoneRadius) -local TransportZoneResult=nil -local TransportZonePos=nil -local TransportZone=nil -if TransportUnit then -local TransportUnitPos=TransportUnit:getPosition().p -if type(LandingZones)=="table"then -for LandingZoneID,LandingZoneName in pairs(LandingZones)do -TransportZone=trigger.misc.getZone(LandingZoneName) -if TransportZone then -TransportZonePos={radius=TransportZone.radius,x=TransportZone.point.x,y=TransportZone.point.y,z=TransportZone.point.z} -if(((TransportUnitPos.x-TransportZonePos.x)^2+(TransportUnitPos.z-TransportZonePos.z)^2)^0.5<=ZoneRadius)then -TransportZoneResult=LandingZoneID -break -end -end -end -else -TransportZone=trigger.misc.getZone(LandingZones) -TransportZonePos={radius=TransportZone.radius,x=TransportZone.point.x,y=TransportZone.point.y,z=TransportZone.point.z} -if(((TransportUnitPos.x-TransportZonePos.x)^2+(TransportUnitPos.z-TransportZonePos.z)^2)^0.5<=ZoneRadius)then -TransportZoneResult=1 -end -end -if TransportZoneResult then -else -end -return TransportZoneResult -else -return nil -end -end -function routines.IsStaticInZones(TransportStatic,LandingZones) -local TransportZoneResult=nil -local TransportZonePos=nil -local TransportZone=nil -local TransportStaticPos=TransportStatic:getPosition().p -if type(LandingZones)=="table"then -for LandingZoneID,LandingZoneName in pairs(LandingZones)do -TransportZone=trigger.misc.getZone(LandingZoneName) -if TransportZone then -TransportZonePos={radius=TransportZone.radius,x=TransportZone.point.x,y=TransportZone.point.y,z=TransportZone.point.z} -if(((TransportStaticPos.x-TransportZonePos.x)^2+(TransportStaticPos.z-TransportZonePos.z)^2)^0.5<=TransportZonePos.radius)then -TransportZoneResult=LandingZoneID -break -end -end -end -else -TransportZone=trigger.misc.getZone(LandingZones) -TransportZonePos={radius=TransportZone.radius,x=TransportZone.point.x,y=TransportZone.point.y,z=TransportZone.point.z} -if(((TransportStaticPos.x-TransportZonePos.x)^2+(TransportStaticPos.z-TransportZonePos.z)^2)^0.5<=TransportZonePos.radius)then -TransportZoneResult=1 -end -end -return TransportZoneResult -end -function routines.IsUnitInRadius(CargoUnit,ReferencePosition,Radius) -local Valid=true -local CargoPos=CargoUnit:getPosition().p -local ReferenceP=ReferencePosition.p -if(((CargoPos.x-ReferenceP.x)^2+(CargoPos.z-ReferenceP.z)^2)^0.5<=Radius)then -else -Valid=false -end -return Valid -end -function routines.IsPartOfGroupInRadius(CargoGroup,ReferencePosition,Radius) -local Valid=true -Valid=routines.ValidateGroup(CargoGroup,"CargoGroup",Valid) -local CargoUnits=CargoGroup:getUnits() -for CargoUnitId,CargoUnit in pairs(CargoUnits)do -local CargoUnitPos=CargoUnit:getPosition().p -local ReferenceP=ReferencePosition.p -if(((CargoUnitPos.x-ReferenceP.x)^2+(CargoUnitPos.z-ReferenceP.z)^2)^0.5<=Radius)then -else -Valid=false -break -end -end -return Valid -end -function routines.ValidateString(Variable,VariableName,Valid) -if type(Variable)=="string"then -if Variable==""then -error("routines.ValidateString: error: "..VariableName.." must be filled out!") -Valid=false -end -else -error("routines.ValidateString: error: "..VariableName.." is not a string.") -Valid=false -end -return Valid -end -function routines.ValidateNumber(Variable,VariableName,Valid) -if type(Variable)=="number"then -else -error("routines.ValidateNumber: error: "..VariableName.." is not a number.") -Valid=false -end -return Valid -end -function routines.ValidateGroup(Variable,VariableName,Valid) -if Variable==nil then -error("routines.ValidateGroup: error: "..VariableName.." is a nil value!") -Valid=false -end -return Valid -end -function routines.ValidateZone(LandingZones,VariableName,Valid) -if LandingZones==nil then -error("routines.ValidateGroup: error: "..VariableName.." is a nil value!") -Valid=false -end -if type(LandingZones)=="table"then -for LandingZoneID,LandingZoneName in pairs(LandingZones)do -if trigger.misc.getZone(LandingZoneName)==nil then -error("routines.ValidateGroup: error: Zone "..LandingZoneName.." does not exist!") -Valid=false -break -end -end -else -if trigger.misc.getZone(LandingZones)==nil then -error("routines.ValidateGroup: error: Zone "..LandingZones.." does not exist!") -Valid=false -end -end -return Valid -end -function routines.ValidateEnumeration(Variable,VariableName,Enum,Valid) -local ValidVariable=false -for EnumId,EnumData in pairs(Enum)do -if Variable==EnumData then -ValidVariable=true -break -end -end -if ValidVariable then -else -error('TransportValidateEnum: " .. VariableName .. " is not a valid type.'..Variable) -Valid=false -end -return Valid -end -function routines.getGroupRoute(groupIdent,task) -local gpId=groupIdent -if type(groupIdent)=='string'and not tonumber(groupIdent)then -gpId=_DATABASE.Templates.Groups[groupIdent].groupId -end -for coa_name,coa_data in pairs(env.mission.coalition)do -if(coa_name=='red'or coa_name=='blue')and type(coa_data)=='table'then -if coa_data.country then -for cntry_id,cntry_data in pairs(coa_data.country)do -for obj_type_name,obj_type_data in pairs(cntry_data)do -if obj_type_name=="helicopter"or obj_type_name=="ship"or obj_type_name=="plane"or obj_type_name=="vehicle"then -if((type(obj_type_data)=='table')and obj_type_data.group and(type(obj_type_data.group)=='table')and(#obj_type_data.group>0))then -for group_num,group_data in pairs(obj_type_data.group)do -if group_data and group_data.groupId==gpId then -if group_data.route and group_data.route.points and#group_data.route.points>0 then -local points={} -for point_num,point in pairs(group_data.route.points)do -local routeData={} -if not point.point then -routeData.x=point.x -routeData.y=point.y -else -routeData.point=point.point -end -routeData.form=point.action -routeData.speed=point.speed -routeData.alt=point.alt -routeData.alt_type=point.alt_type -routeData.airdromeId=point.airdromeId -routeData.helipadId=point.helipadId -routeData.type=point.type -routeData.action=point.action -if task then -routeData.task=point.task -end -points[point_num]=routeData -end -return points -end -return -end -end -end -end -end -end -end -end -end -end -routines.ground.patrolRoute=function(vars) -local tempRoute={} -local useRoute={} -local gpData=vars.gpData -if type(gpData)=='string'then -gpData=Group.getByName(gpData) -end -local useGroupRoute -if not vars.useGroupRoute then -useGroupRoute=vars.gpData -else -useGroupRoute=vars.useGroupRoute -end -local routeProvided=false -if not vars.route then -if useGroupRoute then -tempRoute=routines.getGroupRoute(useGroupRoute) -end -else -useRoute=vars.route -local posStart=routines.getLeadPos(gpData) -useRoute[1]=routines.ground.buildWP(posStart,useRoute[1].action,useRoute[1].speed) -routeProvided=true -end -local overRideSpeed=vars.speed or'default' -local pType=vars.pType -local offRoadForm=vars.offRoadForm or'default' -local onRoadForm=vars.onRoadForm or'default' -if routeProvided==false and#tempRoute>0 then -local posStart=routines.getLeadPos(gpData) -useRoute[#useRoute+1]=routines.ground.buildWP(posStart,offRoadForm,overRideSpeed) -for i=1,#tempRoute do -local tempForm=tempRoute[i].action -local tempSpeed=tempRoute[i].speed -if offRoadForm=='default'then -tempForm=tempRoute[i].action -end -if onRoadForm=='default'then -onRoadForm='On Road' -end -if(string.lower(tempRoute[i].action)=='on road'or string.lower(tempRoute[i].action)=='onroad'or string.lower(tempRoute[i].action)=='on_road')then -tempForm=onRoadForm -else -tempForm=offRoadForm -end -if type(overRideSpeed)=='number'then -tempSpeed=overRideSpeed -end -useRoute[#useRoute+1]=routines.ground.buildWP(tempRoute[i],tempForm,tempSpeed) -end -if pType and string.lower(pType)=='doubleback'then -local curRoute=routines.utils.deepCopy(useRoute) -for i=#curRoute,2,-1 do -useRoute[#useRoute+1]=routines.ground.buildWP(curRoute[i],curRoute[i].action,curRoute[i].speed) -end -end -useRoute[1].action=useRoute[#useRoute].action -end -local cTask3={} -local newPatrol={} -newPatrol.route=useRoute -newPatrol.gpData=gpData:getName() -cTask3[#cTask3+1]='routines.ground.patrolRoute(' -cTask3[#cTask3+1]=routines.utils.oneLineSerialize(newPatrol) -cTask3[#cTask3+1]=')' -cTask3=table.concat(cTask3) -local tempTask={ -id='WrappedAction', -params={ -action={ -id='Script', -params={ -command=cTask3, -}, -}, -}, -} -useRoute[#useRoute].task=tempTask -routines.goRoute(gpData,useRoute) -return -end -routines.ground.patrol=function(gpData,pType,form,speed) -local vars={} -if type(gpData)=='table'and gpData:getName()then -gpData=gpData:getName() -end -vars.useGroupRoute=gpData -vars.gpData=gpData -vars.pType=pType -vars.offRoadForm=form -vars.speed=speed -routines.ground.patrolRoute(vars) -return -end -function routines.GetUnitHeight(CheckUnit) -local UnitPoint=CheckUnit:getPoint() -local UnitPosition={x=UnitPoint.x,y=UnitPoint.z} -local UnitHeight=UnitPoint.y -local LandHeight=land.getHeight(UnitPosition) -return UnitHeight-LandHeight -end -Su34Status={status={}} -boardMsgRed={statusMsg=""} -boardMsgAll={timeMsg=""} -SpawnSettings={} -Su34MenuPath={} -Su34Menus=0 -function Su34AttackCarlVinson(groupName) -local groupSu34=Group.getByName(groupName) -local controllerSu34=groupSu34.getController(groupSu34) -local groupCarlVinson=Group.getByName("US Carl Vinson #001") -controllerSu34.setOption(controllerSu34,AI.Option.Air.id.ROE,AI.Option.Air.val.ROE.OPEN_FIRE) -controllerSu34.setOption(controllerSu34,AI.Option.Air.id.REACTION_ON_THREAT,AI.Option.Air.val.REACTION_ON_THREAT.EVADE_FIRE) -if groupCarlVinson~=nil then -controllerSu34.pushTask(controllerSu34,{id='AttackGroup',params={groupId=groupCarlVinson:getID(),expend=AI.Task.WeaponExpend.ALL,attackQtyLimit=true}}) -end -Su34Status.status[groupName]=1 -MessageToRed(string.format('%s: ',groupName)..'Attacking carrier Carl Vinson. ',10,'RedStatus'..groupName) -end -function Su34AttackWest(groupName) -local groupSu34=Group.getByName(groupName) -local controllerSu34=groupSu34.getController(groupSu34) -local groupShipWest1=Group.getByName("US Ship West #001") -local groupShipWest2=Group.getByName("US Ship West #002") -controllerSu34.setOption(controllerSu34,AI.Option.Air.id.ROE,AI.Option.Air.val.ROE.OPEN_FIRE) -controllerSu34.setOption(controllerSu34,AI.Option.Air.id.REACTION_ON_THREAT,AI.Option.Air.val.REACTION_ON_THREAT.EVADE_FIRE) -if groupShipWest1~=nil then -controllerSu34.pushTask(controllerSu34,{id='AttackGroup',params={groupId=groupShipWest1:getID(),expend=AI.Task.WeaponExpend.ALL,attackQtyLimit=true}}) -end -if groupShipWest2~=nil then -controllerSu34.pushTask(controllerSu34,{id='AttackGroup',params={groupId=groupShipWest2:getID(),expend=AI.Task.WeaponExpend.ALL,attackQtyLimit=true}}) -end -Su34Status.status[groupName]=2 -MessageToRed(string.format('%s: ',groupName)..'Attacking invading ships in the west. ',10,'RedStatus'..groupName) -end -function Su34AttackNorth(groupName) -local groupSu34=Group.getByName(groupName) -local controllerSu34=groupSu34.getController(groupSu34) -local groupShipNorth1=Group.getByName("US Ship North #001") -local groupShipNorth2=Group.getByName("US Ship North #002") -local groupShipNorth3=Group.getByName("US Ship North #003") -controllerSu34.setOption(controllerSu34,AI.Option.Air.id.ROE,AI.Option.Air.val.ROE.OPEN_FIRE) -controllerSu34.setOption(controllerSu34,AI.Option.Air.id.REACTION_ON_THREAT,AI.Option.Air.val.REACTION_ON_THREAT.EVADE_FIRE) -if groupShipNorth1~=nil then -controllerSu34.pushTask(controllerSu34,{id='AttackGroup',params={groupId=groupShipNorth1:getID(),expend=AI.Task.WeaponExpend.ALL,attackQtyLimit=false}}) -end -if groupShipNorth2~=nil then -controllerSu34.pushTask(controllerSu34,{id='AttackGroup',params={groupId=groupShipNorth2:getID(),expend=AI.Task.WeaponExpend.ALL,attackQtyLimit=false}}) -end -if groupShipNorth3~=nil then -controllerSu34.pushTask(controllerSu34,{id='AttackGroup',params={groupId=groupShipNorth3:getID(),expend=AI.Task.WeaponExpend.ALL,attackQtyLimit=false}}) -end -Su34Status.status[groupName]=3 -MessageToRed(string.format('%s: ',groupName)..'Attacking invading ships in the north. ',10,'RedStatus'..groupName) -end -function Su34Orbit(groupName) -local groupSu34=Group.getByName(groupName) -local controllerSu34=groupSu34:getController() -controllerSu34.setOption(controllerSu34,AI.Option.Air.id.ROE,AI.Option.Air.val.ROE.WEAPON_HOLD) -controllerSu34.setOption(controllerSu34,AI.Option.Air.id.REACTION_ON_THREAT,AI.Option.Air.val.REACTION_ON_THREAT.EVADE_FIRE) -controllerSu34:pushTask({id='ControlledTask',params={task={id='Orbit',params={pattern=AI.Task.OrbitPattern.RACE_TRACK}},stopCondition={duration=600}}}) -Su34Status.status[groupName]=4 -MessageToRed(string.format('%s: ',groupName)..'In orbit and awaiting further instructions. ',10,'RedStatus'..groupName) -end -function Su34TakeOff(groupName) -local groupSu34=Group.getByName(groupName) -local controllerSu34=groupSu34:getController() -controllerSu34.setOption(controllerSu34,AI.Option.Air.id.ROE,AI.Option.Air.val.ROE.WEAPON_HOLD) -controllerSu34.setOption(controllerSu34,AI.Option.Air.id.REACTION_ON_THREAT,AI.Option.Air.val.REACTION_ON_THREAT.BYPASS_AND_ESCAPE) -Su34Status.status[groupName]=8 -MessageToRed(string.format('%s: ',groupName)..'Take-Off. ',10,'RedStatus'..groupName) -end -function Su34Hold(groupName) -local groupSu34=Group.getByName(groupName) -local controllerSu34=groupSu34:getController() -controllerSu34.setOption(controllerSu34,AI.Option.Air.id.ROE,AI.Option.Air.val.ROE.WEAPON_HOLD) -controllerSu34.setOption(controllerSu34,AI.Option.Air.id.REACTION_ON_THREAT,AI.Option.Air.val.REACTION_ON_THREAT.BYPASS_AND_ESCAPE) -Su34Status.status[groupName]=5 -MessageToRed(string.format('%s: ',groupName)..'Holding Weapons. ',10,'RedStatus'..groupName) -end -function Su34RTB(groupName) -Su34Status.status[groupName]=6 -MessageToRed(string.format('%s: ',groupName)..'Return to Krasnodar. ',10,'RedStatus'..groupName) -end -function Su34Destroyed(groupName) -Su34Status.status[groupName]=7 -MessageToRed(string.format('%s: ',groupName)..'Destroyed. ',30,'RedStatus'..groupName) -end -function GroupAlive(groupName) -local groupTest=Group.getByName(groupName) -local groupExists=false -if groupTest then -groupExists=groupTest:isExist() -end -return groupExists -end -function Su34IsDead() -end -function Su34OverviewStatus() -local msg="" -local currentStatus=0 -local Exists=false -for groupName,currentStatus in pairs(Su34Status.status)do -env.info(('Su34 Overview Status: GroupName = '..groupName)) -Alive=GroupAlive(groupName) -if Alive then -if currentStatus==1 then -msg=msg..string.format("%s: ",groupName) -msg=msg.."Attacking carrier Carl Vinson. " -elseif currentStatus==2 then -msg=msg..string.format("%s: ",groupName) -msg=msg.."Attacking supporting ships in the west. " -elseif currentStatus==3 then -msg=msg..string.format("%s: ",groupName) -msg=msg.."Attacking invading ships in the north. " -elseif currentStatus==4 then -msg=msg..string.format("%s: ",groupName) -msg=msg.."In orbit and awaiting further instructions. " -elseif currentStatus==5 then -msg=msg..string.format("%s: ",groupName) -msg=msg.."Holding Weapons. " -elseif currentStatus==6 then -msg=msg..string.format("%s: ",groupName) -msg=msg.."Return to Krasnodar. " -elseif currentStatus==7 then -msg=msg..string.format("%s: ",groupName) -msg=msg.."Destroyed. " -elseif currentStatus==8 then -msg=msg..string.format("%s: ",groupName) -msg=msg.."Take-Off. " -end -else -if currentStatus==7 then -msg=msg..string.format("%s: ",groupName) -msg=msg.."Destroyed. " -else -Su34Destroyed(groupName) -end -end -end -boardMsgRed.statusMsg=msg -end -function UpdateBoardMsg() -Su34OverviewStatus() -MessageToRed(boardMsgRed.statusMsg,15,'RedStatus') -end -function MusicReset(flg) -trigger.action.setUserFlag(95,flg) -end -function PlaneActivate(groupNameFormat,flg) -local groupName=groupNameFormat..string.format("#%03d",trigger.misc.getUserFlag(flg)) -trigger.action.activateGroup(Group.getByName(groupName)) -end -function Su34Menu(groupName) -local groupSu34=Group.getByName(groupName) -if Su34Status.status[groupName]==1 or -Su34Status.status[groupName]==2 or -Su34Status.status[groupName]==3 or -Su34Status.status[groupName]==4 or -Su34Status.status[groupName]==5 then -if Su34MenuPath[groupName]==nil then -if planeMenuPath==nil then -planeMenuPath=missionCommands.addSubMenuForCoalition( -coalition.side.RED, -"SU-34 anti-ship flights", -nil -) -end -Su34MenuPath[groupName]=missionCommands.addSubMenuForCoalition( -coalition.side.RED, -"Flight "..groupName, -planeMenuPath -) -missionCommands.addCommandForCoalition( -coalition.side.RED, -"Attack carrier Carl Vinson", -Su34MenuPath[groupName], -Su34AttackCarlVinson, -groupName -) -missionCommands.addCommandForCoalition( -coalition.side.RED, -"Attack ships in the west", -Su34MenuPath[groupName], -Su34AttackWest, -groupName -) -missionCommands.addCommandForCoalition( -coalition.side.RED, -"Attack ships in the north", -Su34MenuPath[groupName], -Su34AttackNorth, -groupName -) -missionCommands.addCommandForCoalition( -coalition.side.RED, -"Hold position and await instructions", -Su34MenuPath[groupName], -Su34Orbit, -groupName -) -missionCommands.addCommandForCoalition( -coalition.side.RED, -"Report status", -Su34MenuPath[groupName], -Su34OverviewStatus -) -end -else -if Su34MenuPath[groupName]then -missionCommands.removeItemForCoalition(coalition.side.RED,Su34MenuPath[groupName]) -end -end -end -function ChooseInfantry(TeleportPrefixTable,TeleportMax) -TeleportPrefixTableCount=#TeleportPrefixTable -TeleportPrefixTableIndex=math.random(1,TeleportPrefixTableCount) -local TeleportFound=false -local TeleportLoop=true -local Index=TeleportPrefixTableIndex -local TeleportPrefix='' -while TeleportLoop do -TeleportPrefix=TeleportPrefixTable[Index] -if SpawnSettings[TeleportPrefix]then -if SpawnSettings[TeleportPrefix]['SpawnCount']-10 then -local PlayerFound=false -local MusicStart=0 -local MusicTime=0 -for SndQueueIdx,SndQueue in pairs(_MusicTable.Queue)do -if SndQueue.PlayerName==PlayerName then -PlayerFound=true -MusicStart=SndQueue.Start -MusicTime=_MusicTable.Files[SndQueue.Ref].Time -break -end -end -if PlayerFound then -if MusicStart+MusicTime<=timer.getTime()then -MusicOut=true -end -else -MusicOut=true -end -end -if MusicOut then -else -end -return MusicOut -end -function MusicScheduler() -if _MusicTable['Queue']~=nil and _MusicTable.FileCnt>0 then -for SndQueueIdx,SndQueue in pairs(_MusicTable.Queue)do -if SndQueue.Continue then -if MusicCanStart(SndQueue.PlayerName)then -MusicToPlayer('',SndQueue.PlayerName,true) -end -end -end -end -end -env.info(('Init: Scripts Loaded v1.1')) -SMOKECOLOR=trigger.smokeColor -FLARECOLOR=trigger.flareColor -UTILS={ -_MarkID=1 -} -UTILS.IsInstanceOf=function(object,className) -if not type(className)=='string'then -if type(className)=='table'and className.IsInstanceOf~=nil then -className=className.ClassName -else -local err_str='className parameter should be a string; parameter received: '..type(className) -self:E(err_str) -return false -end -end -if type(object)=='table'and object.IsInstanceOf~=nil then -return object:IsInstanceOf(className) -else -local basicDataTypes={'string','number','function','boolean','nil','table'} -for _,basicDataType in ipairs(basicDataTypes)do -if className==basicDataType then -return type(object)==basicDataType -end -end -end -return false -end -UTILS.DeepCopy=function(object) -local lookup_table={} -local function _copy(object) -if type(object)~="table"then -return object -elseif lookup_table[object]then -return lookup_table[object] -end -local new_table={} -lookup_table[object]=new_table -for index,value in pairs(object)do -new_table[_copy(index)]=_copy(value) -end -return setmetatable(new_table,getmetatable(object)) -end -local objectreturn=_copy(object) -return objectreturn -end -UTILS.OneLineSerialize=function(tbl) -lookup_table={} -local function _Serialize(tbl) -if type(tbl)=='table'then -if lookup_table[tbl]then -return lookup_table[object] -end -local tbl_str={} -lookup_table[tbl]=tbl_str -tbl_str[#tbl_str+1]='{' -for ind,val in pairs(tbl)do -local ind_str={} -if type(ind)=="number"then -ind_str[#ind_str+1]='[' -ind_str[#ind_str+1]=tostring(ind) -ind_str[#ind_str+1]=']=' -else -ind_str[#ind_str+1]='[' -ind_str[#ind_str+1]=routines.utils.basicSerialize(ind) -ind_str[#ind_str+1]=']=' -end -local val_str={} -if((type(val)=='number')or(type(val)=='boolean'))then -val_str[#val_str+1]=tostring(val) -val_str[#val_str+1]=',' -tbl_str[#tbl_str+1]=table.concat(ind_str) -tbl_str[#tbl_str+1]=table.concat(val_str) -elseif type(val)=='string'then -val_str[#val_str+1]=routines.utils.basicSerialize(val) -val_str[#val_str+1]=',' -tbl_str[#tbl_str+1]=table.concat(ind_str) -tbl_str[#tbl_str+1]=table.concat(val_str) -elseif type(val)=='nil'then -val_str[#val_str+1]='nil,' -tbl_str[#tbl_str+1]=table.concat(ind_str) -tbl_str[#tbl_str+1]=table.concat(val_str) -elseif type(val)=='table'then -if ind=="__index"then -else -val_str[#val_str+1]=_Serialize(val) -val_str[#val_str+1]=',' -tbl_str[#tbl_str+1]=table.concat(ind_str) -tbl_str[#tbl_str+1]=table.concat(val_str) -end -elseif type(val)=='function'then -tbl_str[#tbl_str+1]="f() "..tostring(ind) -tbl_str[#tbl_str+1]=',' -else -env.info('unable to serialize value type '..routines.utils.basicSerialize(type(val))..' at index '..tostring(ind)) -env.info(debug.traceback()) -end -end -tbl_str[#tbl_str+1]='}' -return table.concat(tbl_str) -else -return tostring(tbl) -end -end -local objectreturn=_Serialize(tbl) -return objectreturn -end -UTILS.BasicSerialize=function(s) -if s==nil then -return"\"\"" -else -if((type(s)=='number')or(type(s)=='boolean')or(type(s)=='function')or(type(s)=='table')or(type(s)=='userdata'))then -return tostring(s) -elseif type(s)=='string'then -s=string.format('%q',s) -return s -end -end -end -UTILS.ToDegree=function(angle) -return angle*180/math.pi -end -UTILS.ToRadian=function(angle) -return angle*math.pi/180 -end -UTILS.MetersToNM=function(meters) -return meters/1852 -end -UTILS.MetersToFeet=function(meters) -return meters/0.3048 -end -UTILS.NMToMeters=function(NM) -return NM*1852 -end -UTILS.FeetToMeters=function(feet) -return feet*0.3048 -end -UTILS.MpsToKnots=function(mps) -return mps*3600/1852 -end -UTILS.MpsToKmph=function(mps) -return mps*3.6 -end -UTILS.KnotsToMps=function(knots) -return knots*1852/3600 -end -UTILS.KnotsToKmph=function(knots) -return knots*1.852 -end -UTILS.KmphToMps=function(kmph) -return kmph/3.6 -end -UTILS.tostringLL=function(lat,lon,acc,DMS) -local latHemi,lonHemi -if lat>0 then -latHemi='N' -else -latHemi='S' -end -if lon>0 then -lonHemi='E' -else -lonHemi='W' -end -lat=math.abs(lat) -lon=math.abs(lon) -local latDeg=math.floor(lat) -local latMin=(lat-latDeg)*60 -local lonDeg=math.floor(lon) -local lonMin=(lon-lonDeg)*60 -if DMS then -local oldLatMin=latMin -latMin=math.floor(latMin) -local latSec=UTILS.Round((oldLatMin-latMin)*60,acc) -local oldLonMin=lonMin -lonMin=math.floor(lonMin) -local lonSec=UTILS.Round((oldLonMin-lonMin)*60,acc) -if latSec==60 then -latSec=0 -latMin=latMin+1 -end -if lonSec==60 then -lonSec=0 -lonMin=lonMin+1 -end -local secFrmtStr -secFrmtStr='%02d' -return string.format('%02d',latDeg)..' '..string.format('%02d',latMin)..'\' '..string.format(secFrmtStr,latSec)..'"'..latHemi..' ' -..string.format('%02d',lonDeg)..' '..string.format('%02d',lonMin)..'\' '..string.format(secFrmtStr,lonSec)..'"'..lonHemi -else -latMin=UTILS.Round(latMin,acc) -lonMin=UTILS.Round(lonMin,acc) -if latMin==60 then -latMin=0 -latDeg=latDeg+1 -end -if lonMin==60 then -lonMin=0 -lonDeg=lonDeg+1 -end -local minFrmtStr -if acc<=0 then -minFrmtStr='%02d' -else -local width=3+acc -minFrmtStr='%0'..width..'.'..acc..'f' -end -return string.format('%02d',latDeg)..' '..string.format(minFrmtStr,latMin)..'\''..latHemi..' ' -..string.format('%02d',lonDeg)..' '..string.format(minFrmtStr,lonMin)..'\''..lonHemi -end -end -UTILS.tostringMGRS=function(MGRS,acc) -if acc==0 then -return MGRS.UTMZone..' '..MGRS.MGRSDigraph -else -return MGRS.UTMZone..' '..MGRS.MGRSDigraph..' '..string.format('%0'..acc..'d',UTILS.Round(MGRS.Easting/(10^(5-acc)),0)) -..' '..string.format('%0'..acc..'d',UTILS.Round(MGRS.Northing/(10^(5-acc)),0)) -end -end -function UTILS.Round(num,idp) -local mult=10^(idp or 0) -return math.floor(num*mult+0.5)/mult -end -function UTILS.DoString(s) -local f,err=loadstring(s) -if f then -return true,f() -else -return false,err -end -end -function UTILS.spairs(t,order) -local keys={} -for k in pairs(t)do keys[#keys+1]=k end -if order then -table.sort(keys,function(a,b)return order(t,a,b)end) -else -table.sort(keys) -end -local i=0 -return function() -i=i+1 -if keys[i]then -return keys[i],t[keys[i]] -end -end -end -function UTILS.GetMarkID() -UTILS._MarkID=UTILS._MarkID+1 -return UTILS._MarkID -end -function UTILS.IsInRadius(InVec2,Vec2,Radius) -local InRadius=((InVec2.x-Vec2.x)^2+(InVec2.y-Vec2.y)^2)^0.5<=Radius -return InRadius -end -function UTILS.IsInSphere(InVec3,Vec3,Radius) -local InSphere=((InVec3.x-Vec3.x)^2+(InVec3.y-Vec3.y)^2+(InVec3.z-Vec3.z)^2)^0.5<=Radius -return InSphere -end -local _TraceOnOff=true -local _TraceLevel=1 -local _TraceAll=false -local _TraceClass={} -local _TraceClassMethod={} -local _ClassID=0 -BASE={ -ClassName="BASE", -ClassID=0, -Events={}, -States={}, -} -BASE.__={} -BASE._={ -Schedules={} -} -FORMATION={ -Cone="Cone", -Vee="Vee" -} -function BASE:New() -local self=routines.utils.deepCopy(self) -_ClassID=_ClassID+1 -self.ClassID=_ClassID -return self -end -function BASE:Inherit(Child,Parent) -local Child=routines.utils.deepCopy(Child) -if Child~=nil then -if rawget(Child,"__")then -setmetatable(Child,{__index=Child.__}) -setmetatable(Child.__,{__index=Parent}) -else -setmetatable(Child,{__index=Parent}) -end -end -return Child -end -function BASE:GetParent(Child) -local Parent -if Child.ClassName=='BASE'then -Parent=nil -elseif rawget(Child,"__")then -Parent=getmetatable(Child.__).__index -else -Parent=getmetatable(Child).__index -end -return Parent -end -function BASE:IsInstanceOf(ClassName) -if type(ClassName)~='string'then -if type(ClassName)=='table'and ClassName.ClassName~=nil then -ClassName=ClassName.ClassName -else -local err_str='className parameter should be a string; parameter received: '..type(ClassName) -self:E(err_str) -return false -end -end -ClassName=string.upper(ClassName) -if string.upper(self.ClassName)==ClassName then -return true -end -local Parent=self:GetParent(self) -while Parent do -if string.upper(Parent.ClassName)==ClassName then -return true -end -Parent=Parent:GetParent(Parent) -end -return false -end -function BASE:GetClassNameAndID() -return string.format('%s#%09d',self.ClassName,self.ClassID) -end -function BASE:GetClassName() -return self.ClassName -end -function BASE:GetClassID() -return self.ClassID -end -do -function BASE:EventDispatcher() -return _EVENTDISPATCHER -end -function BASE:GetEventPriority() -return self._.EventPriority or 5 -end -function BASE:SetEventPriority(EventPriority) -self._.EventPriority=EventPriority -end -function BASE:EventRemoveAll() -self:EventDispatcher():RemoveAll(self) -return self -end -function BASE:HandleEvent(Event,EventFunction) -self:EventDispatcher():OnEventGeneric(EventFunction,self,Event) -return self -end -function BASE:UnHandleEvent(Event) -self:EventDispatcher():RemoveEvent(self,Event) -return self -end -end -function BASE:CreateEventBirth(EventTime,Initiator,IniUnitName,place,subplace) -self:F({EventTime,Initiator,IniUnitName,place,subplace}) -local Event={ -id=world.event.S_EVENT_BIRTH, -time=EventTime, -initiator=Initiator, -IniUnitName=IniUnitName, -place=place, -subplace=subplace -} -world.onEvent(Event) -end -function BASE:CreateEventCrash(EventTime,Initiator) -self:F({EventTime,Initiator}) -local Event={ -id=world.event.S_EVENT_CRASH, -time=EventTime, -initiator=Initiator, -} -world.onEvent(Event) -end -function BASE:CreateEventTakeoff(EventTime,Initiator) -self:F({EventTime,Initiator}) -local Event={ -id=world.event.S_EVENT_TAKEOFF, -time=EventTime, -initiator=Initiator, -} -world.onEvent(Event) -end -function BASE:onEvent(event) -if self then -for EventID,EventObject in pairs(self.Events)do -if EventObject.EventEnabled then -if event.id==EventObject.Event then -if self==EventObject.Self then -if event.initiator and event.initiator:isExist()then -event.IniUnitName=event.initiator:getName() -end -if event.target and event.target:isExist()then -event.TgtUnitName=event.target:getName() -end -end -end -end -end -end -end -do -function BASE:ScheduleOnce(Start,SchedulerFunction,...) -self:F2({Start}) -self:T3({...}) -local ObjectName="-" -ObjectName=self.ClassName..self.ClassID -self:F3({"ScheduleOnce: ",ObjectName,Start}) -self.SchedulerObject=self -local ScheduleID=_SCHEDULEDISPATCHER:AddSchedule( -self, -SchedulerFunction, -{...}, -Start, -nil, -nil, -nil -) -self._.Schedules[#self.Schedules+1]=ScheduleID -return self._.Schedules -end -function BASE:ScheduleRepeat(Start,Repeat,RandomizeFactor,Stop,SchedulerFunction,...) -self:F2({Start}) -self:T3({...}) -local ObjectName="-" -ObjectName=self.ClassName..self.ClassID -self:F3({"ScheduleRepeat: ",ObjectName,Start,Repeat,RandomizeFactor,Stop}) -self.SchedulerObject=self -local ScheduleID=_SCHEDULEDISPATCHER:AddSchedule( -self, -SchedulerFunction, -{...}, -Start, -Repeat, -RandomizeFactor, -Stop -) -self._.Schedules[SchedulerFunction]=ScheduleID -return self._.Schedules -end -function BASE:ScheduleStop(SchedulerFunction) -self:F3({"ScheduleStop:"}) -_SCHEDULEDISPATCHER:Stop(self,self._.Schedules[SchedulerFunction]) -end -end -function BASE:SetState(Object,Key,Value) -local ClassNameAndID=Object:GetClassNameAndID() -self.States[ClassNameAndID]=self.States[ClassNameAndID]or{} -self.States[ClassNameAndID][Key]=Value -return self.States[ClassNameAndID][Key] -end -function BASE:GetState(Object,Key) -local ClassNameAndID=Object:GetClassNameAndID() -if self.States[ClassNameAndID]then -local Value=self.States[ClassNameAndID][Key]or false -return Value -end -return nil -end -function BASE:ClearState(Object,StateName) -local ClassNameAndID=Object:GetClassNameAndID() -if self.States[ClassNameAndID]then -self.States[ClassNameAndID][StateName]=nil -end -end -function BASE:TraceOnOff(TraceOnOff) -_TraceOnOff=TraceOnOff -end -function BASE:IsTrace() -if debug and(_TraceAll==true)or(_TraceClass[self.ClassName]or _TraceClassMethod[self.ClassName])then -return true -else -return false -end -end -function BASE:TraceLevel(Level) -_TraceLevel=Level -self:E("Tracing level "..Level) -end -function BASE:TraceAll(TraceAll) -_TraceAll=TraceAll -if _TraceAll then -self:E("Tracing all methods in MOOSE ") -else -self:E("Switched off tracing all methods in MOOSE") -end -end -function BASE:TraceClass(Class) -_TraceClass[Class]=true -_TraceClassMethod[Class]={} -self:E("Tracing class "..Class) -end -function BASE:TraceClassMethod(Class,Method) -if not _TraceClassMethod[Class]then -_TraceClassMethod[Class]={} -_TraceClassMethod[Class].Method={} -end -_TraceClassMethod[Class].Method[Method]=true -self:E("Tracing method "..Method.." of class "..Class) -end -function BASE:_F(Arguments,DebugInfoCurrentParam,DebugInfoFromParam) -if debug and(_TraceAll==true)or(_TraceClass[self.ClassName]or _TraceClassMethod[self.ClassName])then -local DebugInfoCurrent=DebugInfoCurrentParam and DebugInfoCurrentParam or debug.getinfo(2,"nl") -local DebugInfoFrom=DebugInfoFromParam and DebugInfoFromParam or debug.getinfo(3,"l") -local Function="function" -if DebugInfoCurrent.name then -Function=DebugInfoCurrent.name -end -if _TraceAll==true or _TraceClass[self.ClassName]or _TraceClassMethod[self.ClassName].Method[Function]then -local LineCurrent=0 -if DebugInfoCurrent.currentline then -LineCurrent=DebugInfoCurrent.currentline -end -local LineFrom=0 -if DebugInfoFrom then -LineFrom=DebugInfoFrom.currentline -end -env.info(string.format("%6d(%6d)/%1s:%20s%05d.%s(%s)",LineCurrent,LineFrom,"F",self.ClassName,self.ClassID,Function,routines.utils.oneLineSerialize(Arguments))) -end -end -end -function BASE:F(Arguments) -if debug and _TraceOnOff then -local DebugInfoCurrent=debug.getinfo(2,"nl") -local DebugInfoFrom=debug.getinfo(3,"l") -if _TraceLevel>=1 then -self:_F(Arguments,DebugInfoCurrent,DebugInfoFrom) -end -end -end -function BASE:F2(Arguments) -if debug and _TraceOnOff then -local DebugInfoCurrent=debug.getinfo(2,"nl") -local DebugInfoFrom=debug.getinfo(3,"l") -if _TraceLevel>=2 then -self:_F(Arguments,DebugInfoCurrent,DebugInfoFrom) -end -end -end -function BASE:F3(Arguments) -if debug and _TraceOnOff then -local DebugInfoCurrent=debug.getinfo(2,"nl") -local DebugInfoFrom=debug.getinfo(3,"l") -if _TraceLevel>=3 then -self:_F(Arguments,DebugInfoCurrent,DebugInfoFrom) -end -end -end -function BASE:_T(Arguments,DebugInfoCurrentParam,DebugInfoFromParam) -if debug and(_TraceAll==true)or(_TraceClass[self.ClassName]or _TraceClassMethod[self.ClassName])then -local DebugInfoCurrent=DebugInfoCurrentParam and DebugInfoCurrentParam or debug.getinfo(2,"nl") -local DebugInfoFrom=DebugInfoFromParam and DebugInfoFromParam or debug.getinfo(3,"l") -local Function="function" -if DebugInfoCurrent.name then -Function=DebugInfoCurrent.name -end -if _TraceAll==true or _TraceClass[self.ClassName]or _TraceClassMethod[self.ClassName].Method[Function]then -local LineCurrent=0 -if DebugInfoCurrent.currentline then -LineCurrent=DebugInfoCurrent.currentline -end -local LineFrom=0 -if DebugInfoFrom then -LineFrom=DebugInfoFrom.currentline -end -env.info(string.format("%6d(%6d)/%1s:%20s%05d.%s",LineCurrent,LineFrom,"T",self.ClassName,self.ClassID,routines.utils.oneLineSerialize(Arguments))) -end -end -end -function BASE:T(Arguments) -if debug and _TraceOnOff then -local DebugInfoCurrent=debug.getinfo(2,"nl") -local DebugInfoFrom=debug.getinfo(3,"l") -if _TraceLevel>=1 then -self:_T(Arguments,DebugInfoCurrent,DebugInfoFrom) -end -end -end -function BASE:T2(Arguments) -if debug and _TraceOnOff then -local DebugInfoCurrent=debug.getinfo(2,"nl") -local DebugInfoFrom=debug.getinfo(3,"l") -if _TraceLevel>=2 then -self:_T(Arguments,DebugInfoCurrent,DebugInfoFrom) -end -end -end -function BASE:T3(Arguments) -if debug and _TraceOnOff then -local DebugInfoCurrent=debug.getinfo(2,"nl") -local DebugInfoFrom=debug.getinfo(3,"l") -if _TraceLevel>=3 then -self:_T(Arguments,DebugInfoCurrent,DebugInfoFrom) -end -end -end -function BASE:E(Arguments) -if debug then -local DebugInfoCurrent=debug.getinfo(2,"nl") -local DebugInfoFrom=debug.getinfo(3,"l") -local Function="function" -if DebugInfoCurrent.name then -Function=DebugInfoCurrent.name -end -local LineCurrent=DebugInfoCurrent.currentline -local LineFrom=-1 -if DebugInfoFrom then -LineFrom=DebugInfoFrom.currentline -end -env.info(string.format("%6d(%6d)/%1s:%20s%05d.%s(%s)",LineCurrent,LineFrom,"E",self.ClassName,self.ClassID,Function,routines.utils.oneLineSerialize(Arguments))) -end -end -REPORT={ -ClassName="REPORT", -Title="", -} -function REPORT:New(Title) -local self=BASE:Inherit(self,BASE:New()) -self.Report={} -self:SetTitle(Title or"") -self:SetIndent(3) -return self -end -function REPORT:HasText() -return#self.Report>0 -end -function REPORT:SetIndent(Indent) -self.Indent=Indent -return self -end -function REPORT:Add(Text) -self.Report[#self.Report+1]=Text -return self -end -function REPORT:AddIndent(Text) -self.Report[#self.Report+1]=string.rep(" ",self.Indent)..Text:gsub("\n","\n"..string.rep(" ",self.Indent)) -return self -end -function REPORT:Text(Delimiter) -Delimiter=Delimiter or"\n" -local ReportText=(self.Title~=""and self.Title..Delimiter or self.Title)..table.concat(self.Report,Delimiter)or"" -return ReportText -end -function REPORT:SetTitle(Title) -self.Title=Title -return self -end -function REPORT:GetCount() -return#self.Report -end -SCHEDULER={ -ClassName="SCHEDULER", -Schedules={}, -} -function SCHEDULER:New(SchedulerObject,SchedulerFunction,SchedulerArguments,Start,Repeat,RandomizeFactor,Stop) -local self=BASE:Inherit(self,BASE:New()) -self:F2({Start,Repeat,RandomizeFactor,Stop}) -local ScheduleID=nil -self.MasterObject=SchedulerObject -if SchedulerFunction then -ScheduleID=self:Schedule(SchedulerObject,SchedulerFunction,SchedulerArguments,Start,Repeat,RandomizeFactor,Stop) -end -return self,ScheduleID -end -function SCHEDULER:Schedule(SchedulerObject,SchedulerFunction,SchedulerArguments,Start,Repeat,RandomizeFactor,Stop) -self:F2({Start,Repeat,RandomizeFactor,Stop}) -self:T3({SchedulerArguments}) -local ObjectName="-" -if SchedulerObject and SchedulerObject.ClassName and SchedulerObject.ClassID then -ObjectName=SchedulerObject.ClassName..SchedulerObject.ClassID -end -self:F3({"Schedule :",ObjectName,tostring(SchedulerObject),Start,Repeat,RandomizeFactor,Stop}) -self.SchedulerObject=SchedulerObject -local ScheduleID=_SCHEDULEDISPATCHER:AddSchedule( -self, -SchedulerFunction, -SchedulerArguments, -Start, -Repeat, -RandomizeFactor, -Stop -) -self.Schedules[#self.Schedules+1]=ScheduleID -return ScheduleID -end -function SCHEDULER:Start(ScheduleID) -self:F3({ScheduleID}) -_SCHEDULEDISPATCHER:Start(self,ScheduleID) -end -function SCHEDULER:Stop(ScheduleID) -self:F3({ScheduleID}) -_SCHEDULEDISPATCHER:Stop(self,ScheduleID) -end -function SCHEDULER:Remove(ScheduleID) -self:F3({ScheduleID}) -_SCHEDULEDISPATCHER:Remove(self,ScheduleID) -end -function SCHEDULER:Clear() -self:F3() -_SCHEDULEDISPATCHER:Clear(self) -end -SCHEDULEDISPATCHER={ -ClassName="SCHEDULEDISPATCHER", -CallID=0, -} -function SCHEDULEDISPATCHER:New() -local self=BASE:Inherit(self,BASE:New()) -self:F3() -return self -end -function SCHEDULEDISPATCHER:AddSchedule(Scheduler,ScheduleFunction,ScheduleArguments,Start,Repeat,Randomize,Stop) -self:F2({Scheduler,ScheduleFunction,ScheduleArguments,Start,Repeat,Randomize,Stop}) -self.CallID=self.CallID+1 -local CallID=self.CallID.."#"..(Scheduler.MasterObject and Scheduler.MasterObject.GetClassNameAndID and Scheduler.MasterObject:GetClassNameAndID()or"")or"" -self.PersistentSchedulers=self.PersistentSchedulers or{} -self.ObjectSchedulers=self.ObjectSchedulers or setmetatable({},{__mode="v"}) -if Scheduler.MasterObject then -self.ObjectSchedulers[CallID]=Scheduler -self:F3({CallID=CallID,ObjectScheduler=tostring(self.ObjectSchedulers[CallID]),MasterObject=tostring(Scheduler.MasterObject)}) -else -self.PersistentSchedulers[CallID]=Scheduler -self:F3({CallID=CallID,PersistentScheduler=self.PersistentSchedulers[CallID]}) -end -self.Schedule=self.Schedule or setmetatable({},{__mode="k"}) -self.Schedule[Scheduler]=self.Schedule[Scheduler]or{} -self.Schedule[Scheduler][CallID]={} -self.Schedule[Scheduler][CallID].Function=ScheduleFunction -self.Schedule[Scheduler][CallID].Arguments=ScheduleArguments -self.Schedule[Scheduler][CallID].StartTime=timer.getTime()+(Start or 0) -self.Schedule[Scheduler][CallID].Start=Start+.1 -self.Schedule[Scheduler][CallID].Repeat=Repeat or 0 -self.Schedule[Scheduler][CallID].Randomize=Randomize or 0 -self.Schedule[Scheduler][CallID].Stop=Stop -self:T3(self.Schedule[Scheduler][CallID]) -self.Schedule[Scheduler][CallID].CallHandler=function(CallID) -self:F2(CallID) -local ErrorHandler=function(errmsg) -env.info("Error in timer function: "..errmsg) -if debug~=nil then -env.info(debug.traceback()) -end -return errmsg -end -local Scheduler=self.ObjectSchedulers[CallID] -if not Scheduler then -Scheduler=self.PersistentSchedulers[CallID] -end -if Scheduler then -local MasterObject=tostring(Scheduler.MasterObject) -local Schedule=self.Schedule[Scheduler][CallID] -local ScheduleObject=Scheduler.SchedulerObject -local ScheduleFunction=Schedule.Function -local ScheduleArguments=Schedule.Arguments -local Start=Schedule.Start -local Repeat=Schedule.Repeat or 0 -local Randomize=Schedule.Randomize or 0 -local Stop=Schedule.Stop or 0 -local ScheduleID=Schedule.ScheduleID -local Status,Result -if ScheduleObject then -local function Timer() -return ScheduleFunction(ScheduleObject,unpack(ScheduleArguments)) -end -Status,Result=xpcall(Timer,ErrorHandler) -else -local function Timer() -return ScheduleFunction(unpack(ScheduleArguments)) -end -Status,Result=xpcall(Timer,ErrorHandler) -end -local CurrentTime=timer.getTime() -local StartTime=Schedule.StartTime -self:F3({Master=MasterObject,CurrentTime=CurrentTime,StartTime=StartTime,Start=Start,Repeat=Repeat,Randomize=Randomize,Stop=Stop}) -if Status and((Result==nil)or(Result and Result~=false))then -if Repeat~=0 and((Stop==0)or(Stop~=0 and CurrentTime<=StartTime+Stop))then -local ScheduleTime= -CurrentTime+ -Repeat+ -math.random( --(Randomize*Repeat/2), -(Randomize*Repeat/2) -)+ -0.01 -return ScheduleTime -else -self:Stop(Scheduler,CallID) -end -else -self:Stop(Scheduler,CallID) -end -else -self:E("Scheduled obsolete call for CallID: "..CallID) -end -return nil -end -self:Start(Scheduler,CallID) -return CallID -end -function SCHEDULEDISPATCHER:RemoveSchedule(Scheduler,CallID) -self:F2({Remove=CallID,Scheduler=Scheduler}) -if CallID then -self:Stop(Scheduler,CallID) -self.Schedule[Scheduler][CallID]=nil -end -end -function SCHEDULEDISPATCHER:Start(Scheduler,CallID) -self:F2({Start=CallID,Scheduler=Scheduler}) -if CallID then -local Schedule=self.Schedule[Scheduler] -if not Schedule[CallID].ScheduleID then -Schedule[CallID].StartTime=timer.getTime() -Schedule[CallID].ScheduleID=timer.scheduleFunction( -Schedule[CallID].CallHandler, -CallID, -timer.getTime()+Schedule[CallID].Start -) -end -else -for CallID,Schedule in pairs(self.Schedule[Scheduler]or{})do -self:Start(Scheduler,CallID) -end -end -end -function SCHEDULEDISPATCHER:Stop(Scheduler,CallID) -self:F2({Stop=CallID,Scheduler=Scheduler}) -if CallID then -local Schedule=self.Schedule[Scheduler] -if Schedule[CallID].ScheduleID then -timer.removeFunction(Schedule[CallID].ScheduleID) -Schedule[CallID].ScheduleID=nil -end -else -for CallID,Schedule in pairs(self.Schedule[Scheduler]or{})do -self:Stop(Scheduler,CallID) -end -end -end -function SCHEDULEDISPATCHER:Clear(Scheduler) -self:F2({Scheduler=Scheduler}) -for CallID,Schedule in pairs(self.Schedule[Scheduler]or{})do -self:Stop(Scheduler,CallID) -end -end -EVENT={ -ClassName="EVENT", -ClassID=0, -} -world.event.S_EVENT_NEW_CARGO=world.event.S_EVENT_MAX+1000 -world.event.S_EVENT_DELETE_CARGO=world.event.S_EVENT_MAX+1001 -EVENTS={ -Shot=world.event.S_EVENT_SHOT, -Hit=world.event.S_EVENT_HIT, -Takeoff=world.event.S_EVENT_TAKEOFF, -Land=world.event.S_EVENT_LAND, -Crash=world.event.S_EVENT_CRASH, -Ejection=world.event.S_EVENT_EJECTION, -Refueling=world.event.S_EVENT_REFUELING, -Dead=world.event.S_EVENT_DEAD, -PilotDead=world.event.S_EVENT_PILOT_DEAD, -BaseCaptured=world.event.S_EVENT_BASE_CAPTURED, -MissionStart=world.event.S_EVENT_MISSION_START, -MissionEnd=world.event.S_EVENT_MISSION_END, -TookControl=world.event.S_EVENT_TOOK_CONTROL, -RefuelingStop=world.event.S_EVENT_REFUELING_STOP, -Birth=world.event.S_EVENT_BIRTH, -HumanFailure=world.event.S_EVENT_HUMAN_FAILURE, -EngineStartup=world.event.S_EVENT_ENGINE_STARTUP, -EngineShutdown=world.event.S_EVENT_ENGINE_SHUTDOWN, -PlayerEnterUnit=world.event.S_EVENT_PLAYER_ENTER_UNIT, -PlayerLeaveUnit=world.event.S_EVENT_PLAYER_LEAVE_UNIT, -PlayerComment=world.event.S_EVENT_PLAYER_COMMENT, -ShootingStart=world.event.S_EVENT_SHOOTING_START, -ShootingEnd=world.event.S_EVENT_SHOOTING_END, -NewCargo=world.event.S_EVENT_NEW_CARGO, -DeleteCargo=world.event.S_EVENT_DELETE_CARGO, -} -local _EVENTMETA={ -[world.event.S_EVENT_SHOT]={ -Order=1, -Side="I", -Event="OnEventShot", -Text="S_EVENT_SHOT" -}, -[world.event.S_EVENT_HIT]={ -Order=1, -Side="T", -Event="OnEventHit", -Text="S_EVENT_HIT" -}, -[world.event.S_EVENT_TAKEOFF]={ -Order=1, -Side="I", -Event="OnEventTakeoff", -Text="S_EVENT_TAKEOFF" -}, -[world.event.S_EVENT_LAND]={ -Order=1, -Side="I", -Event="OnEventLand", -Text="S_EVENT_LAND" -}, -[world.event.S_EVENT_CRASH]={ -Order=-1, -Side="I", -Event="OnEventCrash", -Text="S_EVENT_CRASH" -}, -[world.event.S_EVENT_EJECTION]={ -Order=1, -Side="I", -Event="OnEventEjection", -Text="S_EVENT_EJECTION" -}, -[world.event.S_EVENT_REFUELING]={ -Order=1, -Side="I", -Event="OnEventRefueling", -Text="S_EVENT_REFUELING" -}, -[world.event.S_EVENT_DEAD]={ -Order=-1, -Side="I", -Event="OnEventDead", -Text="S_EVENT_DEAD" -}, -[world.event.S_EVENT_PILOT_DEAD]={ -Order=1, -Side="I", -Event="OnEventPilotDead", -Text="S_EVENT_PILOT_DEAD" -}, -[world.event.S_EVENT_BASE_CAPTURED]={ -Order=1, -Side="I", -Event="OnEventBaseCaptured", -Text="S_EVENT_BASE_CAPTURED" -}, -[world.event.S_EVENT_MISSION_START]={ -Order=1, -Side="N", -Event="OnEventMissionStart", -Text="S_EVENT_MISSION_START" -}, -[world.event.S_EVENT_MISSION_END]={ -Order=1, -Side="N", -Event="OnEventMissionEnd", -Text="S_EVENT_MISSION_END" -}, -[world.event.S_EVENT_TOOK_CONTROL]={ -Order=1, -Side="N", -Event="OnEventTookControl", -Text="S_EVENT_TOOK_CONTROL" -}, -[world.event.S_EVENT_REFUELING_STOP]={ -Order=1, -Side="I", -Event="OnEventRefuelingStop", -Text="S_EVENT_REFUELING_STOP" -}, -[world.event.S_EVENT_BIRTH]={ -Order=1, -Side="I", -Event="OnEventBirth", -Text="S_EVENT_BIRTH" -}, -[world.event.S_EVENT_HUMAN_FAILURE]={ -Order=1, -Side="I", -Event="OnEventHumanFailure", -Text="S_EVENT_HUMAN_FAILURE" -}, -[world.event.S_EVENT_ENGINE_STARTUP]={ -Order=1, -Side="I", -Event="OnEventEngineStartup", -Text="S_EVENT_ENGINE_STARTUP" -}, -[world.event.S_EVENT_ENGINE_SHUTDOWN]={ -Order=1, -Side="I", -Event="OnEventEngineShutdown", -Text="S_EVENT_ENGINE_SHUTDOWN" -}, -[world.event.S_EVENT_PLAYER_ENTER_UNIT]={ -Order=1, -Side="I", -Event="OnEventPlayerEnterUnit", -Text="S_EVENT_PLAYER_ENTER_UNIT" -}, -[world.event.S_EVENT_PLAYER_LEAVE_UNIT]={ -Order=-1, -Side="I", -Event="OnEventPlayerLeaveUnit", -Text="S_EVENT_PLAYER_LEAVE_UNIT" -}, -[world.event.S_EVENT_PLAYER_COMMENT]={ -Order=1, -Side="I", -Event="OnEventPlayerComment", -Text="S_EVENT_PLAYER_COMMENT" -}, -[world.event.S_EVENT_SHOOTING_START]={ -Order=1, -Side="I", -Event="OnEventShootingStart", -Text="S_EVENT_SHOOTING_START" -}, -[world.event.S_EVENT_SHOOTING_END]={ -Order=1, -Side="I", -Event="OnEventShootingEnd", -Text="S_EVENT_SHOOTING_END" -}, -[EVENTS.NewCargo]={ -Order=1, -Event="OnEventNewCargo", -Text="S_EVENT_NEW_CARGO" -}, -[EVENTS.DeleteCargo]={ -Order=1, -Event="OnEventDeleteCargo", -Text="S_EVENT_DELETE_CARGO" -}, -} -function EVENT:New() -local self=BASE:Inherit(self,BASE:New()) -self:F2() -self.EventHandler=world.addEventHandler(self) -return self -end -function EVENT:Init(EventID,EventClass) -self:F3({_EVENTMETA[EventID].Text,EventClass}) -if not self.Events[EventID]then -self.Events[EventID]={} -end -local EventPriority=EventClass:GetEventPriority() -if not self.Events[EventID][EventPriority]then -self.Events[EventID][EventPriority]=setmetatable({},{__mode="k"}) -end -if not self.Events[EventID][EventPriority][EventClass]then -self.Events[EventID][EventPriority][EventClass]={} -end -return self.Events[EventID][EventPriority][EventClass] -end -function EVENT:RemoveEvent(EventClass,EventID) -self:F2({"Removing subscription for class: ",EventClass:GetClassNameAndID()}) -local EventPriority=EventClass:GetEventPriority() -self.Events=self.Events or{} -self.Events[EventID]=self.Events[EventID]or{} -self.Events[EventID][EventPriority]=self.Events[EventID][EventPriority]or{} -self.Events[EventID][EventPriority][EventClass]=self.Events[EventID][EventPriority][EventClass] -self.Events[EventID][EventPriority][EventClass]=nil -end -function EVENT:Reset(EventObject) -self:E({"Resetting subscriptions for class: ",EventObject:GetClassNameAndID()}) -local EventPriority=EventObject:GetEventPriority() -for EventID,EventData in pairs(self.Events)do -if self.EventsDead then -if self.EventsDead[EventID]then -if self.EventsDead[EventID][EventPriority]then -if self.EventsDead[EventID][EventPriority][EventObject]then -self.Events[EventID][EventPriority][EventObject]=self.EventsDead[EventID][EventPriority][EventObject] -end -end -end -end -end -end -function EVENT:RemoveAll(EventObject) -self:F3({EventObject:GetClassNameAndID()}) -local EventClass=EventObject:GetClassNameAndID() -local EventPriority=EventClass:GetEventPriority() -for EventID,EventData in pairs(self.Events)do -self.Events[EventID][EventPriority][EventClass]=nil -end -end -function EVENT:OnEventForTemplate(EventTemplate,EventFunction,EventClass,EventID) -self:F2(EventTemplate.name) -for EventUnitID,EventUnit in pairs(EventTemplate.units)do -self:OnEventForUnit(EventUnit.name,EventFunction,EventClass,EventID) -end -return self -end -function EVENT:OnEventGeneric(EventFunction,EventClass,EventID) -self:F2({EventID}) -local EventData=self:Init(EventID,EventClass) -EventData.EventFunction=EventFunction -return self -end -function EVENT:OnEventForUnit(UnitName,EventFunction,EventClass,EventID) -self:F2(UnitName) -local EventData=self:Init(EventID,EventClass) -EventData.EventUnit=true -EventData.EventFunction=EventFunction -return self -end -function EVENT:OnEventForGroup(GroupName,EventFunction,EventClass,EventID,...) -self:E(GroupName) -local Event=self:Init(EventID,EventClass) -Event.EventGroup=true -Event.EventFunction=EventFunction -Event.Params=arg -return self -end -do -function EVENT:OnBirthForTemplate(EventTemplate,EventFunction,EventClass) -self:F2(EventTemplate.name) -self:OnEventForTemplate(EventTemplate,EventFunction,EventClass,EVENTS.Birth) -return self -end -end -do -function EVENT:OnCrashForTemplate(EventTemplate,EventFunction,EventClass) -self:F2(EventTemplate.name) -self:OnEventForTemplate(EventTemplate,EventFunction,EventClass,EVENTS.Crash) -return self -end -end -do -function EVENT:OnDeadForTemplate(EventTemplate,EventFunction,EventClass) -self:F2(EventTemplate.name) -self:OnEventForTemplate(EventTemplate,EventFunction,EventClass,EVENTS.Dead) -return self -end -end -do -function EVENT:OnLandForTemplate(EventTemplate,EventFunction,EventClass) -self:F2(EventTemplate.name) -self:OnEventForTemplate(EventTemplate,EventFunction,EventClass,EVENTS.Land) -return self -end -end -do -function EVENT:OnTakeOffForTemplate(EventTemplate,EventFunction,EventClass) -self:F2(EventTemplate.name) -self:OnEventForTemplate(EventTemplate,EventFunction,EventClass,EVENTS.Takeoff) -return self -end -end -do -function EVENT:OnEngineShutDownForTemplate(EventTemplate,EventFunction,EventClass) -self:F2(EventTemplate.name) -self:OnEventForTemplate(EventTemplate,EventFunction,EventClass,EVENTS.EngineShutdown) -return self -end -end -do -function EVENT:CreateEventNewCargo(Cargo) -self:F({Cargo}) -local Event={ -id=EVENTS.NewCargo, -time=timer.getTime(), -cargo=Cargo, -} -world.onEvent(Event) -end -function EVENT:CreateEventDeleteCargo(Cargo) -self:F({Cargo}) -local Event={ -id=EVENTS.DeleteCargo, -time=timer.getTime(), -cargo=Cargo, -} -world.onEvent(Event) -end -function EVENT:CreateEventPlayerEnterUnit(PlayerUnit) -self:F({PlayerUnit}) -local Event={ -id=EVENTS.PlayerEnterUnit, -time=timer.getTime(), -initiator=PlayerUnit:GetDCSObject() -} -world.onEvent(Event) -end -end -function EVENT:onEvent(Event) -local ErrorHandler=function(errmsg) -env.info("Error in SCHEDULER function:"..errmsg) -if debug~=nil then -env.info(debug.traceback()) -end -return errmsg -end -local EventMeta=_EVENTMETA[Event.id] -if self and -self.Events and -self.Events[Event.id]and -(Event.initiator~=nil or(Event.initiator==nil and Event.id~=EVENTS.PlayerLeaveUnit))then -if Event.initiator then -Event.IniObjectCategory=Event.initiator:getCategory() -if Event.IniObjectCategory==Object.Category.UNIT then -Event.IniDCSUnit=Event.initiator -Event.IniDCSUnitName=Event.IniDCSUnit:getName() -Event.IniUnitName=Event.IniDCSUnitName -Event.IniDCSGroup=Event.IniDCSUnit:getGroup() -Event.IniUnit=UNIT:FindByName(Event.IniDCSUnitName) -if not Event.IniUnit then -Event.IniUnit=CLIENT:FindByName(Event.IniDCSUnitName,'',true) -end -Event.IniDCSGroupName="" -if Event.IniDCSGroup and Event.IniDCSGroup:isExist()then -Event.IniDCSGroupName=Event.IniDCSGroup:getName() -Event.IniGroup=GROUP:FindByName(Event.IniDCSGroupName) -if Event.IniGroup then -Event.IniGroupName=Event.IniDCSGroupName -end -end -Event.IniPlayerName=Event.IniDCSUnit:getPlayerName() -Event.IniCoalition=Event.IniDCSUnit:getCoalition() -Event.IniTypeName=Event.IniDCSUnit:getTypeName() -Event.IniCategory=Event.IniDCSUnit:getDesc().category -end -if Event.IniObjectCategory==Object.Category.STATIC then -Event.IniDCSUnit=Event.initiator -Event.IniDCSUnitName=Event.IniDCSUnit:getName() -Event.IniUnitName=Event.IniDCSUnitName -Event.IniUnit=STATIC:FindByName(Event.IniDCSUnitName,false) -Event.IniCoalition=Event.IniDCSUnit:getCoalition() -Event.IniCategory=Event.IniDCSUnit:getDesc().category -Event.IniTypeName=Event.IniDCSUnit:getTypeName() -end -if Event.IniObjectCategory==Object.Category.SCENERY then -Event.IniDCSUnit=Event.initiator -Event.IniDCSUnitName=Event.IniDCSUnit:getName() -Event.IniUnitName=Event.IniDCSUnitName -Event.IniUnit=SCENERY:Register(Event.IniDCSUnitName,Event.initiator) -Event.IniCategory=Event.IniDCSUnit:getDesc().category -Event.IniTypeName=Event.initiator:isExist()and Event.IniDCSUnit:getTypeName()or"SCENERY" -end -end -if Event.target then -Event.TgtObjectCategory=Event.target:getCategory() -if Event.TgtObjectCategory==Object.Category.UNIT then -Event.TgtDCSUnit=Event.target -Event.TgtDCSGroup=Event.TgtDCSUnit:getGroup() -Event.TgtDCSUnitName=Event.TgtDCSUnit:getName() -Event.TgtUnitName=Event.TgtDCSUnitName -Event.TgtUnit=UNIT:FindByName(Event.TgtDCSUnitName) -Event.TgtDCSGroupName="" -if Event.TgtDCSGroup and Event.TgtDCSGroup:isExist()then -Event.TgtDCSGroupName=Event.TgtDCSGroup:getName() -Event.TgtGroup=GROUP:FindByName(Event.TgtDCSGroupName) -if Event.TgtGroup then -Event.TgtGroupName=Event.TgtDCSGroupName -end -end -Event.TgtPlayerName=Event.TgtDCSUnit:getPlayerName() -Event.TgtCoalition=Event.TgtDCSUnit:getCoalition() -Event.TgtCategory=Event.TgtDCSUnit:getDesc().category -Event.TgtTypeName=Event.TgtDCSUnit:getTypeName() -end -if Event.TgtObjectCategory==Object.Category.STATIC then -Event.TgtDCSUnit=Event.target -Event.TgtDCSUnitName=Event.TgtDCSUnit:getName() -Event.TgtUnitName=Event.TgtDCSUnitName -Event.TgtUnit=STATIC:FindByName(Event.TgtDCSUnitName) -Event.TgtCoalition=Event.TgtDCSUnit:getCoalition() -Event.TgtCategory=Event.TgtDCSUnit:getDesc().category -Event.TgtTypeName=Event.TgtDCSUnit:getTypeName() -end -if Event.TgtObjectCategory==Object.Category.SCENERY then -Event.TgtDCSUnit=Event.target -Event.TgtDCSUnitName=Event.TgtDCSUnit:getName() -Event.TgtUnitName=Event.TgtDCSUnitName -Event.TgtUnit=SCENERY:Register(Event.TgtDCSUnitName,Event.target) -Event.TgtCategory=Event.TgtDCSUnit:getDesc().category -Event.TgtTypeName=Event.TgtDCSUnit:getTypeName() -end -end -if Event.weapon then -Event.Weapon=Event.weapon -Event.WeaponName=Event.Weapon:getTypeName() -Event.WeaponUNIT=CLIENT:Find(Event.Weapon,'',true) -Event.WeaponPlayerName=Event.WeaponUNIT and Event.Weapon:getPlayerName() -Event.WeaponCoalition=Event.WeaponUNIT and Event.Weapon:getCoalition() -Event.WeaponCategory=Event.WeaponUNIT and Event.Weapon:getDesc().category -Event.WeaponTypeName=Event.WeaponUNIT and Event.Weapon:getTypeName() -end -if Event.cargo then -Event.Cargo=Event.cargo -Event.CargoName=Event.cargo.Name -end -local PriorityOrder=EventMeta.Order -local PriorityBegin=PriorityOrder==-1 and 5 or 1 -local PriorityEnd=PriorityOrder==-1 and 1 or 5 -if Event.IniObjectCategory~=Object.Category.STATIC then -self:E({EventMeta.Text,Event,Event.IniDCSUnitName,Event.TgtDCSUnitName,PriorityOrder}) -end -for EventPriority=PriorityBegin,PriorityEnd,PriorityOrder do -if self.Events[Event.id][EventPriority]then -for EventClass,EventData in pairs(self.Events[Event.id][EventPriority])do -Event.IniGroup=GROUP:FindByName(Event.IniDCSGroupName) -Event.TgtGroup=GROUP:FindByName(Event.TgtDCSGroupName) -if EventData.EventUnit then -if EventClass:IsAlive()or -Event.id==EVENTS.Crash or -Event.id==EVENTS.Dead then -local UnitName=EventClass:GetName() -if(EventMeta.Side=="I"and UnitName==Event.IniDCSUnitName)or -(EventMeta.Side=="T"and UnitName==Event.TgtDCSUnitName)then -if EventData.EventFunction then -if Event.IniObjectCategory~=3 then -self:E({"Calling EventFunction for UNIT ",EventClass:GetClassNameAndID(),", Unit ",Event.IniUnitName,EventPriority}) -end -local Result,Value=xpcall( -function() -return EventData.EventFunction(EventClass,Event) -end,ErrorHandler) -else -local EventFunction=EventClass[EventMeta.Event] -if EventFunction and type(EventFunction)=="function"then -if Event.IniObjectCategory~=3 then -self:E({"Calling "..EventMeta.Event.." for Class ",EventClass:GetClassNameAndID(),EventPriority}) -end -local Result,Value=xpcall( -function() -return EventFunction(EventClass,Event) -end,ErrorHandler) -end -end -end -else -self:RemoveEvent(EventClass,Event.id) -end -else -if EventData.EventGroup then -if EventClass:IsAlive()or -Event.id==EVENTS.Crash or -Event.id==EVENTS.Dead then -local GroupName=EventClass:GetName() -if(EventMeta.Side=="I"and GroupName==Event.IniDCSGroupName)or -(EventMeta.Side=="T"and GroupName==Event.TgtDCSGroupName)then -if EventData.EventFunction then -if Event.IniObjectCategory~=3 then -self:E({"Calling EventFunction for GROUP ",EventClass:GetClassNameAndID(),", Unit ",Event.IniUnitName,EventPriority}) -end -local Result,Value=xpcall( -function() -return EventData.EventFunction(EventClass,Event,unpack(EventData.Params)) -end,ErrorHandler) -else -local EventFunction=EventClass[EventMeta.Event] -if EventFunction and type(EventFunction)=="function"then -if Event.IniObjectCategory~=3 then -self:E({"Calling "..EventMeta.Event.." for GROUP ",EventClass:GetClassNameAndID(),EventPriority}) -end -local Result,Value=xpcall( -function() -return EventFunction(EventClass,Event,unpack(EventData.Params)) -end,ErrorHandler) -end -end -end -else -end -else -if not EventData.EventUnit then -if EventData.EventFunction then -if Event.IniObjectCategory~=3 then -self:F2({"Calling EventFunction for Class ",EventClass:GetClassNameAndID(),EventPriority}) -end -local Result,Value=xpcall( -function() -return EventData.EventFunction(EventClass,Event) -end,ErrorHandler) -else -local EventFunction=EventClass[EventMeta.Event] -if EventFunction and type(EventFunction)=="function"then -if Event.IniObjectCategory~=3 then -self:F2({"Calling "..EventMeta.Event.." for Class ",EventClass:GetClassNameAndID(),EventPriority}) -end -local Result,Value=xpcall( -function() -local Result,Value=EventFunction(EventClass,Event) -return Result,Value -end,ErrorHandler) -end -end -end -end -end -end -end -end -else -self:E({EventMeta.Text,Event}) -end -Event=nil -end -EVENTHANDLER={ -ClassName="EVENTHANDLER", -ClassID=0, -} -function EVENTHANDLER:New() -self=BASE:Inherit(self,BASE:New()) -return self -end -SETTINGS={ -ClassName="SETTINGS", -} -do -function SETTINGS:Set(PlayerName) -if PlayerName==nil then -local self=BASE:Inherit(self,BASE:New()) -self:SetMetric() -self:SetA2G_BR() -self:SetA2A_BRAA() -self:SetLL_Accuracy(3) -self:SetMGRS_Accuracy(5) -self:SetMessageTime(MESSAGE.Type.Briefing,180) -self:SetMessageTime(MESSAGE.Type.Detailed,60) -self:SetMessageTime(MESSAGE.Type.Information,30) -self:SetMessageTime(MESSAGE.Type.Overview,60) -self:SetMessageTime(MESSAGE.Type.Update,15) -return self -else -local Settings=_DATABASE:GetPlayerSettings(PlayerName) -if not Settings then -Settings=BASE:Inherit(self,BASE:New()) -_DATABASE:SetPlayerSettings(PlayerName,Settings) -end -return Settings -end -end -function SETTINGS:SetMetric() -self.Metric=true -end -function SETTINGS:IsMetric() -return(self.Metric~=nil and self.Metric==true)or(self.Metric==nil and _SETTINGS:IsMetric()) -end -function SETTINGS:SetImperial() -self.Metric=false -end -function SETTINGS:IsImperial() -return(self.Metric~=nil and self.Metric==false)or(self.Metric==nil and _SETTINGS:IsMetric()) -end -function SETTINGS:SetLL_Accuracy(LL_Accuracy) -self.LL_Accuracy=LL_Accuracy -end -function SETTINGS:GetLL_DDM_Accuracy() -return self.LL_DDM_Accuracy or _SETTINGS:GetLL_DDM_Accuracy() -end -function SETTINGS:SetMGRS_Accuracy(MGRS_Accuracy) -self.MGRS_Accuracy=MGRS_Accuracy -end -function SETTINGS:GetMGRS_Accuracy() -return self.MGRS_Accuracy or _SETTINGS:GetMGRS_Accuracy() -end -function SETTINGS:SetMessageTime(MessageType,MessageTime) -self.MessageTypeTimings=self.MessageTypeTimings or{} -self.MessageTypeTimings[MessageType]=MessageTime -end -function SETTINGS:GetMessageTime(MessageType) -return(self.MessageTypeTimings and self.MessageTypeTimings[MessageType])or _SETTINGS:GetMessageTime(MessageType) -end -function SETTINGS:SetA2G_LL_DMS() -self.A2GSystem="LL DMS" -end -function SETTINGS:SetA2G_LL_DDM() -self.A2GSystem="LL DDM" -end -function SETTINGS:IsA2G_LL_DMS() -return(self.A2GSystem and self.A2GSystem=="LL DMS")or(not self.A2GSystem and _SETTINGS:IsA2G_LL_DMS()) -end -function SETTINGS:IsA2G_LL_DDM() -return(self.A2GSystem and self.A2GSystem=="LL DDM")or(not self.A2GSystem and _SETTINGS:IsA2G_LL_DDM()) -end -function SETTINGS:SetA2G_MGRS() -self.A2GSystem="MGRS" -end -function SETTINGS:IsA2G_MGRS() -return(self.A2GSystem and self.A2GSystem=="MGRS")or(not self.A2GSystem and _SETTINGS:IsA2G_MGRS()) -end -function SETTINGS:SetA2G_BR() -self.A2GSystem="BR" -end -function SETTINGS:IsA2G_BR() -return(self.A2GSystem and self.A2GSystem=="BR")or(not self.A2GSystem and _SETTINGS:IsA2G_BR()) -end -function SETTINGS:SetA2A_BRAA() -self.A2ASystem="BRAA" -end -function SETTINGS:IsA2A_BRAA() -self:E({BRA=(self.A2ASystem and self.A2ASystem=="BRAA")or(not self.A2ASystem and _SETTINGS:IsA2A_BRAA())}) -return(self.A2ASystem and self.A2ASystem=="BRAA")or(not self.A2ASystem and _SETTINGS:IsA2A_BRAA()) -end -function SETTINGS:SetA2A_BULLS() -self.A2ASystem="BULLS" -end -function SETTINGS:IsA2A_BULLS() -return(self.A2ASystem and self.A2ASystem=="BULLS")or(not self.A2ASystem and _SETTINGS:IsA2A_BULLS()) -end -function SETTINGS:SetA2A_LL_DMS() -self.A2ASystem="LL DMS" -end -function SETTINGS:SetA2A_LL_DDM() -self.A2ASystem="LL DDM" -end -function SETTINGS:IsA2A_LL_DMS() -return(self.A2ASystem and self.A2ASystem=="LL DMS")or(not self.A2ASystem and _SETTINGS:IsA2A_LL_DMS()) -end -function SETTINGS:IsA2A_LL_DDM() -return(self.A2ASystem and self.A2ASystem=="LL DDM")or(not self.A2ASystem and _SETTINGS:IsA2A_LL_DDM()) -end -function SETTINGS:SetA2A_MGRS() -self.A2ASystem="MGRS" -end -function SETTINGS:IsA2A_MGRS() -return(self.A2ASystem and self.A2ASystem=="MGRS")or(not self.A2ASystem and _SETTINGS:IsA2A_MGRS()) -end -function SETTINGS:SetSystemMenu(MenuGroup,RootMenu) -local MenuText="System Settings" -local MenuTime=timer.getTime() -local SettingsMenu=MENU_GROUP:New(MenuGroup,MenuText,RootMenu):SetTime(MenuTime) -local A2GCoordinateMenu=MENU_GROUP:New(MenuGroup,"A2G Coordinate System",SettingsMenu):SetTime(MenuTime) -if not self:IsA2G_LL_DMS()then -MENU_GROUP_COMMAND:New(MenuGroup,"Lat/Lon Degree Min Sec (LL DMS)",A2GCoordinateMenu,self.A2GMenuSystem,self,MenuGroup,RootMenu,"LL DMS"):SetTime(MenuTime) -end -if not self:IsA2G_LL_DDM()then -MENU_GROUP_COMMAND:New(MenuGroup,"Lat/Lon Degree Dec Min (LL DDM)",A2GCoordinateMenu,self.A2GMenuSystem,self,MenuGroup,RootMenu,"LL DDM"):SetTime(MenuTime) -end -if self:IsA2G_LL_DDM()then -MENU_GROUP_COMMAND:New(MenuGroup,"LL DDM Accuracy 1",A2GCoordinateMenu,self.MenuLL_DDM_Accuracy,self,MenuGroup,RootMenu,1):SetTime(MenuTime) -MENU_GROUP_COMMAND:New(MenuGroup,"LL DDM Accuracy 2",A2GCoordinateMenu,self.MenuLL_DDM_Accuracy,self,MenuGroup,RootMenu,2):SetTime(MenuTime) -MENU_GROUP_COMMAND:New(MenuGroup,"LL DDM Accuracy 3",A2GCoordinateMenu,self.MenuLL_DDM_Accuracy,self,MenuGroup,RootMenu,3):SetTime(MenuTime) -end -if not self:IsA2G_BR()then -MENU_GROUP_COMMAND:New(MenuGroup,"Bearing, Range (BR)",A2GCoordinateMenu,self.A2GMenuSystem,self,MenuGroup,RootMenu,"BR"):SetTime(MenuTime) -end -if not self:IsA2G_MGRS()then -MENU_GROUP_COMMAND:New(MenuGroup,"Military Grid (MGRS)",A2GCoordinateMenu,self.A2GMenuSystem,self,MenuGroup,RootMenu,"MGRS"):SetTime(MenuTime) -end -if self:IsA2G_MGRS()then -MENU_GROUP_COMMAND:New(MenuGroup,"MGRS Accuracy 1",A2GCoordinateMenu,self.MenuMGRS_Accuracy,self,MenuGroup,RootMenu,1):SetTime(MenuTime) -MENU_GROUP_COMMAND:New(MenuGroup,"MGRS Accuracy 2",A2GCoordinateMenu,self.MenuMGRS_Accuracy,self,MenuGroup,RootMenu,2):SetTime(MenuTime) -MENU_GROUP_COMMAND:New(MenuGroup,"MGRS Accuracy 3",A2GCoordinateMenu,self.MenuMGRS_Accuracy,self,MenuGroup,RootMenu,3):SetTime(MenuTime) -MENU_GROUP_COMMAND:New(MenuGroup,"MGRS Accuracy 4",A2GCoordinateMenu,self.MenuMGRS_Accuracy,self,MenuGroup,RootMenu,4):SetTime(MenuTime) -MENU_GROUP_COMMAND:New(MenuGroup,"MGRS Accuracy 5",A2GCoordinateMenu,self.MenuMGRS_Accuracy,self,MenuGroup,RootMenu,5):SetTime(MenuTime) -end -local A2ACoordinateMenu=MENU_GROUP:New(MenuGroup,"A2A Coordinate System",SettingsMenu):SetTime(MenuTime) -if not self:IsA2A_LL_DMS()then -MENU_GROUP_COMMAND:New(MenuGroup,"Lat/Lon Degree Min Sec (LL DMS)",A2ACoordinateMenu,self.A2AMenuSystem,self,MenuGroup,RootMenu,"LL DMS"):SetTime(MenuTime) -end -if not self:IsA2A_LL_DDM()then -MENU_GROUP_COMMAND:New(MenuGroup,"Lat/Lon Degree Dec Min (LL DDM)",A2ACoordinateMenu,self.A2AMenuSystem,self,MenuGroup,RootMenu,"LL DDM"):SetTime(MenuTime) -end -if self:IsA2A_LL_DDM()then -MENU_GROUP_COMMAND:New(MenuGroup,"LL DDM Accuracy 1",A2ACoordinateMenu,self.MenuLL_DDM_Accuracy,self,MenuGroup,RootMenu,1):SetTime(MenuTime) -MENU_GROUP_COMMAND:New(MenuGroup,"LL DDM Accuracy 2",A2ACoordinateMenu,self.MenuLL_DDM_Accuracy,self,MenuGroup,RootMenu,2):SetTime(MenuTime) -MENU_GROUP_COMMAND:New(MenuGroup,"LL DDM Accuracy 3",A2ACoordinateMenu,self.MenuLL_DDM_Accuracy,self,MenuGroup,RootMenu,3):SetTime(MenuTime) -end -if not self:IsA2A_BULLS()then -MENU_GROUP_COMMAND:New(MenuGroup,"Bullseye (BULLS)",A2ACoordinateMenu,self.A2AMenuSystem,self,MenuGroup,RootMenu,"BULLS"):SetTime(MenuTime) -end -if not self:IsA2A_BRAA()then -MENU_GROUP_COMMAND:New(MenuGroup,"Bearing Range Altitude Aspect (BRAA)",A2ACoordinateMenu,self.A2AMenuSystem,self,MenuGroup,RootMenu,"BRAA"):SetTime(MenuTime) -end -if not self:IsA2A_MGRS()then -MENU_GROUP_COMMAND:New(MenuGroup,"Military Grid (MGRS)",A2ACoordinateMenu,self.A2AMenuSystem,self,MenuGroup,RootMenu,"MGRS"):SetTime(MenuTime) -end -if self:IsA2A_MGRS()then -MENU_GROUP_COMMAND:New(MenuGroup,"MGRS Accuracy 1",A2ACoordinateMenu,self.MenuMGRS_Accuracy,self,MenuGroup,RootMenu,1):SetTime(MenuTime) -MENU_GROUP_COMMAND:New(MenuGroup,"MGRS Accuracy 2",A2ACoordinateMenu,self.MenuMGRS_Accuracy,self,MenuGroup,RootMenu,2):SetTime(MenuTime) -MENU_GROUP_COMMAND:New(MenuGroup,"MGRS Accuracy 3",A2ACoordinateMenu,self.MenuMGRS_Accuracy,self,MenuGroup,RootMenu,3):SetTime(MenuTime) -MENU_GROUP_COMMAND:New(MenuGroup,"MGRS Accuracy 4",A2ACoordinateMenu,self.MenuMGRS_Accuracy,self,MenuGroup,RootMenu,4):SetTime(MenuTime) -MENU_GROUP_COMMAND:New(MenuGroup,"MGRS Accuracy 5",A2ACoordinateMenu,self.MenuMGRS_Accuracy,self,MenuGroup,RootMenu,5):SetTime(MenuTime) -end -local MetricsMenu=MENU_GROUP:New(MenuGroup,"Measures and Weights System",SettingsMenu):SetTime(MenuTime) -if self:IsMetric()then -MENU_GROUP_COMMAND:New(MenuGroup,"Imperial (Miles,Feet)",MetricsMenu,self.MenuMWSystem,self,MenuGroup,RootMenu,false):SetTime(MenuTime) -end -if self:IsImperial()then -MENU_GROUP_COMMAND:New(MenuGroup,"Metric (Kilometers,Meters)",MetricsMenu,self.MenuMWSystem,self,MenuGroup,RootMenu,true):SetTime(MenuTime) -end -local MessagesMenu=MENU_GROUP:New(MenuGroup,"Messages and Reports",SettingsMenu):SetTime(MenuTime) -local UpdateMessagesMenu=MENU_GROUP:New(MenuGroup,"Update Messages",MessagesMenu):SetTime(MenuTime) -MENU_GROUP_COMMAND:New(MenuGroup,"Off",UpdateMessagesMenu,self.MenuMessageTimingsSystem,self,MenuGroup,RootMenu,MESSAGE.Type.Update,0):SetTime(MenuTime) -MENU_GROUP_COMMAND:New(MenuGroup,"5 seconds",UpdateMessagesMenu,self.MenuMessageTimingsSystem,self,MenuGroup,RootMenu,MESSAGE.Type.Update,5):SetTime(MenuTime) -MENU_GROUP_COMMAND:New(MenuGroup,"10 seconds",UpdateMessagesMenu,self.MenuMessageTimingsSystem,self,MenuGroup,RootMenu,MESSAGE.Type.Update,10):SetTime(MenuTime) -MENU_GROUP_COMMAND:New(MenuGroup,"15 seconds",UpdateMessagesMenu,self.MenuMessageTimingsSystem,self,MenuGroup,RootMenu,MESSAGE.Type.Update,15):SetTime(MenuTime) -MENU_GROUP_COMMAND:New(MenuGroup,"30 seconds",UpdateMessagesMenu,self.MenuMessageTimingsSystem,self,MenuGroup,RootMenu,MESSAGE.Type.Update,30):SetTime(MenuTime) -MENU_GROUP_COMMAND:New(MenuGroup,"1 minute",UpdateMessagesMenu,self.MenuMessageTimingsSystem,self,MenuGroup,RootMenu,MESSAGE.Type.Update,60):SetTime(MenuTime) -local InformationMessagesMenu=MENU_GROUP:New(MenuGroup,"Information Messages",MessagesMenu):SetTime(MenuTime) -MENU_GROUP_COMMAND:New(MenuGroup,"5 seconds",InformationMessagesMenu,self.MenuMessageTimingsSystem,self,MenuGroup,RootMenu,MESSAGE.Type.Information,5):SetTime(MenuTime) -MENU_GROUP_COMMAND:New(MenuGroup,"10 seconds",InformationMessagesMenu,self.MenuMessageTimingsSystem,self,MenuGroup,RootMenu,MESSAGE.Type.Information,10):SetTime(MenuTime) -MENU_GROUP_COMMAND:New(MenuGroup,"15 seconds",InformationMessagesMenu,self.MenuMessageTimingsSystem,self,MenuGroup,RootMenu,MESSAGE.Type.Information,15):SetTime(MenuTime) -MENU_GROUP_COMMAND:New(MenuGroup,"30 seconds",InformationMessagesMenu,self.MenuMessageTimingsSystem,self,MenuGroup,RootMenu,MESSAGE.Type.Information,30):SetTime(MenuTime) -MENU_GROUP_COMMAND:New(MenuGroup,"1 minute",InformationMessagesMenu,self.MenuMessageTimingsSystem,self,MenuGroup,RootMenu,MESSAGE.Type.Information,60):SetTime(MenuTime) -MENU_GROUP_COMMAND:New(MenuGroup,"2 minutes",InformationMessagesMenu,self.MenuMessageTimingsSystem,self,MenuGroup,RootMenu,MESSAGE.Type.Information,120):SetTime(MenuTime) -local BriefingReportsMenu=MENU_GROUP:New(MenuGroup,"Briefing Reports",MessagesMenu):SetTime(MenuTime) -MENU_GROUP_COMMAND:New(MenuGroup,"15 seconds",BriefingReportsMenu,self.MenuMessageTimingsSystem,self,MenuGroup,RootMenu,MESSAGE.Type.Briefing,15):SetTime(MenuTime) -MENU_GROUP_COMMAND:New(MenuGroup,"30 seconds",BriefingReportsMenu,self.MenuMessageTimingsSystem,self,MenuGroup,RootMenu,MESSAGE.Type.Briefing,30):SetTime(MenuTime) -MENU_GROUP_COMMAND:New(MenuGroup,"1 minute",BriefingReportsMenu,self.MenuMessageTimingsSystem,self,MenuGroup,RootMenu,MESSAGE.Type.Briefing,60):SetTime(MenuTime) -MENU_GROUP_COMMAND:New(MenuGroup,"2 minutes",BriefingReportsMenu,self.MenuMessageTimingsSystem,self,MenuGroup,RootMenu,MESSAGE.Type.Briefing,120):SetTime(MenuTime) -MENU_GROUP_COMMAND:New(MenuGroup,"3 minutes",BriefingReportsMenu,self.MenuMessageTimingsSystem,self,MenuGroup,RootMenu,MESSAGE.Type.Briefing,180):SetTime(MenuTime) -local OverviewReportsMenu=MENU_GROUP:New(MenuGroup,"Overview Reports",MessagesMenu):SetTime(MenuTime) -MENU_GROUP_COMMAND:New(MenuGroup,"15 seconds",OverviewReportsMenu,self.MenuMessageTimingsSystem,self,MenuGroup,RootMenu,MESSAGE.Type.Overview,15):SetTime(MenuTime) -MENU_GROUP_COMMAND:New(MenuGroup,"30 seconds",OverviewReportsMenu,self.MenuMessageTimingsSystem,self,MenuGroup,RootMenu,MESSAGE.Type.Overview,30):SetTime(MenuTime) -MENU_GROUP_COMMAND:New(MenuGroup,"1 minute",OverviewReportsMenu,self.MenuMessageTimingsSystem,self,MenuGroup,RootMenu,MESSAGE.Type.Overview,60):SetTime(MenuTime) -MENU_GROUP_COMMAND:New(MenuGroup,"2 minutes",OverviewReportsMenu,self.MenuMessageTimingsSystem,self,MenuGroup,RootMenu,MESSAGE.Type.Overview,120):SetTime(MenuTime) -MENU_GROUP_COMMAND:New(MenuGroup,"3 minutes",OverviewReportsMenu,self.MenuMessageTimingsSystem,self,MenuGroup,RootMenu,MESSAGE.Type.Overview,180):SetTime(MenuTime) -local DetailedReportsMenu=MENU_GROUP:New(MenuGroup,"Detailed Reports",MessagesMenu):SetTime(MenuTime) -MENU_GROUP_COMMAND:New(MenuGroup,"15 seconds",DetailedReportsMenu,self.MenuMessageTimingsSystem,self,MenuGroup,RootMenu,MESSAGE.Type.DetailedReportsMenu,15):SetTime(MenuTime) -MENU_GROUP_COMMAND:New(MenuGroup,"30 seconds",DetailedReportsMenu,self.MenuMessageTimingsSystem,self,MenuGroup,RootMenu,MESSAGE.Type.DetailedReportsMenu,30):SetTime(MenuTime) -MENU_GROUP_COMMAND:New(MenuGroup,"1 minute",DetailedReportsMenu,self.MenuMessageTimingsSystem,self,MenuGroup,RootMenu,MESSAGE.Type.DetailedReportsMenu,60):SetTime(MenuTime) -MENU_GROUP_COMMAND:New(MenuGroup,"2 minutes",DetailedReportsMenu,self.MenuMessageTimingsSystem,self,MenuGroup,RootMenu,MESSAGE.Type.DetailedReportsMenu,120):SetTime(MenuTime) -MENU_GROUP_COMMAND:New(MenuGroup,"3 minutes",DetailedReportsMenu,self.MenuMessageTimingsSystem,self,MenuGroup,RootMenu,MESSAGE.Type.DetailedReportsMenu,180):SetTime(MenuTime) -SettingsMenu:Remove(MenuTime) -return self -end -function SETTINGS:SetPlayerMenu(PlayerUnit) -local PlayerGroup=PlayerUnit:GetGroup() -local PlayerName=PlayerUnit:GetPlayerName() -local PlayerNames=PlayerGroup:GetPlayerNames() -local PlayerMenu=MENU_GROUP:New(PlayerGroup,'Settings "'..PlayerName..'"') -self.PlayerMenu=PlayerMenu -local A2GCoordinateMenu=MENU_GROUP:New(PlayerGroup,"A2G Coordinate System",PlayerMenu) -if not self:IsA2G_LL_DMS()then -MENU_GROUP_COMMAND:New(PlayerGroup,"Lat/Lon Degree Min Sec (LL DMS)",A2GCoordinateMenu,self.MenuGroupA2GSystem,self,PlayerUnit,PlayerGroup,PlayerName,"LL DMS") -end -if not self:IsA2G_LL_DDM()then -MENU_GROUP_COMMAND:New(PlayerGroup,"Lat/Lon Degree Dec Min (LL DDM)",A2GCoordinateMenu,self.MenuGroupA2GSystem,self,PlayerUnit,PlayerGroup,PlayerName,"LL DDM") -end -if self:IsA2G_LL_DDM()then -MENU_GROUP_COMMAND:New(PlayerGroup,"LL DDM Accuracy 1",A2GCoordinateMenu,self.MenuGroupLL_DDM_AccuracySystem,self,PlayerUnit,PlayerGroup,PlayerName,1) -MENU_GROUP_COMMAND:New(PlayerGroup,"LL DDM Accuracy 2",A2GCoordinateMenu,self.MenuGroupLL_DDM_AccuracySystem,self,PlayerUnit,PlayerGroup,PlayerName,2) -MENU_GROUP_COMMAND:New(PlayerGroup,"LL DDM Accuracy 3",A2GCoordinateMenu,self.MenuGroupLL_DDM_AccuracySystem,self,PlayerUnit,PlayerGroup,PlayerName,3) -end -if not self:IsA2G_BR()then -MENU_GROUP_COMMAND:New(PlayerGroup,"Bearing, Range (BR)",A2GCoordinateMenu,self.MenuGroupA2GSystem,self,PlayerUnit,PlayerGroup,PlayerName,"BR") -end -if not self:IsA2G_MGRS()then -MENU_GROUP_COMMAND:New(PlayerGroup,"Military Grid (MGRS)",A2GCoordinateMenu,self.MenuGroupA2GSystem,self,PlayerUnit,PlayerGroup,PlayerName,"MGRS") -end -if self:IsA2G_MGRS()then -MENU_GROUP_COMMAND:New(PlayerGroup,"MGRS Accuracy 1",A2GCoordinateMenu,self.MenuGroupMGRS_AccuracySystem,self,PlayerUnit,PlayerGroup,PlayerName,1) -MENU_GROUP_COMMAND:New(PlayerGroup,"MGRS Accuracy 2",A2GCoordinateMenu,self.MenuGroupMGRS_AccuracySystem,self,PlayerUnit,PlayerGroup,PlayerName,2) -MENU_GROUP_COMMAND:New(PlayerGroup,"MGRS Accuracy 3",A2GCoordinateMenu,self.MenuGroupMGRS_AccuracySystem,self,PlayerUnit,PlayerGroup,PlayerName,3) -MENU_GROUP_COMMAND:New(PlayerGroup,"MGRS Accuracy 4",A2GCoordinateMenu,self.MenuGroupMGRS_AccuracySystem,self,PlayerUnit,PlayerGroup,PlayerName,4) -MENU_GROUP_COMMAND:New(PlayerGroup,"MGRS Accuracy 5",A2GCoordinateMenu,self.MenuGroupMGRS_AccuracySystem,self,PlayerUnit,PlayerGroup,PlayerName,5) -end -local A2ACoordinateMenu=MENU_GROUP:New(PlayerGroup,"A2A Coordinate System",PlayerMenu) -if not self:IsA2A_LL_DMS()then -MENU_GROUP_COMMAND:New(PlayerGroup,"Lat/Lon Degree Min Sec (LL DMS)",A2GCoordinateMenu,self.MenuGroupA2GSystem,self,PlayerUnit,PlayerGroup,PlayerName,"LL DMS") -end -if not self:IsA2A_LL_DDM()then -MENU_GROUP_COMMAND:New(PlayerGroup,"Lat/Lon Degree Dec Min (LL DDM)",A2GCoordinateMenu,self.MenuGroupA2GSystem,self,PlayerUnit,PlayerGroup,PlayerName,"LL DDM") -end -if self:IsA2A_LL_DDM()then -MENU_GROUP_COMMAND:New(PlayerGroup,"LL DDM Accuracy 1",A2GCoordinateMenu,self.MenuGroupLL_DDM_AccuracySystem,self,PlayerUnit,PlayerGroup,PlayerName,1) -MENU_GROUP_COMMAND:New(PlayerGroup,"LL DDM Accuracy 2",A2GCoordinateMenu,self.MenuGroupLL_DDM_AccuracySystem,self,PlayerUnit,PlayerGroup,PlayerName,2) -MENU_GROUP_COMMAND:New(PlayerGroup,"LL DDM Accuracy 3",A2GCoordinateMenu,self.MenuGroupLL_DDM_AccuracySystem,self,PlayerUnit,PlayerGroup,PlayerName,3) -end -if not self:IsA2A_BULLS()then -MENU_GROUP_COMMAND:New(PlayerGroup,"Bullseye (BULLS)",A2ACoordinateMenu,self.MenuGroupA2ASystem,self,PlayerUnit,PlayerGroup,PlayerName,"BULLS") -end -if not self:IsA2A_BRAA()then -MENU_GROUP_COMMAND:New(PlayerGroup,"Bearing Range Altitude Aspect (BRAA)",A2ACoordinateMenu,self.MenuGroupA2ASystem,self,PlayerUnit,PlayerGroup,PlayerName,"BRAA") -end -if not self:IsA2A_MGRS()then -MENU_GROUP_COMMAND:New(PlayerGroup,"Military Grid (MGRS)",A2ACoordinateMenu,self.MenuGroupA2ASystem,self,PlayerUnit,PlayerGroup,PlayerName,"MGRS") -end -if self:IsA2A_MGRS()then -MENU_GROUP_COMMAND:New(PlayerGroup,"Military Grid (MGRS) Accuracy 1",A2ACoordinateMenu,self.MenuGroupMGRS_AccuracySystem,self,PlayerUnit,PlayerGroup,PlayerName,1) -MENU_GROUP_COMMAND:New(PlayerGroup,"Military Grid (MGRS) Accuracy 2",A2ACoordinateMenu,self.MenuGroupMGRS_AccuracySystem,self,PlayerUnit,PlayerGroup,PlayerName,2) -MENU_GROUP_COMMAND:New(PlayerGroup,"Military Grid (MGRS) Accuracy 3",A2ACoordinateMenu,self.MenuGroupMGRS_AccuracySystem,self,PlayerUnit,PlayerGroup,PlayerName,3) -MENU_GROUP_COMMAND:New(PlayerGroup,"Military Grid (MGRS) Accuracy 4",A2ACoordinateMenu,self.MenuGroupMGRS_AccuracySystem,self,PlayerUnit,PlayerGroup,PlayerName,4) -MENU_GROUP_COMMAND:New(PlayerGroup,"Military Grid (MGRS) Accuracy 5",A2ACoordinateMenu,self.MenuGroupMGRS_AccuracySystem,self,PlayerUnit,PlayerGroup,PlayerName,5) -end -local MetricsMenu=MENU_GROUP:New(PlayerGroup,"Measures and Weights System",PlayerMenu) -if self:IsMetric()then -MENU_GROUP_COMMAND:New(PlayerGroup,"Imperial (Miles,Feet)",MetricsMenu,self.MenuGroupMWSystem,self,PlayerUnit,PlayerGroup,PlayerName,false) -end -if self:IsImperial()then -MENU_GROUP_COMMAND:New(PlayerGroup,"Metric (Kilometers,Meters)",MetricsMenu,self.MenuGroupMWSystem,self,PlayerUnit,PlayerGroup,PlayerName,true) -end -local MessagesMenu=MENU_GROUP:New(PlayerGroup,"Messages and Reports",PlayerMenu) -local UpdateMessagesMenu=MENU_GROUP:New(PlayerGroup,"Update Messages",MessagesMenu) -MENU_GROUP_COMMAND:New(PlayerGroup,"Off",UpdateMessagesMenu,self.MenuGroupMessageTimingsSystem,self,PlayerUnit,PlayerGroup,PlayerName,MESSAGE.Type.Update,0) -MENU_GROUP_COMMAND:New(PlayerGroup,"5 seconds",UpdateMessagesMenu,self.MenuGroupMessageTimingsSystem,self,PlayerUnit,PlayerGroup,PlayerName,MESSAGE.Type.Update,5) -MENU_GROUP_COMMAND:New(PlayerGroup,"10 seconds",UpdateMessagesMenu,self.MenuGroupMessageTimingsSystem,self,PlayerUnit,PlayerGroup,PlayerName,MESSAGE.Type.Update,10) -MENU_GROUP_COMMAND:New(PlayerGroup,"15 seconds",UpdateMessagesMenu,self.MenuGroupMessageTimingsSystem,self,PlayerUnit,PlayerGroup,PlayerName,MESSAGE.Type.Update,15) -MENU_GROUP_COMMAND:New(PlayerGroup,"30 seconds",UpdateMessagesMenu,self.MenuGroupMessageTimingsSystem,self,PlayerUnit,PlayerGroup,PlayerName,MESSAGE.Type.Update,30) -MENU_GROUP_COMMAND:New(PlayerGroup,"1 minute",UpdateMessagesMenu,self.MenuGroupMessageTimingsSystem,self,PlayerUnit,PlayerGroup,PlayerName,MESSAGE.Type.Update,60) -local InformationMessagesMenu=MENU_GROUP:New(PlayerGroup,"Information Messages",MessagesMenu) -MENU_GROUP_COMMAND:New(PlayerGroup,"5 seconds",InformationMessagesMenu,self.MenuGroupMessageTimingsSystem,self,PlayerUnit,PlayerGroup,PlayerName,MESSAGE.Type.Information,5) -MENU_GROUP_COMMAND:New(PlayerGroup,"10 seconds",InformationMessagesMenu,self.MenuGroupMessageTimingsSystem,self,PlayerUnit,PlayerGroup,PlayerName,MESSAGE.Type.Information,10) -MENU_GROUP_COMMAND:New(PlayerGroup,"15 seconds",InformationMessagesMenu,self.MenuGroupMessageTimingsSystem,self,PlayerUnit,PlayerGroup,PlayerName,MESSAGE.Type.Information,15) -MENU_GROUP_COMMAND:New(PlayerGroup,"30 seconds",InformationMessagesMenu,self.MenuGroupMessageTimingsSystem,self,PlayerUnit,PlayerGroup,PlayerName,MESSAGE.Type.Information,30) -MENU_GROUP_COMMAND:New(PlayerGroup,"1 minute",InformationMessagesMenu,self.MenuGroupMessageTimingsSystem,self,PlayerUnit,PlayerGroup,PlayerName,MESSAGE.Type.Information,60) -MENU_GROUP_COMMAND:New(PlayerGroup,"2 minutes",InformationMessagesMenu,self.MenuGroupMessageTimingsSystem,self,PlayerUnit,PlayerGroup,PlayerName,MESSAGE.Type.Information,120) -local BriefingReportsMenu=MENU_GROUP:New(PlayerGroup,"Briefing Reports",MessagesMenu) -MENU_GROUP_COMMAND:New(PlayerGroup,"15 seconds",BriefingReportsMenu,self.MenuGroupMessageTimingsSystem,self,PlayerUnit,PlayerGroup,PlayerName,MESSAGE.Type.Briefing,15) -MENU_GROUP_COMMAND:New(PlayerGroup,"30 seconds",BriefingReportsMenu,self.MenuGroupMessageTimingsSystem,self,PlayerUnit,PlayerGroup,PlayerName,MESSAGE.Type.Briefing,30) -MENU_GROUP_COMMAND:New(PlayerGroup,"1 minute",BriefingReportsMenu,self.MenuGroupMessageTimingsSystem,self,PlayerUnit,PlayerGroup,PlayerName,MESSAGE.Type.Briefing,60) -MENU_GROUP_COMMAND:New(PlayerGroup,"2 minutes",BriefingReportsMenu,self.MenuGroupMessageTimingsSystem,self,PlayerUnit,PlayerGroup,PlayerName,MESSAGE.Type.Briefing,120) -MENU_GROUP_COMMAND:New(PlayerGroup,"3 minutes",BriefingReportsMenu,self.MenuGroupMessageTimingsSystem,self,PlayerUnit,PlayerGroup,PlayerName,MESSAGE.Type.Briefing,180) -local OverviewReportsMenu=MENU_GROUP:New(PlayerGroup,"Overview Reports",MessagesMenu) -MENU_GROUP_COMMAND:New(PlayerGroup,"15 seconds",OverviewReportsMenu,self.MenuGroupMessageTimingsSystem,self,PlayerUnit,PlayerGroup,PlayerName,MESSAGE.Type.Overview,15) -MENU_GROUP_COMMAND:New(PlayerGroup,"30 seconds",OverviewReportsMenu,self.MenuGroupMessageTimingsSystem,self,PlayerUnit,PlayerGroup,PlayerName,MESSAGE.Type.Overview,30) -MENU_GROUP_COMMAND:New(PlayerGroup,"1 minute",OverviewReportsMenu,self.MenuGroupMessageTimingsSystem,self,PlayerUnit,PlayerGroup,PlayerName,MESSAGE.Type.Overview,60) -MENU_GROUP_COMMAND:New(PlayerGroup,"2 minutes",OverviewReportsMenu,self.MenuGroupMessageTimingsSystem,self,PlayerUnit,PlayerGroup,PlayerName,MESSAGE.Type.Overview,120) -MENU_GROUP_COMMAND:New(PlayerGroup,"3 minutes",OverviewReportsMenu,self.MenuGroupMessageTimingsSystem,self,PlayerUnit,PlayerGroup,PlayerName,MESSAGE.Type.Overview,180) -local DetailedReportsMenu=MENU_GROUP:New(PlayerGroup,"Detailed Reports",MessagesMenu) -MENU_GROUP_COMMAND:New(PlayerGroup,"15 seconds",DetailedReportsMenu,self.MenuGroupMessageTimingsSystem,self,PlayerUnit,PlayerGroup,PlayerName,MESSAGE.Type.DetailedReportsMenu,15) -MENU_GROUP_COMMAND:New(PlayerGroup,"30 seconds",DetailedReportsMenu,self.MenuGroupMessageTimingsSystem,self,PlayerUnit,PlayerGroup,PlayerName,MESSAGE.Type.DetailedReportsMenu,30) -MENU_GROUP_COMMAND:New(PlayerGroup,"1 minute",DetailedReportsMenu,self.MenuGroupMessageTimingsSystem,self,PlayerUnit,PlayerGroup,PlayerName,MESSAGE.Type.DetailedReportsMenu,60) -MENU_GROUP_COMMAND:New(PlayerGroup,"2 minutes",DetailedReportsMenu,self.MenuGroupMessageTimingsSystem,self,PlayerUnit,PlayerGroup,PlayerName,MESSAGE.Type.DetailedReportsMenu,120) -MENU_GROUP_COMMAND:New(PlayerGroup,"3 minutes",DetailedReportsMenu,self.MenuGroupMessageTimingsSystem,self,PlayerUnit,PlayerGroup,PlayerName,MESSAGE.Type.DetailedReportsMenu,180) -return self -end -function SETTINGS:RemovePlayerMenu(PlayerUnit) -if self.PlayerMenu then -self.PlayerMenu:Remove() -end -return self -end -function SETTINGS:A2GMenuSystem(MenuGroup,RootMenu,A2GSystem) -self.A2GSystem=A2GSystem -MESSAGE:New(string.format("Settings: Default A2G coordinate system set to %s for all players!",A2GSystem),5):ToAll() -self:SetSystemMenu(MenuGroup,RootMenu) -end -function SETTINGS:A2AMenuSystem(MenuGroup,RootMenu,A2ASystem) -self.A2ASystem=A2ASystem -MESSAGE:New(string.format("Settings: Default A2A coordinate system set to %s for all players!",A2ASystem),5):ToAll() -self:SetSystemMenu(MenuGroup,RootMenu) -end -function SETTINGS:MenuLL_DDM_Accuracy(MenuGroup,RootMenu,LL_Accuracy) -self.LL_Accuracy=LL_Accuracy -MESSAGE:New(string.format("Settings: Default LL accuracy set to %s for all players!",LL_Accuracy),5):ToAll() -self:SetSystemMenu(MenuGroup,RootMenu) -end -function SETTINGS:MenuMGRS_Accuracy(MenuGroup,RootMenu,MGRS_Accuracy) -self.MGRS_Accuracy=MGRS_Accuracy -MESSAGE:New(string.format("Settings: Default MGRS accuracy set to %s for all players!",MGRS_Accuracy),5):ToAll() -self:SetSystemMenu(MenuGroup,RootMenu) -end -function SETTINGS:MenuMWSystem(MenuGroup,RootMenu,MW) -self.Metric=MW -MESSAGE:New(string.format("Settings: Default measurement format set to %s for all players!",MW and"Metric"or"Imperial"),5):ToAll() -self:SetSystemMenu(MenuGroup,RootMenu) -end -function SETTINGS:MenuMessageTimingsSystem(MenuGroup,RootMenu,MessageType,MessageTime) -self:SetMessageTime(MessageType,MessageTime) -MESSAGE:New(string.format("Settings: Default message time set for %s to %d.",MessageType,MessageTime),5):ToAll() -end -do -function SETTINGS:MenuGroupA2GSystem(PlayerUnit,PlayerGroup,PlayerName,A2GSystem) -BASE:E({self,PlayerUnit:GetName(),A2GSystem}) -self.A2GSystem=A2GSystem -MESSAGE:New(string.format("Settings: A2G format set to %s for player %s.",A2GSystem,PlayerName),5):ToGroup(PlayerGroup) -self:RemovePlayerMenu(PlayerUnit) -self:SetPlayerMenu(PlayerUnit) -end -function SETTINGS:MenuGroupA2ASystem(PlayerUnit,PlayerGroup,PlayerName,A2ASystem) -self.A2ASystem=A2ASystem -MESSAGE:New(string.format("Settings: A2A format set to %s for player %s.",A2ASystem,PlayerName),5):ToGroup(PlayerGroup) -self:RemovePlayerMenu(PlayerUnit) -self:SetPlayerMenu(PlayerUnit) -end -function SETTINGS:MenuGroupLL_DDM_AccuracySystem(PlayerUnit,PlayerGroup,PlayerName,LL_Accuracy) -self.LL_Accuracy=LL_Accuracy -MESSAGE:New(string.format("Settings: A2G LL format accuracy set to %d for player %s.",LL_Accuracy,PlayerName),5):ToGroup(PlayerGroup) -self:RemovePlayerMenu(PlayerUnit) -self:SetPlayerMenu(PlayerUnit) -end -function SETTINGS:MenuGroupMGRS_AccuracySystem(PlayerUnit,PlayerGroup,PlayerName,MGRS_Accuracy) -self.MGRS_Accuracy=MGRS_Accuracy -MESSAGE:New(string.format("Settings: A2G MGRS format accuracy set to %d for player %s.",MGRS_Accuracy,PlayerName),5):ToGroup(PlayerGroup) -self:RemovePlayerMenu(PlayerUnit) -self:SetPlayerMenu(PlayerUnit) -end -function SETTINGS:MenuGroupMWSystem(PlayerUnit,PlayerGroup,PlayerName,MW) -self.Metric=MW -MESSAGE:New(string.format("Settings: Measurement format set to %s for player %s.",MW and"Metric"or"Imperial",PlayerName),5):ToGroup(PlayerGroup) -self:RemovePlayerMenu(PlayerUnit) -self:SetPlayerMenu(PlayerUnit) -end -function SETTINGS:MenuGroupMessageTimingsSystem(PlayerUnit,PlayerGroup,PlayerName,MessageType,MessageTime) -self:SetMessageTime(MessageType,MessageTime) -MESSAGE:New(string.format("Settings: Default message time set for %s to %d.",MessageType,MessageTime),5):ToGroup(PlayerGroup) -end -end -end -do -MENU_BASE={ -ClassName="MENU_BASE", -MenuPath=nil, -MenuText="", -MenuParentPath=nil -} -function MENU_BASE:New(MenuText,ParentMenu) -local MenuParentPath={} -if ParentMenu~=nil then -MenuParentPath=ParentMenu.MenuPath -end -local self=BASE:Inherit(self,BASE:New()) -self.MenuPath=nil -self.MenuText=MenuText -self.MenuParentPath=MenuParentPath -self.Menus={} -self.MenuCount=0 -self.MenuRemoveParent=false -self.MenuTime=timer.getTime() -return self -end -function MENU_BASE:GetMenu(MenuText) -self:F2({Menu=self.Menus[MenuText]}) -return self.Menus[MenuText] -end -function MENU_BASE:SetRemoveParent(RemoveParent) -self:F2({RemoveParent}) -self.MenuRemoveParent=RemoveParent -return self -end -function MENU_BASE:SetTime(MenuTime) -self.MenuTime=MenuTime -return self -end -function MENU_BASE:SetTag(MenuTag) -self.MenuTag=MenuTag -return self -end -end -do -MENU_COMMAND_BASE={ -ClassName="MENU_COMMAND_BASE", -CommandMenuFunction=nil, -CommandMenuArgument=nil, -MenuCallHandler=nil, -} -function MENU_COMMAND_BASE:New(MenuText,ParentMenu,CommandMenuFunction,CommandMenuArguments) -local self=BASE:Inherit(self,MENU_BASE:New(MenuText,ParentMenu)) -local ErrorHandler=function(errmsg) -env.info("MOOSE error in MENU COMMAND function: "..errmsg) -if debug~=nil then -env.info(debug.traceback()) -end -return errmsg -end -self:SetCommandMenuFunction(CommandMenuFunction) -self:SetCommandMenuArguments(CommandMenuArguments) -self.MenuCallHandler=function() -local function MenuFunction() -return self.CommandMenuFunction(unpack(self.CommandMenuArguments)) -end -local Status,Result=xpcall(MenuFunction,ErrorHandler) -end -return self -end -function MENU_COMMAND_BASE:SetCommandMenuFunction(CommandMenuFunction) -self.CommandMenuFunction=CommandMenuFunction -return self -end -function MENU_COMMAND_BASE:SetCommandMenuArguments(CommandMenuArguments) -self.CommandMenuArguments=CommandMenuArguments -return self -end -end -do -MENU_MISSION={ -ClassName="MENU_MISSION" -} -function MENU_MISSION:New(MenuText,ParentMenu) -local self=BASE:Inherit(self,MENU_BASE:New(MenuText,ParentMenu)) -self:F({MenuText,ParentMenu}) -self.MenuText=MenuText -self.ParentMenu=ParentMenu -self.Menus={} -self:T({MenuText}) -self.MenuPath=missionCommands.addSubMenu(MenuText,self.MenuParentPath) -self:T({self.MenuPath}) -if ParentMenu and ParentMenu.Menus then -ParentMenu.Menus[self.MenuPath]=self -end -return self -end -function MENU_MISSION:RemoveSubMenus() -self:F(self.MenuPath) -for MenuID,Menu in pairs(self.Menus)do -Menu:Remove() -end -end -function MENU_MISSION:Remove() -self:F(self.MenuPath) -self:RemoveSubMenus() -missionCommands.removeItem(self.MenuPath) -if self.ParentMenu then -self.ParentMenu.Menus[self.MenuPath]=nil -end -return nil -end -end -do -MENU_MISSION_COMMAND={ -ClassName="MENU_MISSION_COMMAND" -} -function MENU_MISSION_COMMAND:New(MenuText,ParentMenu,CommandMenuFunction,...) -local self=BASE:Inherit(self,MENU_COMMAND_BASE:New(MenuText,ParentMenu,CommandMenuFunction,arg)) -self.MenuText=MenuText -self.ParentMenu=ParentMenu -self:T({MenuText,CommandMenuFunction,arg}) -self.MenuPath=missionCommands.addCommand(MenuText,self.MenuParentPath,self.MenuCallHandler) -ParentMenu.Menus[self.MenuPath]=self -return self -end -function MENU_MISSION_COMMAND:Remove() -self:F(self.MenuPath) -missionCommands.removeItem(self.MenuPath) -if self.ParentMenu then -self.ParentMenu.Menus[self.MenuPath]=nil -end -return nil -end -end -do -MENU_COALITION={ -ClassName="MENU_COALITION" -} -function MENU_COALITION:New(Coalition,MenuText,ParentMenu) -local self=BASE:Inherit(self,MENU_BASE:New(MenuText,ParentMenu)) -self:F({Coalition,MenuText,ParentMenu}) -self.Coalition=Coalition -self.MenuText=MenuText -self.ParentMenu=ParentMenu -self.Menus={} -self:T({MenuText}) -self.MenuPath=missionCommands.addSubMenuForCoalition(Coalition,MenuText,self.MenuParentPath) -self:T({self.MenuPath}) -if ParentMenu and ParentMenu.Menus then -ParentMenu.Menus[self.MenuPath]=self -end -return self -end -function MENU_COALITION:RemoveSubMenus() -self:F(self.MenuPath) -for MenuID,Menu in pairs(self.Menus)do -Menu:Remove() -end -end -function MENU_COALITION:Remove() -self:F(self.MenuPath) -self:RemoveSubMenus() -missionCommands.removeItemForCoalition(self.Coalition,self.MenuPath) -if self.ParentMenu then -self.ParentMenu.Menus[self.MenuPath]=nil -end -return nil -end -end -do -MENU_COALITION_COMMAND={ -ClassName="MENU_COALITION_COMMAND" -} -function MENU_COALITION_COMMAND:New(Coalition,MenuText,ParentMenu,CommandMenuFunction,...) -local self=BASE:Inherit(self,MENU_COMMAND_BASE:New(MenuText,ParentMenu,CommandMenuFunction,arg)) -self.MenuCoalition=Coalition -self.MenuText=MenuText -self.ParentMenu=ParentMenu -self:T({MenuText,CommandMenuFunction,arg}) -self.MenuPath=missionCommands.addCommandForCoalition(self.MenuCoalition,MenuText,self.MenuParentPath,self.MenuCallHandler) -ParentMenu.Menus[self.MenuPath]=self -return self -end -function MENU_COALITION_COMMAND:Remove() -self:F(self.MenuPath) -missionCommands.removeItemForCoalition(self.MenuCoalition,self.MenuPath) -if self.ParentMenu then -self.ParentMenu.Menus[self.MenuPath]=nil -end -return nil -end -end -do -local _MENUCLIENTS={} -MENU_CLIENT={ -ClassName="MENU_CLIENT" -} -function MENU_CLIENT:New(Client,MenuText,ParentMenu) -local MenuParentPath={} -if ParentMenu~=nil then -MenuParentPath=ParentMenu.MenuPath -end -local self=BASE:Inherit(self,MENU_BASE:New(MenuText,MenuParentPath)) -self:F({Client,MenuText,ParentMenu}) -self.MenuClient=Client -self.MenuClientGroupID=Client:GetClientGroupID() -self.MenuParentPath=MenuParentPath -self.MenuText=MenuText -self.ParentMenu=ParentMenu -self.Menus={} -if not _MENUCLIENTS[self.MenuClientGroupID]then -_MENUCLIENTS[self.MenuClientGroupID]={} -end -local MenuPath=_MENUCLIENTS[self.MenuClientGroupID] -self:T({Client:GetClientGroupName(),MenuPath[table.concat(MenuParentPath)],MenuParentPath,MenuText}) -local MenuPathID=table.concat(MenuParentPath).."/"..MenuText -if MenuPath[MenuPathID]then -missionCommands.removeItemForGroup(self.MenuClient:GetClientGroupID(),MenuPath[MenuPathID]) -end -self.MenuPath=missionCommands.addSubMenuForGroup(self.MenuClient:GetClientGroupID(),MenuText,MenuParentPath) -MenuPath[MenuPathID]=self.MenuPath -self:T({Client:GetClientGroupName(),self.MenuPath}) -if ParentMenu and ParentMenu.Menus then -ParentMenu.Menus[self.MenuPath]=self -end -return self -end -function MENU_CLIENT:RemoveSubMenus() -self:F(self.MenuPath) -for MenuID,Menu in pairs(self.Menus)do -Menu:Remove() -end -end -function MENU_CLIENT:Remove() -self:F(self.MenuPath) -self:RemoveSubMenus() -if not _MENUCLIENTS[self.MenuClientGroupID]then -_MENUCLIENTS[self.MenuClientGroupID]={} -end -local MenuPath=_MENUCLIENTS[self.MenuClientGroupID] -if MenuPath[table.concat(self.MenuParentPath).."/"..self.MenuText]then -MenuPath[table.concat(self.MenuParentPath).."/"..self.MenuText]=nil -end -missionCommands.removeItemForGroup(self.MenuClient:GetClientGroupID(),self.MenuPath) -self.ParentMenu.Menus[self.MenuPath]=nil -return nil -end -MENU_CLIENT_COMMAND={ -ClassName="MENU_CLIENT_COMMAND" -} -function MENU_CLIENT_COMMAND:New(Client,MenuText,ParentMenu,CommandMenuFunction,...) -local MenuParentPath={} -if ParentMenu~=nil then -MenuParentPath=ParentMenu.MenuPath -end -local self=BASE:Inherit(self,MENU_COMMAND_BASE:New(MenuText,MenuParentPath,CommandMenuFunction,arg)) -self.MenuClient=Client -self.MenuClientGroupID=Client:GetClientGroupID() -self.MenuParentPath=MenuParentPath -self.MenuText=MenuText -self.ParentMenu=ParentMenu -if not _MENUCLIENTS[self.MenuClientGroupID]then -_MENUCLIENTS[self.MenuClientGroupID]={} -end -local MenuPath=_MENUCLIENTS[self.MenuClientGroupID] -self:T({Client:GetClientGroupName(),MenuPath[table.concat(MenuParentPath)],MenuParentPath,MenuText,CommandMenuFunction,arg}) -local MenuPathID=table.concat(MenuParentPath).."/"..MenuText -if MenuPath[MenuPathID]then -missionCommands.removeItemForGroup(self.MenuClient:GetClientGroupID(),MenuPath[MenuPathID]) -end -self.MenuPath=missionCommands.addCommandForGroup(self.MenuClient:GetClientGroupID(),MenuText,MenuParentPath,self.MenuCallHandler) -MenuPath[MenuPathID]=self.MenuPath -if ParentMenu and ParentMenu.Menus then -ParentMenu.Menus[self.MenuPath]=self -end -return self -end -function MENU_CLIENT_COMMAND:Remove() -self:F(self.MenuPath) -if not _MENUCLIENTS[self.MenuClientGroupID]then -_MENUCLIENTS[self.MenuClientGroupID]={} -end -local MenuPath=_MENUCLIENTS[self.MenuClientGroupID] -if MenuPath[table.concat(self.MenuParentPath).."/"..self.MenuText]then -MenuPath[table.concat(self.MenuParentPath).."/"..self.MenuText]=nil -end -missionCommands.removeItemForGroup(self.MenuClient:GetClientGroupID(),self.MenuPath) -self.ParentMenu.Menus[self.MenuPath]=nil -return nil -end -end -do -local _MENUGROUPS={} -MENU_GROUP={ -ClassName="MENU_GROUP" -} -function MENU_GROUP:New(MenuGroup,MenuText,ParentMenu) -MenuGroup._Menus=MenuGroup._Menus or{} -local Path=(ParentMenu and(table.concat(ParentMenu.MenuPath or{},"@").."@"..MenuText))or MenuText -if MenuGroup._Menus[Path]then -self=MenuGroup._Menus[Path] -else -self=BASE:Inherit(self,MENU_BASE:New(MenuText,ParentMenu)) -MenuGroup._Menus[Path]=self -self.MenuGroup=MenuGroup -self.Path=Path -self.MenuGroupID=MenuGroup:GetID() -self.MenuText=MenuText -self.ParentMenu=ParentMenu -self:T({"Adding Menu ",MenuText,self.MenuParentPath}) -self.MenuPath=missionCommands.addSubMenuForGroup(self.MenuGroupID,MenuText,self.MenuParentPath) -if self.ParentMenu and self.ParentMenu.Menus then -self.ParentMenu.Menus[MenuText]=self -self:F({self.ParentMenu.Menus,MenuText}) -self.ParentMenu.MenuCount=self.ParentMenu.MenuCount+1 -end -end -return self -end -function MENU_GROUP:RemoveSubMenus(MenuTime,MenuTag) -self:T({"Removing Group SubMenus:",MenuTime,MenuTag,self.MenuGroup:GetName(),self.MenuPath}) -for MenuText,Menu in pairs(self.Menus)do -Menu:Remove(MenuTime,MenuTag) -end -end -function MENU_GROUP:Remove(MenuTime,MenuTag) -self:RemoveSubMenus(MenuTime,MenuTag) -if not MenuTime or self.MenuTime~=MenuTime then -if(not MenuTag)or(MenuTag and self.MenuTag and MenuTag==self.MenuTag)then -if self.MenuGroup._Menus[self.Path]then -self=self.MenuGroup._Menus[self.Path] -missionCommands.removeItemForGroup(self.MenuGroupID,self.MenuPath) -if self.ParentMenu then -self.ParentMenu.Menus[self.MenuText]=nil -self.ParentMenu.MenuCount=self.ParentMenu.MenuCount-1 -if self.ParentMenu.MenuCount==0 then -if self.MenuRemoveParent==true then -self:T2("Removing Parent Menu ") -self.ParentMenu:Remove() -end -end -end -end -self:T({"Removing Group Menu:",MenuGroup=self.MenuGroup:GetName()}) -self.MenuGroup._Menus[self.Path]=nil -self=nil -end -end -return nil -end -MENU_GROUP_COMMAND={ -ClassName="MENU_GROUP_COMMAND" -} -function MENU_GROUP_COMMAND:New(MenuGroup,MenuText,ParentMenu,CommandMenuFunction,...) -MenuGroup._Menus=MenuGroup._Menus or{} -local Path=(ParentMenu and(table.concat(ParentMenu.MenuPath or{},"@").."@"..MenuText))or MenuText -if MenuGroup._Menus[Path]then -self=MenuGroup._Menus[Path] -self:SetCommandMenuFunction(CommandMenuFunction) -self:SetCommandMenuArguments(arg) -return self -end -self=BASE:Inherit(self,MENU_COMMAND_BASE:New(MenuText,ParentMenu,CommandMenuFunction,arg)) -MenuGroup._Menus[Path]=self -self.Path=Path -self.MenuGroup=MenuGroup -self.MenuGroupID=MenuGroup:GetID() -self.MenuText=MenuText -self.ParentMenu=ParentMenu -self:F({"Adding Group Command Menu:",MenuGroup=MenuGroup:GetName(),MenuText=MenuText,MenuPath=self.MenuParentPath}) -self.MenuPath=missionCommands.addCommandForGroup(self.MenuGroupID,MenuText,self.MenuParentPath,self.MenuCallHandler) -if self.ParentMenu and self.ParentMenu.Menus then -self.ParentMenu.Menus[MenuText]=self -self.ParentMenu.MenuCount=self.ParentMenu.MenuCount+1 -self:F2({ParentMenu.Menus,MenuText}) -end -return self -end -function MENU_GROUP_COMMAND:Remove(MenuTime,MenuTag) -if not MenuTime or self.MenuTime~=MenuTime then -if(not MenuTag)or(MenuTag and self.MenuTag and MenuTag==self.MenuTag)then -if self.MenuGroup._Menus[self.Path]then -self=self.MenuGroup._Menus[self.Path] -missionCommands.removeItemForGroup(self.MenuGroupID,self.MenuPath) -self.ParentMenu.Menus[self.MenuText]=nil -self.ParentMenu.MenuCount=self.ParentMenu.MenuCount-1 -if self.ParentMenu.MenuCount==0 then -if self.MenuRemoveParent==true then -self:T2("Removing Parent Menu ") -self.ParentMenu:Remove() -end -end -self.MenuGroup._Menus[self.Path]=nil -self=nil -end -end -end -return nil -end -end -ZONE_BASE={ -ClassName="ZONE_BASE", -ZoneName="", -ZoneProbability=1, -} -function ZONE_BASE:New(ZoneName) -local self=BASE:Inherit(self,BASE:New()) -self:F(ZoneName) -self.ZoneName=ZoneName -return self -end -function ZONE_BASE:GetName() -self:F2() -return self.ZoneName -end -function ZONE_BASE:IsVec2InZone(Vec2) -self:F2(Vec2) -return false -end -function ZONE_BASE:IsVec3InZone(Vec3) -self:F2(Vec3) -local InZone=self:IsVec2InZone({x=Vec3.x,y=Vec3.z}) -return InZone -end -function ZONE_BASE:IsPointVec2InZone(PointVec2) -self:F2(PointVec2) -local InZone=self:IsVec2InZone(PointVec2:GetVec2()) -return InZone -end -function ZONE_BASE:IsPointVec3InZone(PointVec3) -self:F2(PointVec3) -local InZone=self:IsPointVec2InZone(PointVec3) -return InZone -end -function ZONE_BASE:GetVec2() -self:F2(self.ZoneName) -return nil -end -function ZONE_BASE:GetPointVec2() -self:F2(self.ZoneName) -local Vec2=self:GetVec2() -local PointVec2=POINT_VEC2:NewFromVec2(Vec2) -self:T2({PointVec2}) -return PointVec2 -end -function ZONE_BASE:GetCoordinate() -self:F2(self.ZoneName) -local Vec2=self:GetVec2() -local Coordinate=COORDINATE:NewFromVec2(Vec2) -self:T2({Coordinate}) -return Coordinate -end -function ZONE_BASE:GetVec3(Height) -self:F2(self.ZoneName) -Height=Height or 0 -local Vec2=self:GetVec2() -local Vec3={x=Vec2.x,y=Height and Height or land.getHeight(self:GetVec2()),z=Vec2.y} -self:T2({Vec3}) -return Vec3 -end -function ZONE_BASE:GetPointVec3(Height) -self:F2(self.ZoneName) -local Vec3=self:GetVec3(Height) -local PointVec3=POINT_VEC3:NewFromVec3(Vec3) -self:T2({PointVec3}) -return PointVec3 -end -function ZONE_BASE:GetCoordinate(Height) -self:F2(self.ZoneName) -local Vec3=self:GetVec3(Height) -local PointVec3=COORDINATE:NewFromVec3(Vec3) -self:T2({PointVec3}) -return PointVec3 -end -function ZONE_BASE:GetRandomVec2() -return nil -end -function ZONE_BASE:GetRandomPointVec2() -return nil -end -function ZONE_BASE:GetRandomPointVec3() -return nil -end -function ZONE_BASE:GetBoundingSquare() -return nil -end -function ZONE_BASE:BoundZone() -self:F2() -end -function ZONE_BASE:SmokeZone(SmokeColor) -self:F2(SmokeColor) -end -function ZONE_BASE:SetZoneProbability(ZoneProbability) -self:F2(ZoneProbability) -self.ZoneProbability=ZoneProbability or 1 -return self -end -function ZONE_BASE:GetZoneProbability() -self:F2() -return self.ZoneProbability -end -function ZONE_BASE:GetZoneMaybe() -self:F2() -local Randomization=math.random() -if Randomization<=self.ZoneProbability then -return self -else -return nil -end -end -ZONE_RADIUS={ -ClassName="ZONE_RADIUS", -} -function ZONE_RADIUS:New(ZoneName,Vec2,Radius) -local self=BASE:Inherit(self,ZONE_BASE:New(ZoneName)) -self:F({ZoneName,Vec2,Radius}) -self.Radius=Radius -self.Vec2=Vec2 -return self -end -function ZONE_RADIUS:BoundZone(Points,CountryID,UnBound) -local Point={} -local Vec2=self:GetVec2() -Points=Points and Points or 360 -local Angle -local RadialBase=math.pi*2 -for Angle=0,360,(360/Points)do -local Radial=Angle*RadialBase/360 -Point.x=Vec2.x+math.cos(Radial)*self:GetRadius() -Point.y=Vec2.y+math.sin(Radial)*self:GetRadius() -local CountryName=_DATABASE.COUNTRY_NAME[CountryID] -local Tire={ -["country"]=CountryName, -["category"]="Fortifications", -["canCargo"]=false, -["shape_name"]="H-tyre_B_WF", -["type"]="Black_Tyre_WF", -["y"]=Point.y, -["x"]=Point.x, -["name"]=string.format("%s-Tire #%0d",self:GetName(),Angle), -["heading"]=0, -} -local Group=coalition.addStaticObject(CountryID,Tire) -if UnBound and UnBound==true then -Group:destroy() -end -end -return self -end -function ZONE_RADIUS:SmokeZone(SmokeColor,Points) -self:F2(SmokeColor) -local Point={} -local Vec2=self:GetVec2() -Points=Points and Points or 360 -local Angle -local RadialBase=math.pi*2 -for Angle=0,360,360/Points do -local Radial=Angle*RadialBase/360 -Point.x=Vec2.x+math.cos(Radial)*self:GetRadius() -Point.y=Vec2.y+math.sin(Radial)*self:GetRadius() -POINT_VEC2:New(Point.x,Point.y):Smoke(SmokeColor) -end -return self -end -function ZONE_RADIUS:FlareZone(FlareColor,Points,Azimuth) -self:F2({FlareColor,Azimuth}) -local Point={} -local Vec2=self:GetVec2() -Points=Points and Points or 360 -local Angle -local RadialBase=math.pi*2 -for Angle=0,360,360/Points do -local Radial=Angle*RadialBase/360 -Point.x=Vec2.x+math.cos(Radial)*self:GetRadius() -Point.y=Vec2.y+math.sin(Radial)*self:GetRadius() -POINT_VEC2:New(Point.x,Point.y):Flare(FlareColor,Azimuth) -end -return self -end -function ZONE_RADIUS:GetRadius() -self:F2(self.ZoneName) -self:T2({self.Radius}) -return self.Radius -end -function ZONE_RADIUS:SetRadius(Radius) -self:F2(self.ZoneName) -self.Radius=Radius -self:T2({self.Radius}) -return self.Radius -end -function ZONE_RADIUS:GetVec2() -self:F2(self.ZoneName) -self:T2({self.Vec2}) -return self.Vec2 -end -function ZONE_RADIUS:SetVec2(Vec2) -self:F2(self.ZoneName) -self.Vec2=Vec2 -self:T2({self.Vec2}) -return self.Vec2 -end -function ZONE_RADIUS:GetVec3(Height) -self:F2({self.ZoneName,Height}) -Height=Height or 0 -local Vec2=self:GetVec2() -local Vec3={x=Vec2.x,y=land.getHeight(self:GetVec2())+Height,z=Vec2.y} -self:T2({Vec3}) -return Vec3 -end -function ZONE_RADIUS:IsVec2InZone(Vec2) -self:F2(Vec2) -local ZoneVec2=self:GetVec2() -if ZoneVec2 then -if((Vec2.x-ZoneVec2.x)^2+(Vec2.y-ZoneVec2.y)^2)^0.5<=self:GetRadius()then -return true -end -end -return false -end -function ZONE_RADIUS:IsVec3InZone(Vec3) -self:F2(Vec3) -local InZone=self:IsVec2InZone({x=Vec3.x,y=Vec3.z}) -return InZone -end -function ZONE_RADIUS:GetRandomVec2(inner,outer) -self:F(self.ZoneName,inner,outer) -local Point={} -local Vec2=self:GetVec2() -local _inner=inner or 0 -local _outer=outer or self:GetRadius() -local angle=math.random()*math.pi*2; -Point.x=Vec2.x+math.cos(angle)*math.random(_inner,_outer); -Point.y=Vec2.y+math.sin(angle)*math.random(_inner,_outer); -self:T({Point}) -return Point -end -function ZONE_RADIUS:GetRandomPointVec2(inner,outer) -self:F(self.ZoneName,inner,outer) -local PointVec2=POINT_VEC2:NewFromVec2(self:GetRandomVec2()) -self:T3({PointVec2}) -return PointVec2 -end -function ZONE_RADIUS:GetRandomPointVec3(inner,outer) -self:F(self.ZoneName,inner,outer) -local PointVec3=POINT_VEC3:NewFromVec2(self:GetRandomVec2()) -self:T3({PointVec3}) -return PointVec3 -end -function ZONE_RADIUS:GetRandomCoordinate(inner,outer) -self:F(self.ZoneName,inner,outer) -local Coordinate=COORDINATE:NewFromVec2(self:GetRandomVec2()) -self:T3({Coordinate=Coordinate}) -return Coordinate -end -ZONE={ -ClassName="ZONE", -} -function ZONE:New(ZoneName) -local Zone=trigger.misc.getZone(ZoneName) -if not Zone then -error("Zone "..ZoneName.." does not exist.") -return nil -end -local self=BASE:Inherit(self,ZONE_RADIUS:New(ZoneName,{x=Zone.point.x,y=Zone.point.z},Zone.radius)) -self:F(ZoneName) -self.Zone=Zone -return self -end -ZONE_UNIT={ -ClassName="ZONE_UNIT", -} -function ZONE_UNIT:New(ZoneName,ZoneUNIT,Radius) -local self=BASE:Inherit(self,ZONE_RADIUS:New(ZoneName,ZoneUNIT:GetVec2(),Radius)) -self:F({ZoneName,ZoneUNIT:GetVec2(),Radius}) -self.ZoneUNIT=ZoneUNIT -self.LastVec2=ZoneUNIT:GetVec2() -return self -end -function ZONE_UNIT:GetVec2() -self:F2(self.ZoneName) -local ZoneVec2=self.ZoneUNIT:GetVec2() -if ZoneVec2 then -self.LastVec2=ZoneVec2 -return ZoneVec2 -else -return self.LastVec2 -end -self:T2({ZoneVec2}) -return nil -end -function ZONE_UNIT:GetRandomVec2() -self:F(self.ZoneName) -local RandomVec2={} -local Vec2=self.ZoneUNIT:GetVec2() -if not Vec2 then -Vec2=self.LastVec2 -end -local angle=math.random()*math.pi*2; -RandomVec2.x=Vec2.x+math.cos(angle)*math.random()*self:GetRadius(); -RandomVec2.y=Vec2.y+math.sin(angle)*math.random()*self:GetRadius(); -self:T({RandomVec2}) -return RandomVec2 -end -function ZONE_UNIT:GetVec3(Height) -self:F2(self.ZoneName) -Height=Height or 0 -local Vec2=self:GetVec2() -local Vec3={x=Vec2.x,y=land.getHeight(self:GetVec2())+Height,z=Vec2.y} -self:T2({Vec3}) -return Vec3 -end -ZONE_GROUP={ -ClassName="ZONE_GROUP", -} -function ZONE_GROUP:New(ZoneName,ZoneGROUP,Radius) -local self=BASE:Inherit(self,ZONE_RADIUS:New(ZoneName,ZoneGROUP:GetVec2(),Radius)) -self:F({ZoneName,ZoneGROUP:GetVec2(),Radius}) -self._.ZoneGROUP=ZoneGROUP -return self -end -function ZONE_GROUP:GetVec2() -self:F(self.ZoneName) -local ZoneVec2=self._.ZoneGROUP:GetVec2() -self:T({ZoneVec2}) -return ZoneVec2 -end -function ZONE_GROUP:GetRandomVec2() -self:F(self.ZoneName) -local Point={} -local Vec2=self._.ZoneGROUP:GetVec2() -local angle=math.random()*math.pi*2; -Point.x=Vec2.x+math.cos(angle)*math.random()*self:GetRadius(); -Point.y=Vec2.y+math.sin(angle)*math.random()*self:GetRadius(); -self:T({Point}) -return Point -end -function ZONE_GROUP:GetRandomPointVec2(inner,outer) -self:F(self.ZoneName,inner,outer) -local PointVec2=POINT_VEC2:NewFromVec2(self:GetRandomVec2()) -self:T3({PointVec2}) -return PointVec2 -end -ZONE_POLYGON_BASE={ -ClassName="ZONE_POLYGON_BASE", -} -function ZONE_POLYGON_BASE:New(ZoneName,PointsArray) -local self=BASE:Inherit(self,ZONE_BASE:New(ZoneName)) -self:F({ZoneName,PointsArray}) -local i=0 -self._.Polygon={} -for i=1,#PointsArray do -self._.Polygon[i]={} -self._.Polygon[i].x=PointsArray[i].x -self._.Polygon[i].y=PointsArray[i].y -end -return self -end -function ZONE_POLYGON_BASE:GetVec2() -self:F(self.ZoneName) -local Bounds=self:GetBoundingSquare() -return{x=(Bounds.x2+Bounds.x1)/2,y=(Bounds.y2+Bounds.y1)/2} -end -function ZONE_POLYGON_BASE:Flush() -self:F2() -self:E({Polygon=self.ZoneName,Coordinates=self._.Polygon}) -return self -end -function ZONE_POLYGON_BASE:BoundZone(UnBound) -local i -local j -local Segments=10 -i=1 -j=#self._.Polygon -while i<=#self._.Polygon do -self:T({i,j,self._.Polygon[i],self._.Polygon[j]}) -local DeltaX=self._.Polygon[j].x-self._.Polygon[i].x -local DeltaY=self._.Polygon[j].y-self._.Polygon[i].y -for Segment=0,Segments do -local PointX=self._.Polygon[i].x+(Segment*DeltaX/Segments) -local PointY=self._.Polygon[i].y+(Segment*DeltaY/Segments) -local Tire={ -["country"]="USA", -["category"]="Fortifications", -["canCargo"]=false, -["shape_name"]="H-tyre_B_WF", -["type"]="Black_Tyre_WF", -["y"]=PointY, -["x"]=PointX, -["name"]=string.format("%s-Tire #%0d",self:GetName(),((i-1)*Segments)+Segment), -["heading"]=0, -} -local Group=coalition.addStaticObject(country.id.USA,Tire) -if UnBound and UnBound==true then -Group:destroy() -end -end -j=i -i=i+1 -end -return self -end -function ZONE_POLYGON_BASE:SmokeZone(SmokeColor) -self:F2(SmokeColor) -local i -local j -local Segments=10 -i=1 -j=#self._.Polygon -while i<=#self._.Polygon do -self:T({i,j,self._.Polygon[i],self._.Polygon[j]}) -local DeltaX=self._.Polygon[j].x-self._.Polygon[i].x -local DeltaY=self._.Polygon[j].y-self._.Polygon[i].y -for Segment=0,Segments do -local PointX=self._.Polygon[i].x+(Segment*DeltaX/Segments) -local PointY=self._.Polygon[i].y+(Segment*DeltaY/Segments) -POINT_VEC2:New(PointX,PointY):Smoke(SmokeColor) -end -j=i -i=i+1 -end -return self -end -function ZONE_POLYGON_BASE:IsVec2InZone(Vec2) -self:F2(Vec2) -local Next -local Prev -local InPolygon=false -Next=1 -Prev=#self._.Polygon -while Next<=#self._.Polygon do -self:T({Next,Prev,self._.Polygon[Next],self._.Polygon[Prev]}) -if(((self._.Polygon[Next].y>Vec2.y)~=(self._.Polygon[Prev].y>Vec2.y))and -(Vec2.x<(self._.Polygon[Prev].x-self._.Polygon[Next].x)*(Vec2.y-self._.Polygon[Next].y)/(self._.Polygon[Prev].y-self._.Polygon[Next].y)+self._.Polygon[Next].x) -)then -InPolygon=not InPolygon -end -self:T2({InPolygon=InPolygon}) -Prev=Next -Next=Next+1 -end -self:T({InPolygon=InPolygon}) -return InPolygon -end -function ZONE_POLYGON_BASE:GetRandomVec2() -self:F2() -local Vec2Found=false -local Vec2 -local BS=self:GetBoundingSquare() -self:T2(BS) -while Vec2Found==false do -Vec2={x=math.random(BS.x1,BS.x2),y=math.random(BS.y1,BS.y2)} -self:T2(Vec2) -if self:IsVec2InZone(Vec2)then -Vec2Found=true -end -end -self:T2(Vec2) -return Vec2 -end -function ZONE_POLYGON_BASE:GetRandomPointVec2() -self:F2() -local PointVec2=POINT_VEC2:NewFromVec2(self:GetRandomVec2()) -self:T2(PointVec2) -return PointVec2 -end -function ZONE_POLYGON_BASE:GetRandomPointVec3() -self:F2() -local PointVec3=POINT_VEC3:NewFromVec2(self:GetRandomVec2()) -self:T2(PointVec3) -return PointVec3 -end -function ZONE_POLYGON_BASE:GetRandomCoordinate() -self:F2() -local Coordinate=COORDINATE:NewFromVec2(self:GetRandomVec2()) -self:T2(Coordinate) -return Coordinate -end -function ZONE_POLYGON_BASE:GetBoundingSquare() -local x1=self._.Polygon[1].x -local y1=self._.Polygon[1].y -local x2=self._.Polygon[1].x -local y2=self._.Polygon[1].y -for i=2,#self._.Polygon do -self:T2({self._.Polygon[i],x1,y1,x2,y2}) -x1=(x1>self._.Polygon[i].x)and self._.Polygon[i].x or x1 -x2=(x2self._.Polygon[i].y)and self._.Polygon[i].y or y1 -y2=(y20))then -for group_num,Template in pairs(obj_type_data.group)do -if obj_type_name~="static"and Template and Template.units and type(Template.units)=='table'then -self:_RegisterGroupTemplate( -Template, -CoalitionSide, -_DATABASECategory[string.lower(CategoryName)], -CountryID -) -else -self:_RegisterStaticTemplate( -Template, -CoalitionSide, -_DATABASECategory[string.lower(CategoryName)], -CountryID -) -end -end -end -end -end -end -end -end -end -end -for ZoneID,ZoneData in pairs(env.mission.triggers.zones)do -local ZoneName=ZoneData.name -self.ZONENAMES[ZoneName]=ZoneName -end -return self -end -SET_BASE={ -ClassName="SET_BASE", -Filter={}, -Set={}, -List={}, -Index={}, -} -function SET_BASE:New(Database) -local self=BASE:Inherit(self,BASE:New()) -self.Database=Database -self.YieldInterval=10 -self.TimeInterval=0.001 -self.Set={} -self.Index={} -self.CallScheduler=SCHEDULER:New(self) -self:SetEventPriority(2) -return self -end -function SET_BASE:_Find(ObjectName) -local ObjectFound=self.Set[ObjectName] -return ObjectFound -end -function SET_BASE:GetSet() -self:F2() -return self.Set -end -function SET_BASE:Add(ObjectName,Object) -self:F(ObjectName) -self.Set[ObjectName]=Object -table.insert(self.Index,ObjectName) -end -function SET_BASE:AddObject(Object) -self:F2(Object.ObjectName) -self:T(Object.UnitName) -self:T(Object.ObjectName) -self:Add(Object.ObjectName,Object) -end -function SET_BASE:Remove(ObjectName) -local Object=self.Set[ObjectName] -self:F3({ObjectName,Object}) -if Object then -for Index,Key in ipairs(self.Index)do -if Key==ObjectName then -table.remove(self.Index,Index) -self.Set[ObjectName]=nil -break -end -end -end -end -function SET_BASE:Get(ObjectName) -self:F(ObjectName) -local Object=self.Set[ObjectName] -self:T3({ObjectName,Object}) -return Object -end -function SET_BASE:GetFirst() -local ObjectName=self.Index[1] -local FirstObject=self.Set[ObjectName] -self:T3({FirstObject}) -return FirstObject -end -function SET_BASE:GetLast() -local ObjectName=self.Index[#self.Index] -local LastObject=self.Set[ObjectName] -self:T3({LastObject}) -return LastObject -end -function SET_BASE:GetRandom() -local RandomItem=self.Set[self.Index[math.random(#self.Index)]] -self:T3({RandomItem}) -return RandomItem -end -function SET_BASE:Count() -return self.Index and#self.Index or 0 -end -function SET_BASE:SetDatabase(BaseSet) -local OtherFilter=routines.utils.deepCopy(BaseSet.Filter) -self.Filter=OtherFilter -self.Database=BaseSet:GetSet() -return self -end -function SET_BASE:SetIteratorIntervals(YieldInterval,TimeInterval) -self.YieldInterval=YieldInterval -self.TimeInterval=TimeInterval -return self -end -function SET_BASE:FilterOnce() -for ObjectName,Object in pairs(self.Database)do -if self:IsIncludeObject(Object)then -self:Add(ObjectName,Object) -end -end -return self -end -function SET_BASE:_FilterStart() -for ObjectName,Object in pairs(self.Database)do -if self:IsIncludeObject(Object)then -self:E({"Adding Object:",ObjectName}) -self:Add(ObjectName,Object) -end -end -self:HandleEvent(EVENTS.Birth,self._EventOnBirth) -self:HandleEvent(EVENTS.Dead,self._EventOnDeadOrCrash) -self:HandleEvent(EVENTS.Crash,self._EventOnDeadOrCrash) -self:HandleEvent(EVENTS.PlayerEnterUnit,self._EventOnPlayerEnterUnit) -self:HandleEvent(EVENTS.PlayerLeaveUnit,self._EventOnPlayerLeaveUnit) -return self -end -function SET_BASE:FilterDeads() -self:HandleEvent(EVENTS.Dead,self._EventOnDeadOrCrash) -return self -end -function SET_BASE:FilterCrashes() -self:HandleEvent(EVENTS.Crash,self._EventOnDeadOrCrash) -return self -end -function SET_BASE:FilterStop() -self:UnHandleEvent(EVENTS.Birth) -self:UnHandleEvent(EVENTS.Dead) -self:UnHandleEvent(EVENTS.Crash) -return self -end -function SET_BASE:FindNearestObjectFromPointVec2(PointVec2) -self:F2(PointVec2) -local NearestObject=nil -local ClosestDistance=nil -for ObjectID,ObjectData in pairs(self.Set)do -if NearestObject==nil then -NearestObject=ObjectData -ClosestDistance=PointVec2:DistanceFromVec2(ObjectData:GetVec2()) -else -local Distance=PointVec2:DistanceFromVec2(ObjectData:GetVec2()) -if DistanceMaxThreatLevelA2G then -MaxThreatLevelA2G=ThreatLevelA2G -MaxThreatText=ThreatText -end -end -self:F({MaxThreatLevelA2G=MaxThreatLevelA2G,MaxThreatText=MaxThreatText}) -return MaxThreatLevelA2G,MaxThreatText -end -function SET_UNIT:GetCoordinate() -local Coordinate=self:GetFirst():GetCoordinate() -local x1=Coordinate.x -local x2=Coordinate.x -local y1=Coordinate.y -local y2=Coordinate.y -local z1=Coordinate.z -local z2=Coordinate.z -local MaxVelocity=0 -local AvgHeading=nil -local MovingCount=0 -for UnitName,UnitData in pairs(self:GetSet())do -local Unit=UnitData -local Coordinate=Unit:GetCoordinate() -x1=(Coordinate.xx2)and Coordinate.x or x2 -y1=(Coordinate.yy2)and Coordinate.y or y2 -z1=(Coordinate.yz2)and Coordinate.z or z2 -local Velocity=Coordinate:GetVelocity() -if Velocity~=0 then -MaxVelocity=(MaxVelocity5 then -HeadingSet=nil -break -end -end -end -end -return HeadingSet -end -function SET_UNIT:HasRadar(RadarType) -self:F2(RadarType) -local RadarCount=0 -for UnitID,UnitData in pairs(self:GetSet())do -local UnitSensorTest=UnitData -local HasSensors -if RadarType then -HasSensors=UnitSensorTest:HasSensors(Unit.SensorType.RADAR,RadarType) -else -HasSensors=UnitSensorTest:HasSensors(Unit.SensorType.RADAR) -end -self:T3(HasSensors) -if HasSensors then -RadarCount=RadarCount+1 -end -end -return RadarCount -end -function SET_UNIT:HasSEAD() -self:F2() -local SEADCount=0 -for UnitID,UnitData in pairs(self:GetSet())do -local UnitSEAD=UnitData -if UnitSEAD:IsAlive()then -local UnitSEADAttributes=UnitSEAD:GetDesc().attributes -local HasSEAD=UnitSEAD:HasSEAD() -self:T3(HasSEAD) -if HasSEAD then -SEADCount=SEADCount+1 -end -end -end -return SEADCount -end -function SET_UNIT:HasGroundUnits() -self:F2() -local GroundUnitCount=0 -for UnitID,UnitData in pairs(self:GetSet())do -local UnitTest=UnitData -if UnitTest:IsGround()then -GroundUnitCount=GroundUnitCount+1 -end -end -return GroundUnitCount -end -function SET_UNIT:HasFriendlyUnits(FriendlyCoalition) -self:F2() -local FriendlyUnitCount=0 -for UnitID,UnitData in pairs(self:GetSet())do -local UnitTest=UnitData -if UnitTest:IsFriendly(FriendlyCoalition)then -FriendlyUnitCount=FriendlyUnitCount+1 -end -end -return FriendlyUnitCount -end -function SET_UNIT:IsIncludeObject(MUnit) -self:F2(MUnit) -local MUnitInclude=true -if self.Filter.Coalitions then -local MUnitCoalition=false -for CoalitionID,CoalitionName in pairs(self.Filter.Coalitions)do -self:T3({"Coalition:",MUnit:GetCoalition(),self.FilterMeta.Coalitions[CoalitionName],CoalitionName}) -if self.FilterMeta.Coalitions[CoalitionName]and self.FilterMeta.Coalitions[CoalitionName]==MUnit:GetCoalition()then -MUnitCoalition=true -end -end -MUnitInclude=MUnitInclude and MUnitCoalition -end -if self.Filter.Categories then -local MUnitCategory=false -for CategoryID,CategoryName in pairs(self.Filter.Categories)do -self:T3({"Category:",MUnit:GetDesc().category,self.FilterMeta.Categories[CategoryName],CategoryName}) -if self.FilterMeta.Categories[CategoryName]and self.FilterMeta.Categories[CategoryName]==MUnit:GetDesc().category then -MUnitCategory=true -end -end -MUnitInclude=MUnitInclude and MUnitCategory -end -if self.Filter.Types then -local MUnitType=false -for TypeID,TypeName in pairs(self.Filter.Types)do -self:T3({"Type:",MUnit:GetTypeName(),TypeName}) -if TypeName==MUnit:GetTypeName()then -MUnitType=true -end -end -MUnitInclude=MUnitInclude and MUnitType -end -if self.Filter.Countries then -local MUnitCountry=false -for CountryID,CountryName in pairs(self.Filter.Countries)do -self:T3({"Country:",MUnit:GetCountry(),CountryName}) -if country.id[CountryName]==MUnit:GetCountry()then -MUnitCountry=true -end -end -MUnitInclude=MUnitInclude and MUnitCountry -end -if self.Filter.UnitPrefixes then -local MUnitPrefix=false -for UnitPrefixId,UnitPrefix in pairs(self.Filter.UnitPrefixes)do -self:T3({"Prefix:",string.find(MUnit:GetName(),UnitPrefix,1),UnitPrefix}) -if string.find(MUnit:GetName(),UnitPrefix,1)then -MUnitPrefix=true -end -end -MUnitInclude=MUnitInclude and MUnitPrefix -end -if self.Filter.RadarTypes then -local MUnitRadar=false -for RadarTypeID,RadarType in pairs(self.Filter.RadarTypes)do -self:T3({"Radar:",RadarType}) -if MUnit:HasSensors(Unit.SensorType.RADAR,RadarType)==true then -if MUnit:GetRadar()==true then -self:T3("RADAR Found") -end -MUnitRadar=true -end -end -MUnitInclude=MUnitInclude and MUnitRadar -end -if self.Filter.SEAD then -local MUnitSEAD=false -if MUnit:HasSEAD()==true then -self:T3("SEAD Found") -MUnitSEAD=true -end -MUnitInclude=MUnitInclude and MUnitSEAD -end -self:T2(MUnitInclude) -return MUnitInclude -end -function SET_UNIT:GetTypeNames(Delimiter) -Delimiter=Delimiter or", " -local TypeReport=REPORT:New() -local Types={} -for UnitName,UnitData in pairs(self:GetSet())do -local Unit=UnitData -local UnitTypeName=Unit:GetTypeName() -if not Types[UnitTypeName]then -Types[UnitTypeName]=UnitTypeName -TypeReport:Add(UnitTypeName) -end -end -return TypeReport:Text(Delimiter) -end -SET_CLIENT={ -ClassName="SET_CLIENT", -Clients={}, -Filter={ -Coalitions=nil, -Categories=nil, -Types=nil, -Countries=nil, -ClientPrefixes=nil, -}, -FilterMeta={ -Coalitions={ -red=coalition.side.RED, -blue=coalition.side.BLUE, -neutral=coalition.side.NEUTRAL, -}, -Categories={ -plane=Unit.Category.AIRPLANE, -helicopter=Unit.Category.HELICOPTER, -ground=Unit.Category.GROUND_UNIT, -ship=Unit.Category.SHIP, -structure=Unit.Category.STRUCTURE, -}, -}, -} -function SET_CLIENT:New() -local self=BASE:Inherit(self,SET_BASE:New(_DATABASE.CLIENTS)) -return self -end -function SET_CLIENT:AddClientsByName(AddClientNames) -local AddClientNamesArray=(type(AddClientNames)=="table")and AddClientNames or{AddClientNames} -for AddClientID,AddClientName in pairs(AddClientNamesArray)do -self:Add(AddClientName,CLIENT:FindByName(AddClientName)) -end -return self -end -function SET_CLIENT:RemoveClientsByName(RemoveClientNames) -local RemoveClientNamesArray=(type(RemoveClientNames)=="table")and RemoveClientNames or{RemoveClientNames} -for RemoveClientID,RemoveClientName in pairs(RemoveClientNamesArray)do -self:Remove(RemoveClientName.ClientName) -end -return self -end -function SET_CLIENT:FindClient(ClientName) -local ClientFound=self.Set[ClientName] -return ClientFound -end -function SET_CLIENT:FilterCoalitions(Coalitions) -if not self.Filter.Coalitions then -self.Filter.Coalitions={} -end -if type(Coalitions)~="table"then -Coalitions={Coalitions} -end -for CoalitionID,Coalition in pairs(Coalitions)do -self.Filter.Coalitions[Coalition]=Coalition -end -return self -end -function SET_CLIENT:FilterCategories(Categories) -if not self.Filter.Categories then -self.Filter.Categories={} -end -if type(Categories)~="table"then -Categories={Categories} -end -for CategoryID,Category in pairs(Categories)do -self.Filter.Categories[Category]=Category -end -return self -end -function SET_CLIENT:FilterTypes(Types) -if not self.Filter.Types then -self.Filter.Types={} -end -if type(Types)~="table"then -Types={Types} -end -for TypeID,Type in pairs(Types)do -self.Filter.Types[Type]=Type -end -return self -end -function SET_CLIENT:FilterCountries(Countries) -if not self.Filter.Countries then -self.Filter.Countries={} -end -if type(Countries)~="table"then -Countries={Countries} -end -for CountryID,Country in pairs(Countries)do -self.Filter.Countries[Country]=Country -end -return self -end -function SET_CLIENT:FilterPrefixes(Prefixes) -if not self.Filter.ClientPrefixes then -self.Filter.ClientPrefixes={} -end -if type(Prefixes)~="table"then -Prefixes={Prefixes} -end -for PrefixID,Prefix in pairs(Prefixes)do -self.Filter.ClientPrefixes[Prefix]=Prefix -end -return self -end -function SET_CLIENT:FilterStart() -if _DATABASE then -self:_FilterStart() -end -return self -end -function SET_CLIENT:AddInDatabase(Event) -self:F3({Event}) -return Event.IniDCSUnitName,self.Database[Event.IniDCSUnitName] -end -function SET_CLIENT:FindInDatabase(Event) -self:F3({Event}) -return Event.IniDCSUnitName,self.Database[Event.IniDCSUnitName] -end -function SET_CLIENT:ForEachClient(IteratorFunction,...) -self:F2(arg) -self:ForEach(IteratorFunction,arg,self.Set) -return self -end -function SET_CLIENT:ForEachClientInZone(ZoneObject,IteratorFunction,...) -self:F2(arg) -self:ForEach(IteratorFunction,arg,self.Set, -function(ZoneObject,ClientObject) -if ClientObject:IsInZone(ZoneObject)then -return true -else -return false -end -end,{ZoneObject}) -return self -end -function SET_CLIENT:ForEachClientNotInZone(ZoneObject,IteratorFunction,...) -self:F2(arg) -self:ForEach(IteratorFunction,arg,self.Set, -function(ZoneObject,ClientObject) -if ClientObject:IsNotInZone(ZoneObject)then -return true -else -return false -end -end,{ZoneObject}) -return self -end -function SET_CLIENT:IsIncludeObject(MClient) -self:F2(MClient) -local MClientInclude=true -if MClient then -local MClientName=MClient.UnitName -if self.Filter.Coalitions then -local MClientCoalition=false -for CoalitionID,CoalitionName in pairs(self.Filter.Coalitions)do -local ClientCoalitionID=_DATABASE:GetCoalitionFromClientTemplate(MClientName) -self:T3({"Coalition:",ClientCoalitionID,self.FilterMeta.Coalitions[CoalitionName],CoalitionName}) -if self.FilterMeta.Coalitions[CoalitionName]and self.FilterMeta.Coalitions[CoalitionName]==ClientCoalitionID then -MClientCoalition=true -end -end -self:T({"Evaluated Coalition",MClientCoalition}) -MClientInclude=MClientInclude and MClientCoalition -end -if self.Filter.Categories then -local MClientCategory=false -for CategoryID,CategoryName in pairs(self.Filter.Categories)do -local ClientCategoryID=_DATABASE:GetCategoryFromClientTemplate(MClientName) -self:T3({"Category:",ClientCategoryID,self.FilterMeta.Categories[CategoryName],CategoryName}) -if self.FilterMeta.Categories[CategoryName]and self.FilterMeta.Categories[CategoryName]==ClientCategoryID then -MClientCategory=true -end -end -self:T({"Evaluated Category",MClientCategory}) -MClientInclude=MClientInclude and MClientCategory -end -if self.Filter.Types then -local MClientType=false -for TypeID,TypeName in pairs(self.Filter.Types)do -self:T3({"Type:",MClient:GetTypeName(),TypeName}) -if TypeName==MClient:GetTypeName()then -MClientType=true -end -end -self:T({"Evaluated Type",MClientType}) -MClientInclude=MClientInclude and MClientType -end -if self.Filter.Countries then -local MClientCountry=false -for CountryID,CountryName in pairs(self.Filter.Countries)do -local ClientCountryID=_DATABASE:GetCountryFromClientTemplate(MClientName) -self:T3({"Country:",ClientCountryID,country.id[CountryName],CountryName}) -if country.id[CountryName]and country.id[CountryName]==ClientCountryID then -MClientCountry=true -end -end -self:T({"Evaluated Country",MClientCountry}) -MClientInclude=MClientInclude and MClientCountry -end -if self.Filter.ClientPrefixes then -local MClientPrefix=false -for ClientPrefixId,ClientPrefix in pairs(self.Filter.ClientPrefixes)do -self:T3({"Prefix:",string.find(MClient.UnitName,ClientPrefix,1),ClientPrefix}) -if string.find(MClient.UnitName,ClientPrefix,1)then -MClientPrefix=true -end -end -self:T({"Evaluated Prefix",MClientPrefix}) -MClientInclude=MClientInclude and MClientPrefix -end -end -self:T2(MClientInclude) -return MClientInclude -end -SET_AIRBASE={ -ClassName="SET_AIRBASE", -Airbases={}, -Filter={ -Coalitions=nil, -}, -FilterMeta={ -Coalitions={ -red=coalition.side.RED, -blue=coalition.side.BLUE, -neutral=coalition.side.NEUTRAL, -}, -Categories={ -airdrome=Airbase.Category.AIRDROME, -helipad=Airbase.Category.HELIPAD, -ship=Airbase.Category.SHIP, -}, -}, -} -function SET_AIRBASE:New() -local self=BASE:Inherit(self,SET_BASE:New(_DATABASE.AIRBASES)) -return self -end -function SET_AIRBASE:AddAirbasesByName(AddAirbaseNames) -local AddAirbaseNamesArray=(type(AddAirbaseNames)=="table")and AddAirbaseNames or{AddAirbaseNames} -for AddAirbaseID,AddAirbaseName in pairs(AddAirbaseNamesArray)do -self:Add(AddAirbaseName,AIRBASE:FindByName(AddAirbaseName)) -end -return self -end -function SET_AIRBASE:RemoveAirbasesByName(RemoveAirbaseNames) -local RemoveAirbaseNamesArray=(type(RemoveAirbaseNames)=="table")and RemoveAirbaseNames or{RemoveAirbaseNames} -for RemoveAirbaseID,RemoveAirbaseName in pairs(RemoveAirbaseNamesArray)do -self:Remove(RemoveAirbaseName.AirbaseName) -end -return self -end -function SET_AIRBASE:FindAirbase(AirbaseName) -local AirbaseFound=self.Set[AirbaseName] -return AirbaseFound -end -function SET_AIRBASE:FilterCoalitions(Coalitions) -if not self.Filter.Coalitions then -self.Filter.Coalitions={} -end -if type(Coalitions)~="table"then -Coalitions={Coalitions} -end -for CoalitionID,Coalition in pairs(Coalitions)do -self.Filter.Coalitions[Coalition]=Coalition -end -return self -end -function SET_AIRBASE:FilterCategories(Categories) -if not self.Filter.Categories then -self.Filter.Categories={} -end -if type(Categories)~="table"then -Categories={Categories} -end -for CategoryID,Category in pairs(Categories)do -self.Filter.Categories[Category]=Category -end -return self -end -function SET_AIRBASE:FilterStart() -if _DATABASE then -self:_FilterStart() -end -return self -end -function SET_AIRBASE:AddInDatabase(Event) -self:F3({Event}) -return Event.IniDCSUnitName,self.Database[Event.IniDCSUnitName] -end -function SET_AIRBASE:FindInDatabase(Event) -self:F3({Event}) -return Event.IniDCSUnitName,self.Database[Event.IniDCSUnitName] -end -function SET_AIRBASE:ForEachAirbase(IteratorFunction,...) -self:F2(arg) -self:ForEach(IteratorFunction,arg,self.Set) -return self -end -function SET_AIRBASE:FindNearestAirbaseFromPointVec2(PointVec2) -self:F2(PointVec2) -local NearestAirbase=self:FindNearestObjectFromPointVec2(PointVec2) -return NearestAirbase -end -function SET_AIRBASE:IsIncludeObject(MAirbase) -self:F2(MAirbase) -local MAirbaseInclude=true -if MAirbase then -local MAirbaseName=MAirbase:GetName() -if self.Filter.Coalitions then -local MAirbaseCoalition=false -for CoalitionID,CoalitionName in pairs(self.Filter.Coalitions)do -local AirbaseCoalitionID=_DATABASE:GetCoalitionFromAirbase(MAirbaseName) -self:T3({"Coalition:",AirbaseCoalitionID,self.FilterMeta.Coalitions[CoalitionName],CoalitionName}) -if self.FilterMeta.Coalitions[CoalitionName]and self.FilterMeta.Coalitions[CoalitionName]==AirbaseCoalitionID then -MAirbaseCoalition=true -end -end -self:T({"Evaluated Coalition",MAirbaseCoalition}) -MAirbaseInclude=MAirbaseInclude and MAirbaseCoalition -end -if self.Filter.Categories then -local MAirbaseCategory=false -for CategoryID,CategoryName in pairs(self.Filter.Categories)do -local AirbaseCategoryID=_DATABASE:GetCategoryFromAirbase(MAirbaseName) -self:T3({"Category:",AirbaseCategoryID,self.FilterMeta.Categories[CategoryName],CategoryName}) -if self.FilterMeta.Categories[CategoryName]and self.FilterMeta.Categories[CategoryName]==AirbaseCategoryID then -MAirbaseCategory=true -end -end -self:T({"Evaluated Category",MAirbaseCategory}) -MAirbaseInclude=MAirbaseInclude and MAirbaseCategory -end -end -self:T2(MAirbaseInclude) -return MAirbaseInclude -end -SET_CARGO={ -ClassName="SET_CARGO", -Cargos={}, -Filter={ -Coalitions=nil, -Types=nil, -Countries=nil, -ClientPrefixes=nil, -}, -FilterMeta={ -Coalitions={ -red=coalition.side.RED, -blue=coalition.side.BLUE, -neutral=coalition.side.NEUTRAL, -}, -}, -} -function SET_CARGO:New() -local self=BASE:Inherit(self,SET_BASE:New(_DATABASE.CARGOS)) -return self -end -function SET_CARGO:AddCargosByName(AddCargoNames) -local AddCargoNamesArray=(type(AddCargoNames)=="table")and AddCargoNames or{AddCargoNames} -for AddCargoID,AddCargoName in pairs(AddCargoNamesArray)do -self:Add(AddCargoName,CARGO:FindByName(AddCargoName)) -end -return self -end -function SET_CARGO:RemoveCargosByName(RemoveCargoNames) -local RemoveCargoNamesArray=(type(RemoveCargoNames)=="table")and RemoveCargoNames or{RemoveCargoNames} -for RemoveCargoID,RemoveCargoName in pairs(RemoveCargoNamesArray)do -self:Remove(RemoveCargoName.CargoName) -end -return self -end -function SET_CARGO:FindCargo(CargoName) -local CargoFound=self.Set[CargoName] -return CargoFound -end -function SET_CARGO:FilterCoalitions(Coalitions) -if not self.Filter.Coalitions then -self.Filter.Coalitions={} -end -if type(Coalitions)~="table"then -Coalitions={Coalitions} -end -for CoalitionID,Coalition in pairs(Coalitions)do -self.Filter.Coalitions[Coalition]=Coalition -end -return self -end -function SET_CARGO:FilterTypes(Types) -if not self.Filter.Types then -self.Filter.Types={} -end -if type(Types)~="table"then -Types={Types} -end -for TypeID,Type in pairs(Types)do -self.Filter.Types[Type]=Type -end -return self -end -function SET_CARGO:FilterCountries(Countries) -if not self.Filter.Countries then -self.Filter.Countries={} -end -if type(Countries)~="table"then -Countries={Countries} -end -for CountryID,Country in pairs(Countries)do -self.Filter.Countries[Country]=Country -end -return self -end -function SET_CARGO:FilterPrefixes(Prefixes) -if not self.Filter.CargoPrefixes then -self.Filter.CargoPrefixes={} -end -if type(Prefixes)~="table"then -Prefixes={Prefixes} -end -for PrefixID,Prefix in pairs(Prefixes)do -self.Filter.CargoPrefixes[Prefix]=Prefix -end -return self -end -function SET_CARGO:FilterStart() -if _DATABASE then -self:_FilterStart() -end -self:HandleEvent(EVENTS.NewCargo) -self:HandleEvent(EVENTS.DeleteCargo) -return self -end -function SET_CARGO:AddInDatabase(Event) -self:F3({Event}) -return Event.IniDCSUnitName,self.Database[Event.IniDCSUnitName] -end -function SET_CARGO:FindInDatabase(Event) -self:F3({Event}) -return Event.IniDCSUnitName,self.Database[Event.IniDCSUnitName] -end -function SET_CARGO:ForEachCargo(IteratorFunction,...) -self:F2(arg) -self:ForEach(IteratorFunction,arg,self.Set) -return self -end -function SET_CARGO:FindNearestCargoFromPointVec2(PointVec2) -self:F2(PointVec2) -local NearestCargo=self:FindNearestObjectFromPointVec2(PointVec2) -return NearestCargo -end -function SET_CARGO:IsIncludeObject(MCargo) -self:F2(MCargo) -local MCargoInclude=true -if MCargo then -local MCargoName=MCargo:GetName() -if self.Filter.Coalitions then -local MCargoCoalition=false -for CoalitionID,CoalitionName in pairs(self.Filter.Coalitions)do -local CargoCoalitionID=MCargo:GetCoalition() -self:T3({"Coalition:",CargoCoalitionID,self.FilterMeta.Coalitions[CoalitionName],CoalitionName}) -if self.FilterMeta.Coalitions[CoalitionName]and self.FilterMeta.Coalitions[CoalitionName]==CargoCoalitionID then -MCargoCoalition=true -end -end -self:T({"Evaluated Coalition",MCargoCoalition}) -MCargoInclude=MCargoInclude and MCargoCoalition -end -if self.Filter.Types then -local MCargoType=false -for TypeID,TypeName in pairs(self.Filter.Types)do -self:T3({"Type:",MCargo:GetType(),TypeName}) -if TypeName==MCargo:GetType()then -MCargoType=true -end -end -self:T({"Evaluated Type",MCargoType}) -MCargoInclude=MCargoInclude and MCargoType -end -if self.Filter.CargoPrefixes then -local MCargoPrefix=false -for CargoPrefixId,CargoPrefix in pairs(self.Filter.CargoPrefixes)do -self:T3({"Prefix:",string.find(MCargo.Name,CargoPrefix,1),CargoPrefix}) -if string.find(MCargo.Name,CargoPrefix,1)then -MCargoPrefix=true -end -end -self:T({"Evaluated Prefix",MCargoPrefix}) -MCargoInclude=MCargoInclude and MCargoPrefix -end -end -self:T2(MCargoInclude) -return MCargoInclude -end -function SET_CARGO:OnEventNewCargo(EventData) -if EventData.Cargo then -if EventData.Cargo and self:IsIncludeObject(EventData.Cargo)then -self:Add(EventData.Cargo.Name,EventData.Cargo) -end -end -end -function SET_CARGO:OnEventDeleteCargo(EventData) -self:F3({EventData}) -if EventData.Cargo then -local Cargo=_DATABASE:FindCargo(EventData.Cargo.Name) -if Cargo and Cargo.Name then -self:Remove(Cargo.Name) -end -end -end -do -COORDINATE={ -ClassName="COORDINATE", -} -function COORDINATE:New(x,y,z) -local self=BASE:Inherit(self,BASE:New()) -self.x=x -self.y=y -self.z=z -return self -end -function COORDINATE:NewFromVec2(Vec2,LandHeightAdd) -local LandHeight=land.getHeight(Vec2) -LandHeightAdd=LandHeightAdd or 0 -LandHeight=LandHeight+LandHeightAdd -local self=self:New(Vec2.x,LandHeight,Vec2.y) -self:F2(self) -return self -end -function COORDINATE:NewFromVec3(Vec3) -local self=self:New(Vec3.x,Vec3.y,Vec3.z) -self:F2(self) -return self -end -function COORDINATE:GetVec3() -return{x=self.x,y=self.y,z=self.z} -end -function COORDINATE:GetVec2() -return{x=self.x,y=self.z} -end -function COORDINATE:DistanceFromVec2(Vec2Reference) -self:F2(Vec2Reference) -local Distance=((Vec2Reference.x-self.x)^2+(Vec2Reference.y-self.z)^2)^0.5 -self:T2(Distance) -return Distance -end -function COORDINATE:Translate(Distance,Angle) -local SX=self.x -local SY=self.z -local Radians=Angle/180*math.pi -local TX=Distance*math.cos(Radians)+SX -local TY=Distance*math.sin(Radians)+SY -return COORDINATE:NewFromVec2({x=TX,y=TY}) -end -function COORDINATE:GetRandomVec2InRadius(OuterRadius,InnerRadius) -self:F2({OuterRadius,InnerRadius}) -local Theta=2*math.pi*math.random() -local Radials=math.random()+math.random() -if Radials>1 then -Radials=2-Radials -end -local RadialMultiplier -if InnerRadius and InnerRadius<=OuterRadius then -RadialMultiplier=(OuterRadius-InnerRadius)*Radials+InnerRadius -else -RadialMultiplier=OuterRadius*Radials -end -local RandomVec2 -if OuterRadius>0 then -RandomVec2={x=math.cos(Theta)*RadialMultiplier+self.x,y=math.sin(Theta)*RadialMultiplier+self.z} -else -RandomVec2={x=self.x,y=self.z} -end -return RandomVec2 -end -function COORDINATE:GetRandomVec3InRadius(OuterRadius,InnerRadius) -local RandomVec2=self:GetRandomVec2InRadius(OuterRadius,InnerRadius) -local y=self.y+math.random(InnerRadius,OuterRadius) -local RandomVec3={x=RandomVec2.x,y=y,z=RandomVec2.y} -return RandomVec3 -end -function COORDINATE:GetLandHeight() -local Vec2={x=self.x,y=self.z} -return land.getHeight(Vec2) -end -function COORDINATE:SetHeading(Heading) -self.Heading=Heading -end -function COORDINATE:GetHeading() -return self.Heading -end -function COORDINATE:SetVelocity(Velocity) -self.Velocity=Velocity -end -function COORDINATE:GetVelocity() -local Velocity=self.Velocity -return Velocity or 0 -end -function COORDINATE:GetMovingText(Settings) -return self:GetVelocityText(Settings)..", "..self:GetHeadingText(Settings) -end -function COORDINATE:GetDirectionVec3(TargetCoordinate) -return{x=TargetCoordinate.x-self.x,y=TargetCoordinate.y-self.y,z=TargetCoordinate.z-self.z} -end -function COORDINATE:GetNorthCorrectionRadians() -local TargetVec3=self:GetVec3() -local lat,lon=coord.LOtoLL(TargetVec3) -local north_posit=coord.LLtoLO(lat+1,lon) -return math.atan2(north_posit.z-TargetVec3.z,north_posit.x-TargetVec3.x) -end -function COORDINATE:GetAngleRadians(DirectionVec3) -local DirectionRadians=math.atan2(DirectionVec3.z,DirectionVec3.x) -if DirectionRadians<0 then -DirectionRadians=DirectionRadians+2*math.pi -end -return DirectionRadians -end -function COORDINATE:GetAngleDegrees(DirectionVec3) -local AngleRadians=self:GetAngleRadians(DirectionVec3) -local Angle=UTILS.ToDegree(AngleRadians) -return Angle -end -function COORDINATE:Get2DDistance(TargetCoordinate) -local TargetVec3=TargetCoordinate:GetVec3() -local SourceVec3=self:GetVec3() -return((TargetVec3.x-SourceVec3.x)^2+(TargetVec3.z-SourceVec3.z)^2)^0.5 -end -function COORDINATE:Get3DDistance(TargetCoordinate) -local TargetVec3=TargetCoordinate:GetVec3() -local SourceVec3=self:GetVec3() -return((TargetVec3.x-SourceVec3.x)^2+(TargetVec3.y-SourceVec3.y)^2+(TargetVec3.z-SourceVec3.z)^2)^0.5 -end -function COORDINATE:GetBearingText(AngleRadians,Precision,Settings) -local Settings=Settings or _SETTINGS -local AngleDegrees=UTILS.Round(UTILS.ToDegree(AngleRadians),Precision) -local s=string.format('%03d°',AngleDegrees) -return s -end -function COORDINATE:GetDistanceText(Distance,Settings) -local Settings=Settings or _SETTINGS -local DistanceText -if Settings:IsMetric()then -DistanceText=" for "..UTILS.Round(Distance/1000,2).." km" -else -DistanceText=" for "..UTILS.Round(UTILS.MetersToNM(Distance),2).." miles" -end -return DistanceText -end -function COORDINATE:GetAltitudeText(Settings) -local Altitude=self.y -local Settings=Settings or _SETTINGS -if Altitude~=0 then -if Settings:IsMetric()then -return" at "..UTILS.Round(self.y,-3).." meters" -else -return" at "..UTILS.Round(UTILS.MetersToFeet(self.y),-3).." feet" -end -else -return"" -end -end -function COORDINATE:GetVelocityText(Settings) -local Velocity=self:GetVelocity() -local Settings=Settings or _SETTINGS -if Velocity then -if Settings:IsMetric()then -return string.format(" moving at %d km/h",UTILS.MpsToKmph(Velocity)) -else -return string.format(" moving at %d mi/h",UTILS.MpsToKmph(Velocity)/1.852) -end -else -return" stationary" -end -end -function COORDINATE:GetHeadingText(Settings) -local Heading=self:GetHeading() -if Heading then -return string.format(" bearing %3d°",Heading) -else -return" bearing unknown" -end -end -function COORDINATE:GetBRText(AngleRadians,Distance,Settings) -local Settings=Settings or _SETTINGS -local BearingText=self:GetBearingText(AngleRadians,0,Settings) -local DistanceText=self:GetDistanceText(Distance,Settings) -local BRText=BearingText..DistanceText -return BRText -end -function COORDINATE:GetBRAText(AngleRadians,Distance,Settings) -local Settings=Settings or _SETTINGS -local BearingText=self:GetBearingText(AngleRadians,0,Settings) -local DistanceText=self:GetDistanceText(Distance,Settings) -local AltitudeText=self:GetAltitudeText(Settings) -local BRAText=BearingText..DistanceText..AltitudeText -return BRAText -end -function COORDINATE:Translate(Distance,Angle) -local SX=self.x -local SZ=self.z -local Radians=Angle/180*math.pi -local TX=Distance*math.cos(Radians)+SX -local TZ=Distance*math.sin(Radians)+SZ -return COORDINATE:New(TX,self.y,TZ) -end -function COORDINATE:WaypointAir(AltType,Type,Action,Speed,SpeedLocked) -self:F2({AltType,Type,Action,Speed,SpeedLocked}) -local RoutePoint={} -RoutePoint.x=self.x -RoutePoint.y=self.z -RoutePoint.alt=self.y -RoutePoint.alt_type=AltType or"RADIO" -RoutePoint.type=Type or nil -RoutePoint.action=Action or nil -RoutePoint.speed=(Speed and Speed/3.6)or(500/3.6) -RoutePoint.speed_locked=true -RoutePoint.task={} -RoutePoint.task.id="ComboTask" -RoutePoint.task.params={} -RoutePoint.task.params.tasks={} -return RoutePoint -end -function COORDINATE:WaypointGround(Speed,Formation) -self:F2({Formation,Speed}) -local RoutePoint={} -RoutePoint.x=self.x -RoutePoint.y=self.z -RoutePoint.action=Formation or"" -RoutePoint.speed=(Speed or 999)/3.6 -RoutePoint.speed_locked=true -RoutePoint.task={} -RoutePoint.task.id="ComboTask" -RoutePoint.task.params={} -RoutePoint.task.params.tasks={} -return RoutePoint -end -function COORDINATE:Explosion(ExplosionIntensity) -self:F2({ExplosionIntensity}) -trigger.action.explosion(self:GetVec3(),ExplosionIntensity) -end -function COORDINATE:IlluminationBomb() -self:F2() -trigger.action.illuminationBomb(self:GetVec3()) -end -function COORDINATE:Smoke(SmokeColor) -self:F2({SmokeColor}) -trigger.action.smoke(self:GetVec3(),SmokeColor) -end -function COORDINATE:SmokeGreen() -self:F2() -self:Smoke(SMOKECOLOR.Green) -end -function COORDINATE:SmokeRed() -self:F2() -self:Smoke(SMOKECOLOR.Red) -end -function COORDINATE:SmokeWhite() -self:F2() -self:Smoke(SMOKECOLOR.White) -end -function COORDINATE:SmokeOrange() -self:F2() -self:Smoke(SMOKECOLOR.Orange) -end -function COORDINATE:SmokeBlue() -self:F2() -self:Smoke(SMOKECOLOR.Blue) -end -function COORDINATE:Flare(FlareColor,Azimuth) -self:F2({FlareColor}) -trigger.action.signalFlare(self:GetVec3(),FlareColor,Azimuth and Azimuth or 0) -end -function COORDINATE:FlareWhite(Azimuth) -self:F2(Azimuth) -self:Flare(FLARECOLOR.White,Azimuth) -end -function COORDINATE:FlareYellow(Azimuth) -self:F2(Azimuth) -self:Flare(FLARECOLOR.Yellow,Azimuth) -end -function COORDINATE:FlareGreen(Azimuth) -self:F2(Azimuth) -self:Flare(FLARECOLOR.Green,Azimuth) -end -function COORDINATE:FlareRed(Azimuth) -self:F2(Azimuth) -self:Flare(FLARECOLOR.Red,Azimuth) -end -do -function COORDINATE:MarkToAll(MarkText) -local MarkID=UTILS.GetMarkID() -trigger.action.markToAll(MarkID,MarkText,self:GetVec3()) -return MarkID -end -function COORDINATE:MarkToCoalition(MarkText,Coalition) -local MarkID=UTILS.GetMarkID() -trigger.action.markToCoalition(MarkID,MarkText,self:GetVec3(),Coalition) -return MarkID -end -function COORDINATE:MarkToCoalitionRed(MarkText) -return self:MarkToCoalition(MarkText,coalition.side.RED) -end -function COORDINATE:MarkToCoalitionBlue(MarkText) -return self:MarkToCoalition(MarkText,coalition.side.BLUE) -end -function COORDINATE:MarkToGroup(MarkText,MarkGroup) -local MarkID=UTILS.GetMarkID() -trigger.action.markToGroup(MarkID,MarkText,self:GetVec3(),MarkGroup:GetID()) -return MarkID -end -function COORDINATE:RemoveMark(MarkID) -trigger.action.removeMark(MarkID) -end -end -function COORDINATE:IsLOS(ToCoordinate) -local FromVec3=self:GetVec3() -FromVec3.y=FromVec3.y+2 -local ToVec3=ToCoordinate:GetVec3() -ToVec3.y=ToVec3.y+2 -local IsLOS=land.isVisible(FromVec3,ToVec3) -return IsLOS -end -function COORDINATE:IsInRadius(Coordinate,Radius) -local InVec2=self:GetVec2() -local Vec2=Coordinate:GetVec2() -local InRadius=UTILS.IsInRadius(InVec2,Vec2,Radius) -return InRadius -end -function COORDINATE:IsInSphere(Coordinate,Radius) -local InVec3=self:GetVec3() -local Vec3=Coordinate:GetVec3() -local InSphere=UTILS.IsInSphere(InVec3,Vec3,Radius) -return InSphere -end -function COORDINATE:ToStringBR(FromCoordinate,Settings) -local DirectionVec3=FromCoordinate:GetDirectionVec3(self) -local AngleRadians=self:GetAngleRadians(DirectionVec3) -local Distance=self:Get2DDistance(FromCoordinate) -return"BR, "..self:GetBRText(AngleRadians,Distance,Settings) -end -function COORDINATE:ToStringBRA(FromCoordinate,Settings) -local DirectionVec3=FromCoordinate:GetDirectionVec3(self) -local AngleRadians=self:GetAngleRadians(DirectionVec3) -local Distance=FromCoordinate:Get2DDistance(self) -local Altitude=self:GetAltitudeText() -return"BRA, "..self:GetBRAText(AngleRadians,Distance,Settings) -end -function COORDINATE:ToStringBULLS(Coalition,Settings) -local TargetCoordinate=COORDINATE:NewFromVec3(coalition.getMainRefPoint(Coalition)) -local DirectionVec3=self:GetDirectionVec3(TargetCoordinate) -local AngleRadians=self:GetAngleRadians(DirectionVec3) -local Distance=self:Get2DDistance(TargetCoordinate) -local Altitude=self:GetAltitudeText() -return"BULLS, "..self:GetBRText(AngleRadians,Distance,Settings) -end -function COORDINATE:ToStringAspect(TargetCoordinate) -local Heading=self.Heading -local DirectionVec3=self:GetDirectionVec3(TargetCoordinate) -local Angle=self:GetAngleDegrees(DirectionVec3) -if Heading then -local Aspect=Angle-Heading -if Aspect>-135 and Aspect<=-45 then -return"Flanking" -end -if Aspect>-45 and Aspect<=45 then -return"Hot" -end -if Aspect>45 and Aspect<=135 then -return"Flanking" -end -if Aspect>135 or Aspect<=-135 then -return"Cold" -end -end -return"" -end -function COORDINATE:ToStringLLDMS(Settings) -local LL_Accuracy=Settings and Settings.LL_Accuracy or _SETTINGS.LL_Accuracy -local lat,lon=coord.LOtoLL(self:GetVec3()) -return"LL DMS, "..UTILS.tostringLL(lat,lon,LL_Accuracy,true) -end -function COORDINATE:ToStringLLDDM(Settings) -local LL_Accuracy=Settings and Settings.LL_Accuracy or _SETTINGS.LL_Accuracy -local lat,lon=coord.LOtoLL(self:GetVec3()) -return"LL DDM, "..UTILS.tostringLL(lat,lon,LL_Accuracy,false) -end -function COORDINATE:ToStringMGRS(Settings) -local MGRS_Accuracy=Settings and Settings.MGRS_Accuracy or _SETTINGS.MGRS_Accuracy -local lat,lon=coord.LOtoLL(self:GetVec3()) -local MGRS=coord.LLtoMGRS(lat,lon) -return"MGRS, "..UTILS.tostringMGRS(MGRS,MGRS_Accuracy) -end -function COORDINATE:ToStringFromRP(ReferenceCoord,ReferenceName,Controllable,Settings) -self:E({ReferenceCoord=ReferenceCoord,ReferenceName=ReferenceName}) -local Settings=Settings or(Controllable and _DATABASE:GetPlayerSettings(Controllable:GetPlayerName()))or _SETTINGS -local IsAir=Controllable and Controllable:IsAirPlane()or false -if IsAir then -local DirectionVec3=ReferenceCoord:GetDirectionVec3(self) -local AngleRadians=self:GetAngleRadians(DirectionVec3) -local Distance=self:Get2DDistance(ReferenceCoord) -return"Targets are the last seen "..self:GetBRText(AngleRadians,Distance,Settings).." from "..ReferenceName -else -local DirectionVec3=ReferenceCoord:GetDirectionVec3(self) -local AngleRadians=self:GetAngleRadians(DirectionVec3) -local Distance=self:Get2DDistance(ReferenceCoord) -return"Target are located "..self:GetBRText(AngleRadians,Distance,Settings).." from "..ReferenceName -end -return nil -end -function COORDINATE:ToStringA2G(Controllable,Settings) -self:F({Controllable=Controllable and Controllable:GetName()}) -local Settings=Settings or(Controllable and _DATABASE:GetPlayerSettings(Controllable:GetPlayerName()))or _SETTINGS -if Settings:IsA2G_BR()then -if Controllable then -local Coordinate=Controllable:GetCoordinate() -return Controllable and self:ToStringBR(Coordinate,Settings)or self:ToStringMGRS(Settings) -else -return self:ToStringMGRS(Settings) -end -end -if Settings:IsA2G_LL_DMS()then -return self:ToStringLLDMS(Settings) -end -if Settings:IsA2G_LL_DDM()then -return self:ToStringLLDDM(Settings) -end -if Settings:IsA2G_MGRS()then -return self:ToStringMGRS(Settings) -end -return nil -end -function COORDINATE:ToStringA2A(Controllable,Settings) -self:F({Controllable=Controllable and Controllable:GetName()}) -local Settings=Settings or(Controllable and _DATABASE:GetPlayerSettings(Controllable:GetPlayerName()))or _SETTINGS -if Settings:IsA2A_BRAA()then -if Controllable then -local Coordinate=Controllable:GetCoordinate() -return self:ToStringBRA(Coordinate,Settings) -else -return self:ToStringMGRS(Settings) -end -end -if Settings:IsA2A_BULLS()then -local Coalition=Controllable:GetCoalition() -return self:ToStringBULLS(Coalition,Settings) -end -if Settings:IsA2A_LL_DMS()then -return self:ToStringLLDMS(Settings) -end -if Settings:IsA2A_LL_DDM()then -return self:ToStringLLDDM(Settings) -end -if Settings:IsA2A_MGRS()then -return self:ToStringMGRS(Settings) -end -return nil -end -function COORDINATE:ToString(Controllable,Settings,Task) -self:F({Controllable=Controllable and Controllable:GetName()}) -local Settings=Settings or(Controllable and _DATABASE:GetPlayerSettings(Controllable:GetPlayerName()))or _SETTINGS -local ModeA2A=true -if Task then -if Task:IsInstanceOf(TASK_A2A)then -ModeA2A=true -else -if Task:IsInstanceOf(TASK_A2G)then -ModeA2A=false -else -if Task:IsInstanceOf(TASK_CARGO)then -ModeA2A=false -end -end -end -else -local IsAir=Controllable and Controllable:IsAirPlane()or false -if IsAir then -ModeA2A=true -else -ModeA2A=false -end -end -if ModeA2A==true then -return self:ToStringA2A(Controllable,Settings) -else -return self:ToStringA2G(Controllable,Settings) -end -return nil -end -end -do -POINT_VEC3={ -ClassName="POINT_VEC3", -Metric=true, -RoutePointAltType={ -BARO="BARO", -}, -RoutePointType={ -TakeOffParking="TakeOffParking", -TurningPoint="Turning Point", -}, -RoutePointAction={ -FromParkingArea="From Parking Area", -TurningPoint="Turning Point", -}, -} -function POINT_VEC3:New(x,y,z) -local self=BASE:Inherit(self,COORDINATE:New(x,y,z)) -self:F2(self) -return self -end -function POINT_VEC3:NewFromVec2(Vec2,LandHeightAdd) -local self=BASE:Inherit(self,COORDINATE:NewFromVec2(Vec2,LandHeightAdd)) -self:F2(self) -return self -end -function POINT_VEC3:NewFromVec3(Vec3) -local self=BASE:Inherit(self,COORDINATE:NewFromVec3(Vec3)) -self:F2(self) -return self -end -function POINT_VEC3:GetX() -return self.x -end -function POINT_VEC3:GetY() -return self.y -end -function POINT_VEC3:GetZ() -return self.z -end -function POINT_VEC3:SetX(x) -self.x=x -return self -end -function POINT_VEC3:SetY(y) -self.y=y -return self -end -function POINT_VEC3:SetZ(z) -self.z=z -return self -end -function POINT_VEC3:AddX(x) -self.x=self.x+x -return self -end -function POINT_VEC3:AddY(y) -self.y=self.y+y -return self -end -function POINT_VEC3:AddZ(z) -self.z=self.z+z -return self -end -function POINT_VEC3:GetRandomPointVec3InRadius(OuterRadius,InnerRadius) -return POINT_VEC3:NewFromVec3(self:GetRandomVec3InRadius(OuterRadius,InnerRadius)) -end -end -do -POINT_VEC2={ -ClassName="POINT_VEC2", -} -function POINT_VEC2:New(x,y,LandHeightAdd) -local LandHeight=land.getHeight({["x"]=x,["y"]=y}) -LandHeightAdd=LandHeightAdd or 0 -LandHeight=LandHeight+LandHeightAdd -local self=BASE:Inherit(self,COORDINATE:New(x,LandHeight,y)) -self:F2(self) -return self -end -function POINT_VEC2:NewFromVec2(Vec2,LandHeightAdd) -local LandHeight=land.getHeight(Vec2) -LandHeightAdd=LandHeightAdd or 0 -LandHeight=LandHeight+LandHeightAdd -local self=BASE:Inherit(self,COORDINATE:NewFromVec2(Vec2,LandHeightAdd)) -self:F2(self) -return self -end -function POINT_VEC2:NewFromVec3(Vec3) -local self=BASE:Inherit(self,COORDINATE:NewFromVec3(Vec3)) -self:F2(self) -return self -end -function POINT_VEC2:GetX() -return self.x -end -function POINT_VEC2:GetY() -return self.z -end -function POINT_VEC2:SetX(x) -self.x=x -return self -end -function POINT_VEC2:SetY(y) -self.z=y -return self -end -function POINT_VEC2:GetLat() -return self.x -end -function POINT_VEC2:SetLat(x) -self.x=x -return self -end -function POINT_VEC2:GetLon() -return self.z -end -function POINT_VEC2:SetLon(z) -self.z=z -return self -end -function POINT_VEC2:GetAlt() -return self.y~=0 or land.getHeight({x=self.x,y=self.z}) -end -function POINT_VEC2:SetAlt(Altitude) -self.y=Altitude or land.getHeight({x=self.x,y=self.z}) -return self -end -function POINT_VEC2:AddX(x) -self.x=self.x+x -return self -end -function POINT_VEC2:AddY(y) -self.z=self.z+y -return self -end -function POINT_VEC2:AddAlt(Altitude) -self.y=land.getHeight({x=self.x,y=self.z})+Altitude or 0 -return self -end -function POINT_VEC2:GetRandomPointVec2InRadius(OuterRadius,InnerRadius) -self:F2({OuterRadius,InnerRadius}) -return POINT_VEC2:NewFromVec2(self:GetRandomVec2InRadius(OuterRadius,InnerRadius)) -end -function POINT_VEC2:DistanceFromPointVec2(PointVec2Reference) -self:F2(PointVec2Reference) -local Distance=((PointVec2Reference.x-self.x)^2+(PointVec2Reference.z-self.z)^2)^0.5 -self:T2(Distance) -return Distance -end -end -MESSAGE={ -ClassName="MESSAGE", -MessageCategory=0, -MessageID=0, -} -MESSAGE.Type={ -Update="Update", -Information="Information", -Briefing="Briefing Report", -Overview="Overview Report", -Detailed="Detailed Report" -} -function MESSAGE:New(MessageText,MessageDuration,MessageCategory) -local self=BASE:Inherit(self,BASE:New()) -self:F({MessageText,MessageDuration,MessageCategory}) -self.MessageType=nil -if MessageCategory and MessageCategory~=""then -if MessageCategory:sub(-1)~="\n"then -self.MessageCategory=MessageCategory..": " -else -self.MessageCategory=MessageCategory:sub(1,-2)..":\n" -end -else -self.MessageCategory="" -end -self.MessageDuration=MessageDuration or 5 -self.MessageTime=timer.getTime() -self.MessageText=MessageText:gsub("^\n","",1):gsub("\n$","",1) -self.MessageSent=false -self.MessageGroup=false -self.MessageCoalition=false -return self -end -function MESSAGE:NewType(MessageText,MessageType) -local self=BASE:Inherit(self,BASE:New()) -self:F({MessageText}) -self.MessageType=MessageType -self.MessageTime=timer.getTime() -self.MessageText=MessageText:gsub("^\n","",1):gsub("\n$","",1) -return self -end -function MESSAGE:ToClient(Client,Settings) -self:F(Client) -if Client and Client:GetClientGroupID()then -if self.MessageType then -local Settings=Settings or(Client and _DATABASE:GetPlayerSettings(Client:GetPlayerName()))or _SETTINGS -self.MessageDuration=Settings:GetMessageTime(self.MessageType) -self.MessageCategory=self.MessageType..": " -end -if self.MessageDuration~=0 then -local ClientGroupID=Client:GetClientGroupID() -self:T(self.MessageCategory..self.MessageText:gsub("\n$",""):gsub("\n$","").." / "..self.MessageDuration) -trigger.action.outTextForGroup(ClientGroupID,self.MessageCategory..self.MessageText:gsub("\n$",""):gsub("\n$",""),self.MessageDuration) -end -end -return self -end -function MESSAGE:ToGroup(Group,Settings) -self:F(Group.GroupName) -if Group then -if self.MessageType then -local Settings=Settings or(Group and _DATABASE:GetPlayerSettings(Group:GetPlayerName()))or _SETTINGS -self.MessageDuration=Settings:GetMessageTime(self.MessageType) -self.MessageCategory=self.MessageType..": " -end -if self.MessageDuration~=0 then -self:T(self.MessageCategory..self.MessageText:gsub("\n$",""):gsub("\n$","").." / "..self.MessageDuration) -trigger.action.outTextForGroup(Group:GetID(),self.MessageCategory..self.MessageText:gsub("\n$",""):gsub("\n$",""),self.MessageDuration) -end -end -return self -end -function MESSAGE:ToBlue() -self:F() -self:ToCoalition(coalition.side.BLUE) -return self -end -function MESSAGE:ToRed() -self:F() -self:ToCoalition(coalition.side.RED) -return self -end -function MESSAGE:ToCoalition(CoalitionSide,Settings) -self:F(CoalitionSide) -if self.MessageType then -local Settings=Settings or _SETTINGS -self.MessageDuration=Settings:GetMessageTime(self.MessageType) -self.MessageCategory=self.MessageType..": " -end -if CoalitionSide then -if self.MessageDuration~=0 then -self:T(self.MessageCategory..self.MessageText:gsub("\n$",""):gsub("\n$","").." / "..self.MessageDuration) -trigger.action.outTextForCoalition(CoalitionSide,self.MessageCategory..self.MessageText:gsub("\n$",""):gsub("\n$",""),self.MessageDuration) -end -end -return self -end -function MESSAGE:ToCoalitionIf(CoalitionSide,Condition) -self:F(CoalitionSide) -if Condition and Condition==true then -self:ToCoalition(CoalitionSide) -end -return self -end -function MESSAGE:ToAll() -self:F() -if self.MessageType then -local Settings=Settings or _SETTINGS -self.MessageDuration=Settings:GetMessageTime(self.MessageType) -self.MessageCategory=self.MessageType..": " -end -if self.MessageDuration~=0 then -self:T(self.MessageCategory..self.MessageText:gsub("\n$",""):gsub("\n$","").." / "..self.MessageDuration) -trigger.action.outText(self.MessageCategory..self.MessageText:gsub("\n$",""):gsub("\n$",""),self.MessageDuration) -end -return self -end -function MESSAGE:ToAllIf(Condition) -if Condition and Condition==true then -self:ToAll() -end -return self -end -do -FSM={ -ClassName="FSM", -} -function FSM:New(FsmT) -self=BASE:Inherit(self,BASE:New()) -self.options=options or{} -self.options.subs=self.options.subs or{} -self.current=self.options.initial or'none' -self.Events={} -self.subs={} -self.endstates={} -self.Scores={} -self._StartState="none" -self._Transitions={} -self._Processes={} -self._EndStates={} -self._Scores={} -self._EventSchedules={} -self.CallScheduler=SCHEDULER:New(self) -return self -end -function FSM:SetStartState(State) -self._StartState=State -self.current=State -end -function FSM:GetStartState() -return self._StartState or{} -end -function FSM:AddTransition(From,Event,To) -local Transition={} -Transition.From=From -Transition.Event=Event -Transition.To=To -self:T2(Transition) -self._Transitions[Transition]=Transition -self:_eventmap(self.Events,Transition) -end -function FSM:GetTransitions() -return self._Transitions or{} -end -function FSM:AddProcess(From,Event,Process,ReturnEvents) -self:T({From,Event}) -local Sub={} -Sub.From=From -Sub.Event=Event -Sub.fsm=Process -Sub.StartEvent="Start" -Sub.ReturnEvents=ReturnEvents -self._Processes[Sub]=Sub -self:_submap(self.subs,Sub,nil) -self:AddTransition(From,Event,From) -return Process -end -function FSM:GetProcesses() -return self._Processes or{} -end -function FSM:GetProcess(From,Event) -for ProcessID,Process in pairs(self:GetProcesses())do -if Process.From==From and Process.Event==Event then -return Process.fsm -end -end -error("Sub-Process from state "..From.." with event "..Event.." not found!") -end -function FSM:AddEndState(State) -self._EndStates[State]=State -self.endstates[State]=State -end -function FSM:GetEndStates() -return self._EndStates or{} -end -function FSM:AddScore(State,ScoreText,Score) -self:F({State,ScoreText,Score}) -self._Scores[State]=self._Scores[State]or{} -self._Scores[State].ScoreText=ScoreText -self._Scores[State].Score=Score -return self -end -function FSM:AddScoreProcess(From,Event,State,ScoreText,Score) -self:F({From,Event,State,ScoreText,Score}) -local Process=self:GetProcess(From,Event) -Process._Scores[State]=Process._Scores[State]or{} -Process._Scores[State].ScoreText=ScoreText -Process._Scores[State].Score=Score -self:T(Process._Scores) -return Process -end -function FSM:GetScores() -return self._Scores or{} -end -function FSM:GetSubs() -return self.options.subs -end -function FSM:LoadCallBacks(CallBackTable) -for name,callback in pairs(CallBackTable or{})do -self[name]=callback -end -end -function FSM:_eventmap(Events,EventStructure) -local Event=EventStructure.Event -local __Event="__"..EventStructure.Event -self[Event]=self[Event]or self:_create_transition(Event) -self[__Event]=self[__Event]or self:_delayed_transition(Event) -self:T2("Added methods: "..Event..", "..__Event) -Events[Event]=self.Events[Event]or{map={}} -self:_add_to_map(Events[Event].map,EventStructure) -end -function FSM:_submap(subs,sub,name) -subs[sub.From]=subs[sub.From]or{} -subs[sub.From][sub.Event]=subs[sub.From][sub.Event]or{} -subs[sub.From][sub.Event][sub]={} -subs[sub.From][sub.Event][sub].fsm=sub.fsm -subs[sub.From][sub.Event][sub].StartEvent=sub.StartEvent -subs[sub.From][sub.Event][sub].ReturnEvents=sub.ReturnEvents or{} -subs[sub.From][sub.Event][sub].name=name -subs[sub.From][sub.Event][sub].fsmparent=self -end -function FSM:_call_handler(handler,params,EventName) -local ErrorHandler=function(errmsg) -env.info("Error in SCHEDULER function:"..errmsg) -if debug~=nil then -env.info(debug.traceback()) -end -return errmsg -end -if self[handler]then -self:T2("Calling "..handler) -self._EventSchedules[EventName]=nil -local Result,Value=xpcall(function()return self[handler](self,unpack(params))end,ErrorHandler) -return Value -end -end -function FSM._handler(self,EventName,...) -local Can,to=self:can(EventName) -if to=="*"then -to=self.current -end -if Can then -local from=self.current -local params={from,EventName,to,...} -if self.Controllable then -self:T("FSM Transition for "..self.Controllable.ControllableName.." :"..self.current.." --> "..EventName.." --> "..to) -else -self:T("FSM Transition:"..self.current.." --> "..EventName.." --> "..to) -end -if(self:_call_handler("onbefore"..EventName,params,EventName)==false) -or(self:_call_handler("OnBefore"..EventName,params,EventName)==false) -or(self:_call_handler("onleave"..from,params,EventName)==false) -or(self:_call_handler("OnLeave"..from,params,EventName)==false)then -self:T("Cancel Transition") -return false -end -self.current=to -local execute=true -local subtable=self:_gosub(from,EventName) -for _,sub in pairs(subtable)do -self:T("calling sub start event: "..sub.StartEvent) -sub.fsm.fsmparent=self -sub.fsm.ReturnEvents=sub.ReturnEvents -sub.fsm[sub.StartEvent](sub.fsm) -execute=false -end -local fsmparent,Event=self:_isendstate(to) -if fsmparent and Event then -self:F2({"end state: ",fsmparent,Event}) -self:_call_handler("onenter"..to,params,EventName) -self:_call_handler("OnEnter"..to,params,EventName) -self:_call_handler("onafter"..EventName,params,EventName) -self:_call_handler("OnAfter"..EventName,params,EventName) -self:_call_handler("onstatechange",params,EventName) -fsmparent[Event](fsmparent) -execute=false -end -if execute then -self:_call_handler("onenter"..to,params,EventName) -self:_call_handler("OnEnter"..to,params,EventName) -self:_call_handler("onafter"..EventName,params,EventName) -self:_call_handler("OnAfter"..EventName,params,EventName) -self:_call_handler("onstatechange",params,EventName) -end -else -self:T("Cannot execute transition.") -self:T({From=self.current,Event=EventName,To=to,Can=Can}) -end -return nil -end -function FSM:_delayed_transition(EventName) -return function(self,DelaySeconds,...) -self:T2("Delayed Event: "..EventName) -local CallID=0 -if DelaySeconds~=nil then -if DelaySeconds<0 then -DelaySeconds=math.abs(DelaySeconds) -if not self._EventSchedules[EventName]then -CallID=self.CallScheduler:Schedule(self,self._handler,{EventName,...},DelaySeconds or 1) -self._EventSchedules[EventName]=CallID -else -end -else -CallID=self.CallScheduler:Schedule(self,self._handler,{EventName,...},DelaySeconds or 1) -end -else -error("FSM: An asynchronous event trigger requires a DelaySeconds parameter!!! This can be positive or negative! Sorry, but will not process this.") -end -self:T2({CallID=CallID}) -end -end -function FSM:_create_transition(EventName) -return function(self,...)return self._handler(self,EventName,...)end -end -function FSM:_gosub(ParentFrom,ParentEvent) -local fsmtable={} -if self.subs[ParentFrom]and self.subs[ParentFrom][ParentEvent]then -self:T({ParentFrom,ParentEvent,self.subs[ParentFrom],self.subs[ParentFrom][ParentEvent]}) -return self.subs[ParentFrom][ParentEvent] -else -return{} -end -end -function FSM:_isendstate(Current) -local FSMParent=self.fsmparent -if FSMParent and self.endstates[Current]then -self:T({state=Current,endstates=self.endstates,endstate=self.endstates[Current]}) -FSMParent.current=Current -local ParentFrom=FSMParent.current -self:T(ParentFrom) -self:T(self.ReturnEvents) -local Event=self.ReturnEvents[Current] -self:T({ParentFrom,Event,self.ReturnEvents}) -if Event then -return FSMParent,Event -else -self:T({"Could not find parent event name for state ",ParentFrom}) -end -end -return nil -end -function FSM:_add_to_map(Map,Event) -self:F3({Map,Event}) -if type(Event.From)=='string'then -Map[Event.From]=Event.To -else -for _,From in ipairs(Event.From)do -Map[From]=Event.To -end -end -self:T3({Map,Event}) -end -function FSM:GetState() -return self.current -end -function FSM:Is(State) -return self.current==State -end -function FSM:is(state) -return self.current==state -end -function FSM:can(e) -local Event=self.Events[e] -self:F3({self.current,Event}) -local To=Event and Event.map[self.current]or Event.map['*'] -return To~=nil,To -end -function FSM:cannot(e) -return not self:can(e) -end -end -do -FSM_CONTROLLABLE={ -ClassName="FSM_CONTROLLABLE", -} -function FSM_CONTROLLABLE:New(FSMT,Controllable) -local self=BASE:Inherit(self,FSM:New(FSMT)) -if Controllable then -self:SetControllable(Controllable) -end -self:AddTransition("*","Stop","Stopped") -return self -end -function FSM_CONTROLLABLE:OnAfterStop(Controllable,From,Event,To) -self.CallScheduler:Clear() -end -function FSM_CONTROLLABLE:SetControllable(FSMControllable) -self.Controllable=FSMControllable -end -function FSM_CONTROLLABLE:GetControllable() -return self.Controllable -end -function FSM_CONTROLLABLE:_call_handler(handler,params,EventName) -local ErrorHandler=function(errmsg) -env.info("Error in SCHEDULER function:"..errmsg) -if debug~=nil then -env.info(debug.traceback()) -end -return errmsg -end -if self[handler]then -self:F3("Calling "..handler) -self._EventSchedules[EventName]=nil -local Result,Value=xpcall(function()return self[handler](self,self.Controllable,unpack(params))end,ErrorHandler) -return Value -end -end -end -do -FSM_PROCESS={ -ClassName="FSM_PROCESS", -} -function FSM_PROCESS:New(Controllable,Task) -local self=BASE:Inherit(self,FSM_CONTROLLABLE:New()) -self:Assign(Controllable,Task) -return self -end -function FSM_PROCESS:Init(FsmProcess) -self:T("No Initialisation") -end -function FSM_PROCESS:_call_handler(handler,params,EventName) -local ErrorHandler=function(errmsg) -env.info("Error in FSM_PROCESS call handler:"..errmsg) -if debug~=nil then -env.info(debug.traceback()) -end -return errmsg -end -if self[handler]then -self:F3("Calling "..handler) -self._EventSchedules[EventName]=nil -local Result,Value=xpcall(function()return self[handler](self,self.Controllable,self.Task,unpack(params))end,ErrorHandler) -return Value -end -end -function FSM_PROCESS:Copy(Controllable,Task) -self:T({self:GetClassNameAndID()}) -local NewFsm=self:New(Controllable,Task) -NewFsm:Assign(Controllable,Task) -NewFsm:Init(self) -NewFsm:SetStartState(self:GetStartState()) -for TransitionID,Transition in pairs(self:GetTransitions())do -NewFsm:AddTransition(Transition.From,Transition.Event,Transition.To) -end -for ProcessID,Process in pairs(self:GetProcesses())do -local FsmProcess=NewFsm:AddProcess(Process.From,Process.Event,Process.fsm:Copy(Controllable,Task),Process.ReturnEvents) -end -for EndStateID,EndState in pairs(self:GetEndStates())do -self:T(EndState) -NewFsm:AddEndState(EndState) -end -for ScoreID,Score in pairs(self:GetScores())do -self:T(Score) -NewFsm:AddScore(ScoreID,Score.ScoreText,Score.Score) -end -return NewFsm -end -function FSM_PROCESS:Remove() -self:F({self:GetClassNameAndID()}) -self:F("Clearing Schedules") -self.CallScheduler:Clear() -for ProcessID,Process in pairs(self:GetProcesses())do -if Process.fsm then -Process.fsm:Remove() -Process.fsm=nil -end -end -return self -end -function FSM_PROCESS:SetTask(Task) -self.Task=Task -return self -end -function FSM_PROCESS:GetTask() -return self.Task -end -function FSM_PROCESS:GetMission() -return self.Task.Mission -end -function FSM_PROCESS:GetCommandCenter() -return self:GetTask():GetMission():GetCommandCenter() -end -function FSM_PROCESS:Message(Message) -self:F({Message=Message}) -local CC=self:GetCommandCenter() -local TaskGroup=self.Controllable:GetGroup() -local PlayerName=self.Controllable:GetPlayerName() -PlayerName=PlayerName and" ("..PlayerName..")"or"" -local Callsign=self.Controllable:GetCallsign() -local Prefix=Callsign and" @ "..Callsign..PlayerName or"" -Message=Prefix..": "..Message -CC:MessageToGroup(Message,TaskGroup) -end -function FSM_PROCESS:Assign(ProcessUnit,Task) -self:SetControllable(ProcessUnit) -self:SetTask(Task) -return self -end -function FSM_PROCESS:onenterAssigned(ProcessUnit) -self:T("Assign") -self.Task:Assign() -end -function FSM_PROCESS:onenterFailed(ProcessUnit) -self:T("Failed") -self.Task:Fail() -end -function FSM_PROCESS:onstatechange(ProcessUnit,Task,From,Event,To,Dummy) -self:T({ProcessUnit:GetName(),From,Event,To,Dummy,self:IsTrace()}) -if self:IsTrace()then -end -self:T({Scores=self._Scores,To=To}) -if self._Scores[To]then -local Task=self.Task -local Scoring=Task:GetScoring() -if Scoring then -Scoring:_AddMissionTaskScore(Task.Mission,ProcessUnit,self._Scores[To].ScoreText,self._Scores[To].Score) -end -end -end -end -do -FSM_TASK={ -ClassName="FSM_TASK", -} -function FSM_TASK:New(FSMT) -local self=BASE:Inherit(self,FSM_CONTROLLABLE:New(FSMT)) -self["onstatechange"]=self.OnStateChange -return self -end -function FSM_TASK:_call_handler(handler,params,EventName) -if self[handler]then -self:T("Calling "..handler) -self._EventSchedules[EventName]=nil -return self[handler](self,unpack(params)) -end -end -end -do -FSM_SET={ -ClassName="FSM_SET", -} -function FSM_SET:New(FSMSet) -self=BASE:Inherit(self,FSM:New()) -if FSMSet then -self:Set(FSMSet) -end -return self -end -function FSM_SET:Set(FSMSet) -self:F(FSMSet) -self.Set=FSMSet -end -function FSM_SET:Get() -return self.Controllable -end -function FSM_SET:_call_handler(handler,params,EventName) -if self[handler]then -self:T("Calling "..handler) -self._EventSchedules[EventName]=nil -return self[handler](self,self.Set,unpack(params)) -end -end -end -RADIO={ -ClassName="RADIO", -FileName="", -Frequency=0, -Modulation=radio.modulation.AM, -Subtitle="", -SubtitleDuration=0, -Power=100, -Loop=true, -} -function RADIO:New(Positionable) -local self=BASE:Inherit(self,BASE:New()) -self.Loop=true -self:F(Positionable) -if Positionable:GetPointVec2()then -self.Positionable=Positionable -return self -end -self:E({"The passed positionable is invalid, no RADIO created",Positionable}) -return nil -end -function RADIO:SetFileName(FileName) -self:F2(FileName) -if type(FileName)=="string"then -if FileName:find(".ogg")or FileName:find(".wav")then -if not FileName:find("l10n/DEFAULT/")then -FileName="l10n/DEFAULT/"..FileName -end -self.FileName=FileName -return self -end -end -self:E({"File name invalid. Maybe something wrong with the extension ?",self.FileName}) -return self -end -function RADIO:SetFrequency(Frequency) -self:F2(Frequency) -if type(Frequency)=="number"then -if(Frequency>=30 and Frequency<88)or(Frequency>=108 and Frequency<152)or(Frequency>=225 and Frequency<400)then -self.Frequency=Frequency*1000000 -if self.Positionable.ClassName=="UNIT"or self.Positionable.ClassName=="GROUP"then -self.Positionable:SetCommand({ -id="SetFrequency", -params={ -frequency=self.Frequency, -modulation=self.Modulation, -} -}) -end -return self -end -end -self:E({"Frequency is outside of DCS Frequency ranges (30-80, 108-152, 225-400). Frequency unchanged.",self.Frequency}) -return self -end -function RADIO:SetModulation(Modulation) -self:F2(Modulation) -if type(Modulation)=="number"then -if Modulation==radio.modulation.AM or Modulation==radio.modulation.FM then -self.Modulation=Modulation -return self -end -end -self:E({"Modulation is invalid. Use DCS's enum radio.modulation. Modulation unchanged.",self.Modulation}) -return self -end -function RADIO:SetPower(Power) -self:F2(Power) -if type(Power)=="number"then -self.Power=math.floor(math.abs(Power)) -return self -end -self:E({"Power is invalid. Power unchanged.",self.Power}) -return self -end -function RADIO:SetLoop(Loop) -self:F2(Loop) -if type(Loop)=="boolean"then -self.Loop=Loop -return self -end -self:E({"Loop is invalid. Loop unchanged.",self.Loop}) -return self -end -function RADIO:SetSubtitle(Subtitle,SubtitleDuration) -self:F2({Subtitle,SubtitleDuration}) -if type(Subtitle)=="string"then -self.Subtitle=Subtitle -else -self.Subtitle="" -self:E({"Subtitle is invalid. Subtitle reset.",self.Subtitle}) -end -if type(SubtitleDuration)=="number"then -if math.floor(math.abs(SubtitleDuration))==SubtitleDuration then -self.SubtitleDuration=SubtitleDuration -return self -end -end -self.SubtitleDuration=0 -self:E({"SubtitleDuration is invalid. SubtitleDuration reset.",self.SubtitleDuration}) -end -function RADIO:NewGenericTransmission(FileName,Frequency,Modulation,Power,Loop) -self:F({FileName,Frequency,Modulation,Power}) -self:SetFileName(FileName) -if Frequency then self:SetFrequency(Frequency)end -if Modulation then self:SetModulation(Modulation)end -if Power then self:SetPower(Power)end -if Loop then self:SetLoop(Loop)end -return self -end -function RADIO:NewUnitTransmission(FileName,Subtitle,SubtitleDuration,Frequency,Modulation,Loop) -self:F({FileName,Subtitle,SubtitleDuration,Frequency,Modulation,Loop}) -self:SetFileName(FileName) -if Subtitle then self:SetSubtitle(Subtitle)end -if SubtitleDuration then self:SetSubtitleDuration(SubtitleDuration)end -if Frequency then self:SetFrequency(Frequency)end -if Modulation then self:SetModulation(Modulation)end -if Loop then self:SetLoop(Loop)end -return self -end -function RADIO:Broadcast() -self:F() -if self.Positionable.ClassName=="UNIT"or self.Positionable.ClassName=="GROUP"then -self:T2("Broadcasting from a UNIT or a GROUP") -self.Positionable:SetCommand({ -id="TransmitMessage", -params={ -file=self.FileName, -duration=self.SubtitleDuration, -subtitle=self.Subtitle, -loop=self.Loop, -} -}) -else -self:T2("Broadcasting from a POSITIONABLE") -trigger.action.radioTransmission(self.FileName,self.Positionable:GetPositionVec3(),self.Modulation,self.Loop,self.Frequency,self.Power,tostring(self.ID)) -end -return self -end -function RADIO:StopBroadcast() -self:F() -if self.Positionable.ClassName=="UNIT"or self.Positionable.ClassName=="GROUP"then -self.Positionable:SetCommand({ -id="StopTransmission", -params={} -}) -else -trigger.action.stopRadioTransmission(tostring(self.ID)) -end -return self -end -BEACON={ -ClassName="BEACON", -} -function BEACON:New(Positionable) -local self=BASE:Inherit(self,BASE:New()) -self:F(Positionable) -if Positionable:GetPointVec2()then -self.Positionable=Positionable -return self -end -self:E({"The passed positionable is invalid, no BEACON created",Positionable}) -return nil -end -function BEACON:_TACANToFrequency(TACANChannel,TACANMode) -self:F3({TACANChannel,TACANMode}) -if type(TACANChannel)~="number"then -if TACANMode~="X"and TACANMode~="Y"then -return nil -end -end -local A=1151 -local B=64 -if TACANChannel<64 then -B=1 -end -if TACANMode=='Y'then -A=1025 -if TACANChannel<64 then -A=1088 -end -else -if TACANChannel<64 then -A=962 -end -end -return(A+TACANChannel-B)*1000000 -end -function BEACON:AATACAN(TACANChannel,Message,Bearing,BeaconDuration) -self:F({TACANChannel,Message,Bearing,BeaconDuration}) -local IsValid=true -if not self.Positionable:IsAir()then -self:E({"The POSITIONABLE you want to attach the AA Tacan Beacon is not an aircraft ! The BEACON is not emitting",self.Positionable}) -IsValid=false -end -local Frequency=self:_TACANToFrequency(TACANChannel,"Y") -if not Frequency then -self:E({"The passed TACAN channel is invalid, the BEACON is not emitting"}) -IsValid=false -end -local System -if Bearing then -System=5 -else -System=14 -end -if IsValid then -self:T2({"AA TACAN BEACON started !"}) -self.Positionable:SetCommand({ -id="ActivateBeacon", -params={ -type=4, -system=System, -callsign=Message, -frequency=Frequency, -} -}) -if BeaconDuration then -SCHEDULER:New(nil, -function() -self:StopAATACAN() -end,{},BeaconDuration) -end -end -return self -end -function BEACON:StopAATACAN() -self:F() -if not self.Positionable then -self:E({"Start the beacon first before stoping it !"}) -else -self.Positionable:SetCommand({ -id='DeactivateBeacon', -params={ -} -}) -end -end -function BEACON:RadioBeacon(FileName,Frequency,Modulation,Power,BeaconDuration) -self:F({FileName,Frequency,Modulation,Power,BeaconDuration}) -local IsValid=false -if type(FileName)=="string"then -if FileName:find(".ogg")or FileName:find(".wav")then -if not FileName:find("l10n/DEFAULT/")then -FileName="l10n/DEFAULT/"..FileName -end -IsValid=true -end -end -if not IsValid then -self:E({"File name invalid. Maybe something wrong with the extension ? ",FileName}) -end -if type(Frequency)~="number"and IsValid then -self:E({"Frequency invalid. ",Frequency}) -IsValid=false -end -Frequency=Frequency*1000000 -if Modulation~=radio.modulation.AM and Modulation~=radio.modulation.FM and IsValid then -self:E({"Modulation is invalid. Use DCS's enum radio.modulation.",Modulation}) -IsValid=false -end -if type(Power)~="number"and IsValid then -self:E({"Power is invalid. ",Power}) -IsValid=false -end -Power=math.floor(math.abs(Power)) -if IsValid then -self:T2({"Activating Beacon on ",Frequency,Modulation}) -trigger.action.radioTransmission(FileName,self.Positionable:GetPositionVec3(),Modulation,true,Frequency,Power,tostring(self.ID)) -if BeaconDuration then -SCHEDULER:New(nil, -function() -self:StopRadioBeacon() -end,{},BeaconDuration) -end -end -end -function BEACON:StopRadioBeacon() -self:F() -trigger.action.stopRadioTransmission(tostring(self.ID)) -end -SPAWNSTATIC={ -ClassName="SPAWNSTATIC", -} -function SPAWNSTATIC:NewFromStatic(SpawnTemplatePrefix,CountryID) -local self=BASE:Inherit(self,BASE:New()) -self:F({SpawnTemplatePrefix}) -local TemplateStatic=StaticObject.getByName(SpawnTemplatePrefix) -if TemplateStatic then -self.SpawnTemplatePrefix=SpawnTemplatePrefix -self.CountryID=CountryID -self.SpawnIndex=0 -else -error("SPAWNSTATIC:New: There is no group declared in the mission editor with SpawnTemplatePrefix = '"..SpawnTemplatePrefix.."'") -end -self:SetEventPriority(5) -return self -end -function SPAWNSTATIC:NewFromType(SpawnTypeName,SpawnShapeName,SpawnCategory,CountryID) -local self=BASE:Inherit(self,BASE:New()) -self:F({SpawnTypeName}) -self.SpawnTypeName=SpawnTypeName -self.CountryID=CountryID -self.SpawnIndex=0 -self:SetEventPriority(5) -return self -end -function SPAWNSTATIC:SpawnFromPointVec2(PointVec2,Heading,NewName) -self:F({PointVec2,Heading,NewName}) -local CountryName=_DATABASE.COUNTRY_NAME[self.CountryID] -local StaticTemplate=_DATABASE:GetStaticUnitTemplate(self.SpawnTemplatePrefix) -StaticTemplate.x=PointVec2:GetLat() -StaticTemplate.y=PointVec2:GetLon() -StaticTemplate.name=NewName or string.format("%s#%05d",self.SpawnTemplatePrefix,self.SpawnIndex) -StaticTemplate.heading=(Heading/180)*math.pi -StaticTemplate.CountryID=nil -StaticTemplate.CoalitionID=nil -StaticTemplate.CategoryID=nil -local Static=coalition.addStaticObject(self.CountryID,StaticTemplate) -self.SpawnIndex=self.SpawnIndex+1 -return Static -end -function SPAWNSTATIC:SpawnFromZone(Zone,Heading,NewName) -self:F({Zone,Heading,NewName}) -local Static=self:SpawnFromPointVec2(Zone:GetPointVec2(),Heading,NewName) -return Static -end -CARGOS={} -do -CARGO={ -ClassName="CARGO", -Type=nil, -Name=nil, -Weight=nil, -CargoObject=nil, -CargoCarrier=nil, -Representable=false, -Slingloadable=false, -Moveable=false, -Containable=false, -} -function CARGO:New(Type,Name,Weight) -local self=BASE:Inherit(self,FSM:New()) -self:F({Type,Name,Weight}) -self:SetStartState("UnLoaded") -self:AddTransition({"UnLoaded","Boarding"},"Board","Boarding") -self:AddTransition("Boarding","Boarding","Boarding") -self:AddTransition("Boarding","CancelBoarding","UnLoaded") -self:AddTransition("Boarding","Load","Loaded") -self:AddTransition("UnLoaded","Load","Loaded") -self:AddTransition("Loaded","UnBoard","UnBoarding") -self:AddTransition("UnBoarding","UnBoarding","UnBoarding") -self:AddTransition("UnBoarding","UnLoad","UnLoaded") -self:AddTransition("Loaded","UnLoad","UnLoaded") -self:AddTransition("*","Damaged","Damaged") -self:AddTransition("*","Destroyed","Destroyed") -self:AddTransition("*","Respawn","UnLoaded") -self.Type=Type -self.Name=Name -self.Weight=Weight -self.CargoObject=nil -self.CargoCarrier=nil -self.Representable=false -self.Slingloadable=false -self.Moveable=false -self.Containable=false -self:SetDeployed(false) -self.CargoScheduler=SCHEDULER:New() -CARGOS[self.Name]=self -return self -end -function CARGO:Destroy() -if self.CargoObject then -self.CargoObject:Destroy() -end -self:Destroyed() -end -function CARGO:GetName() -return self.Name -end -function CARGO:GetObjectName() -if self:IsLoaded()then -return self.CargoCarrier:GetName() -else -return self.CargoObject:GetName() -end -end -function CARGO:GetType() -return self.Type -end -function CARGO:GetCoordinate() -return self.CargoObject:GetCoordinate() -end -function CARGO:IsDestroyed() -return self:Is("Destroyed") -end -function CARGO:IsLoaded() -return self:Is("Loaded") -end -function CARGO:IsUnLoaded() -return self:Is("UnLoaded") -end -function CARGO:IsAlive() -if self:IsLoaded()then -return self.CargoCarrier:IsAlive() -else -return self.CargoObject:IsAlive() -end -end -function CARGO:SetDeployed(Deployed) -self.Deployed=Deployed -end -function CARGO:IsDeployed() -return self.Deployed -end -function CARGO:Spawn(PointVec2) -self:F() -end -function CARGO:Flare(FlareColor) -if self:IsUnLoaded()then -trigger.action.signalFlare(self.CargoObject:GetVec3(),FlareColor,0) -end -end -function CARGO:FlareWhite() -self:Flare(trigger.flareColor.White) -end -function CARGO:FlareYellow() -self:Flare(trigger.flareColor.Yellow) -end -function CARGO:FlareGreen() -self:Flare(trigger.flareColor.Green) -end -function CARGO:FlareRed() -self:Flare(trigger.flareColor.Red) -end -function CARGO:Smoke(SmokeColor,Range) -self:F2() -if self:IsUnLoaded()then -if Range then -trigger.action.smoke(self.CargoObject:GetRandomVec3(Range),SmokeColor) -else -trigger.action.smoke(self.CargoObject:GetVec3(),SmokeColor) -end -end -end -function CARGO:SmokeGreen() -self:Smoke(trigger.smokeColor.Green,Range) -end -function CARGO:SmokeRed() -self:Smoke(trigger.smokeColor.Red,Range) -end -function CARGO:SmokeWhite() -self:Smoke(trigger.smokeColor.White,Range) -end -function CARGO:SmokeOrange() -self:Smoke(trigger.smokeColor.Orange,Range) -end -function CARGO:SmokeBlue() -self:Smoke(trigger.smokeColor.Blue,Range) -end -function CARGO:IsInZone(Zone) -self:F({Zone}) -if self:IsLoaded()then -return Zone:IsPointVec2InZone(self.CargoCarrier:GetPointVec2()) -else -self:F({Size=self.CargoObject:GetSize(),Units=self.CargoObject:GetUnits()}) -if self.CargoObject:GetSize()~=0 then -return Zone:IsPointVec2InZone(self.CargoObject:GetPointVec2()) -else -return false -end -end -return nil -end -function CARGO:IsNear(PointVec2,NearRadius) -self:F({PointVec2,NearRadius}) -local Distance=PointVec2:DistanceFromPointVec2(self.CargoObject:GetPointVec2()) -self:T(Distance) -if Distance<=NearRadius then -return true -else -return false -end -end -function CARGO:GetPointVec2() -return self.CargoObject:GetPointVec2() -end -function CARGO:GetCoordinate() -return self.CargoObject:GetCoordinate() -end -function CARGO:SetWeight(Weight) -self.Weight=Weight -return self -end -end -do -CARGO_REPRESENTABLE={ -ClassName="CARGO_REPRESENTABLE" -} -function CARGO_REPRESENTABLE:New(CargoObject,Type,Name,Weight,ReportRadius,NearRadius) -local self=BASE:Inherit(self,CARGO:New(Type,Name,Weight,ReportRadius,NearRadius)) -self:F({Type,Name,Weight,ReportRadius,NearRadius}) -return self -end -function CARGO_REPRESENTABLE:RouteTo(ToPointVec2,Speed) -self:F2(ToPointVec2) -local Points={} -local PointStartVec2=self.CargoObject:GetPointVec2() -Points[#Points+1]=PointStartVec2:WaypointGround(Speed) -Points[#Points+1]=ToPointVec2:WaypointGround(Speed) -local TaskRoute=self.CargoObject:TaskRoute(Points) -self.CargoObject:SetTask(TaskRoute,2) -return self -end -end -do -CARGO_REPORTABLE={ -ClassName="CARGO_REPORTABLE" -} -function CARGO_REPORTABLE:New(CargoObject,Type,Name,Weight,ReportRadius) -local self=BASE:Inherit(self,CARGO:New(Type,Name,Weight)) -self:F({Type,Name,Weight,ReportRadius}) -self.CargoSet=SET_CARGO:New() -self.ReportRadius=ReportRadius or 1000 -self.CargoObject=CargoObject -return self -end -function CARGO_REPORTABLE:IsInRadius(PointVec2) -self:F({PointVec2}) -local Distance=0 -if self:IsLoaded()then -Distance=PointVec2:DistanceFromPointVec2(self.CargoCarrier:GetPointVec2()) -else -Distance=PointVec2:DistanceFromPointVec2(self.CargoObject:GetPointVec2()) -end -self:T(Distance) -if Distance<=self.ReportRadius then -return true -else -return false -end -end -function CARGO_REPORTABLE:MessageToGroup(Message,TaskGroup,Name) -local Prefix=Name and"@ "..Name..": "or"@ "..TaskGroup:GetCallsign()..": " -Message=Prefix..Message -MESSAGE:New(Message,20,"Cargo: "..self:GetName()):ToGroup(TaskGroup) -end -function CARGO_REPORTABLE:GetBoardingRange() -return self.ReportRadius -end -function CARGO_REPORTABLE:Respawn() -self:F({"Respawning"}) -for CargoID,CargoData in pairs(self.CargoSet:GetSet())do -local Cargo=CargoData -Cargo:Destroy() -Cargo:SetStartState("UnLoaded") -end -local CargoObject=self.CargoObject -CargoObject:Destroy() -local Template=CargoObject:GetTemplate() -CargoObject:Respawn(Template) -self:SetDeployed(false) -local WeightGroup=0 -self:SetStartState("UnLoaded") -end -end -do -CARGO_UNIT={ -ClassName="CARGO_UNIT" -} -function CARGO_UNIT:New(CargoUnit,Type,Name,Weight,NearRadius) -local self=BASE:Inherit(self,CARGO_REPRESENTABLE:New(CargoUnit,Type,Name,Weight,NearRadius)) -self:F({Type,Name,Weight,NearRadius}) -self:T(CargoUnit) -self.CargoObject=CargoUnit -self:T(self.ClassName) -self:SetEventPriority(5) -return self -end -function CARGO_UNIT:Destroy() -self:F({CargoName=self:GetName()}) -_EVENTDISPATCHER:CreateEventDeleteCargo(self) -return self -end -function CARGO_UNIT:onenterUnBoarding(From,Event,To,ToPointVec2,NearRadius) -self:F({From,Event,To,ToPointVec2,NearRadius}) -NearRadius=NearRadius or 25 -local Angle=180 -local Speed=60 -local DeployDistance=9 -local RouteDistance=60 -if From=="Loaded"then -local CargoCarrier=self.CargoCarrier -local CargoCarrierPointVec2=CargoCarrier:GetPointVec2() -local CargoCarrierHeading=self.CargoCarrier:GetHeading() -local CargoDeployHeading=((CargoCarrierHeading+Angle)>=360)and(CargoCarrierHeading+Angle-360)or(CargoCarrierHeading+Angle) -local CargoRoutePointVec2=CargoCarrierPointVec2:Translate(RouteDistance,CargoDeployHeading) -ToPointVec2=ToPointVec2 or CargoRoutePointVec2 -local DirectionVec3=CargoCarrierPointVec2:GetDirectionVec3(ToPointVec2) -local Angle=CargoCarrierPointVec2:GetAngleDegrees(DirectionVec3) -local CargoDeployPointVec2=CargoCarrierPointVec2:Translate(DeployDistance,Angle) -local FromPointVec2=CargoCarrierPointVec2 -if self.CargoObject then -self.CargoObject:ReSpawn(CargoDeployPointVec2:GetVec3(),CargoDeployHeading) -self:F({"CargoUnits:",self.CargoObject:GetGroup():GetName()}) -self.CargoCarrier=nil -local Points={} -Points[#Points+1]=CargoCarrierPointVec2:WaypointGround(Speed) -Points[#Points+1]=ToPointVec2:WaypointGround(Speed) -local TaskRoute=self.CargoObject:TaskRoute(Points) -self.CargoObject:SetTask(TaskRoute,1) -self:__UnBoarding(1,ToPointVec2,NearRadius) -end -end -end -function CARGO_UNIT:onleaveUnBoarding(From,Event,To,ToPointVec2,NearRadius) -self:F({From,Event,To,ToPointVec2,NearRadius}) -NearRadius=NearRadius or 25 -local Angle=180 -local Speed=10 -local Distance=5 -if From=="UnBoarding"then -if self:IsNear(ToPointVec2,NearRadius)then -return true -else -self:__UnBoarding(1,ToPointVec2,NearRadius) -end -return false -end -end -function CARGO_UNIT:onafterUnBoarding(From,Event,To,ToPointVec2,NearRadius) -self:F({From,Event,To,ToPointVec2,NearRadius}) -NearRadius=NearRadius or 25 -self.CargoInAir=self.CargoObject:InAir() -self:T(self.CargoInAir) -if not self.CargoInAir then -end -self:__UnLoad(1,ToPointVec2,NearRadius) -end -function CARGO_UNIT:onenterUnLoaded(From,Event,To,ToPointVec2) -self:F({ToPointVec2,From,Event,To}) -local Angle=180 -local Speed=10 -local Distance=5 -if From=="Loaded"then -local StartPointVec2=self.CargoCarrier:GetPointVec2() -local CargoCarrierHeading=self.CargoCarrier:GetHeading() -local CargoDeployHeading=((CargoCarrierHeading+Angle)>=360)and(CargoCarrierHeading+Angle-360)or(CargoCarrierHeading+Angle) -local CargoDeployPointVec2=StartPointVec2:Translate(Distance,CargoDeployHeading) -ToPointVec2=ToPointVec2 or POINT_VEC2:New(CargoDeployPointVec2:GetX(),CargoDeployPointVec2:GetY()) -if self.CargoObject then -self.CargoObject:ReSpawn(ToPointVec2:GetVec3(),0) -self.CargoCarrier=nil -end -end -if self.OnUnLoadedCallBack then -self.OnUnLoadedCallBack(self,unpack(self.OnUnLoadedParameters)) -self.OnUnLoadedCallBack=nil -end -end -function CARGO_UNIT:onafterBoard(From,Event,To,CargoCarrier,NearRadius,...) -self:F({From,Event,To,CargoCarrier,NearRadius}) -local NearRadius=NearRadius or 25 -self.CargoInAir=self.CargoObject:InAir() -self:T(self.CargoInAir) -if not self.CargoInAir then -if self:IsNear(CargoCarrier:GetPointVec2(),NearRadius)then -self:Load(CargoCarrier,NearRadius,...) -else -local Speed=90 -local Angle=180 -local Distance=5 -NearRadius=NearRadius or 25 -local CargoCarrierPointVec2=CargoCarrier:GetPointVec2() -local CargoCarrierHeading=CargoCarrier:GetHeading() -local CargoDeployHeading=((CargoCarrierHeading+Angle)>=360)and(CargoCarrierHeading+Angle-360)or(CargoCarrierHeading+Angle) -local CargoDeployPointVec2=CargoCarrierPointVec2:Translate(Distance,CargoDeployHeading) -local Points={} -local PointStartVec2=self.CargoObject:GetPointVec2() -Points[#Points+1]=PointStartVec2:WaypointGround(Speed) -Points[#Points+1]=CargoDeployPointVec2:WaypointGround(Speed) -local TaskRoute=self.CargoObject:TaskRoute(Points) -self.CargoObject:SetTask(TaskRoute,2) -self:__Boarding(-1,CargoCarrier,NearRadius) -self.RunCount=0 -end -end -end -function CARGO_UNIT:onafterBoarding(From,Event,To,CargoCarrier,NearRadius,...) -self:F({From,Event,To,CargoCarrier.UnitName,NearRadius}) -if CargoCarrier and CargoCarrier:IsAlive()then -if CargoCarrier:InAir()==false then -if self:IsNear(CargoCarrier:GetPointVec2(),NearRadius)then -self:__Load(1,CargoCarrier,...) -else -self:__Boarding(-1,CargoCarrier,NearRadius,...) -self.RunCount=self.RunCount+1 -if self.RunCount>=20 then -self.RunCount=0 -local Speed=90 -local Angle=180 -local Distance=5 -NearRadius=NearRadius or 25 -local CargoCarrierPointVec2=CargoCarrier:GetPointVec2() -local CargoCarrierHeading=CargoCarrier:GetHeading() -local CargoDeployHeading=((CargoCarrierHeading+Angle)>=360)and(CargoCarrierHeading+Angle-360)or(CargoCarrierHeading+Angle) -local CargoDeployPointVec2=CargoCarrierPointVec2:Translate(Distance,CargoDeployHeading) -local Points={} -local PointStartVec2=self.CargoObject:GetPointVec2() -Points[#Points+1]=PointStartVec2:WaypointGround(Speed) -Points[#Points+1]=CargoDeployPointVec2:WaypointGround(Speed) -local TaskRoute=self.CargoObject:TaskRoute(Points) -self.CargoObject:SetTask(TaskRoute,0.2) -end -end -else -self.CargoObject:MessageToGroup("Cancelling Boarding... Get back on the ground!",5,CargoCarrier:GetGroup(),self:GetName()) -self:CancelBoarding(CargoCarrier,NearRadius,...) -self.CargoObject:SetCommand(self.CargoObject:CommandStopRoute(true)) -end -else -self:E("Something is wrong") -end -end -function CARGO_UNIT:onenterBoarding(From,Event,To,CargoCarrier,NearRadius,...) -self:F({From,Event,To,CargoCarrier.UnitName,NearRadius}) -local Speed=90 -local Angle=180 -local Distance=5 -local NearRadius=NearRadius or 25 -if From=="UnLoaded"or From=="Boarding"then -end -end -function CARGO_UNIT:onenterLoaded(From,Event,To,CargoCarrier) -self:F({From,Event,To,CargoCarrier}) -self.CargoCarrier=CargoCarrier -if self.CargoObject then -self:T("Destroying") -self.CargoObject:Destroy() -end -end -end -do -CARGO_GROUP={ -ClassName="CARGO_GROUP", -} -function CARGO_GROUP:New(CargoGroup,Type,Name,ReportRadius) -local self=BASE:Inherit(self,CARGO_REPORTABLE:New(CargoGroup,Type,Name,0,ReportRadius)) -self:F({Type,Name,ReportRadius}) -self.CargoObject=CargoGroup -self:SetDeployed(false) -self.CargoGroup=CargoGroup -local WeightGroup=0 -for UnitID,UnitData in pairs(CargoGroup:GetUnits())do -local Unit=UnitData -local WeightUnit=Unit:GetDesc().massEmpty -WeightGroup=WeightGroup+WeightUnit -local CargoUnit=CARGO_UNIT:New(Unit,Type,Unit:GetName(),WeightUnit) -self.CargoSet:Add(CargoUnit:GetName(),CargoUnit) -end -self:SetWeight(WeightGroup) -self:T({"Weight Cargo",WeightGroup}) -_EVENTDISPATCHER:CreateEventNewCargo(self) -self:HandleEvent(EVENTS.Dead,self.OnEventCargoDead) -self:HandleEvent(EVENTS.Crash,self.OnEventCargoDead) -self:HandleEvent(EVENTS.PlayerLeaveUnit,self.OnEventCargoDead) -self:SetEventPriority(4) -return self -end -function CARGO_GROUP:OnEventCargoDead(EventData) -local Destroyed=false -if self:IsDestroyed()or self:IsUnLoaded()then -Destroyed=true -for CargoID,CargoData in pairs(self.CargoSet:GetSet())do -local Cargo=CargoData -if Cargo:IsAlive()then -Destroyed=false -else -Cargo:Destroyed() -end -end -else -local CarrierName=self.CargoCarrier:GetName() -if CarrierName==EventData.IniDCSUnitName then -MESSAGE:New("Cargo is lost from carrier "..CarrierName,15):ToAll() -Destroyed=true -self.CargoCarrier:ClearCargo() -end -end -if Destroyed then -self:Destroyed() -self:E({"Cargo group destroyed"}) -end -end -function CARGO_GROUP:onenterBoarding(From,Event,To,CargoCarrier,NearRadius,...) -self:F({CargoCarrier.UnitName,From,Event,To}) -local NearRadius=NearRadius or 25 -if From=="UnLoaded"then -self.CargoSet:ForEach( -function(Cargo,...) -Cargo:__Board(1,CargoCarrier,NearRadius,...) -end,... -) -self:__Boarding(1,CargoCarrier,NearRadius,...) -end -end -function CARGO_GROUP:onenterLoaded(From,Event,To,CargoCarrier,...) -self:F({From,Event,To,CargoCarrier,...}) -if From=="UnLoaded"then -for CargoID,Cargo in pairs(self.CargoSet:GetSet())do -Cargo:Load(CargoCarrier) -end -end -self.CargoCarrier=CargoCarrier -end -function CARGO_GROUP:onafterBoarding(From,Event,To,CargoCarrier,NearRadius,...) -self:F({CargoCarrier.UnitName,From,Event,To}) -local NearRadius=NearRadius or 25 -local Boarded=true -local Cancelled=false -local Dead=true -self.CargoSet:Flush() -for CargoID,Cargo in pairs(self.CargoSet:GetSet())do -self:T({Cargo:GetName(),Cargo.current}) -if not Cargo:is("Loaded")then -Boarded=false -end -if Cargo:is("UnLoaded")then -Cancelled=true -end -if not Cargo:is("Destroyed")then -Dead=false -end -end -if not Dead then -if not Cancelled then -if not Boarded then -self:__Boarding(1,CargoCarrier,NearRadius,...) -else -self:__Load(1,CargoCarrier,...) -end -else -self:__CancelBoarding(1,CargoCarrier,NearRadius,...) -end -else -self:__Destroyed(1,CargoCarrier,NearRadius,...) -end -end -function CARGO_GROUP:GetCount() -return self.CargoSet:Count() -end -function CARGO_GROUP:onenterUnBoarding(From,Event,To,ToPointVec2,NearRadius,...) -self:F({From,Event,To,ToPointVec2,NearRadius}) -NearRadius=NearRadius or 25 -local Timer=1 -if From=="Loaded"then -if self.CargoObject then -self.CargoObject:Destroy() -end -self.CargoSet:ForEach( -function(Cargo,NearRadius) -Cargo:__UnBoard(Timer,ToPointVec2,NearRadius) -Timer=Timer+10 -end,{NearRadius} -) -self:__UnBoarding(1,ToPointVec2,NearRadius,...) -end -end -function CARGO_GROUP:onleaveUnBoarding(From,Event,To,ToPointVec2,NearRadius,...) -self:F({From,Event,To,ToPointVec2,NearRadius}) -local Angle=180 -local Speed=10 -local Distance=5 -if From=="UnBoarding"then -local UnBoarded=true -for CargoID,Cargo in pairs(self.CargoSet:GetSet())do -self:T(Cargo.current) -if not Cargo:is("UnLoaded")then -UnBoarded=false -end -end -if UnBoarded then -return true -else -self:__UnBoarding(1,ToPointVec2,NearRadius,...) -end -return false -end -end -function CARGO_GROUP:onafterUnBoarding(From,Event,To,ToPointVec2,NearRadius,...) -self:F({From,Event,To,ToPointVec2,NearRadius}) -self:__UnLoad(1,ToPointVec2,...) -end -function CARGO_GROUP:onenterUnLoaded(From,Event,To,ToPointVec2,...) -self:F({From,Event,To,ToPointVec2}) -if From=="Loaded"then -self.CargoSet:ForEach( -function(Cargo) -Cargo:UnLoad(ToPointVec2) -end -) -end -end -function CARGO_GROUP:RespawnOnDestroyed(RespawnDestroyed) -self:F({"In function RespawnOnDestroyed"}) -if RespawnDestroyed then -self.onenterDestroyed=function(self) -self:F("IN FUNCTION") -self:Respawn() -end -else -self.onenterDestroyed=nil -end -end -end -do -CARGO_PACKAGE={ -ClassName="CARGO_PACKAGE" -} -function CARGO_PACKAGE:New(CargoCarrier,Type,Name,Weight,ReportRadius,NearRadius) -local self=BASE:Inherit(self,CARGO_REPRESENTABLE:New(CargoCarrier,Type,Name,Weight,ReportRadius,NearRadius)) -self:F({Type,Name,Weight,ReportRadius,NearRadius}) -self:T(CargoCarrier) -self.CargoCarrier=CargoCarrier -return self -end -function CARGO_PACKAGE:onafterOnBoard(From,Event,To,CargoCarrier,Speed,BoardDistance,LoadDistance,Angle) -self:F() -self.CargoInAir=self.CargoCarrier:InAir() -self:T(self.CargoInAir) -if not self.CargoInAir then -local Points={} -local StartPointVec2=self.CargoCarrier:GetPointVec2() -local CargoCarrierHeading=CargoCarrier:GetHeading() -local CargoDeployHeading=((CargoCarrierHeading+Angle)>=360)and(CargoCarrierHeading+Angle-360)or(CargoCarrierHeading+Angle) -self:T({CargoCarrierHeading,CargoDeployHeading}) -local CargoDeployPointVec2=CargoCarrier:GetPointVec2():Translate(BoardDistance,CargoDeployHeading) -Points[#Points+1]=StartPointVec2:WaypointGround(Speed) -Points[#Points+1]=CargoDeployPointVec2:WaypointGround(Speed) -local TaskRoute=self.CargoCarrier:TaskRoute(Points) -self.CargoCarrier:SetTask(TaskRoute,1) -end -self:Boarded(CargoCarrier,Speed,BoardDistance,LoadDistance,Angle) -end -function CARGO_PACKAGE:IsNear(CargoCarrier) -self:F() -local CargoCarrierPoint=CargoCarrier:GetPointVec2() -local Distance=CargoCarrierPoint:DistanceFromPointVec2(self.CargoCarrier:GetPointVec2()) -self:T(Distance) -if Distance<=self.NearRadius then -return true -else -return false -end -end -function CARGO_PACKAGE:onafterOnBoarded(From,Event,To,CargoCarrier,Speed,BoardDistance,LoadDistance,Angle) -self:F() -if self:IsNear(CargoCarrier)then -self:__Load(1,CargoCarrier,Speed,LoadDistance,Angle) -else -self:__Boarded(1,CargoCarrier,Speed,BoardDistance,LoadDistance,Angle) -end -end -function CARGO_PACKAGE:onafterUnBoard(From,Event,To,CargoCarrier,Speed,UnLoadDistance,UnBoardDistance,Radius,Angle) -self:F() -self.CargoInAir=self.CargoCarrier:InAir() -self:T(self.CargoInAir) -if not self.CargoInAir then -self:_Next(self.FsmP.UnLoad,UnLoadDistance,Angle) -local Points={} -local StartPointVec2=CargoCarrier:GetPointVec2() -local CargoCarrierHeading=self.CargoCarrier:GetHeading() -local CargoDeployHeading=((CargoCarrierHeading+Angle)>=360)and(CargoCarrierHeading+Angle-360)or(CargoCarrierHeading+Angle) -self:T({CargoCarrierHeading,CargoDeployHeading}) -local CargoDeployPointVec2=StartPointVec2:Translate(UnBoardDistance,CargoDeployHeading) -Points[#Points+1]=StartPointVec2:WaypointGround(Speed) -Points[#Points+1]=CargoDeployPointVec2:WaypointGround(Speed) -local TaskRoute=CargoCarrier:TaskRoute(Points) -CargoCarrier:SetTask(TaskRoute,1) -end -self:__UnBoarded(1,CargoCarrier,Speed) -end -function CARGO_PACKAGE:onafterUnBoarded(From,Event,To,CargoCarrier,Speed) -self:F() -if self:IsNear(CargoCarrier)then -self:__UnLoad(1,CargoCarrier,Speed) -else -self:__UnBoarded(1,CargoCarrier,Speed) -end -end -function CARGO_PACKAGE:onafterLoad(From,Event,To,CargoCarrier,Speed,LoadDistance,Angle) -self:F() -self.CargoCarrier=CargoCarrier -local StartPointVec2=self.CargoCarrier:GetPointVec2() -local CargoCarrierHeading=self.CargoCarrier:GetHeading() -local CargoDeployHeading=((CargoCarrierHeading+Angle)>=360)and(CargoCarrierHeading+Angle-360)or(CargoCarrierHeading+Angle) -local CargoDeployPointVec2=StartPointVec2:Translate(LoadDistance,CargoDeployHeading) -local Points={} -Points[#Points+1]=StartPointVec2:WaypointGround(Speed) -Points[#Points+1]=CargoDeployPointVec2:WaypointGround(Speed) -local TaskRoute=self.CargoCarrier:TaskRoute(Points) -self.CargoCarrier:SetTask(TaskRoute,1) -end -function CARGO_PACKAGE:onafterUnLoad(From,Event,To,CargoCarrier,Speed,Distance,Angle) -self:F() -local StartPointVec2=self.CargoCarrier:GetPointVec2() -local CargoCarrierHeading=self.CargoCarrier:GetHeading() -local CargoDeployHeading=((CargoCarrierHeading+Angle)>=360)and(CargoCarrierHeading+Angle-360)or(CargoCarrierHeading+Angle) -local CargoDeployPointVec2=StartPointVec2:Translate(Distance,CargoDeployHeading) -self.CargoCarrier=CargoCarrier -local Points={} -Points[#Points+1]=StartPointVec2:WaypointGround(Speed) -Points[#Points+1]=CargoDeployPointVec2:WaypointGround(Speed) -local TaskRoute=self.CargoCarrier:TaskRoute(Points) -self.CargoCarrier:SetTask(TaskRoute,1) -end -end -do -SPOT={ -ClassName="SPOT", -} -function SPOT:New(Recce) -local self=BASE:Inherit(self,FSM:New()) -self:F({}) -self:SetStartState("Off") -self:AddTransition("Off","LaseOn","On") -self:AddTransition("On","Lasing","On") -self:AddTransition({"On","Destroyed"},"LaseOff","Off") -self:AddTransition("*","Destroyed","Destroyed") -self.Recce=Recce -self.LaseScheduler=SCHEDULER:New(self) -self:SetEventPriority(5) -self.Lasing=false -return self -end -function SPOT:onafterLaseOn(From,Event,To,Target,LaserCode,Duration) -self:E({"LaseOn",Target,LaserCode,Duration}) -local function StopLase(self) -self:LaseOff() -end -self.Target=Target -self.LaserCode=LaserCode -self.Lasing=true -local RecceDcsUnit=self.Recce:GetDCSObject() -self.SpotIR=Spot.createInfraRed(RecceDcsUnit,{x=0,y=2,z=0},Target:GetPointVec3():AddY(1):GetVec3()) -self.SpotLaser=Spot.createLaser(RecceDcsUnit,{x=0,y=2,z=0},Target:GetPointVec3():AddY(1):GetVec3(),LaserCode) -if Duration then -self.ScheduleID=self.LaseScheduler:Schedule(self,StopLase,{self},Duration) -end -self:HandleEvent(EVENTS.Dead) -self:__Lasing(-1) -end -function SPOT:OnEventDead(EventData) -self:E({Dead=EventData.IniDCSUnitName,Target=self.Target}) -if self.Target then -if EventData.IniDCSUnitName==self.Target:GetName()then -self:E({"Target dead ",self.Target:GetName()}) -self:Destroyed() -self:LaseOff() -end -end -end -function SPOT:onafterLasing(From,Event,To) -if self.Target:IsAlive()then -self.SpotIR:setPoint(self.Target:GetPointVec3():AddY(1):AddY(math.random(-100,100)/100):AddX(math.random(-100,100)/100):GetVec3()) -self.SpotLaser:setPoint(self.Target:GetPointVec3():AddY(1):GetVec3()) -self:__Lasing(-0.2) -else -self:E({"Target is not alive",self.Target:IsAlive()}) -end -end -function SPOT:onafterLaseOff(From,Event,To) -self:E({"Stopped lasing for ",self.Target:GetName(),SpotIR=self.SportIR,SpotLaser=self.SpotLaser}) -self.Lasing=false -self.SpotIR:destroy() -self.SpotLaser:destroy() -self.SpotIR=nil -self.SpotLaser=nil -if self.ScheduleID then -self.LaseScheduler:Stop(self.ScheduleID) -end -self.ScheduleID=nil -self.Target=nil -return self -end -function SPOT:IsLasing() -return self.Lasing -end -end -OBJECT={ -ClassName="OBJECT", -ObjectName="", -} -function OBJECT:New(ObjectName,Test) -local self=BASE:Inherit(self,BASE:New()) -self:F2(ObjectName) -self.ObjectName=ObjectName -return self -end -function OBJECT:GetID() -self:F2(self.ObjectName) -local DCSObject=self:GetDCSObject() -if DCSObject then -local ObjectID=DCSObject:getID() -return ObjectID -end -return nil -end -function OBJECT:Destroy() -self:F2(self.ObjectName) -local DCSObject=self:GetDCSObject() -if DCSObject then -DCSObject:destroy() -end -return nil -end -IDENTIFIABLE={ -ClassName="IDENTIFIABLE", -IdentifiableName="", -} -local _CategoryName={ -[Unit.Category.AIRPLANE]="Airplane", -[Unit.Category.HELICOPTER]="Helicoper", -[Unit.Category.GROUND_UNIT]="Ground Identifiable", -[Unit.Category.SHIP]="Ship", -[Unit.Category.STRUCTURE]="Structure", -} -function IDENTIFIABLE:New(IdentifiableName) -local self=BASE:Inherit(self,OBJECT:New(IdentifiableName)) -self:F2(IdentifiableName) -self.IdentifiableName=IdentifiableName -return self -end -function IDENTIFIABLE:IsAlive() -self:F3(self.IdentifiableName) -local DCSIdentifiable=self:GetDCSObject() -if DCSIdentifiable then -local IdentifiableIsAlive=DCSIdentifiable:isExist() -return IdentifiableIsAlive -end -return false -end -function IDENTIFIABLE:GetName() -self:F2(self.IdentifiableName) -local IdentifiableName=self.IdentifiableName -return IdentifiableName -end -function IDENTIFIABLE:GetTypeName() -self:F2(self.IdentifiableName) -local DCSIdentifiable=self:GetDCSObject() -if DCSIdentifiable then -local IdentifiableTypeName=DCSIdentifiable:getTypeName() -self:T3(IdentifiableTypeName) -return IdentifiableTypeName -end -self:E(self.ClassName.." "..self.IdentifiableName.." not found!") -return nil -end -function IDENTIFIABLE:GetCategory() -self:F2(self.ObjectName) -local DCSObject=self:GetDCSObject() -if DCSObject then -local ObjectCategory=DCSObject:getCategory() -self:T3(ObjectCategory) -return ObjectCategory -end -return nil -end -function IDENTIFIABLE:GetCategoryName() -local DCSIdentifiable=self:GetDCSObject() -if DCSIdentifiable then -local IdentifiableCategoryName=_CategoryName[self:GetDesc().category] -return IdentifiableCategoryName -end -self:E(self.ClassName.." "..self.IdentifiableName.." not found!") -return nil -end -function IDENTIFIABLE:GetCoalition() -self:F2(self.IdentifiableName) -local DCSIdentifiable=self:GetDCSObject() -if DCSIdentifiable then -local IdentifiableCoalition=DCSIdentifiable:getCoalition() -self:T3(IdentifiableCoalition) -return IdentifiableCoalition -end -self:E(self.ClassName.." "..self.IdentifiableName.." not found!") -return nil -end -function IDENTIFIABLE:GetCountry() -self:F2(self.IdentifiableName) -local DCSIdentifiable=self:GetDCSObject() -if DCSIdentifiable then -local IdentifiableCountry=DCSIdentifiable:getCountry() -self:T3(IdentifiableCountry) -return IdentifiableCountry -end -self:E(self.ClassName.." "..self.IdentifiableName.." not found!") -return nil -end -function IDENTIFIABLE:GetDesc() -self:F2(self.IdentifiableName) -local DCSIdentifiable=self:GetDCSObject() -if DCSIdentifiable then -local IdentifiableDesc=DCSIdentifiable:getDesc() -self:T2(IdentifiableDesc) -return IdentifiableDesc -end -self:E(self.ClassName.." "..self.IdentifiableName.." not found!") -return nil -end -function IDENTIFIABLE:GetCallsign() -return'' -end -function IDENTIFIABLE:GetThreatLevel() -return 0,"Scenery" -end -POSITIONABLE={ -ClassName="POSITIONABLE", -PositionableName="", -} -POSITIONABLE.__={} -POSITIONABLE.__.Cargo={} -function POSITIONABLE:New(PositionableName) -local self=BASE:Inherit(self,IDENTIFIABLE:New(PositionableName)) -self.PositionableName=PositionableName -return self -end -function POSITIONABLE:GetPositionVec3() -self:F2(self.PositionableName) -local DCSPositionable=self:GetDCSObject() -if DCSPositionable then -local PositionablePosition=DCSPositionable:getPosition().p -self:T3(PositionablePosition) -return PositionablePosition -end -return nil -end -function POSITIONABLE:GetVec2() -self:F2(self.PositionableName) -local DCSPositionable=self:GetDCSObject() -if DCSPositionable then -local PositionableVec3=DCSPositionable:getPosition().p -local PositionableVec2={} -PositionableVec2.x=PositionableVec3.x -PositionableVec2.y=PositionableVec3.z -self:T2(PositionableVec2) -return PositionableVec2 -end -return nil -end -function POSITIONABLE:GetPointVec2() -self:F2(self.PositionableName) -local DCSPositionable=self:GetDCSObject() -if DCSPositionable then -local PositionableVec3=DCSPositionable:getPosition().p -local PositionablePointVec2=POINT_VEC2:NewFromVec3(PositionableVec3) -self:T2(PositionablePointVec2) -return PositionablePointVec2 -end -return nil -end -function POSITIONABLE:GetPointVec3() -self:F2(self.PositionableName) -local DCSPositionable=self:GetDCSObject() -if DCSPositionable then -local PositionableVec3=self:GetPositionVec3() -local PositionablePointVec3=POINT_VEC3:NewFromVec3(PositionableVec3) -self:T2(PositionablePointVec3) -return PositionablePointVec3 -end -return nil -end -function POSITIONABLE:GetCoordinate() -self:F2(self.PositionableName) -local DCSPositionable=self:GetDCSObject() -if DCSPositionable then -local PositionableVec3=self:GetPositionVec3() -local PositionableCoordinate=COORDINATE:NewFromVec3(PositionableVec3) -PositionableCoordinate:SetHeading(self:GetHeading()) -PositionableCoordinate:SetVelocity(self:GetVelocityMPS()) -self:T2(PositionableCoordinate) -return PositionableCoordinate -end -return nil -end -function POSITIONABLE:GetRandomVec3(Radius) -self:F2(self.PositionableName) -local DCSPositionable=self:GetDCSObject() -if DCSPositionable then -local PositionablePointVec3=DCSPositionable:getPosition().p -if Radius then -local PositionableRandomVec3={} -local angle=math.random()*math.pi*2; -PositionableRandomVec3.x=PositionablePointVec3.x+math.cos(angle)*math.random()*Radius; -PositionableRandomVec3.y=PositionablePointVec3.y -PositionableRandomVec3.z=PositionablePointVec3.z+math.sin(angle)*math.random()*Radius; -self:T3(PositionableRandomVec3) -return PositionableRandomVec3 -else -self:E("Radius is nil, returning the PointVec3 of the POSITIONABLE",PositionablePointVec3) -return PositionablePointVec3 -end -end -return nil -end -function POSITIONABLE:GetVec3() -self:F2(self.PositionableName) -local DCSPositionable=self:GetDCSObject() -if DCSPositionable then -local PositionableVec3=DCSPositionable:getPosition().p -self:T3(PositionableVec3) -return PositionableVec3 -end -return nil -end -function POSITIONABLE:GetBoundingBox() -self:F2() -local DCSPositionable=self:GetDCSObject() -if DCSPositionable then -local PositionableDesc=DCSPositionable:getDesc() -if PositionableDesc then -local PositionableBox=PositionableDesc.box -return PositionableBox -end -end -return nil -end -function POSITIONABLE:GetAltitude() -self:F2() -local DCSPositionable=self:GetDCSObject() -if DCSPositionable then -local PositionablePointVec3=DCSPositionable:getPoint() -return PositionablePointVec3.y -end -return nil -end -function POSITIONABLE:IsAboveRunway() -self:F2(self.PositionableName) -local DCSPositionable=self:GetDCSObject() -if DCSPositionable then -local Vec2=self:GetVec2() -local SurfaceType=land.getSurfaceType(Vec2) -local IsAboveRunway=SurfaceType==land.SurfaceType.RUNWAY -self:T2(IsAboveRunway) -return IsAboveRunway -end -return nil -end -function POSITIONABLE:GetHeading() -local DCSPositionable=self:GetDCSObject() -if DCSPositionable then -local PositionablePosition=DCSPositionable:getPosition() -if PositionablePosition then -local PositionableHeading=math.atan2(PositionablePosition.x.z,PositionablePosition.x.x) -if PositionableHeading<0 then -PositionableHeading=PositionableHeading+2*math.pi -end -PositionableHeading=PositionableHeading*180/math.pi -self:T2(PositionableHeading) -return PositionableHeading -end -end -return nil -end -function POSITIONABLE:InAir() -self:F2(self.PositionableName) -return nil -end -function POSITIONABLE:GetVelocity() -self:F2(self.PositionableName) -local DCSPositionable=self:GetDCSObject() -if DCSPositionable then -local PositionableVelocityVec3=DCSPositionable:getVelocity() -self:T3(PositionableVelocityVec3) -return PositionableVelocityVec3 -end -return nil -end -function POSITIONABLE:GetHeight() -self:F2(self.PositionableName) -local DCSPositionable=self:GetDCSObject() -if DCSPositionable then -local PositionablePosition=DCSPositionable:getPosition() -if PositionablePosition then -local PositionableHeight=PositionablePosition.p.y -self:T2(PositionableHeight) -return PositionableHeight -end -end -return nil -end -function POSITIONABLE:GetVelocityKMH() -self:F2(self.PositionableName) -local DCSPositionable=self:GetDCSObject() -if DCSPositionable then -local VelocityVec3=self:GetVelocity() -local Velocity=(VelocityVec3.x^2+VelocityVec3.y^2+VelocityVec3.z^2)^0.5 -local Velocity=Velocity*3.6 -self:T3(Velocity) -return Velocity -end -return 0 -end -function POSITIONABLE:GetVelocityMPS() -self:F2(self.PositionableName) -local DCSPositionable=self:GetDCSObject() -if DCSPositionable then -local VelocityVec3=self:GetVelocity() -local Velocity=(VelocityVec3.x^2+VelocityVec3.y^2+VelocityVec3.z^2)^0.5 -self:T3(Velocity) -return Velocity -end -return 0 -end -function POSITIONABLE:GetMessageText(Message,Name) -local DCSObject=self:GetDCSObject() -if DCSObject then -Name=Name and(" ("..Name..")")or"" -local Callsign=string.format("[%s]",self:GetCallsign()~=""and self:GetCallsign()or self:GetName()) -local MessageText=Callsign..Name..": "..Message -return MessageText -end -return nil -end -function POSITIONABLE:GetMessage(Message,Duration,Name) -local DCSObject=self:GetDCSObject() -if DCSObject then -local MessageText=self:GetMessageText(Message,Name) -return MESSAGE:New(MessageText,Duration) -end -return nil -end -function POSITIONABLE:GetMessageType(Message,MessageType,Name) -local DCSObject=self:GetDCSObject() -if DCSObject then -local MessageText=self:GetMessageText(Message,Name) -return MESSAGE:NewType(MessageText,MessageType) -end -return nil -end -function POSITIONABLE:MessageToAll(Message,Duration,Name) -self:F2({Message,Duration}) -local DCSObject=self:GetDCSObject() -if DCSObject then -self:GetMessage(Message,Duration,Name):ToAll() -end -return nil -end -function POSITIONABLE:MessageToCoalition(Message,Duration,MessageCoalition) -self:F2({Message,Duration}) -local Name="" -local DCSObject=self:GetDCSObject() -if DCSObject then -if MessageCoalition==coalition.side.BLUE then -Name="Blue coalition" -end -if MessageCoalition==coalition.side.RED then -Name="Red coalition" -end -self:GetMessage(Message,Duration,Name):ToCoalition(MessageCoalition) -end -return nil -end -function POSITIONABLE:MessageTypeToCoalition(Message,MessageType,MessageCoalition) -self:F2({Message,MessageType}) -local Name="" -local DCSObject=self:GetDCSObject() -if DCSObject then -if MessageCoalition==coalition.side.BLUE then -Name="Blue coalition" -end -if MessageCoalition==coalition.side.RED then -Name="Red coalition" -end -self:GetMessageType(Message,MessageType,Name):ToCoalition(MessageCoalition) -end -return nil -end -function POSITIONABLE:MessageToRed(Message,Duration,Name) -self:F2({Message,Duration}) -local DCSObject=self:GetDCSObject() -if DCSObject then -self:GetMessage(Message,Duration,Name):ToRed() -end -return nil -end -function POSITIONABLE:MessageToBlue(Message,Duration,Name) -self:F2({Message,Duration}) -local DCSObject=self:GetDCSObject() -if DCSObject then -self:GetMessage(Message,Duration,Name):ToBlue() -end -return nil -end -function POSITIONABLE:MessageToClient(Message,Duration,Client,Name) -self:F2({Message,Duration}) -local DCSObject=self:GetDCSObject() -if DCSObject then -self:GetMessage(Message,Duration,Name):ToClient(Client) -end -return nil -end -function POSITIONABLE:MessageToGroup(Message,Duration,MessageGroup,Name) -self:F2({Message,Duration}) -local DCSObject=self:GetDCSObject() -if DCSObject then -if DCSObject:isExist()then -self:GetMessage(Message,Duration,Name):ToGroup(MessageGroup) -end -end -return nil -end -function POSITIONABLE:MessageTypeToGroup(Message,MessageType,MessageGroup,Name) -self:F2({Message,MessageType}) -local DCSObject=self:GetDCSObject() -if DCSObject then -if DCSObject:isExist()then -self:GetMessageType(Message,MessageType,Name):ToGroup(MessageGroup) -end -end -return nil -end -function POSITIONABLE:MessageToSetGroup(Message,Duration,MessageSetGroup,Name) -self:F2({Message,Duration}) -local DCSObject=self:GetDCSObject() -if DCSObject then -if DCSObject:isExist()then -MessageSetGroup:ForEachGroup( -function(MessageGroup) -self:GetMessage(Message,Duration,Name):ToGroup(MessageGroup) -end -) -end -end -return nil -end -function POSITIONABLE:Message(Message,Duration,Name) -self:F2({Message,Duration}) -local DCSObject=self:GetDCSObject() -if DCSObject then -self:GetMessage(Message,Duration,Name):ToGroup(self) -end -return nil -end -function POSITIONABLE:GetRadio() -self:F2(self) -return RADIO:New(self) -end -function POSITIONABLE:GetBeacon() -self:F2(self) -return BEACON:New(self) -end -function POSITIONABLE:LaseUnit(Target,LaserCode,Duration) -self:F2() -LaserCode=LaserCode or math.random(1000,9999) -local RecceDcsUnit=self:GetDCSObject() -local TargetVec3=Target:GetVec3() -self:E("bulding spot") -self.Spot=SPOT:New(self) -self.Spot:LaseOn(Target,LaserCode,Duration) -self.LaserCode=LaserCode -return self.Spot -end -function POSITIONABLE:LaseOff() -self:F2() -if self.Spot then -self.Spot:LaseOff() -self.Spot=nil -end -return self -end -function POSITIONABLE:IsLasing() -self:F2() -local Lasing=false -if self.Spot then -Lasing=self.Spot:IsLasing() -end -return Lasing -end -function POSITIONABLE:GetSpot() -return self.Spot -end -function POSITIONABLE:GetLaserCode() -return self.LaserCode -end -function POSITIONABLE:AddCargo(Cargo) -self.__.Cargo[Cargo]=Cargo -return self -end -function POSITIONABLE:RemoveCargo(Cargo) -self.__.Cargo[Cargo]=nil -return self -end -function POSITIONABLE:HasCargo(Cargo) -return self.__.Cargo[Cargo] -end -function POSITIONABLE:ClearCargo() -self.__.Cargo={} -end -function POSITIONABLE:CargoItemCount() -local ItemCount=0 -for CargoName,Cargo in pairs(self.__.Cargo)do -ItemCount=ItemCount+Cargo:GetCount() -end -return ItemCount -end -function POSITIONABLE:Flare(FlareColor) -self:F2() -trigger.action.signalFlare(self:GetVec3(),FlareColor,0) -end -function POSITIONABLE:FlareWhite() -self:F2() -trigger.action.signalFlare(self:GetVec3(),trigger.flareColor.White,0) -end -function POSITIONABLE:FlareYellow() -self:F2() -trigger.action.signalFlare(self:GetVec3(),trigger.flareColor.Yellow,0) -end -function POSITIONABLE:FlareGreen() -self:F2() -trigger.action.signalFlare(self:GetVec3(),trigger.flareColor.Green,0) -end -function POSITIONABLE:FlareRed() -self:F2() -local Vec3=self:GetVec3() -if Vec3 then -trigger.action.signalFlare(Vec3,trigger.flareColor.Red,0) -end -end -function POSITIONABLE:Smoke(SmokeColor,Range,AddHeight) -self:F2() -if Range then -local Vec3=self:GetRandomVec3(Range) -Vec3.y=Vec3.y+AddHeight or 0 -trigger.action.smoke(Vec3,SmokeColor) -else -local Vec3=self:GetVec3() -Vec3.y=Vec3.y+AddHeight or 0 -trigger.action.smoke(self:GetVec3(),SmokeColor) -end -end -function POSITIONABLE:SmokeGreen() -self:F2() -trigger.action.smoke(self:GetVec3(),trigger.smokeColor.Green) -end -function POSITIONABLE:SmokeRed() -self:F2() -trigger.action.smoke(self:GetVec3(),trigger.smokeColor.Red) -end -function POSITIONABLE:SmokeWhite() -self:F2() -trigger.action.smoke(self:GetVec3(),trigger.smokeColor.White) -end -function POSITIONABLE:SmokeOrange() -self:F2() -trigger.action.smoke(self:GetVec3(),trigger.smokeColor.Orange) -end -function POSITIONABLE:SmokeBlue() -self:F2() -trigger.action.smoke(self:GetVec3(),trigger.smokeColor.Blue) -end -CONTROLLABLE={ -ClassName="CONTROLLABLE", -ControllableName="", -WayPointFunctions={}, -} -function CONTROLLABLE:New(ControllableName) -local self=BASE:Inherit(self,POSITIONABLE:New(ControllableName)) -self:F2(ControllableName) -self.ControllableName=ControllableName -self.TaskScheduler=SCHEDULER:New(self) -return self -end -function CONTROLLABLE:_GetController() -local DCSControllable=self:GetDCSObject() -if DCSControllable then -local ControllableController=DCSControllable:getController() -return ControllableController -end -return nil -end -function CONTROLLABLE:GetUnits() -self:F2({self.ControllableName}) -local DCSControllable=self:GetDCSObject() -if DCSControllable then -local DCSUnits=DCSControllable:getUnits() -local Units={} -for Index,UnitData in pairs(DCSUnits)do -Units[#Units+1]=UNIT:Find(UnitData) -end -self:T3(Units) -return Units -end -return nil -end -function CONTROLLABLE:GetLife() -self:F2(self.ControllableName) -local DCSControllable=self:GetDCSObject() -if DCSControllable then -local UnitLife=0 -local Units=self:GetUnits() -if#Units==1 then -local Unit=Units[1] -UnitLife=Unit:GetLife() -else -local UnitLifeTotal=0 -for UnitID,Unit in pairs(Units)do -local Unit=Unit -UnitLifeTotal=UnitLifeTotal+Unit:GetLife() -end -UnitLife=UnitLifeTotal/#Units -end -return UnitLife -end -return nil -end -function CONTROLLABLE:GetLife0() -self:F2(self.ControllableName) -local DCSControllable=self:GetDCSObject() -if DCSControllable then -local UnitLife=0 -local Units=self:GetUnits() -if#Units==1 then -local Unit=Units[1] -UnitLife=Unit:GetLife0() -else -local UnitLifeTotal=0 -for UnitID,Unit in pairs(Units)do -local Unit=Unit -UnitLifeTotal=UnitLifeTotal+Unit:GetLife0() -end -UnitLife=UnitLifeTotal/#Units -end -return UnitLife -end -return nil -end -function CONTROLLABLE:GetFuel() -self:F(self.ControllableName) -return nil -end -function CONTROLLABLE:ClearTasks() -self:F2() -local DCSControllable=self:GetDCSObject() -if DCSControllable then -local Controller=self:_GetController() -Controller:resetTask() -return self -end -return nil -end -function CONTROLLABLE:PopCurrentTask() -self:F2() -local DCSControllable=self:GetDCSObject() -if DCSControllable then -local Controller=self:_GetController() -Controller:popTask() -return self -end -return nil -end -function CONTROLLABLE:PushTask(DCSTask,WaitTime) -self:F2() -local DCSControllable=self:GetDCSObject() -if DCSControllable then -local Controller=self:_GetController() -if WaitTime then -self.TaskScheduler:Schedule(Controller,Controller.pushTask,{DCSTask},WaitTime) -else -Controller:pushTask(DCSTask) -end -return self -end -return nil -end -function CONTROLLABLE:SetTask(DCSTask,WaitTime) -self:F2({DCSTask=DCSTask}) -local DCSControllable=self:GetDCSObject() -if DCSControllable then -local DCSControllableName=self:GetName() -local function SetTask(Controller,DCSTask) -if self and self:IsAlive()then -local Controller=self:_GetController() -Controller:setTask(DCSTask) -else -BASE:E(DCSControllableName.." is not alive anymore. Cannot set DCSTask "..DCSTask) -end -end -if not WaitTime or WaitTime==0 then -SetTask(self,DCSTask) -else -self.TaskScheduler:Schedule(self,SetTask,{DCSTask},WaitTime) -end -return self -end -return nil -end -function CONTROLLABLE:HasTask() -local HasTaskResult=false -local DCSControllable=self:GetDCSObject() -if DCSControllable then -local Controller=self:_GetController() -HasTaskResult=Controller:hasTask() -end -return HasTaskResult -end -function CONTROLLABLE:TaskCondition(time,userFlag,userFlagValue,condition,duration,lastWayPoint) -self:F2({time,userFlag,userFlagValue,condition,duration,lastWayPoint}) -local DCSStopCondition={} -DCSStopCondition.time=time -DCSStopCondition.userFlag=userFlag -DCSStopCondition.userFlagValue=userFlagValue -DCSStopCondition.condition=condition -DCSStopCondition.duration=duration -DCSStopCondition.lastWayPoint=lastWayPoint -self:T3({DCSStopCondition}) -return DCSStopCondition -end -function CONTROLLABLE:TaskControlled(DCSTask,DCSStopCondition) -self:F2({DCSTask,DCSStopCondition}) -local DCSTaskControlled -DCSTaskControlled={ -id='ControlledTask', -params={ -task=DCSTask, -stopCondition=DCSStopCondition -} -} -self:T3({DCSTaskControlled}) -return DCSTaskControlled -end -function CONTROLLABLE:TaskCombo(DCSTasks) -self:F2({DCSTasks}) -local DCSTaskCombo -DCSTaskCombo={ -id='ComboTask', -params={ -tasks=DCSTasks -} -} -for TaskID,Task in ipairs(DCSTasks)do -self:T(Task) -end -self:T3({DCSTaskCombo}) -return DCSTaskCombo -end -function CONTROLLABLE:TaskWrappedAction(DCSCommand,Index) -self:F2({DCSCommand}) -local DCSTaskWrappedAction -DCSTaskWrappedAction={ -id="WrappedAction", -enabled=true, -number=Index or 1, -auto=false, -params={ -action=DCSCommand, -}, -} -self:T3({DCSTaskWrappedAction}) -return DCSTaskWrappedAction -end -function CONTROLLABLE:SetTaskWaypoint(Waypoint,Task) -Waypoint.task=self:TaskCombo({Task}) -self:T3({Waypoint.task}) -return Waypoint.task -end -function CONTROLLABLE:SetCommand(DCSCommand) -self:F2(DCSCommand) -local DCSControllable=self:GetDCSObject() -if DCSControllable then -local Controller=self:_GetController() -Controller:setCommand(DCSCommand) -return self -end -return nil -end -function CONTROLLABLE:CommandSwitchWayPoint(FromWayPoint,ToWayPoint) -self:F2({FromWayPoint,ToWayPoint}) -local CommandSwitchWayPoint={ -id='SwitchWaypoint', -params={ -fromWaypointIndex=FromWayPoint, -goToWaypointIndex=ToWayPoint, -}, -} -self:T3({CommandSwitchWayPoint}) -return CommandSwitchWayPoint -end -function CONTROLLABLE:CommandStopRoute(StopRoute) -self:F2({StopRoute}) -local CommandStopRoute={ -id='StopRoute', -params={ -value=StopRoute, -}, -} -self:T3({CommandStopRoute}) -return CommandStopRoute -end -function CONTROLLABLE:TaskAttackGroup(AttackGroup,WeaponType,WeaponExpend,AttackQty,Direction,Altitude,AttackQtyLimit) -self:F2({self.ControllableName,AttackGroup,WeaponType,WeaponExpend,AttackQty,Direction,Altitude,AttackQtyLimit}) -local DirectionEnabled=nil -if Direction then -DirectionEnabled=true -end -local AltitudeEnabled=nil -if Altitude then -AltitudeEnabled=true -end -local DCSTask -DCSTask={id='AttackGroup', -params={ -groupId=AttackGroup:GetID(), -weaponType=WeaponType, -expend=WeaponExpend, -attackQty=AttackQty, -directionEnabled=DirectionEnabled, -direction=Direction, -altitudeEnabled=AltitudeEnabled, -altitude=Altitude, -attackQtyLimit=AttackQtyLimit, -}, -}, -self:T3({DCSTask}) -return DCSTask -end -function CONTROLLABLE:TaskAttackUnit(AttackUnit,GroupAttack,WeaponExpend,AttackQty,Direction,Altitude,Visible,WeaponType) -self:F2({self.ControllableName,AttackUnit,GroupAttack,WeaponExpend,AttackQty,Direction,Altitude,Visible,WeaponType}) -local DCSTask -DCSTask={ -id='AttackUnit', -params={ -unitId=AttackUnit:GetID(), -groupAttack=GroupAttack or false, -visible=Visible or false, -expend=WeaponExpend or"Auto", -directionEnabled=Direction and true or false, -direction=Direction, -altitudeEnabled=Altitude and true or false, -altitude=Altitude or 30, -attackQtyLimit=AttackQty and true or false, -attackQty=AttackQty, -weaponType=WeaponType -} -} -self:T3(DCSTask) -return DCSTask -end -function CONTROLLABLE:TaskBombing(Vec2,GroupAttack,WeaponExpend,AttackQty,Direction,Altitude,WeaponType) -self:F2({self.ControllableName,Vec2,GroupAttack,WeaponExpend,AttackQty,Direction,Altitude,WeaponType}) -local DCSTask -DCSTask={ -id='Bombing', -params={ -point=Vec2, -groupAttack=GroupAttack or false, -expend=WeaponExpend or"Auto", -attackQtyLimit=AttackQty and true or false, -attackQty=AttackQty, -directionEnabled=Direction and true or false, -direction=Direction, -altitudeEnabled=Altitude and true or false, -altitude=Altitude or 30, -weaponType=WeaponType, -}, -}, -self:T3({DCSTask}) -return DCSTask -end -function CONTROLLABLE:TaskAttackMapObject(Vec2,GroupAttack,WeaponExpend,AttackQty,Direction,Altitude,WeaponType) -self:F2({self.ControllableName,Vec2,GroupAttack,WeaponExpend,AttackQty,Direction,Altitude,WeaponType}) -local DCSTask -DCSTask={ -id='AttackMapObject', -params={ -point=Vec2, -groupAttack=GroupAttack or false, -expend=WeaponExpend or"Auto", -attackQtyLimit=AttackQty and true or false, -attackQty=AttackQty, -directionEnabled=Direction and true or false, -direction=Direction, -altitudeEnabled=Altitude and true or false, -altitude=Altitude or 30, -weaponType=WeaponType, -}, -}, -self:T3({DCSTask}) -return DCSTask -end -function CONTROLLABLE:TaskOrbitCircleAtVec2(Point,Altitude,Speed) -self:F2({self.ControllableName,Point,Altitude,Speed}) -local LandHeight=land.getHeight(Point) -self:T3({LandHeight}) -local DCSTask={id='Orbit', -params={pattern=AI.Task.OrbitPattern.CIRCLE, -point=Point, -speed=Speed, -altitude=Altitude+LandHeight -} -} -return DCSTask -end -function CONTROLLABLE:TaskOrbitCircle(Altitude,Speed) -self:F2({self.ControllableName,Altitude,Speed}) -local DCSControllable=self:GetDCSObject() -if DCSControllable then -local ControllablePoint=self:GetVec2() -return self:TaskOrbitCircleAtVec2(ControllablePoint,Altitude,Speed) -end -return nil -end -function CONTROLLABLE:TaskHoldPosition() -self:F2({self.ControllableName}) -return self:TaskOrbitCircle(30,10) -end -function CONTROLLABLE:TaskBombingRunway(Airbase,WeaponType,WeaponExpend,AttackQty,Direction,ControllableAttack) -self:F2({self.ControllableName,Airbase,WeaponType,WeaponExpend,AttackQty,Direction,ControllableAttack}) -local DCSTask -DCSTask={id='BombingRunway', -params={ -point=Airbase:GetID(), -weaponType=WeaponType, -expend=WeaponExpend, -attackQty=AttackQty, -direction=Direction, -controllableAttack=ControllableAttack, -}, -}, -self:T3({DCSTask}) -return DCSTask -end -function CONTROLLABLE:TaskRefueling() -self:F2({self.ControllableName}) -local DCSTask -DCSTask={id='Refueling', -params={ -}, -}, -self:T3({DCSTask}) -return DCSTask -end -function CONTROLLABLE:TaskLandAtVec2(Point,Duration) -self:F2({self.ControllableName,Point,Duration}) -local DCSTask -if Duration and Duration>0 then -DCSTask={id='Land', -params={ -point=Point, -durationFlag=true, -duration=Duration, -}, -} -else -DCSTask={id='Land', -params={ -point=Point, -durationFlag=false, -}, -} -end -self:T3(DCSTask) -return DCSTask -end -function CONTROLLABLE:TaskLandAtZone(Zone,Duration,RandomPoint) -self:F2({self.ControllableName,Zone,Duration,RandomPoint}) -local Point -if RandomPoint then -Point=Zone:GetRandomVec2() -else -Point=Zone:GetVec2() -end -local DCSTask=self:TaskLandAtVec2(Point,Duration) -self:T3(DCSTask) -return DCSTask -end -function CONTROLLABLE:TaskFollow(FollowControllable,Vec3,LastWaypointIndex) -self:F2({self.ControllableName,FollowControllable,Vec3,LastWaypointIndex}) -local LastWaypointIndexFlag=false -if LastWaypointIndex then -LastWaypointIndexFlag=true -end -local DCSTask -DCSTask={ -id='Follow', -params={ -groupId=FollowControllable:GetID(), -pos=Vec3, -lastWptIndexFlag=LastWaypointIndexFlag, -lastWptIndex=LastWaypointIndex -} -} -self:T3({DCSTask}) -return DCSTask -end -function CONTROLLABLE:TaskEscort(FollowControllable,Vec3,LastWaypointIndex,EngagementDistance,TargetTypes) -self:F2({self.ControllableName,FollowControllable,Vec3,LastWaypointIndex,EngagementDistance,TargetTypes}) -local LastWaypointIndexFlag=false -if LastWaypointIndex then -LastWaypointIndexFlag=true -end -local DCSTask -DCSTask={id='Escort', -params={ -groupId=FollowControllable:GetID(), -pos=Vec3, -lastWptIndexFlag=LastWaypointIndexFlag, -lastWptIndex=LastWaypointIndex, -engagementDistMax=EngagementDistance, -targetTypes=TargetTypes, -}, -}, -self:T3({DCSTask}) -return DCSTask -end -function CONTROLLABLE:TaskFireAtPoint(Vec2,Radius,AmmoCount) -self:F2({self.ControllableName,Vec2,Radius,AmmoCount}) -local DCSTask -DCSTask={id='FireAtPoint', -params={ -point=Vec2, -radius=Radius, -expendQty=100, -expendQtyEnabled=false, -} -} -if AmmoCount then -DCSTask.params.expendQty=AmmoCount -DCSTask.params.expendQtyEnabled=true -end -self:T3({DCSTask}) -return DCSTask -end -function CONTROLLABLE:TaskHold() -self:F2({self.ControllableName}) -local DCSTask -DCSTask={id='Hold', -params={ -} -} -self:T3({DCSTask}) -return DCSTask -end -function CONTROLLABLE:TaskFAC_AttackGroup(AttackGroup,WeaponType,Designation,Datalink) -self:F2({self.ControllableName,AttackGroup,WeaponType,Designation,Datalink}) -local DCSTask -DCSTask={id='FAC_AttackGroup', -params={ -groupId=AttackGroup:GetID(), -weaponType=WeaponType, -designation=Designation, -datalink=Datalink, -} -} -self:T3({DCSTask}) -return DCSTask -end -function CONTROLLABLE:EnRouteTaskEngageTargets(Distance,TargetTypes,Priority) -self:F2({self.ControllableName,Distance,TargetTypes,Priority}) -local DCSTask -DCSTask={id='EngageTargets', -params={ -maxDist=Distance, -targetTypes=TargetTypes, -priority=Priority -} -} -self:T3({DCSTask}) -return DCSTask -end -function CONTROLLABLE:EnRouteTaskEngageTargetsInZone(Vec2,Radius,TargetTypes,Priority) -self:F2({self.ControllableName,Vec2,Radius,TargetTypes,Priority}) -local DCSTask -DCSTask={id='EngageTargetsInZone', -params={ -point=Vec2, -zoneRadius=Radius, -targetTypes=TargetTypes, -priority=Priority -} -} -self:T3({DCSTask}) -return DCSTask -end -function CONTROLLABLE:EnRouteTaskEngageGroup(AttackGroup,Priority,WeaponType,WeaponExpend,AttackQty,Direction,Altitude,AttackQtyLimit) -self:F2({self.ControllableName,AttackGroup,Priority,WeaponType,WeaponExpend,AttackQty,Direction,Altitude,AttackQtyLimit}) -local DirectionEnabled=nil -if Direction then -DirectionEnabled=true -end -local AltitudeEnabled=nil -if Altitude then -AltitudeEnabled=true -end -local DCSTask -DCSTask={id='EngageControllable', -params={ -groupId=AttackGroup:GetID(), -weaponType=WeaponType, -expend=WeaponExpend, -attackQty=AttackQty, -directionEnabled=DirectionEnabled, -direction=Direction, -altitudeEnabled=AltitudeEnabled, -altitude=Altitude, -attackQtyLimit=AttackQtyLimit, -priority=Priority, -}, -}, -self:T3({DCSTask}) -return DCSTask -end -function CONTROLLABLE:EnRouteTaskEngageUnit(EngageUnit,Priority,GroupAttack,WeaponExpend,AttackQty,Direction,Altitude,Visible,ControllableAttack) -self:F2({self.ControllableName,EngageUnit,Priority,GroupAttack,WeaponExpend,AttackQty,Direction,Altitude,Visible,ControllableAttack}) -local DCSTask -DCSTask={id='EngageUnit', -params={ -unitId=EngageUnit:GetID(), -priority=Priority or 1, -groupAttack=GroupAttack or false, -visible=Visible or false, -expend=WeaponExpend or"Auto", -directionEnabled=Direction and true or false, -direction=Direction, -altitudeEnabled=Altitude and true or false, -altitude=Altitude, -attackQtyLimit=AttackQty and true or false, -attackQty=AttackQty, -controllableAttack=ControllableAttack, -}, -}, -self:T3({DCSTask}) -return DCSTask -end -function CONTROLLABLE:EnRouteTaskAWACS() -self:F2({self.ControllableName}) -local DCSTask -DCSTask={id='AWACS', -params={ -} -} -self:T3({DCSTask}) -return DCSTask -end -function CONTROLLABLE:EnRouteTaskTanker() -self:F2({self.ControllableName}) -local DCSTask -DCSTask={id='Tanker', -params={ -} -} -self:T3({DCSTask}) -return DCSTask -end -function CONTROLLABLE:EnRouteTaskEWR() -self:F2({self.ControllableName}) -local DCSTask -DCSTask={id='EWR', -params={ -} -} -self:T3({DCSTask}) -return DCSTask -end -function CONTROLLABLE:EnRouteTaskFAC_EngageGroup(AttackGroup,Priority,WeaponType,Designation,Datalink) -self:F2({self.ControllableName,AttackGroup,WeaponType,Priority,Designation,Datalink}) -local DCSTask -DCSTask={id='FAC_EngageControllable', -params={ -groupId=AttackGroup:GetID(), -weaponType=WeaponType, -designation=Designation, -datalink=Datalink, -priority=Priority, -} -} -self:T3({DCSTask}) -return DCSTask -end -function CONTROLLABLE:EnRouteTaskFAC(Radius,Priority) -self:F2({self.ControllableName,Radius,Priority}) -local DCSTask -DCSTask={id='FAC', -params={ -radius=Radius, -priority=Priority -} -} -self:T3({DCSTask}) -return DCSTask -end -function CONTROLLABLE:TaskEmbarking(Point,Duration,EmbarkingControllable) -self:F2({self.ControllableName,Point,Duration,EmbarkingControllable.DCSControllable}) -local DCSTask -DCSTask={id='Embarking', -params={x=Point.x, -y=Point.y, -duration=Duration, -controllablesForEmbarking={EmbarkingControllable.ControllableID}, -durationFlag=true, -distributionFlag=false, -distribution={}, -} -} -self:T3({DCSTask}) -return DCSTask -end -function CONTROLLABLE:TaskEmbarkToTransport(Point,Radius) -self:F2({self.ControllableName,Point,Radius}) -local DCSTask -DCSTask={id='EmbarkToTransport', -params={x=Point.x, -y=Point.y, -zoneRadius=Radius, -} -} -self:T3({DCSTask}) -return DCSTask -end -function CONTROLLABLE:TaskFunction(FunctionString,...) -self:F2({FunctionString,arg}) -local DCSTask -local DCSScript={} -DCSScript[#DCSScript+1]="local MissionControllable = GROUP:Find( ... ) " -if arg and arg.n>0 then -local ArgumentKey='_'..tostring(arg):match("table: (.*)") -self:SetState(self,ArgumentKey,arg) -DCSScript[#DCSScript+1]="local Arguments = MissionControllable:GetState( MissionControllable, '"..ArgumentKey.."' ) " -DCSScript[#DCSScript+1]=FunctionString.."( MissionControllable, unpack( Arguments ) )" -else -DCSScript[#DCSScript+1]=FunctionString.."( MissionControllable )" -end -DCSTask=self:TaskWrappedAction( -self:CommandDoScript( -table.concat(DCSScript) -) -) -self:T(DCSTask) -return DCSTask -end -function CONTROLLABLE:TaskMission(TaskMission) -self:F2(Points) -local DCSTask -DCSTask={id='Mission',params={TaskMission,},} -self:T3({DCSTask}) -return DCSTask -end -do -function CONTROLLABLE:PatrolRoute() -local PatrolGroup=self -if not self:IsInstanceOf("GROUP")then -PatrolGroup=self:GetGroup() -end -self:E({PatrolGroup=PatrolGroup:GetName()}) -if PatrolGroup:IsGround()or PatrolGroup:IsShip()then -local Waypoints=PatrolGroup:GetTemplateRoutePoints() -local FromCoord=PatrolGroup:GetCoordinate() -local From=FromCoord:WaypointGround(120) -table.insert(Waypoints,1,From) -local TaskRoute=PatrolGroup:TaskFunction("CONTROLLABLE.PatrolRoute") -self:E({Waypoints=Waypoints}) -local Waypoint=Waypoints[#Waypoints] -PatrolGroup:SetTaskWaypoint(Waypoint,TaskRoute) -PatrolGroup:Route(Waypoints) -end -end -function CONTROLLABLE:PatrolRouteRandom(Speed,Formation,ToWaypoint) -local PatrolGroup=self -if not self:IsInstanceOf("GROUP")then -PatrolGroup=self:GetGroup() -end -self:E({PatrolGroup=PatrolGroup:GetName()}) -if PatrolGroup:IsGround()or PatrolGroup:IsShip()then -local Waypoints=PatrolGroup:GetTemplateRoutePoints() -local FromCoord=PatrolGroup:GetCoordinate() -local FromWaypoint=1 -if ToWaypoint then -FromWaypoint=ToWaypoint -end -local ToWaypoint -repeat -ToWaypoint=math.random(1,#Waypoints) -until(ToWaypoint~=FromWaypoint) -self:E({FromWaypoint=FromWaypoint,ToWaypoint=ToWaypoint}) -local Waypoint=Waypoints[ToWaypoint] -local ToCoord=COORDINATE:NewFromVec2({x=Waypoint.x,y=Waypoint.y}) -local Route={} -Route[#Route+1]=FromCoord:WaypointGround(0) -Route[#Route+1]=ToCoord:WaypointGround(Speed,Formation) -local TaskRouteToZone=PatrolGroup:TaskFunction("CONTROLLABLE.PatrolRouteRandom",Speed,Formation,ToWaypoint) -PatrolGroup:SetTaskWaypoint(Route[#Route],TaskRouteToZone) -PatrolGroup:Route(Route,1) -end -end -function CONTROLLABLE:PatrolZones(ZoneList,Speed,Formation) -if not type(ZoneList)=="table"then -ZoneList={ZoneList} -end -local PatrolGroup=self -if not self:IsInstanceOf("GROUP")then -PatrolGroup=self:GetGroup() -end -self:E({PatrolGroup=PatrolGroup:GetName()}) -if PatrolGroup:IsGround()or PatrolGroup:IsShip()then -local Waypoints=PatrolGroup:GetTemplateRoutePoints() -local Waypoint=Waypoints[math.random(1,#Waypoints)] -local FromCoord=PatrolGroup:GetCoordinate() -local RandomZone=ZoneList[math.random(1,#ZoneList)] -local ToCoord=RandomZone:GetRandomCoordinate(10) -local Route={} -Route[#Route+1]=FromCoord:WaypointGround(120) -Route[#Route+1]=ToCoord:WaypointGround(Speed,Formation) -local TaskRouteToZone=PatrolGroup:TaskFunction("CONTROLLABLE.PatrolZones",ZoneList,Speed,Formation) -PatrolGroup:SetTaskWaypoint(Route[#Route],TaskRouteToZone) -PatrolGroup:Route(Route,1) -end -end -end -function CONTROLLABLE:TaskRoute(Points) -self:F2(Points) -local DCSTask -DCSTask={id='Mission',params={route={points=Points,},},} -self:T3({DCSTask}) -return DCSTask -end -function CONTROLLABLE:RouteToVec2(Point,Speed) -self:F2({Point,Speed}) -local ControllablePoint=self:GetUnit(1):GetVec2() -local PointFrom={} -PointFrom.x=ControllablePoint.x -PointFrom.y=ControllablePoint.y -PointFrom.type="Turning Point" -PointFrom.action="Turning Point" -PointFrom.speed=Speed -PointFrom.speed_locked=true -PointFrom.properties={ -["vnav"]=1, -["scale"]=0, -["angle"]=0, -["vangle"]=0, -["steer"]=2, -} -local PointTo={} -PointTo.x=Point.x -PointTo.y=Point.y -PointTo.type="Turning Point" -PointTo.action="Fly Over Point" -PointTo.speed=Speed -PointTo.speed_locked=true -PointTo.properties={ -["vnav"]=1, -["scale"]=0, -["angle"]=0, -["vangle"]=0, -["steer"]=2, -} -local Points={PointFrom,PointTo} -self:T3(Points) -self:Route(Points) -return self -end -function CONTROLLABLE:RouteToVec3(Point,Speed) -self:F2({Point,Speed}) -local ControllableVec3=self:GetUnit(1):GetVec3() -local PointFrom={} -PointFrom.x=ControllableVec3.x -PointFrom.y=ControllableVec3.z -PointFrom.alt=ControllableVec3.y -PointFrom.alt_type="BARO" -PointFrom.type="Turning Point" -PointFrom.action="Turning Point" -PointFrom.speed=Speed -PointFrom.speed_locked=true -PointFrom.properties={ -["vnav"]=1, -["scale"]=0, -["angle"]=0, -["vangle"]=0, -["steer"]=2, -} -local PointTo={} -PointTo.x=Point.x -PointTo.y=Point.z -PointTo.alt=Point.y -PointTo.alt_type="BARO" -PointTo.type="Turning Point" -PointTo.action="Fly Over Point" -PointTo.speed=Speed -PointTo.speed_locked=true -PointTo.properties={ -["vnav"]=1, -["scale"]=0, -["angle"]=0, -["vangle"]=0, -["steer"]=2, -} -local Points={PointFrom,PointTo} -self:T3(Points) -self:Route(Points) -return self -end -function CONTROLLABLE:Route(Route,DelaySeconds) -self:F2(Route) -local DCSControllable=self:GetDCSObject() -if DCSControllable then -local RouteTask=self:TaskRoute(Route) -self:SetTask(RouteTask,DelaySeconds or 1) -return self -end -return nil -end -function CONTROLLABLE:RouteGroundTo(ToCoordinate,Speed,Formation,DelaySeconds) -local FromCoordinate=self:GetCoordinate() -local FromWP=FromCoordinate:WaypointGround() -local ToWP=ToCoordinate:WaypointGround(Speed,Formation) -self:Route({FromWP,ToWP},DelaySeconds) -return self -end -function CONTROLLABLE:RouteAirTo(ToCoordinate,AltType,Type,Action,Speed,DelaySeconds) -local FromCoordinate=self:GetCoordinate() -local FromWP=FromCoordinate:WaypointAir() -local ToWP=ToCoordinate:WaypointAir(AltType,Type,Action,Speed) -self:Route({FromWP,ToWP},DelaySeconds) -return self -end -function CONTROLLABLE:TaskRouteToZone(Zone,Randomize,Speed,Formation) -self:F2(Zone) -local DCSControllable=self:GetDCSObject() -if DCSControllable then -local ControllablePoint=self:GetVec2() -local PointFrom={} -PointFrom.x=ControllablePoint.x -PointFrom.y=ControllablePoint.y -PointFrom.type="Turning Point" -PointFrom.action=Formation or"Cone" -PointFrom.speed=20/1.6 -local PointTo={} -local ZonePoint -if Randomize then -ZonePoint=Zone:GetRandomVec2() -else -ZonePoint=Zone:GetVec2() -end -PointTo.x=ZonePoint.x -PointTo.y=ZonePoint.y -PointTo.type="Turning Point" -if Formation then -PointTo.action=Formation -else -PointTo.action="Cone" -end -if Speed then -PointTo.speed=Speed -else -PointTo.speed=20/1.6 -end -local Points={PointFrom,PointTo} -self:T3(Points) -self:Route(Points) -return self -end -return nil -end -function CONTROLLABLE:TaskRouteToVec2(Vec2,Speed,Formation) -local DCSControllable=self:GetDCSObject() -if DCSControllable then -local ControllablePoint=self:GetVec2() -local PointFrom={} -PointFrom.x=ControllablePoint.x -PointFrom.y=ControllablePoint.y -PointFrom.type="Turning Point" -PointFrom.action=Formation or"Cone" -PointFrom.speed=20/1.6 -local PointTo={} -PointTo.x=Vec2.x -PointTo.y=Vec2.y -PointTo.type="Turning Point" -if Formation then -PointTo.action=Formation -else -PointTo.action="Cone" -end -if Speed then -PointTo.speed=Speed -else -PointTo.speed=60/3.6 -end -local Points={PointFrom,PointTo} -self:T3(Points) -self:Route(Points) -return self -end -return nil -end -function CONTROLLABLE:CommandDoScript(DoScript) -local DCSDoScript={ -id="Script", -params={ -command=DoScript, -}, -} -self:T3(DCSDoScript) -return DCSDoScript -end -function CONTROLLABLE:GetTaskMission() -self:F2(self.ControllableName) -return routines.utils.deepCopy(_DATABASE.Templates.Controllables[self.ControllableName].Template) -end -function CONTROLLABLE:GetTaskRoute() -self:F2(self.ControllableName) -return routines.utils.deepCopy(_DATABASE.Templates.Controllables[self.ControllableName].Template.route.points) -end -function CONTROLLABLE:CopyRoute(Begin,End,Randomize,Radius) -self:F2({Begin,End}) -local Points={} -local ControllableName=string.match(self:GetName(),".*#") -if ControllableName then -ControllableName=ControllableName:sub(1,-2) -else -ControllableName=self:GetName() -end -self:T3({ControllableName}) -local Template=_DATABASE.Templates.Controllables[ControllableName].Template -if Template then -if not Begin then -Begin=0 -end -if not End then -End=0 -end -for TPointID=Begin+1,#Template.route.points-End do -if Template.route.points[TPointID]then -Points[#Points+1]=routines.utils.deepCopy(Template.route.points[TPointID]) -if Randomize then -if not Radius then -Radius=500 -end -Points[#Points].x=Points[#Points].x+math.random(Radius*-1,Radius) -Points[#Points].y=Points[#Points].y+math.random(Radius*-1,Radius) -end -end -end -return Points -else -error("Template not found for Controllable : "..ControllableName) -end -return nil -end -function CONTROLLABLE:GetDetectedTargets(DetectVisual,DetectOptical,DetectRadar,DetectIRST,DetectRWR,DetectDLINK) -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 -local DetectionIRST=(DetectIRST and DetectIRST==true)and Controller.Detection.IRST or nil -local DetectionRWR=(DetectRWR and DetectRWR==true)and Controller.Detection.RWR or nil -local DetectionDLINK=(DetectDLINK and DetectDLINK==true)and Controller.Detection.DLINK or nil -self:T({DetectionVisual,DetectionOptical,DetectionRadar,DetectionIRST,DetectionRWR,DetectionDLINK}) -return self:_GetController():getDetectedTargets(DetectionVisual,DetectionOptical,DetectionRadar,DetectionIRST,DetectionRWR,DetectionDLINK) -end -return nil -end -function CONTROLLABLE:IsTargetDetected(DCSObject,DetectVisual,DetectOptical,DetectRadar,DetectIRST,DetectRWR,DetectDLINK) -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 -local DetectionIRST=(DetectIRST and DetectIRST==true)and Controller.Detection.IRST or nil -local DetectionRWR=(DetectRWR and DetectRWR==true)and Controller.Detection.RWR or nil -local DetectionDLINK=(DetectDLINK and DetectDLINK==true)and Controller.Detection.DLINK or nil -local Controller=self:_GetController() -local TargetIsDetected,TargetIsVisible,TargetLastTime,TargetKnowType,TargetKnowDistance,TargetLastPos,TargetLastVelocity -=Controller:isTargetDetected(DCSObject,DetectionVisual,DetectionOptical,DetectionRadar,DetectionIRST,DetectionRWR,DetectionDLINK) -return TargetIsDetected,TargetIsVisible,TargetLastTime,TargetKnowType,TargetKnowDistance,TargetLastPos,TargetLastVelocity -end -return nil -end -function CONTROLLABLE:OptionROEHoldFirePossible() -self:F2({self.ControllableName}) -local DCSControllable=self:GetDCSObject() -if DCSControllable then -if self:IsAir()or self:IsGround()or self:IsShip()then -return true -end -return false -end -return nil -end -function CONTROLLABLE:OptionROEHoldFire() -self:F2({self.ControllableName}) -local DCSControllable=self:GetDCSObject() -if DCSControllable then -local Controller=self:_GetController() -if self:IsAir()then -Controller:setOption(AI.Option.Air.id.ROE,AI.Option.Air.val.ROE.WEAPON_HOLD) -elseif self:IsGround()then -Controller:setOption(AI.Option.Ground.id.ROE,AI.Option.Ground.val.ROE.WEAPON_HOLD) -elseif self:IsShip()then -Controller:setOption(AI.Option.Naval.id.ROE,AI.Option.Naval.val.ROE.WEAPON_HOLD) -end -return self -end -return nil -end -function CONTROLLABLE:OptionROEReturnFirePossible() -self:F2({self.ControllableName}) -local DCSControllable=self:GetDCSObject() -if DCSControllable then -if self:IsAir()or self:IsGround()or self:IsShip()then -return true -end -return false -end -return nil -end -function CONTROLLABLE:OptionROEReturnFire() -self:F2({self.ControllableName}) -local DCSControllable=self:GetDCSObject() -if DCSControllable then -local Controller=self:_GetController() -if self:IsAir()then -Controller:setOption(AI.Option.Air.id.ROE,AI.Option.Air.val.ROE.RETURN_FIRE) -elseif self:IsGround()then -Controller:setOption(AI.Option.Ground.id.ROE,AI.Option.Ground.val.ROE.RETURN_FIRE) -elseif self:IsShip()then -Controller:setOption(AI.Option.Naval.id.ROE,AI.Option.Naval.val.ROE.RETURN_FIRE) -end -return self -end -return nil -end -function CONTROLLABLE:OptionROEOpenFirePossible() -self:F2({self.ControllableName}) -local DCSControllable=self:GetDCSObject() -if DCSControllable then -if self:IsAir()or self:IsGround()or self:IsShip()then -return true -end -return false -end -return nil -end -function CONTROLLABLE:OptionROEOpenFire() -self:F2({self.ControllableName}) -local DCSControllable=self:GetDCSObject() -if DCSControllable then -local Controller=self:_GetController() -if self:IsAir()then -Controller:setOption(AI.Option.Air.id.ROE,AI.Option.Air.val.ROE.OPEN_FIRE) -elseif self:IsGround()then -Controller:setOption(AI.Option.Ground.id.ROE,AI.Option.Ground.val.ROE.OPEN_FIRE) -elseif self:IsShip()then -Controller:setOption(AI.Option.Naval.id.ROE,AI.Option.Naval.val.ROE.OPEN_FIRE) -end -return self -end -return nil -end -function CONTROLLABLE:OptionROEWeaponFreePossible() -self:F2({self.ControllableName}) -local DCSControllable=self:GetDCSObject() -if DCSControllable then -if self:IsAir()then -return true -end -return false -end -return nil -end -function CONTROLLABLE:OptionROEWeaponFree() -self:F2({self.ControllableName}) -local DCSControllable=self:GetDCSObject() -if DCSControllable then -local Controller=self:_GetController() -if self:IsAir()then -Controller:setOption(AI.Option.Air.id.ROE,AI.Option.Air.val.ROE.WEAPON_FREE) -end -return self -end -return nil -end -function CONTROLLABLE:OptionROTNoReactionPossible() -self:F2({self.ControllableName}) -local DCSControllable=self:GetDCSObject() -if DCSControllable then -if self:IsAir()then -return true -end -return false -end -return nil -end -function CONTROLLABLE:OptionROTNoReaction() -self:F2({self.ControllableName}) -local DCSControllable=self:GetDCSObject() -if DCSControllable then -local Controller=self:_GetController() -if self:IsAir()then -Controller:setOption(AI.Option.Air.id.REACTION_ON_THREAT,AI.Option.Air.val.REACTION_ON_THREAT.NO_REACTION) -end -return self -end -return nil -end -function CONTROLLABLE:OptionROTPassiveDefensePossible() -self:F2({self.ControllableName}) -local DCSControllable=self:GetDCSObject() -if DCSControllable then -if self:IsAir()then -return true -end -return false -end -return nil -end -function CONTROLLABLE:OptionROTPassiveDefense() -self:F2({self.ControllableName}) -local DCSControllable=self:GetDCSObject() -if DCSControllable then -local Controller=self:_GetController() -if self:IsAir()then -Controller:setOption(AI.Option.Air.id.REACTION_ON_THREAT,AI.Option.Air.val.REACTION_ON_THREAT.PASSIVE_DEFENCE) -end -return self -end -return nil -end -function CONTROLLABLE:OptionROTEvadeFirePossible() -self:F2({self.ControllableName}) -local DCSControllable=self:GetDCSObject() -if DCSControllable then -if self:IsAir()then -return true -end -return false -end -return nil -end -function CONTROLLABLE:OptionROTEvadeFire() -self:F2({self.ControllableName}) -local DCSControllable=self:GetDCSObject() -if DCSControllable then -local Controller=self:_GetController() -if self:IsAir()then -Controller:setOption(AI.Option.Air.id.REACTION_ON_THREAT,AI.Option.Air.val.REACTION_ON_THREAT.EVADE_FIRE) -end -return self -end -return nil -end -function CONTROLLABLE:OptionROTVerticalPossible() -self:F2({self.ControllableName}) -local DCSControllable=self:GetDCSObject() -if DCSControllable then -if self:IsAir()then -return true -end -return false -end -return nil -end -function CONTROLLABLE:OptionROTVertical() -self:F2({self.ControllableName}) -local DCSControllable=self:GetDCSObject() -if DCSControllable then -local Controller=self:_GetController() -if self:IsAir()then -Controller:setOption(AI.Option.Air.id.REACTION_ON_THREAT,AI.Option.Air.val.REACTION_ON_THREAT.BYPASS_AND_ESCAPE) -end -return self -end -return nil -end -function CONTROLLABLE:OptionRTBBingoFuel(RTB) -self:F2({self.ControllableName}) -RTB=RTB or true -local DCSControllable=self:GetDCSObject() -if DCSControllable then -local Controller=self:_GetController() -if self:IsAir()then -Controller:setOption(AI.Option.Air.id.RTB_ON_BINGO,RTB) -end -return self -end -return nil -end -function CONTROLLABLE:OptionRTBAmmo(WeaponsFlag) -self:F2({self.ControllableName}) -local DCSControllable=self:GetDCSObject() -if DCSControllable then -local Controller=self:_GetController() -if self:IsAir()then -Controller:setOption(AI.Option.GROUND.id.RTB_ON_OUT_OF_AMMO,WeaponsFlag) -end -return self -end -return nil -end -function CONTROLLABLE:WayPointInitialize(WayPoints) -self:F({WayPoints}) -if WayPoints then -self.WayPoints=WayPoints -else -self.WayPoints=self:GetTaskRoute() -end -return self -end -function CONTROLLABLE:GetWayPoints() -self:F() -if self.WayPoints then -return self.WayPoints -end -return nil -end -function CONTROLLABLE:WayPointFunction(WayPoint,WayPointIndex,WayPointFunction,...) -self:F2({WayPoint,WayPointIndex,WayPointFunction}) -table.insert(self.WayPoints[WayPoint].task.params.tasks,WayPointIndex) -self.WayPoints[WayPoint].task.params.tasks[WayPointIndex]=self:TaskFunction(WayPointFunction,arg) -return self -end -function CONTROLLABLE:WayPointExecute(WayPoint,WaitTime) -self:F({WayPoint,WaitTime}) -if not WayPoint then -WayPoint=1 -end -for TaskPointID=1,WayPoint-1 do -table.remove(self.WayPoints,1) -end -self:T3(self.WayPoints) -self:SetTask(self:TaskRoute(self.WayPoints),WaitTime) -return self -end -function CONTROLLABLE:IsAirPlane() -self:F2() -local DCSObject=self:GetDCSObject() -if DCSObject then -local Category=DCSObject:getDesc().category -return Category==Unit.Category.AIRPLANE -end -return nil -end -function CONTROLLABLE:GetSize() -local DCSObject=self:GetDCSObject() -if DCSObject then -return 1 -else -return 0 -end -end -GROUP={ -ClassName="GROUP", -} -GROUP.Takeoff={ -Air=1, -Runway=2, -Hot=3, -Cold=4, -} -GROUPTEMPLATE={} -GROUPTEMPLATE.Takeoff={ -[GROUP.Takeoff.Air]={"Turning Point","Turning Point"}, -[GROUP.Takeoff.Runway]={"TakeOff","From Runway"}, -[GROUP.Takeoff.Hot]={"TakeOffParkingHot","From Parking Area Hot"}, -[GROUP.Takeoff.Cold]={"TakeOffParking","From Parking Area"} -} -function GROUP:Register(GroupName) -self=BASE:Inherit(self,CONTROLLABLE:New(GroupName)) -self:F2(GroupName) -self.GroupName=GroupName -self:SetEventPriority(4) -return self -end -function GROUP:Find(DCSGroup) -local GroupName=DCSGroup:getName() -local GroupFound=_DATABASE:FindGroup(GroupName) -return GroupFound -end -function GROUP:FindByName(GroupName) -local GroupFound=_DATABASE:FindGroup(GroupName) -return GroupFound -end -function GROUP:GetDCSObject() -local DCSGroup=Group.getByName(self.GroupName) -if DCSGroup then -return DCSGroup -end -return nil -end -function GROUP:GetPositionVec3() -self:F2(self.PositionableName) -local DCSPositionable=self:GetDCSObject() -if DCSPositionable then -local PositionablePosition=DCSPositionable:getUnits()[1]:getPosition().p -self:T3(PositionablePosition) -return PositionablePosition -end -return nil -end -function GROUP:IsAlive() -self:F2(self.GroupName) -local DCSGroup=self:GetDCSObject() -if DCSGroup then -if DCSGroup:isExist()then -local DCSUnit=DCSGroup:getUnit(1) -if DCSUnit then -local GroupIsAlive=DCSUnit:isActive() -self:T3(GroupIsAlive) -return GroupIsAlive -end -end -end -return nil -end -function GROUP:Destroy() -self:F2(self.GroupName) -local DCSGroup=self:GetDCSObject() -if DCSGroup then -for Index,UnitData in pairs(DCSGroup:getUnits())do -self:CreateEventCrash(timer.getTime(),UnitData) -end -DCSGroup:destroy() -DCSGroup=nil -end -return nil -end -function GROUP:GetCategory() -self:F2(self.GroupName) -local DCSGroup=self:GetDCSObject() -if DCSGroup then -local GroupCategory=DCSGroup:getCategory() -self:T3(GroupCategory) -return GroupCategory -end -return nil -end -function GROUP:GetCategoryName() -self:F2(self.GroupName) -local DCSGroup=self:GetDCSObject() -if DCSGroup then -local CategoryNames={ -[Group.Category.AIRPLANE]="Airplane", -[Group.Category.HELICOPTER]="Helicopter", -[Group.Category.GROUND]="Ground Unit", -[Group.Category.SHIP]="Ship", -} -local GroupCategory=DCSGroup:getCategory() -self:T3(GroupCategory) -return CategoryNames[GroupCategory] -end -return nil -end -function GROUP:GetCoalition() -self:F2(self.GroupName) -local DCSGroup=self:GetDCSObject() -if DCSGroup then -local GroupCoalition=DCSGroup:getCoalition() -self:T3(GroupCoalition) -return GroupCoalition -end -return nil -end -function GROUP:GetCountry() -self:F2(self.GroupName) -local DCSGroup=self:GetDCSObject() -if DCSGroup then -local GroupCountry=DCSGroup:getUnit(1):getCountry() -self:T3(GroupCountry) -return GroupCountry -end -return nil -end -function GROUP:GetUnit(UnitNumber) -self:F2({self.GroupName,UnitNumber}) -local DCSGroup=self:GetDCSObject() -if DCSGroup then -local DCSUnit=DCSGroup:getUnit(UnitNumber) -local UnitFound=UNIT:Find(DCSGroup:getUnit(UnitNumber)) -self:T2(UnitFound) -return UnitFound -end -return nil -end -function GROUP:GetDCSUnit(UnitNumber) -self:F2({self.GroupName,UnitNumber}) -local DCSGroup=self:GetDCSObject() -if DCSGroup then -local DCSUnitFound=DCSGroup:getUnit(UnitNumber) -self:T3(DCSUnitFound) -return DCSUnitFound -end -return nil -end -function GROUP:GetSize() -self:F2({self.GroupName}) -local DCSGroup=self:GetDCSObject() -if DCSGroup then -local GroupSize=DCSGroup:getSize() -if GroupSize then -self:T3(GroupSize) -return GroupSize -else -return 0 -end -end -return nil -end -function GROUP:GetInitialSize() -self:F2({self.GroupName}) -local DCSGroup=self:GetDCSObject() -if DCSGroup then -local GroupInitialSize=DCSGroup:getInitialSize() -self:T3(GroupInitialSize) -return GroupInitialSize -end -return nil -end -function GROUP:GetDCSUnits() -self:F2({self.GroupName}) -local DCSGroup=self:GetDCSObject() -if DCSGroup then -local DCSUnits=DCSGroup:getUnits() -self:T3(DCSUnits) -return DCSUnits -end -return nil -end -function GROUP:Activate() -self:F2({self.GroupName}) -trigger.action.activateGroup(self:GetDCSObject()) -return self:GetDCSObject() -end -function GROUP:GetTypeName() -self:F2(self.GroupName) -local DCSGroup=self:GetDCSObject() -if DCSGroup then -local GroupTypeName=DCSGroup:getUnit(1):getTypeName() -self:T3(GroupTypeName) -return(GroupTypeName) -end -return nil -end -function GROUP:GetPlayerName() -self:F2(self.GroupName) -local DCSGroup=self:GetDCSObject() -if DCSGroup then -local PlayerName=DCSGroup:getUnit(1):getPlayerName() -self:T3(PlayerName) -return(PlayerName) -end -return nil -end -function GROUP:GetCallsign() -self:F2(self.GroupName) -local DCSGroup=self:GetDCSObject() -if DCSGroup then -local GroupCallSign=DCSGroup:getUnit(1):getCallsign() -self:T3(GroupCallSign) -return GroupCallSign -end -return nil -end -function GROUP:GetVec2() -self:F2(self.GroupName) -local UnitPoint=self:GetUnit(1) -UnitPoint:GetVec2() -local GroupPointVec2=UnitPoint:GetVec2() -self:T3(GroupPointVec2) -return GroupPointVec2 -end -function GROUP:GetVec3() -self:F2(self.GroupName) -local GroupVec3=self:GetUnit(1):GetVec3() -self:T3(GroupVec3) -return GroupVec3 -end -function GROUP:GetPointVec2() -self:F2(self.GroupName) -local FirstUnit=self:GetUnit(1) -if FirstUnit then -local FirstUnitPointVec2=FirstUnit:GetPointVec2() -self:T3(FirstUnitPointVec2) -return FirstUnitPointVec2 -end -return nil -end -function GROUP:GetCoordinate() -self:F2(self.PositionableName) -local FirstUnit=self:GetUnit(1) -if FirstUnit then -local FirstUnitCoordinate=FirstUnit:GetCoordinate() -self:T3(FirstUnitCoordinate) -return FirstUnitCoordinate -end -return nil -end -function GROUP:GetRandomVec3(Radius) -self:F2(self.GroupName) -local FirstUnit=self:GetUnit(1) -if FirstUnit then -local FirstUnitRandomPointVec3=FirstUnit:GetRandomVec3(Radius) -self:T3(FirstUnitRandomPointVec3) -return FirstUnitRandomPointVec3 -end -return nil -end -function GROUP:GetHeading() -self:F2(self.GroupName) -local GroupSize=self:GetSize() -local HeadingAccumulator=0 -if GroupSize then -for i=1,GroupSize do -HeadingAccumulator=HeadingAccumulator+self:GetUnit(i):GetHeading() -end -return math.floor(HeadingAccumulator/GroupSize) -end -return nil -end -function GROUP:GetFuel() -self:F(self.ControllableName) -local DCSControllable=self:GetDCSObject() -if DCSControllable then -local GroupSize=self:GetSize() -local TotalFuel=0 -for UnitID,UnitData in pairs(self:GetUnits())do -local Unit=UnitData -local UnitFuel=Unit:GetFuel() -self:F({Fuel=UnitFuel}) -TotalFuel=TotalFuel+UnitFuel -end -local GroupFuel=TotalFuel/GroupSize -return GroupFuel -end -return 0 -end -do -function GROUP:IsCompletelyInZone(Zone) -self:F2({self.GroupName,Zone}) -if not self:IsAlive()then return false end -for UnitID,UnitData in pairs(self:GetUnits())do -local Unit=UnitData -if Zone:IsVec3InZone(Unit:GetVec3())then -else -return false -end -end -return true -end -function GROUP:IsPartlyInZone(Zone) -self:F2({self.GroupName,Zone}) -local IsOneUnitInZone=false -local IsOneUnitOutsideZone=false -if not self:IsAlive()then return false end -for UnitID,UnitData in pairs(self:GetUnits())do -local Unit=UnitData -if Zone:IsVec3InZone(Unit:GetVec3())then -IsOneUnitInZone=true -else -IsOneUnitOutsideZone=true -end -end -if IsOneUnitInZone and IsOneUnitOutsideZone then -return true -else -return false -end -end -function GROUP:IsNotInZone(Zone) -self:F2({self.GroupName,Zone}) -if not self:IsAlive()then return true end -for UnitID,UnitData in pairs(self:GetUnits())do -local Unit=UnitData -if Zone:IsVec3InZone(Unit:GetVec3())then -return false -end -end -return true -end -function GROUP:CountInZone(Zone) -self:F2({self.GroupName,Zone}) -local Count=0 -if not self:IsAlive()then return Count end -for UnitID,UnitData in pairs(self:GetUnits())do -local Unit=UnitData -if Zone:IsVec3InZone(Unit:GetVec3())then -Count=Count+1 -end -end -return Count -end -function GROUP:IsAir() -self:F2(self.GroupName) -local DCSGroup=self:GetDCSObject() -if DCSGroup then -local IsAirResult=DCSGroup:getCategory()==Group.Category.AIRPLANE or DCSGroup:getCategory()==Group.Category.HELICOPTER -self:T3(IsAirResult) -return IsAirResult -end -return nil -end -function GROUP:IsHelicopter() -self:F2(self.GroupName) -local DCSGroup=self:GetDCSObject() -if DCSGroup then -local GroupCategory=DCSGroup:getCategory() -self:T2(GroupCategory) -return GroupCategory==Group.Category.HELICOPTER -end -return nil -end -function GROUP:IsAirPlane() -self:F2() -local DCSGroup=self:GetDCSObject() -if DCSGroup then -local GroupCategory=DCSGroup:getCategory() -self:T2(GroupCategory) -return GroupCategory==Group.Category.AIRPLANE -end -return nil -end -function GROUP:IsGround() -self:F2() -local DCSGroup=self:GetDCSObject() -if DCSGroup then -local GroupCategory=DCSGroup:getCategory() -self:T2(GroupCategory) -return GroupCategory==Group.Category.GROUND -end -return nil -end -function GROUP:IsShip() -self:F2() -local DCSGroup=self:GetDCSObject() -if DCSGroup then -local GroupCategory=DCSGroup:getCategory() -self:T2(GroupCategory) -return GroupCategory==Group.Category.SHIP -end -return nil -end -function GROUP:AllOnGround() -self:F2() -local DCSGroup=self:GetDCSObject() -if DCSGroup then -local AllOnGroundResult=true -for Index,UnitData in pairs(DCSGroup:getUnits())do -if UnitData:inAir()then -AllOnGroundResult=false -end -end -self:T3(AllOnGroundResult) -return AllOnGroundResult -end -return nil -end -end -do -function GROUP:SetAIOnOff(AIOnOff) -local DCSGroup=self:GetDCSObject() -if DCSGroup then -local DCSController=DCSGroup:getController() -if DCSController then -DCSController:setOnOff(AIOnOff) -return self -end -end -return nil -end -function GROUP:SetAIOn() -return self:SetAIOnOff(true) -end -function GROUP:SetAIOff() -return self:SetAIOnOff(false) -end -end -function GROUP:GetMaxVelocity() -self:F2() -local DCSGroup=self:GetDCSObject() -if DCSGroup then -local GroupVelocityMax=0 -for Index,UnitData in pairs(DCSGroup:getUnits())do -local UnitVelocityVec3=UnitData:getVelocity() -local UnitVelocity=math.abs(UnitVelocityVec3.x)+math.abs(UnitVelocityVec3.y)+math.abs(UnitVelocityVec3.z) -if UnitVelocity>GroupVelocityMax then -GroupVelocityMax=UnitVelocity -end -end -return GroupVelocityMax -end -return nil -end -function GROUP:GetMinHeight() -self:F2() -end -function GROUP:GetMaxHeight() -self:F2() -end -function GROUP:Respawn(Template) -if self:IsAlive()then -local Vec3=self:GetVec3() -Template.x=Vec3.x -Template.y=Vec3.z -self:E(#Template.units) -for UnitID,UnitData in pairs(self:GetUnits())do -local GroupUnit=UnitData -self:E(GroupUnit:GetName()) -if GroupUnit:IsAlive()then -local GroupUnitVec3=GroupUnit:GetVec3() -local GroupUnitHeading=GroupUnit:GetHeading() -Template.units[UnitID].alt=GroupUnitVec3.y -Template.units[UnitID].x=GroupUnitVec3.x -Template.units[UnitID].y=GroupUnitVec3.z -Template.units[UnitID].heading=GroupUnitHeading -self:E({UnitID,Template.units[UnitID],Template.units[UnitID]}) -end -end -end -self:Destroy() -_DATABASE:Spawn(Template) -self:ResetEvents() -end -function GROUP:GetTemplate() -local GroupName=self:GetName() -return UTILS.DeepCopy(_DATABASE:GetGroupTemplate(GroupName)) -end -function GROUP:GetTemplateRoutePoints() -local GroupName=self:GetName() -return UTILS.DeepCopy(_DATABASE:GetGroupTemplate(GroupName).route.points) -end -function GROUP:SetTemplateControlled(Template,Controlled) -Template.uncontrolled=not Controlled -return Template -end -function GROUP:SetTemplateCountry(Template,CountryID) -Template.CountryID=CountryID -return Template -end -function GROUP:SetTemplateCoalition(Template,CoalitionID) -Template.CoalitionID=CoalitionID -return Template -end -function GROUP:GetTaskMission() -self:F2(self.GroupName) -return routines.utils.deepCopy(_DATABASE.Templates.Groups[self.GroupName].Template) -end -function GROUP:GetTaskRoute() -self:F2(self.GroupName) -return routines.utils.deepCopy(_DATABASE.Templates.Groups[self.GroupName].Template.route.points) -end -function GROUP:CopyRoute(Begin,End,Randomize,Radius) -self:F2({Begin,End}) -local Points={} -local GroupName=string.match(self:GetName(),".*#") -if GroupName then -GroupName=GroupName:sub(1,-2) -else -GroupName=self:GetName() -end -self:T3({GroupName}) -local Template=_DATABASE.Templates.Groups[GroupName].Template -if Template then -if not Begin then -Begin=0 -end -if not End then -End=0 -end -for TPointID=Begin+1,#Template.route.points-End do -if Template.route.points[TPointID]then -Points[#Points+1]=routines.utils.deepCopy(Template.route.points[TPointID]) -if Randomize then -if not Radius then -Radius=500 -end -Points[#Points].x=Points[#Points].x+math.random(Radius*-1,Radius) -Points[#Points].y=Points[#Points].y+math.random(Radius*-1,Radius) -end -end -end -return Points -else -error("Template not found for Group : "..GroupName) -end -return nil -end -function GROUP:CalculateThreatLevelA2G() -local MaxThreatLevelA2G=0 -for UnitName,UnitData in pairs(self:GetUnits())do -local ThreatUnit=UnitData -local ThreatLevelA2G=ThreatUnit:GetThreatLevel() -if ThreatLevelA2G>MaxThreatLevelA2G then -MaxThreatLevelA2G=ThreatLevelA2G -end -end -self:T3(MaxThreatLevelA2G) -return MaxThreatLevelA2G -end -function GROUP:InAir() -self:F2(self.GroupName) -local DCSGroup=self:GetDCSObject() -if DCSGroup then -local DCSUnit=DCSGroup:getUnit(1) -if DCSUnit then -local GroupInAir=DCSGroup:getUnit(1):inAir() -self:T3(GroupInAir) -return GroupInAir -end -end -return nil -end -do -function GROUP:RouteRTB(RTBAirbase,Speed) -self:F2({RTBAirbase,Speed}) -local DCSGroup=self:GetDCSObject() -if DCSGroup then -if RTBAirbase then -local GroupPoint=self:GetVec2() -local GroupVelocity=self:GetUnit(1):GetDesc().speedMax -local PointFrom={} -PointFrom.x=GroupPoint.x -PointFrom.y=GroupPoint.y -PointFrom.type="Turning Point" -PointFrom.action="Turning Point" -PointFrom.speed=GroupVelocity -local PointTo={} -local AirbasePointVec2=RTBAirbase:GetPointVec2() -local AirbaseAirPoint=AirbasePointVec2:WaypointAir( -POINT_VEC3.RoutePointAltType.BARO, -"Land", -"Landing", -Speed or self:GetUnit(1):GetDesc().speedMax -) -AirbaseAirPoint["airdromeId"]=RTBAirbase:GetID() -AirbaseAirPoint["speed_locked"]=true, -self:E(AirbaseAirPoint) -local Points={PointFrom,AirbaseAirPoint} -self:T3(Points) -local Template=self:GetTemplate() -Template.route.points=Points -self:Respawn(Template) -self:Route(Points) -self:Respawn(Template) -else -self:ClearTasks() -end -end -return self -end -end -function GROUP:OnReSpawn(ReSpawnFunction) -self.ReSpawnFunction=ReSpawnFunction -end -do -function GROUP:HandleEvent(Event,EventFunction,...) -self:EventDispatcher():OnEventForGroup(self:GetName(),EventFunction,self,Event,...) -return self -end -function GROUP:UnHandleEvent(Event) -self:EventDispatcher():RemoveEvent(self,Event) -return self -end -function GROUP:ResetEvents() -self:EventDispatcher():Reset(self) -for UnitID,UnitData in pairs(self:GetUnits())do -UnitData:ResetEvents() -end -return self -end -end -do -function GROUP:GetPlayerNames() -local PlayerNames={} -local Units=self:GetUnits() -for UnitID,UnitData in pairs(Units)do -local Unit=UnitData -local PlayerName=Unit:GetPlayerName() -if PlayerName and PlayerName~=""then -PlayerNames=PlayerNames or{} -table.insert(PlayerNames,PlayerName) -end -end -self:F2(PlayerNames) -return PlayerNames -end -end -UNIT={ -ClassName="UNIT", -} -function UNIT:Register(UnitName) -local self=BASE:Inherit(self,CONTROLLABLE:New(UnitName)) -self.UnitName=UnitName -self:SetEventPriority(3) -return self -end -function UNIT:Find(DCSUnit) -local UnitName=DCSUnit:getName() -local UnitFound=_DATABASE:FindUnit(UnitName) -return UnitFound -end -function UNIT:FindByName(UnitName) -local UnitFound=_DATABASE:FindUnit(UnitName) -return UnitFound -end -function UNIT:Name() -return self.UnitName -end -function UNIT:GetDCSObject() -local DCSUnit=Unit.getByName(self.UnitName) -if DCSUnit then -return DCSUnit -end -return nil -end -function UNIT:ReSpawn(SpawnVec3,Heading) -local SpawnGroupTemplate=UTILS.DeepCopy(_DATABASE:GetGroupTemplateFromUnitName(self:Name())) -self:T(SpawnGroupTemplate) -local SpawnGroup=self:GetGroup() -if SpawnGroup then -local Vec3=SpawnGroup:GetVec3() -SpawnGroupTemplate.x=SpawnVec3.x -SpawnGroupTemplate.y=SpawnVec3.z -self:E(#SpawnGroupTemplate.units) -for UnitID,UnitData in pairs(SpawnGroup:GetUnits())do -local GroupUnit=UnitData -self:E(GroupUnit:GetName()) -if GroupUnit:IsAlive()then -local GroupUnitVec3=GroupUnit:GetVec3() -local GroupUnitHeading=GroupUnit:GetHeading() -SpawnGroupTemplate.units[UnitID].alt=GroupUnitVec3.y -SpawnGroupTemplate.units[UnitID].x=GroupUnitVec3.x -SpawnGroupTemplate.units[UnitID].y=GroupUnitVec3.z -SpawnGroupTemplate.units[UnitID].heading=GroupUnitHeading -self:E({UnitID,SpawnGroupTemplate.units[UnitID],SpawnGroupTemplate.units[UnitID]}) -end -end -end -for UnitTemplateID,UnitTemplateData in pairs(SpawnGroupTemplate.units)do -self:T(UnitTemplateData.name) -if UnitTemplateData.name==self:Name()then -self:T("Adjusting") -SpawnGroupTemplate.units[UnitTemplateID].alt=SpawnVec3.y -SpawnGroupTemplate.units[UnitTemplateID].x=SpawnVec3.x -SpawnGroupTemplate.units[UnitTemplateID].y=SpawnVec3.z -SpawnGroupTemplate.units[UnitTemplateID].heading=Heading -self:E({UnitTemplateID,SpawnGroupTemplate.units[UnitTemplateID],SpawnGroupTemplate.units[UnitTemplateID]}) -else -self:E(SpawnGroupTemplate.units[UnitTemplateID].name) -local GroupUnit=UNIT:FindByName(SpawnGroupTemplate.units[UnitTemplateID].name) -if GroupUnit and GroupUnit:IsAlive()then -local GroupUnitVec3=GroupUnit:GetVec3() -local GroupUnitHeading=GroupUnit:GetHeading() -UnitTemplateData.alt=GroupUnitVec3.y -UnitTemplateData.x=GroupUnitVec3.x -UnitTemplateData.y=GroupUnitVec3.z -UnitTemplateData.heading=GroupUnitHeading -else -if SpawnGroupTemplate.units[UnitTemplateID].name~=self:Name()then -self:T("nilling") -SpawnGroupTemplate.units[UnitTemplateID].delete=true -end -end -end -end -local i=1 -while i<=#SpawnGroupTemplate.units do -local UnitTemplateData=SpawnGroupTemplate.units[i] -self:T(UnitTemplateData.name) -if UnitTemplateData.delete then -table.remove(SpawnGroupTemplate.units,i) -else -i=i+1 -end -end -_DATABASE:Spawn(SpawnGroupTemplate) -end -function UNIT:IsActive() -self:F2(self.UnitName) -local DCSUnit=self:GetDCSObject() -if DCSUnit then -local UnitIsActive=DCSUnit:isActive() -return UnitIsActive -end -return nil -end -function UNIT:IsAlive() -self:F3(self.UnitName) -local DCSUnit=self:GetDCSObject() -if DCSUnit then -local UnitIsAlive=DCSUnit:isExist()and DCSUnit:isActive() -return UnitIsAlive -end -return nil -end -function UNIT:GetCallsign() -self:F2(self.UnitName) -local DCSUnit=self:GetDCSObject() -if DCSUnit then -local UnitCallSign=DCSUnit:getCallsign() -return UnitCallSign -end -self:E(self.ClassName.." "..self.UnitName.." not found!") -return nil -end -function UNIT:GetPlayerName() -self:F2(self.UnitName) -local DCSUnit=self:GetDCSObject() -if DCSUnit then -local PlayerName=DCSUnit:getPlayerName() -if PlayerName==nil then -PlayerName="" -end -return PlayerName -end -return nil -end -function UNIT:GetNumber() -self:F2(self.UnitName) -local DCSUnit=self:GetDCSObject() -if DCSUnit then -local UnitNumber=DCSUnit:getNumber() -return UnitNumber -end -return nil -end -function UNIT:GetGroup() -self:F2(self.UnitName) -local DCSUnit=self:GetDCSObject() -if DCSUnit then -local UnitGroup=GROUP:Find(DCSUnit:getGroup()) -return UnitGroup -end -return nil -end -function UNIT:GetPrefix() -self:F2(self.UnitName) -local DCSUnit=self:GetDCSObject() -if DCSUnit then -local UnitPrefix=string.match(self.UnitName,".*#"):sub(1,-2) -self:T3(UnitPrefix) -return UnitPrefix -end -return nil -end -function UNIT:GetAmmo() -self:F2(self.UnitName) -local DCSUnit=self:GetDCSObject() -if DCSUnit then -local UnitAmmo=DCSUnit:getAmmo() -return UnitAmmo -end -return nil -end -function UNIT:GetSensors() -self:F2(self.UnitName) -local DCSUnit=self:GetDCSObject() -if DCSUnit then -local UnitSensors=DCSUnit:getSensors() -return UnitSensors -end -return nil -end -function UNIT:HasSensors(...) -self:F2(arg) -local DCSUnit=self:GetDCSObject() -if DCSUnit then -local HasSensors=DCSUnit:hasSensors(unpack(arg)) -return HasSensors -end -return nil -end -function UNIT:HasSEAD() -self:F2() -local DCSUnit=self:GetDCSObject() -if DCSUnit then -local UnitSEADAttributes=DCSUnit:getDesc().attributes -local HasSEAD=false -if UnitSEADAttributes["RADAR_BAND1_FOR_ARM"]and UnitSEADAttributes["RADAR_BAND1_FOR_ARM"]==true or -UnitSEADAttributes["RADAR_BAND2_FOR_ARM"]and UnitSEADAttributes["RADAR_BAND2_FOR_ARM"]==true then -HasSEAD=true -end -return HasSEAD -end -return nil -end -function UNIT:GetRadar() -self:F2(self.UnitName) -local DCSUnit=self:GetDCSObject() -if DCSUnit then -local UnitRadarOn,UnitRadarObject=DCSUnit:getRadar() -return UnitRadarOn,UnitRadarObject -end -return nil,nil -end -function UNIT:GetFuel() -self:F(self.UnitName) -local DCSUnit=self:GetDCSObject() -if DCSUnit then -local UnitFuel=DCSUnit:getFuel() -return UnitFuel -end -return nil -end -function UNIT:GetUnits() -self:F2({self.UnitName}) -local DCSUnit=self:GetDCSObject() -if DCSUnit then -local DCSUnits=DCSUnit:getUnits() -local Units={} -Units[1]=UNIT:Find(DCSUnit) -self:T3(Units) -return Units -end -return nil -end -function UNIT:GetLife() -self:F2(self.UnitName) -local DCSUnit=self:GetDCSObject() -if DCSUnit then -local UnitLife=DCSUnit:getLife() -return UnitLife -end -return-1 -end -function UNIT:GetLife0() -self:F2(self.UnitName) -local DCSUnit=self:GetDCSObject() -if DCSUnit then -local UnitLife0=DCSUnit:getLife0() -return UnitLife0 -end -return 0 -end -function UNIT:GetCategoryName() -self:F3(self.UnitName) -local DCSUnit=self:GetDCSObject() -if DCSUnit then -local CategoryNames={ -[Unit.Category.AIRPLANE]="Airplane", -[Unit.Category.HELICOPTER]="Helicopter", -[Unit.Category.GROUND_UNIT]="Ground Unit", -[Unit.Category.SHIP]="Ship", -[Unit.Category.STRUCTURE]="Structure", -} -local UnitCategory=DCSUnit:getDesc().category -self:T3(UnitCategory) -return CategoryNames[UnitCategory] -end -return nil -end -function UNIT:GetThreatLevel() -local ThreatLevel=0 -local ThreatText="" -local Descriptor=self:GetDesc() -if Descriptor then -local Attributes=Descriptor.attributes -self:T(Attributes) -if self:IsGround()then -self:T("Ground") -local ThreatLevels={ -"Unarmed", -"Infantry", -"Old Tanks & APCs", -"Tanks & IFVs without ATGM", -"Tanks & IFV with ATGM", -"Modern Tanks", -"AAA", -"IR Guided SAMs", -"SR SAMs", -"MR SAMs", -"LR SAMs" -} -if Attributes["LR SAM"]then ThreatLevel=10 -elseif Attributes["MR SAM"]then ThreatLevel=9 -elseif Attributes["SR SAM"]and -not Attributes["IR Guided SAM"]then ThreatLevel=8 -elseif(Attributes["SR SAM"]or Attributes["MANPADS"])and -Attributes["IR Guided SAM"]then ThreatLevel=7 -elseif Attributes["AAA"]then ThreatLevel=6 -elseif Attributes["Modern Tanks"]then ThreatLevel=5 -elseif(Attributes["Tanks"]or Attributes["IFV"])and -Attributes["ATGM"]then ThreatLevel=4 -elseif(Attributes["Tanks"]or Attributes["IFV"])and -not Attributes["ATGM"]then ThreatLevel=3 -elseif Attributes["Old Tanks"]or Attributes["APC"]or Attributes["Artillery"]then ThreatLevel=2 -elseif Attributes["Infantry"]then ThreatLevel=1 -end -ThreatText=ThreatLevels[ThreatLevel+1] -end -if self:IsAir()then -self:T("Air") -local ThreatLevels={ -"Unarmed", -"Tanker", -"AWACS", -"Transport Helicopter", -"UAV", -"Bomber", -"Strategic Bomber", -"Attack Helicopter", -"Battleplane", -"Multirole Fighter", -"Fighter" -} -if Attributes["Fighters"]then ThreatLevel=10 -elseif Attributes["Multirole fighters"]then ThreatLevel=9 -elseif Attributes["Battleplanes"]then ThreatLevel=8 -elseif Attributes["Attack helicopters"]then ThreatLevel=7 -elseif Attributes["Strategic bombers"]then ThreatLevel=6 -elseif Attributes["Bombers"]then ThreatLevel=5 -elseif Attributes["UAVs"]then ThreatLevel=4 -elseif Attributes["Transport helicopters"]then ThreatLevel=3 -elseif Attributes["AWACS"]then ThreatLevel=2 -elseif Attributes["Tankers"]then ThreatLevel=1 -end -ThreatText=ThreatLevels[ThreatLevel+1] -end -if self:IsShip()then -self:T("Ship") -local ThreatLevels={ -"Unarmed ship", -"Light armed ships", -"Corvettes", -"", -"Frigates", -"", -"Cruiser", -"", -"Destroyer", -"", -"Aircraft Carrier" -} -if Attributes["Aircraft Carriers"]then ThreatLevel=10 -elseif Attributes["Destroyers"]then ThreatLevel=8 -elseif Attributes["Cruisers"]then ThreatLevel=6 -elseif Attributes["Frigates"]then ThreatLevel=4 -elseif Attributes["Corvettes"]then ThreatLevel=2 -elseif Attributes["Light armed ships"]then ThreatLevel=1 -end -ThreatText=ThreatLevels[ThreatLevel+1] -end -end -self:T2(ThreatLevel) -return ThreatLevel,ThreatText -end -function UNIT:IsInZone(Zone) -self:F2({self.UnitName,Zone}) -if self:IsAlive()then -local IsInZone=Zone:IsVec3InZone(self:GetVec3()) -self:T2({IsInZone}) -return IsInZone -end -return false -end -function UNIT:IsNotInZone(Zone) -self:F2({self.UnitName,Zone}) -if self:IsAlive()then -local IsInZone=not Zone:IsVec3InZone(self:GetVec3()) -self:T({IsInZone}) -return IsInZone -else -return false -end -end -function UNIT:OtherUnitInRadius(AwaitUnit,Radius) -self:F2({self.UnitName,AwaitUnit.UnitName,Radius}) -local DCSUnit=self:GetDCSObject() -if DCSUnit then -local UnitVec3=self:GetVec3() -local AwaitUnitVec3=AwaitUnit:GetVec3() -if(((UnitVec3.x-AwaitUnitVec3.x)^2+(UnitVec3.z-AwaitUnitVec3.z)^2)^0.5<=Radius)then -self:T3("true") -return true -else -self:T3("false") -return false -end -end -return nil -end -function UNIT:IsAir() -self:F2() -local DCSUnit=self:GetDCSObject() -if DCSUnit then -local UnitDescriptor=DCSUnit:getDesc() -self:T3({UnitDescriptor.category,Unit.Category.AIRPLANE,Unit.Category.HELICOPTER}) -local IsAirResult=(UnitDescriptor.category==Unit.Category.AIRPLANE)or(UnitDescriptor.category==Unit.Category.HELICOPTER) -self:T3(IsAirResult) -return IsAirResult -end -return nil -end -function UNIT:IsGround() -self:F2() -local DCSUnit=self:GetDCSObject() -if DCSUnit then -local UnitDescriptor=DCSUnit:getDesc() -self:T3({UnitDescriptor.category,Unit.Category.GROUND_UNIT}) -local IsGroundResult=(UnitDescriptor.category==Unit.Category.GROUND_UNIT) -self:T3(IsGroundResult) -return IsGroundResult -end -return nil -end -function UNIT:IsFriendly(FriendlyCoalition) -self:F2() -local DCSUnit=self:GetDCSObject() -if DCSUnit then -local UnitCoalition=DCSUnit:getCoalition() -self:T3({UnitCoalition,FriendlyCoalition}) -local IsFriendlyResult=(UnitCoalition==FriendlyCoalition) -self:E(IsFriendlyResult) -return IsFriendlyResult -end -return nil -end -function UNIT:IsShip() -self:F2() -local DCSUnit=self:GetDCSObject() -if DCSUnit then -local UnitDescriptor=DCSUnit:getDesc() -self:T3({UnitDescriptor.category,Unit.Category.SHIP}) -local IsShipResult=(UnitDescriptor.category==Unit.Category.SHIP) -self:T3(IsShipResult) -return IsShipResult -end -return nil -end -function UNIT:InAir() -self:F2(self.UnitName) -local DCSUnit=self:GetDCSObject() -if DCSUnit then -local UnitInAir=DCSUnit:inAir() -self:T3(UnitInAir) -return UnitInAir -end -return nil -end -do -function UNIT:HandleEvent(Event,EventFunction) -self:EventDispatcher():OnEventForUnit(self:GetName(),EventFunction,self,Event) -return self -end -function UNIT:UnHandleEvent(Event) -self:EventDispatcher():RemoveForUnit(self:GetName(),self,Event) -return self -end -function UNIT:ResetEvents() -self:EventDispatcher():Reset(self) -return self -end -end -do -function UNIT:IsDetected(TargetUnit) -local TargetIsDetected,TargetIsVisible,TargetLastTime,TargetKnowType,TargetKnowDistance,TargetLastPos,TargetLastVelocity=self:IsTargetDetected(TargetUnit:GetDCSObject()) -return TargetIsDetected -end -function UNIT:IsLOS(TargetUnit) -local IsLOS=self:GetPointVec3():IsLOS(TargetUnit:GetPointVec3()) -return IsLOS -end -end -CLIENT={ -ONBOARDSIDE={ -NONE=0, -LEFT=1, -RIGHT=2, -BACK=3, -FRONT=4 -}, -ClassName="CLIENT", -ClientName=nil, -ClientAlive=false, -ClientTransport=false, -ClientBriefingShown=false, -_Menus={}, -_Tasks={}, -Messages={ -} -} -function CLIENT:Find(DCSUnit,Error) -local ClientName=DCSUnit:getName() -local ClientFound=_DATABASE:FindClient(ClientName) -if ClientFound then -ClientFound:F(ClientName) -return ClientFound -end -if not Error then -error("CLIENT not found for: "..ClientName) -end -end -function CLIENT:FindByName(ClientName,ClientBriefing,Error) -local ClientFound=_DATABASE:FindClient(ClientName) -if ClientFound then -ClientFound:F({ClientName,ClientBriefing}) -ClientFound:AddBriefing(ClientBriefing) -ClientFound.MessageSwitch=true -return ClientFound -end -if not Error then -error("CLIENT not found for: "..ClientName) -end -end -function CLIENT:Register(ClientName) -local self=BASE:Inherit(self,UNIT:Register(ClientName)) -self:F(ClientName) -self.ClientName=ClientName -self.MessageSwitch=true -self.ClientAlive2=false -self.AliveCheckScheduler=SCHEDULER:New(self,self._AliveCheckScheduler,{"Client Alive "..ClientName},1,5) -self:E(self) -return self -end -function CLIENT:Transport() -self:F() -self.ClientTransport=true -return self -end -function CLIENT:AddBriefing(ClientBriefing) -self:F(ClientBriefing) -self.ClientBriefing=ClientBriefing -self.ClientBriefingShown=false -return self -end -function CLIENT:ShowBriefing() -self:F({self.ClientName,self.ClientBriefingShown}) -if not self.ClientBriefingShown then -self.ClientBriefingShown=true -local Briefing="" -if self.ClientBriefing then -Briefing=Briefing..self.ClientBriefing -end -Briefing=Briefing.." Press [LEFT ALT]+[B] to view the complete mission briefing." -self:Message(Briefing,60,"Briefing") -end -return self -end -function CLIENT:ShowMissionBriefing(MissionBriefing) -self:F({self.ClientName}) -if MissionBriefing then -self:Message(MissionBriefing,60,"Mission Briefing") -end -return self -end -function CLIENT:Reset(ClientName) -self:F() -self._Menus={} -end -function CLIENT:IsMultiSeated() -self:F(self.ClientName) -local ClientMultiSeatedTypes={ -["Mi-8MT"]="Mi-8MT", -["UH-1H"]="UH-1H", -["P-51B"]="P-51B" -} -if self:IsAlive()then -local ClientTypeName=self:GetClientGroupUnit():GetTypeName() -if ClientMultiSeatedTypes[ClientTypeName]then -return true -end -end -return false -end -function CLIENT:Alive(CallBackFunction,...) -self:F() -self.ClientCallBack=CallBackFunction -self.ClientParameters=arg -return self -end -function CLIENT:_AliveCheckScheduler(SchedulerName) -self:F3({SchedulerName,self.ClientName,self.ClientAlive2,self.ClientBriefingShown,self.ClientCallBack}) -if self:IsAlive()then -if self.ClientAlive2==false then -self:ShowBriefing() -if self.ClientCallBack then -self:T("Calling Callback function") -self.ClientCallBack(self,unpack(self.ClientParameters)) -end -self.ClientAlive2=true -end -else -if self.ClientAlive2==true then -self.ClientAlive2=false -end -end -return true -end -function CLIENT:GetDCSGroup() -self:F3() -local ClientUnit=Unit.getByName(self.ClientName) -local CoalitionsData={AlivePlayersRed=coalition.getPlayers(coalition.side.RED),AlivePlayersBlue=coalition.getPlayers(coalition.side.BLUE)} -for CoalitionId,CoalitionData in pairs(CoalitionsData)do -self:T3({"CoalitionData:",CoalitionData}) -for UnitId,UnitData in pairs(CoalitionData)do -self:T3({"UnitData:",UnitData}) -if UnitData and UnitData:isExist()then -if ClientUnit then -local ClientGroup=ClientUnit:getGroup() -if ClientGroup then -self:T3("ClientGroup = "..self.ClientName) -if ClientGroup:isExist()and UnitData:getGroup():isExist()then -if ClientGroup:getID()==UnitData:getGroup():getID()then -self:T3("Normal logic") -self:T3(self.ClientName.." : group found!") -self.ClientGroupID=ClientGroup:getID() -self.ClientGroupName=ClientGroup:getName() -return ClientGroup -end -else -self:T3("Bug 1.5 logic") -local ClientGroupTemplate=_DATABASE.Templates.Units[self.ClientName].GroupTemplate -self.ClientGroupID=ClientGroupTemplate.groupId -self.ClientGroupName=_DATABASE.Templates.Units[self.ClientName].GroupName -self:T3(self.ClientName.." : group found in bug 1.5 resolvement logic!") -return ClientGroup -end -end -else -end -end -end -end -if ClientUnit then -local ClientGroup=ClientUnit:getGroup() -if ClientGroup then -self:T3("ClientGroup = "..self.ClientName) -if ClientGroup:isExist()then -self:T3("Normal logic") -self:T3(self.ClientName.." : group found!") -return ClientGroup -end -end -end -self.ClientGroupID=nil -self.ClientGroupUnit=nil -return nil -end -function CLIENT:GetClientGroupID() -local ClientGroup=self:GetDCSGroup() -return self.ClientGroupID -end -function CLIENT:GetClientGroupName() -local ClientGroup=self:GetDCSGroup() -self:T(self.ClientGroupName) -return self.ClientGroupName -end -function CLIENT:GetClientGroupUnit() -self:F2() -local ClientDCSUnit=Unit.getByName(self.ClientName) -self:T(self.ClientDCSUnit) -if ClientDCSUnit and ClientDCSUnit:isExist()then -local ClientUnit=_DATABASE:FindUnit(self.ClientName) -self:T2(ClientUnit) -return ClientUnit -end -end -function CLIENT:GetClientGroupDCSUnit() -self:F2() -local ClientDCSUnit=Unit.getByName(self.ClientName) -if ClientDCSUnit and ClientDCSUnit:isExist()then -self:T2(ClientDCSUnit) -return ClientDCSUnit -end -end -function CLIENT:IsTransport() -self:F() -return self.ClientTransport -end -function CLIENT:ShowCargo() -self:F() -local CargoMsg="" -for CargoName,Cargo in pairs(CARGOS)do -if self==Cargo:IsLoadedInClient()then -CargoMsg=CargoMsg..Cargo.CargoName.." Type:"..Cargo.CargoType.." Weight: "..Cargo.CargoWeight.."\n" -end -end -if CargoMsg==""then -CargoMsg="empty" -end -self:Message(CargoMsg,15,"Co-Pilot: Cargo Status",30) -end -function CLIENT.SwitchMessages(PrmTable) -PrmTable[1].MessageSwitch=PrmTable[2] -end -function CLIENT:Message(Message,MessageDuration,MessageCategory,MessageInterval,MessageID) -self:F({Message,MessageDuration,MessageCategory,MessageInterval}) -if self.MessageSwitch==true then -if MessageCategory==nil then -MessageCategory="Messages" -end -if MessageID~=nil then -if self.Messages[MessageID]==nil then -self.Messages[MessageID]={} -self.Messages[MessageID].MessageId=MessageID -self.Messages[MessageID].MessageTime=timer.getTime() -self.Messages[MessageID].MessageDuration=MessageDuration -if MessageInterval==nil then -self.Messages[MessageID].MessageInterval=600 -else -self.Messages[MessageID].MessageInterval=MessageInterval -end -MESSAGE:New(Message,MessageDuration,MessageCategory):ToClient(self) -else -if self:GetClientGroupDCSUnit()and not self:GetClientGroupDCSUnit():inAir()then -if timer.getTime()-self.Messages[MessageID].MessageTime>=self.Messages[MessageID].MessageDuration+10 then -MESSAGE:New(Message,MessageDuration,MessageCategory):ToClient(self) -self.Messages[MessageID].MessageTime=timer.getTime() -end -else -if timer.getTime()-self.Messages[MessageID].MessageTime>=self.Messages[MessageID].MessageDuration+self.Messages[MessageID].MessageInterval then -MESSAGE:New(Message,MessageDuration,MessageCategory):ToClient(self) -self.Messages[MessageID].MessageTime=timer.getTime() -end -end -end -else -MESSAGE:New(Message,MessageDuration,MessageCategory):ToClient(self) -end -end -end -STATIC={ -ClassName="STATIC", -} -function STATIC:FindByName(StaticName,RaiseError) -local StaticFound=_DATABASE:FindStatic(StaticName) -self.StaticName=StaticName -if StaticFound then -StaticFound:F3({StaticName}) -return StaticFound -end -if RaiseError==nil or RaiseError==true then -error("STATIC not found for: "..StaticName) -end -return nil -end -function STATIC:Register(StaticName) -local self=BASE:Inherit(self,POSITIONABLE:New(StaticName)) -self.StaticName=StaticName -return self -end -function STATIC:GetDCSObject() -local DCSStatic=StaticObject.getByName(self.StaticName) -if DCSStatic then -return DCSStatic -end -return nil -end -function STATIC:GetThreatLevel() -return 1,"Static" -end -AIRBASE={ -ClassName="AIRBASE", -CategoryName={ -[Airbase.Category.AIRDROME]="Airdrome", -[Airbase.Category.HELIPAD]="Helipad", -[Airbase.Category.SHIP]="Ship", -}, -} -AIRBASE.Caucasus={ -["Gelendzhik"]="Gelendzhik", -["Krasnodar_Pashkovsky"]="Krasnodar-Pashkovsky", -["Sukhumi_Babushara"]="Sukhumi-Babushara", -["Gudauta"]="Gudauta", -["Batumi"]="Batumi", -["Senaki_Kolkhi"]="Senaki-Kolkhi", -["Kobuleti"]="Kobuleti", -["Kutaisi"]="Kutaisi", -["Tbilisi_Lochini"]="Tbilisi-Lochini", -["Soganlug"]="Soganlug", -["Vaziani"]="Vaziani", -["Anapa_Vityazevo"]="Anapa-Vityazevo", -["Krasnodar_Center"]="Krasnodar-Center", -["Novorossiysk"]="Novorossiysk", -["Krymsk"]="Krymsk", -["Maykop_Khanskaya"]="Maykop-Khanskaya", -["Sochi_Adler"]="Sochi-Adler", -["Mineralnye_Vody"]="Mineralnye Vody", -["Nalchik"]="Nalchik", -["Mozdok"]="Mozdok", -["Beslan"]="Beslan", -} -AIRBASE.Nevada={ -["Creech_AFB"]="Creech AFB", -["Groom_Lake_AFB"]="Groom Lake AFB", -["McCarran_International_Airport"]="McCarran International Airport", -["Nellis_AFB"]="Nellis AFB", -["Beatty_Airport"]="Beatty Airport", -["Boulder_City_Airport"]="Boulder City Airport", -["Echo_Bay"]="Echo Bay", -["Henderson_Executive_Airport"]="Henderson Executive Airport", -["Jean_Airport"]="Jean Airport", -["Laughlin_Airport"]="Laughlin Airport", -["Lincoln_County"]="Lincoln County", -["Mellan_Airstrip"]="Mellan Airstrip", -["Mesquite"]="Mesquite", -["Mina_Airport_3Q0"]="Mina Airport 3Q0", -["North_Las_Vegas"]="North Las Vegas", -["Pahute_Mesa_Airstrip"]="Pahute Mesa Airstrip", -["Tonopah_Airport"]="Tonopah Airport", -["Tonopah_Test_Range_Airfield"]="Tonopah Test Range Airfield", -} -AIRBASE.Normandy={ -["Saint_Pierre_du_Mont"]="Saint Pierre du Mont", -["Lignerolles"]="Lignerolles", -["Cretteville"]="Cretteville", -["Maupertus"]="Maupertus", -["Brucheville"]="Brucheville", -["Meautis"]="Meautis", -["Cricqueville_en_Bessin"]="Cricqueville-en-Bessin", -["Lessay"]="Lessay", -["Sainte_Laurent_sur_Mer"]="Sainte-Laurent-sur-Mer", -["Biniville"]="Biniville", -["Cardonville"]="Cardonville", -["Deux_Jumeaux"]="Deux Jumeaux", -["Chippelle"]="Chippelle", -["Beuzeville"]="Beuzeville", -["Azeville"]="Azeville", -["Picauville"]="Picauville", -["Le_Molay"]="Le Molay", -["Longues_sur_Mer"]="Longues-sur-Mer", -["Carpiquet"]="Carpiquet", -["Bazenville"]="Bazenville", -["Sainte_Croix_sur_Mer"]="Sainte-Croix-sur-Mer", -["Beny_sur_Mer"]="Beny-sur-Mer", -["Rucqueville"]="Rucqueville", -["Sommervieu"]="Sommervieu", -["Lantheuil"]="Lantheuil", -["Evreux"]="Evreux", -["Chailey"]="Chailey", -["Needs_Oar_Point"]="Needs Oar Point", -["Funtington"]="Funtington", -["Tangmere"]="Tangmere", -["Ford"]="Ford", -} -function AIRBASE:Register(AirbaseName) -local self=BASE:Inherit(self,POSITIONABLE:New(AirbaseName)) -self.AirbaseName=AirbaseName -self.AirbaseZone=ZONE_RADIUS:New(AirbaseName,self:GetVec2(),8000) -return self -end -function AIRBASE:Find(DCSAirbase) -local AirbaseName=DCSAirbase:getName() -local AirbaseFound=_DATABASE:FindAirbase(AirbaseName) -return AirbaseFound -end -function AIRBASE:FindByName(AirbaseName) -local AirbaseFound=_DATABASE:FindAirbase(AirbaseName) -return AirbaseFound -end -function AIRBASE:GetDCSObject() -local DCSAirbase=Airbase.getByName(self.AirbaseName) -if DCSAirbase then -return DCSAirbase -end -return nil -end -function AIRBASE:GetZone() -return self.AirbaseZone -end -SCENERY={ -ClassName="SCENERY", -} -function SCENERY:Register(SceneryName,SceneryObject) -local self=BASE:Inherit(self,POSITIONABLE:New(SceneryName)) -self.SceneryName=SceneryName -self.SceneryObject=SceneryObject -return self -end -function SCENERY:GetDCSObject() -return self.SceneryObject -end -function SCENERY:GetThreatLevel() -return 0,"Scenery" -end -SCORING={ -ClassName="SCORING", -ClassID=0, -Players={}, -} -local _SCORINGCoalition= -{ -[1]="Red", -[2]="Blue", -} -local _SCORINGCategory= -{ -[Unit.Category.AIRPLANE]="Plane", -[Unit.Category.HELICOPTER]="Helicopter", -[Unit.Category.GROUND_UNIT]="Vehicle", -[Unit.Category.SHIP]="Ship", -[Unit.Category.STRUCTURE]="Structure", -} -function SCORING:New(GameName) -local self=BASE:Inherit(self,BASE:New()) -if GameName then -self.GameName=GameName -else -error("A game name must be given to register the scoring results") -end -self.ScoringObjects={} -self.ScoringZones={} -self:SetMessagesToAll() -self:SetMessagesHit(true) -self:SetMessagesDestroy(true) -self:SetMessagesScore(true) -self:SetMessagesZone(true) -self:SetScaleDestroyScore(10) -self:SetScaleDestroyPenalty(30) -self:SetFratricide(self.ScaleDestroyPenalty*3) -self:SetCoalitionChangePenalty(self.ScaleDestroyPenalty) -self:SetDisplayMessagePrefix() -self:HandleEvent(EVENTS.Dead,self._EventOnDeadOrCrash) -self:HandleEvent(EVENTS.Crash,self._EventOnDeadOrCrash) -self:HandleEvent(EVENTS.Hit,self._EventOnHit) -self:HandleEvent(EVENTS.PlayerEnterUnit) -self:HandleEvent(EVENTS.PlayerLeaveUnit) -self:OpenCSV(GameName) -return self -end -function SCORING:SetDisplayMessagePrefix(DisplayMessagePrefix) -self.DisplayMessagePrefix=DisplayMessagePrefix or"" -return self -end -function SCORING:SetScaleDestroyScore(Scale) -self.ScaleDestroyScore=Scale -return self -end -function SCORING:SetScaleDestroyPenalty(Scale) -self.ScaleDestroyPenalty=Scale -return self -end -function SCORING:AddUnitScore(ScoreUnit,Score) -local UnitName=ScoreUnit:GetName() -self.ScoringObjects[UnitName]=Score -return self -end -function SCORING:RemoveUnitScore(ScoreUnit) -local UnitName=ScoreUnit:GetName() -self.ScoringObjects[UnitName]=nil -return self -end -function SCORING:AddStaticScore(ScoreStatic,Score) -local StaticName=ScoreStatic:GetName() -self.ScoringObjects[StaticName]=Score -return self -end -function SCORING:RemoveStaticScore(ScoreStatic) -local StaticName=ScoreStatic:GetName() -self.ScoringObjects[StaticName]=nil -return self -end -function SCORING:AddScoreGroup(ScoreGroup,Score) -local ScoreUnits=ScoreGroup:GetUnits() -for ScoreUnitID,ScoreUnit in pairs(ScoreUnits)do -local UnitName=ScoreUnit:GetName() -self.ScoringObjects[UnitName]=Score -end -return self -end -function SCORING:AddZoneScore(ScoreZone,Score) -local ZoneName=ScoreZone:GetName() -self.ScoringZones[ZoneName]={} -self.ScoringZones[ZoneName].ScoreZone=ScoreZone -self.ScoringZones[ZoneName].Score=Score -return self -end -function SCORING:RemoveZoneScore(ScoreZone) -local ZoneName=ScoreZone:GetName() -self.ScoringZones[ZoneName]=nil -return self -end -function SCORING:SetMessagesHit(OnOff) -self.MessagesHit=OnOff -return self -end -function SCORING:IfMessagesHit() -return self.MessagesHit -end -function SCORING:SetMessagesDestroy(OnOff) -self.MessagesDestroy=OnOff -return self -end -function SCORING:IfMessagesDestroy() -return self.MessagesDestroy -end -function SCORING:SetMessagesScore(OnOff) -self.MessagesScore=OnOff -return self -end -function SCORING:IfMessagesScore() -return self.MessagesScore -end -function SCORING:SetMessagesZone(OnOff) -self.MessagesZone=OnOff -return self -end -function SCORING:IfMessagesZone() -return self.MessagesZone -end -function SCORING:SetMessagesToAll() -self.MessagesAudience=1 -return self -end -function SCORING:IfMessagesToAll() -return self.MessagesAudience==1 -end -function SCORING:SetMessagesToCoalition() -self.MessagesAudience=2 -return self -end -function SCORING:IfMessagesToCoalition() -return self.MessagesAudience==2 -end -function SCORING:SetFratricide(Fratricide) -self.Fratricide=Fratricide -return self -end -function SCORING:SetCoalitionChangePenalty(CoalitionChangePenalty) -self.CoalitionChangePenalty=CoalitionChangePenalty -return self -end -function SCORING:_AddPlayerFromUnit(UnitData) -self:F(UnitData) -if UnitData:IsAlive()then -local UnitName=UnitData:GetName() -local PlayerName=UnitData:GetPlayerName() -local UnitDesc=UnitData:GetDesc() -local UnitCategory=UnitDesc.category -local UnitCoalition=UnitData:GetCoalition() -local UnitTypeName=UnitData:GetTypeName() -local UnitThreatLevel,UnitThreatType=UnitData:GetThreatLevel() -self:T({PlayerName,UnitName,UnitCategory,UnitCoalition,UnitTypeName}) -if self.Players[PlayerName]==nil then -self.Players[PlayerName]={} -self.Players[PlayerName].Hit={} -self.Players[PlayerName].Destroy={} -self.Players[PlayerName].Goals={} -self.Players[PlayerName].Mission={} -self.Players[PlayerName].HitPlayers={} -self.Players[PlayerName].Score=0 -self.Players[PlayerName].Penalty=0 -self.Players[PlayerName].PenaltyCoalition=0 -self.Players[PlayerName].PenaltyWarning=0 -end -if not self.Players[PlayerName].UnitCoalition then -self.Players[PlayerName].UnitCoalition=UnitCoalition -else -if self.Players[PlayerName].UnitCoalition~=UnitCoalition then -self.Players[PlayerName].Penalty=self.Players[PlayerName].Penalty+50 -self.Players[PlayerName].PenaltyCoalition=self.Players[PlayerName].PenaltyCoalition+1 -MESSAGE:NewType(self.DisplayMessagePrefix.."Player '"..PlayerName.."' changed coalition from ".._SCORINGCoalition[self.Players[PlayerName].UnitCoalition].." to ".._SCORINGCoalition[UnitCoalition].. -"(changed "..self.Players[PlayerName].PenaltyCoalition.." times the coalition). 50 Penalty points added.", -MESSAGE.Type.Information -):ToAll() -self:ScoreCSV(PlayerName,"","COALITION_PENALTY",1,-50,self.Players[PlayerName].UnitName,_SCORINGCoalition[self.Players[PlayerName].UnitCoalition],_SCORINGCategory[self.Players[PlayerName].UnitCategory],self.Players[PlayerName].UnitType, -UnitName,_SCORINGCoalition[UnitCoalition],_SCORINGCategory[UnitCategory],UnitData:GetTypeName()) -end -end -self.Players[PlayerName].UnitName=UnitName -self.Players[PlayerName].UnitCoalition=UnitCoalition -self.Players[PlayerName].UnitCategory=UnitCategory -self.Players[PlayerName].UnitType=UnitTypeName -self.Players[PlayerName].UNIT=UnitData -self.Players[PlayerName].ThreatLevel=UnitThreatLevel -self.Players[PlayerName].ThreatType=UnitThreatType -if self.Players[PlayerName].Penalty>self.Fratricide*0.50 then -if self.Players[PlayerName].PenaltyWarning<1 then -MESSAGE:NewType(self.DisplayMessagePrefix.."Player '"..PlayerName.."': WARNING! If you continue to commit FRATRICIDE and have a PENALTY score higher than "..self.Fratricide..", you will be COURT MARTIALED and DISMISSED from this mission! \nYour total penalty is: "..self.Players[PlayerName].Penalty, -MESSAGE.Type.Information -):ToAll() -self.Players[PlayerName].PenaltyWarning=self.Players[PlayerName].PenaltyWarning+1 -end -end -if self.Players[PlayerName].Penalty>self.Fratricide then -MESSAGE:NewType(self.DisplayMessagePrefix.."Player '"..PlayerName.."' committed FRATRICIDE, he will be COURT MARTIALED and is DISMISSED from this mission!", -MESSAGE.Type.Information -):ToAll() -UnitData:GetGroup():Destroy() -end -end -end -function SCORING:AddGoalScore(PlayerUnit,GoalTag,Text,Score) -local PlayerName=PlayerUnit:GetPlayerName() -self:E({PlayerUnit.UnitName,PlayerName,GoalTag,Text,Score}) -if PlayerName then -local PlayerData=self.Players[PlayerName] -PlayerData.Goals[GoalTag]=PlayerData.Goals[GoalTag]or{Score=0} -PlayerData.Goals[GoalTag].Score=PlayerData.Goals[GoalTag].Score+Score -PlayerData.Score=PlayerData.Score+Score -MESSAGE:NewType(self.DisplayMessagePrefix..Text,MESSAGE.Type.Information):ToAll() -self:ScoreCSV(PlayerName,"","GOAL_"..string.upper(GoalTag),1,Score,PlayerUnit:GetName()) -end -end -function SCORING:_AddMissionTaskScore(Mission,PlayerUnit,Text,Score) -local PlayerName=PlayerUnit:GetPlayerName() -local MissionName=Mission:GetName() -self:E({Mission:GetName(),PlayerUnit.UnitName,PlayerName,Text,Score}) -if PlayerName then -local PlayerData=self.Players[PlayerName] -if not PlayerData.Mission[MissionName]then -PlayerData.Mission[MissionName]={} -PlayerData.Mission[MissionName].ScoreTask=0 -PlayerData.Mission[MissionName].ScoreMission=0 -end -self:T(PlayerName) -self:T(PlayerData.Mission[MissionName]) -PlayerData.Score=self.Players[PlayerName].Score+Score -PlayerData.Mission[MissionName].ScoreTask=self.Players[PlayerName].Mission[MissionName].ScoreTask+Score -MESSAGE:NewType(self.DisplayMessagePrefix..MissionName.." : "..Text.." Score: "..Score,MESSAGE.Type.Information):ToAll() -self:ScoreCSV(PlayerName,"","TASK_"..MissionName:gsub(' ','_'),1,Score,PlayerUnit:GetName()) -end -end -function SCORING:_AddMissionScore(Mission,Text,Score) -local MissionName=Mission:GetName() -self:E({Mission,Text,Score}) -self:E(self.Players) -for PlayerName,PlayerData in pairs(self.Players)do -self:E(PlayerData) -if PlayerData.Mission[MissionName]then -PlayerData.Score=PlayerData.Score+Score -PlayerData.Mission[MissionName].ScoreMission=PlayerData.Mission[MissionName].ScoreMission+Score -MESSAGE:NewType(self.DisplayMessagePrefix.."Player '"..PlayerName.."' has "..Text.." in Mission '"..MissionName.."'. ".. -Score.." mission score!", -MESSAGE.Type.Information):ToAll() -self:ScoreCSV(PlayerName,"","MISSION_"..MissionName:gsub(' ','_'),1,Score) -end -end -end -function SCORING:OnEventPlayerEnterUnit(Event) -if Event.IniUnit then -self:_AddPlayerFromUnit(Event.IniUnit) -local Menu=MENU_GROUP:New(Event.IniGroup,'Scoring') -local ReportGroupSummary=MENU_GROUP_COMMAND:New(Event.IniGroup,'Summary report players in group',Menu,SCORING.ReportScoreGroupSummary,self,Event.IniGroup) -local ReportGroupDetailed=MENU_GROUP_COMMAND:New(Event.IniGroup,'Detailed report players in group',Menu,SCORING.ReportScoreGroupDetailed,self,Event.IniGroup) -local ReportToAllSummary=MENU_GROUP_COMMAND:New(Event.IniGroup,'Summary report all players',Menu,SCORING.ReportScoreAllSummary,self,Event.IniGroup) -self:SetState(Event.IniUnit,"ScoringMenu",Menu) -end -end -function SCORING:OnEventPlayerLeaveUnit(Event) -if Event.IniUnit then -local Menu=self:GetState(Event.IniUnit,"ScoringMenu") -if Menu then -end -end -end -function SCORING:_EventOnHit(Event) -self:F({Event}) -local InitUnit=nil -local InitUNIT=nil -local InitUnitName="" -local InitGroup=nil -local InitGroupName="" -local InitPlayerName=nil -local InitCoalition=nil -local InitCategory=nil -local InitType=nil -local InitUnitCoalition=nil -local InitUnitCategory=nil -local InitUnitType=nil -local TargetUnit=nil -local TargetUNIT=nil -local TargetUnitName="" -local TargetGroup=nil -local TargetGroupName="" -local TargetPlayerName=nil -local TargetCoalition=nil -local TargetCategory=nil -local TargetType=nil -local TargetUnitCoalition=nil -local TargetUnitCategory=nil -local TargetUnitType=nil -if Event.IniDCSUnit then -InitUnit=Event.IniDCSUnit -InitUNIT=Event.IniUnit -InitUnitName=Event.IniDCSUnitName -InitGroup=Event.IniDCSGroup -InitGroupName=Event.IniDCSGroupName -InitPlayerName=Event.IniPlayerName -InitCoalition=Event.IniCoalition -InitCategory=Event.IniCategory -InitType=Event.IniTypeName -InitUnitCoalition=_SCORINGCoalition[InitCoalition] -InitUnitCategory=_SCORINGCategory[InitCategory] -InitUnitType=InitType -self:T({InitUnitName,InitGroupName,InitPlayerName,InitCoalition,InitCategory,InitType,InitUnitCoalition,InitUnitCategory,InitUnitType}) -end -if Event.TgtDCSUnit then -TargetUnit=Event.TgtDCSUnit -TargetUNIT=Event.TgtUnit -TargetUnitName=Event.TgtDCSUnitName -TargetGroup=Event.TgtDCSGroup -TargetGroupName=Event.TgtDCSGroupName -TargetPlayerName=Event.TgtPlayerName -TargetCoalition=Event.TgtCoalition -TargetCategory=Event.TgtCategory -TargetType=Event.TgtTypeName -TargetUnitCoalition=_SCORINGCoalition[TargetCoalition] -TargetUnitCategory=_SCORINGCategory[TargetCategory] -TargetUnitType=TargetType -self:T({TargetUnitName,TargetGroupName,TargetPlayerName,TargetCoalition,TargetCategory,TargetType,TargetUnitCoalition,TargetUnitCategory,TargetUnitType}) -end -if InitPlayerName~=nil then -self:_AddPlayerFromUnit(InitUNIT) -if self.Players[InitPlayerName]then -if TargetPlayerName~=nil then -self:_AddPlayerFromUnit(TargetUNIT) -end -self:T("Hitting Something") -if TargetCategory then -local Player=self.Players[InitPlayerName] -Player.Hit[TargetCategory]=Player.Hit[TargetCategory]or{} -Player.Hit[TargetCategory][TargetUnitName]=Player.Hit[TargetCategory][TargetUnitName]or{} -local PlayerHit=Player.Hit[TargetCategory][TargetUnitName] -PlayerHit.Score=PlayerHit.Score or 0 -PlayerHit.Penalty=PlayerHit.Penalty or 0 -PlayerHit.ScoreHit=PlayerHit.ScoreHit or 0 -PlayerHit.PenaltyHit=PlayerHit.PenaltyHit or 0 -PlayerHit.TimeStamp=PlayerHit.TimeStamp or 0 -PlayerHit.UNIT=PlayerHit.UNIT or TargetUNIT -PlayerHit.ThreatLevel,PlayerHit.ThreatType=PlayerHit.UNIT:GetThreatLevel() -if timer.getTime()-PlayerHit.TimeStamp>1 then -PlayerHit.TimeStamp=timer.getTime() -if TargetPlayerName~=nil then -Player.HitPlayers[TargetPlayerName]=true -end -local Score=0 -if InitCoalition then -if InitCoalition==TargetCoalition then -Player.Penalty=Player.Penalty+10 -PlayerHit.Penalty=PlayerHit.Penalty+10 -PlayerHit.PenaltyHit=PlayerHit.PenaltyHit+1 -if TargetPlayerName~=nil then -MESSAGE -:NewType(self.DisplayMessagePrefix.."Player '"..InitPlayerName.."' hit friendly player '"..TargetPlayerName.."' ".. -TargetUnitCategory.." ( "..TargetType.." ) "..PlayerHit.PenaltyHit.." times. ".. -"Penalty: -"..PlayerHit.Penalty..". Score Total:"..Player.Score-Player.Penalty, -MESSAGE.Type.Update -) -:ToAllIf(self:IfMessagesHit()and self:IfMessagesToAll()) -:ToCoalitionIf(InitCoalition,self:IfMessagesHit()and self:IfMessagesToCoalition()) -else -MESSAGE -:NewType(self.DisplayMessagePrefix.."Player '"..InitPlayerName.."' hit friendly target ".. -TargetUnitCategory.." ( "..TargetType.." ) "..PlayerHit.PenaltyHit.." times. ".. -"Penalty: -"..PlayerHit.Penalty..". Score Total:"..Player.Score-Player.Penalty, -MESSAGE.Type.Update -) -:ToAllIf(self:IfMessagesHit()and self:IfMessagesToAll()) -:ToCoalitionIf(InitCoalition,self:IfMessagesHit()and self:IfMessagesToCoalition()) -end -self:ScoreCSV(InitPlayerName,TargetPlayerName,"HIT_PENALTY",1,-10,InitUnitName,InitUnitCoalition,InitUnitCategory,InitUnitType,TargetUnitName,TargetUnitCoalition,TargetUnitCategory,TargetUnitType) -else -Player.Score=Player.Score+1 -PlayerHit.Score=PlayerHit.Score+1 -PlayerHit.ScoreHit=PlayerHit.ScoreHit+1 -if TargetPlayerName~=nil then -MESSAGE -:NewType(self.DisplayMessagePrefix.."Player '"..InitPlayerName.."' hit enemy player '"..TargetPlayerName.."' ".. -TargetUnitCategory.." ( "..TargetType.." ) "..PlayerHit.ScoreHit.." times. ".. -"Score: "..PlayerHit.Score..". Score Total:"..Player.Score-Player.Penalty, -MESSAGE.Type.Update -) -:ToAllIf(self:IfMessagesHit()and self:IfMessagesToAll()) -:ToCoalitionIf(InitCoalition,self:IfMessagesHit()and self:IfMessagesToCoalition()) -else -MESSAGE -:NewType(self.DisplayMessagePrefix.."Player '"..InitPlayerName.."' hit enemy target ".. -TargetUnitCategory.." ( "..TargetType.." ) "..PlayerHit.ScoreHit.." times. ".. -"Score: "..PlayerHit.Score..". Score Total:"..Player.Score-Player.Penalty, -MESSAGE.Type.Update -) -:ToAllIf(self:IfMessagesHit()and self:IfMessagesToAll()) -:ToCoalitionIf(InitCoalition,self:IfMessagesHit()and self:IfMessagesToCoalition()) -end -self:ScoreCSV(InitPlayerName,TargetPlayerName,"HIT_SCORE",1,1,InitUnitName,InitUnitCoalition,InitUnitCategory,InitUnitType,TargetUnitName,TargetUnitCoalition,TargetUnitCategory,TargetUnitType) -end -else -MESSAGE -:NewType(self.DisplayMessagePrefix.."Player '"..InitPlayerName.."' hit scenery object.", -MESSAGE.Type.Update -) -:ToAllIf(self:IfMessagesHit()and self:IfMessagesToAll()) -:ToCoalitionIf(InitCoalition,self:IfMessagesHit()and self:IfMessagesToCoalition()) -self:ScoreCSV(InitPlayerName,"","HIT_SCORE",1,0,InitUnitName,InitUnitCoalition,InitUnitCategory,InitUnitType,TargetUnitName,"","Scenery",TargetUnitType) -end -end -end -end -elseif InitPlayerName==nil then -end -if Event.WeaponPlayerName~=nil then -self:_AddPlayerFromUnit(Event.WeaponUNIT) -if self.Players[Event.WeaponPlayerName]then -if TargetPlayerName~=nil then -self:_AddPlayerFromUnit(TargetUNIT) -end -self:T("Hitting Scenery") -if TargetCategory then -local Player=self.Players[Event.WeaponPlayerName] -Player.Hit[TargetCategory]=Player.Hit[TargetCategory]or{} -Player.Hit[TargetCategory][TargetUnitName]=Player.Hit[TargetCategory][TargetUnitName]or{} -local PlayerHit=Player.Hit[TargetCategory][TargetUnitName] -PlayerHit.Score=PlayerHit.Score or 0 -PlayerHit.Penalty=PlayerHit.Penalty or 0 -PlayerHit.ScoreHit=PlayerHit.ScoreHit or 0 -PlayerHit.PenaltyHit=PlayerHit.PenaltyHit or 0 -PlayerHit.TimeStamp=PlayerHit.TimeStamp or 0 -PlayerHit.UNIT=PlayerHit.UNIT or TargetUNIT -PlayerHit.ThreatLevel,PlayerHit.ThreatType=PlayerHit.UNIT:GetThreatLevel() -if timer.getTime()-PlayerHit.TimeStamp>1 then -PlayerHit.TimeStamp=timer.getTime() -local Score=0 -if InitCoalition then -if InitCoalition==TargetCoalition then -Player.Penalty=Player.Penalty+10 -PlayerHit.Penalty=PlayerHit.Penalty+10 -PlayerHit.PenaltyHit=PlayerHit.PenaltyHit+1 -MESSAGE -:NewType(self.DisplayMessagePrefix.."Player '"..Event.WeaponPlayerName.."' hit friendly target ".. -TargetUnitCategory.." ( "..TargetType.." ) ".. -"Penalty: -"..PlayerHit.Penalty.." = "..Player.Score-Player.Penalty, -MESSAGE.Type.Update -) -:ToAllIf(self:IfMessagesHit()and self:IfMessagesToAll()) -:ToCoalitionIf(Event.WeaponCoalition,self:IfMessagesHit()and self:IfMessagesToCoalition()) -self:ScoreCSV(Event.WeaponPlayerName,TargetPlayerName,"HIT_PENALTY",1,-10,Event.WeaponName,Event.WeaponCoalition,Event.WeaponCategory,Event.WeaponTypeName,TargetUnitName,TargetUnitCoalition,TargetUnitCategory,TargetUnitType) -else -Player.Score=Player.Score+1 -PlayerHit.Score=PlayerHit.Score+1 -PlayerHit.ScoreHit=PlayerHit.ScoreHit+1 -MESSAGE -:NewType(self.DisplayMessagePrefix.."Player '"..Event.WeaponPlayerName.."' hit enemy target ".. -TargetUnitCategory.." ( "..TargetType.." ) ".. -"Score: +"..PlayerHit.Score.." = "..Player.Score-Player.Penalty, -MESSAGE.Type.Update -) -:ToAllIf(self:IfMessagesHit()and self:IfMessagesToAll()) -:ToCoalitionIf(Event.WeaponCoalition,self:IfMessagesHit()and self:IfMessagesToCoalition()) -self:ScoreCSV(Event.WeaponPlayerName,TargetPlayerName,"HIT_SCORE",1,1,Event.WeaponName,Event.WeaponCoalition,Event.WeaponCategory,Event.WeaponTypeName,TargetUnitName,TargetUnitCoalition,TargetUnitCategory,TargetUnitType) -end -else -MESSAGE -:NewType(self.DisplayMessagePrefix.."Player '"..Event.WeaponPlayerName.."' hit scenery object.", -MESSAGE.Type.Update -) -:ToAllIf(self:IfMessagesHit()and self:IfMessagesToAll()) -:ToCoalitionIf(InitCoalition,self:IfMessagesHit()and self:IfMessagesToCoalition()) -self:ScoreCSV(Event.WeaponPlayerName,"","HIT_SCORE",1,0,Event.WeaponName,Event.WeaponCoalition,Event.WeaponCategory,Event.WeaponTypeName,TargetUnitName,"","Scenery",TargetUnitType) -end -end -end -end -end -end -function SCORING:_EventOnDeadOrCrash(Event) -self:F({Event}) -local TargetUnit=nil -local TargetGroup=nil -local TargetUnitName="" -local TargetGroupName="" -local TargetPlayerName="" -local TargetCoalition=nil -local TargetCategory=nil -local TargetType=nil -local TargetUnitCoalition=nil -local TargetUnitCategory=nil -local TargetUnitType=nil -if Event.IniDCSUnit then -TargetUnit=Event.IniUnit -TargetUnitName=Event.IniDCSUnitName -TargetGroup=Event.IniDCSGroup -TargetGroupName=Event.IniDCSGroupName -TargetPlayerName=Event.IniPlayerName -TargetCoalition=Event.IniCoalition -TargetCategory=Event.IniCategory -TargetType=Event.IniTypeName -TargetUnitCoalition=_SCORINGCoalition[TargetCoalition] -TargetUnitCategory=_SCORINGCategory[TargetCategory] -TargetUnitType=TargetType -self:T({TargetUnitName,TargetGroupName,TargetPlayerName,TargetCoalition,TargetCategory,TargetType}) -end -for PlayerName,Player in pairs(self.Players)do -if Player then -self:T("Something got destroyed") -local InitUnitName=Player.UnitName -local InitUnitType=Player.UnitType -local InitCoalition=Player.UnitCoalition -local InitCategory=Player.UnitCategory -local InitUnitCoalition=_SCORINGCoalition[InitCoalition] -local InitUnitCategory=_SCORINGCategory[InitCategory] -self:T({InitUnitName,InitUnitType,InitUnitCoalition,InitCoalition,InitUnitCategory,InitCategory}) -local Destroyed=false -if Player and Player.Hit and Player.Hit[TargetCategory]and Player.Hit[TargetCategory][TargetUnitName]and Player.Hit[TargetCategory][TargetUnitName].TimeStamp~=0 then -local TargetThreatLevel=Player.Hit[TargetCategory][TargetUnitName].ThreatLevel -local TargetThreatType=Player.Hit[TargetCategory][TargetUnitName].ThreatType -Player.Destroy[TargetCategory]=Player.Destroy[TargetCategory]or{} -Player.Destroy[TargetCategory][TargetType]=Player.Destroy[TargetCategory][TargetType]or{} -local TargetDestroy=Player.Destroy[TargetCategory][TargetType] -TargetDestroy.Score=TargetDestroy.Score or 0 -TargetDestroy.ScoreDestroy=TargetDestroy.ScoreDestroy or 0 -TargetDestroy.Penalty=TargetDestroy.Penalty or 0 -TargetDestroy.PenaltyDestroy=TargetDestroy.PenaltyDestroy or 0 -if TargetCoalition then -if InitCoalition==TargetCoalition then -local ThreatLevelTarget=TargetThreatLevel -local ThreatTypeTarget=TargetThreatType -local ThreatLevelPlayer=Player.ThreatLevel/10+1 -local ThreatPenalty=math.ceil((ThreatLevelTarget/ThreatLevelPlayer)*self.ScaleDestroyPenalty/10) -self:E({ThreatLevel=ThreatPenalty,ThreatLevelTarget=ThreatLevelTarget,ThreatTypeTarget=ThreatTypeTarget,ThreatLevelPlayer=ThreatLevelPlayer}) -Player.Penalty=Player.Penalty+ThreatPenalty -TargetDestroy.Penalty=TargetDestroy.Penalty+ThreatPenalty -TargetDestroy.PenaltyDestroy=TargetDestroy.PenaltyDestroy+1 -if Player.HitPlayers[TargetPlayerName]then -MESSAGE -:NewType(self.DisplayMessagePrefix.."Player '"..PlayerName.."' destroyed friendly player '"..TargetPlayerName.."' ".. -TargetUnitCategory.." ( "..ThreatTypeTarget.." ) ".. -"Penalty: -"..TargetDestroy.Penalty.." = "..Player.Score-Player.Penalty, -MESSAGE.Type.Information -) -:ToAllIf(self:IfMessagesDestroy()and self:IfMessagesToAll()) -:ToCoalitionIf(InitCoalition,self:IfMessagesDestroy()and self:IfMessagesToCoalition()) -else -MESSAGE -:NewType(self.DisplayMessagePrefix.."Player '"..PlayerName.."' destroyed friendly target ".. -TargetUnitCategory.." ( "..ThreatTypeTarget.." ) ".. -"Penalty: -"..TargetDestroy.Penalty.." = "..Player.Score-Player.Penalty, -MESSAGE.Type.Information -) -:ToAllIf(self:IfMessagesDestroy()and self:IfMessagesToAll()) -:ToCoalitionIf(InitCoalition,self:IfMessagesDestroy()and self:IfMessagesToCoalition()) -end -Destroyed=true -self:ScoreCSV(PlayerName,TargetPlayerName,"DESTROY_PENALTY",1,ThreatPenalty,InitUnitName,InitUnitCoalition,InitUnitCategory,InitUnitType,TargetUnitName,TargetUnitCoalition,TargetUnitCategory,TargetUnitType) -else -local ThreatLevelTarget=TargetThreatLevel -local ThreatTypeTarget=TargetThreatType -local ThreatLevelPlayer=Player.ThreatLevel/10+1 -local ThreatScore=math.ceil((ThreatLevelTarget/ThreatLevelPlayer)*self.ScaleDestroyScore/10) -self:E({ThreatLevel=ThreatScore,ThreatLevelTarget=ThreatLevelTarget,ThreatTypeTarget=ThreatTypeTarget,ThreatLevelPlayer=ThreatLevelPlayer}) -Player.Score=Player.Score+ThreatScore -TargetDestroy.Score=TargetDestroy.Score+ThreatScore -TargetDestroy.ScoreDestroy=TargetDestroy.ScoreDestroy+1 -if Player.HitPlayers[TargetPlayerName]then -MESSAGE -:NewType(self.DisplayMessagePrefix.."Player '"..PlayerName.."' destroyed enemy player '"..TargetPlayerName.."' ".. -TargetUnitCategory.." ( "..ThreatTypeTarget.." ) ".. -"Score: +"..TargetDestroy.Score.." = "..Player.Score-Player.Penalty, -MESSAGE.Type.Information -) -:ToAllIf(self:IfMessagesDestroy()and self:IfMessagesToAll()) -:ToCoalitionIf(InitCoalition,self:IfMessagesDestroy()and self:IfMessagesToCoalition()) -else -MESSAGE -:NewType(self.DisplayMessagePrefix.."Player '"..PlayerName.."' destroyed enemy ".. -TargetUnitCategory.." ( "..ThreatTypeTarget.." ) ".. -"Score: +"..TargetDestroy.Score.." = "..Player.Score-Player.Penalty, -MESSAGE.Type.Information -) -:ToAllIf(self:IfMessagesDestroy()and self:IfMessagesToAll()) -:ToCoalitionIf(InitCoalition,self:IfMessagesDestroy()and self:IfMessagesToCoalition()) -end -Destroyed=true -self:ScoreCSV(PlayerName,TargetPlayerName,"DESTROY_SCORE",1,ThreatScore,InitUnitName,InitUnitCoalition,InitUnitCategory,InitUnitType,TargetUnitName,TargetUnitCoalition,TargetUnitCategory,TargetUnitType) -local UnitName=TargetUnit:GetName() -local Score=self.ScoringObjects[UnitName] -if Score then -Player.Score=Player.Score+Score -TargetDestroy.Score=TargetDestroy.Score+Score -MESSAGE -:NewType(self.DisplayMessagePrefix.."Special target '"..TargetUnitCategory.." ( "..ThreatTypeTarget.." ) ".." destroyed! ".. -"Player '"..PlayerName.."' receives an extra "..Score.." points! Total: "..Player.Score-Player.Penalty, -MESSAGE.Type.Information -) -:ToAllIf(self:IfMessagesScore()and self:IfMessagesToAll()) -:ToCoalitionIf(InitCoalition,self:IfMessagesScore()and self:IfMessagesToCoalition()) -self:ScoreCSV(PlayerName,TargetPlayerName,"DESTROY_SCORE",1,Score,InitUnitName,InitUnitCoalition,InitUnitCategory,InitUnitType,TargetUnitName,TargetUnitCoalition,TargetUnitCategory,TargetUnitType) -Destroyed=true -end -for ZoneName,ScoreZoneData in pairs(self.ScoringZones)do -self:E({ScoringZone=ScoreZoneData}) -local ScoreZone=ScoreZoneData.ScoreZone -local Score=ScoreZoneData.Score -if ScoreZone:IsVec2InZone(TargetUnit:GetVec2())then -Player.Score=Player.Score+Score -TargetDestroy.Score=TargetDestroy.Score+Score -MESSAGE -:NewType(self.DisplayMessagePrefix.."Target destroyed in zone '"..ScoreZone:GetName().."'.".. -"Player '"..PlayerName.."' receives an extra "..Score.." points! ".. -"Total: "..Player.Score-Player.Penalty, -MESSAGE.Type.Information) -:ToAllIf(self:IfMessagesZone()and self:IfMessagesToAll()) -:ToCoalitionIf(InitCoalition,self:IfMessagesZone()and self:IfMessagesToCoalition()) -self:ScoreCSV(PlayerName,TargetPlayerName,"DESTROY_SCORE",1,Score,InitUnitName,InitUnitCoalition,InitUnitCategory,InitUnitType,TargetUnitName,TargetUnitCoalition,TargetUnitCategory,TargetUnitType) -Destroyed=true -end -end -end -else -for ZoneName,ScoreZoneData in pairs(self.ScoringZones)do -self:E({ScoringZone=ScoreZoneData}) -local ScoreZone=ScoreZoneData.ScoreZone -local Score=ScoreZoneData.Score -if ScoreZone:IsVec2InZone(TargetUnit:GetVec2())then -Player.Score=Player.Score+Score -TargetDestroy.Score=TargetDestroy.Score+Score -MESSAGE -:NewType(self.DisplayMessagePrefix.."Scenery destroyed in zone '"..ScoreZone:GetName().."'.".. -"Player '"..PlayerName.."' receives an extra "..Score.." points! ".. -"Total: "..Player.Score-Player.Penalty, -MESSAGE.Type.Information -) -:ToAllIf(self:IfMessagesZone()and self:IfMessagesToAll()) -:ToCoalitionIf(InitCoalition,self:IfMessagesZone()and self:IfMessagesToCoalition()) -Destroyed=true -self:ScoreCSV(PlayerName,"","DESTROY_SCORE",1,Score,InitUnitName,InitUnitCoalition,InitUnitCategory,InitUnitType,TargetUnitName,"","Scenery",TargetUnitType) -end -end -end -if Destroyed then -Player.Hit[TargetCategory][TargetUnitName].TimeStamp=0 -end -end -end -end -end -function SCORING:ReportDetailedPlayerHits(PlayerName) -local ScoreMessage="" -local PlayerScore=0 -local PlayerPenalty=0 -local PlayerData=self.Players[PlayerName] -if PlayerData then -self:T("Score Player: "..PlayerName) -local InitUnitCoalition=_SCORINGCoalition[PlayerData.UnitCoalition] -local InitUnitCategory=_SCORINGCategory[PlayerData.UnitCategory] -local InitUnitType=PlayerData.UnitType -local InitUnitName=PlayerData.UnitName -local ScoreMessageHits="" -for CategoryID,CategoryName in pairs(_SCORINGCategory)do -self:T(CategoryName) -if PlayerData.Hit[CategoryID]then -self:T("Hit scores exist for player "..PlayerName) -local Score=0 -local ScoreHit=0 -local Penalty=0 -local PenaltyHit=0 -for UnitName,UnitData in pairs(PlayerData.Hit[CategoryID])do -Score=Score+UnitData.Score -ScoreHit=ScoreHit+UnitData.ScoreHit -Penalty=Penalty+UnitData.Penalty -PenaltyHit=UnitData.PenaltyHit -end -local ScoreMessageHit=string.format("%s:%d ",CategoryName,Score-Penalty) -self:T(ScoreMessageHit) -ScoreMessageHits=ScoreMessageHits..ScoreMessageHit -PlayerScore=PlayerScore+Score -PlayerPenalty=PlayerPenalty+Penalty -else -end -end -if ScoreMessageHits~=""then -ScoreMessage="Hits: "..ScoreMessageHits -end -end -return ScoreMessage,PlayerScore,PlayerPenalty -end -function SCORING:ReportDetailedPlayerDestroys(PlayerName) -local ScoreMessage="" -local PlayerScore=0 -local PlayerPenalty=0 -local PlayerData=self.Players[PlayerName] -if PlayerData then -self:T("Score Player: "..PlayerName) -local InitUnitCoalition=_SCORINGCoalition[PlayerData.UnitCoalition] -local InitUnitCategory=_SCORINGCategory[PlayerData.UnitCategory] -local InitUnitType=PlayerData.UnitType -local InitUnitName=PlayerData.UnitName -local ScoreMessageDestroys="" -for CategoryID,CategoryName in pairs(_SCORINGCategory)do -if PlayerData.Destroy[CategoryID]then -self:T("Destroy scores exist for player "..PlayerName) -local Score=0 -local ScoreDestroy=0 -local Penalty=0 -local PenaltyDestroy=0 -for UnitName,UnitData in pairs(PlayerData.Destroy[CategoryID])do -self:E({UnitData=UnitData}) -if UnitData~={}then -Score=Score+UnitData.Score -ScoreDestroy=ScoreDestroy+UnitData.ScoreDestroy -Penalty=Penalty+UnitData.Penalty -PenaltyDestroy=PenaltyDestroy+UnitData.PenaltyDestroy -end -end -local ScoreMessageDestroy=string.format(" %s:%d ",CategoryName,Score-Penalty) -self:T(ScoreMessageDestroy) -ScoreMessageDestroys=ScoreMessageDestroys..ScoreMessageDestroy -PlayerScore=PlayerScore+Score -PlayerPenalty=PlayerPenalty+Penalty -else -end -end -if ScoreMessageDestroys~=""then -ScoreMessage="Destroys: "..ScoreMessageDestroys -end -end -return ScoreMessage,PlayerScore,PlayerPenalty -end -function SCORING:ReportDetailedPlayerCoalitionChanges(PlayerName) -local ScoreMessage="" -local PlayerScore=0 -local PlayerPenalty=0 -local PlayerData=self.Players[PlayerName] -if PlayerData then -self:T("Score Player: "..PlayerName) -local InitUnitCoalition=_SCORINGCoalition[PlayerData.UnitCoalition] -local InitUnitCategory=_SCORINGCategory[PlayerData.UnitCategory] -local InitUnitType=PlayerData.UnitType -local InitUnitName=PlayerData.UnitName -local ScoreMessageCoalitionChangePenalties="" -if PlayerData.PenaltyCoalition~=0 then -ScoreMessageCoalitionChangePenalties=ScoreMessageCoalitionChangePenalties..string.format(" -%d (%d changed)",PlayerData.Penalty,PlayerData.PenaltyCoalition) -PlayerPenalty=PlayerPenalty+PlayerData.Penalty -end -if ScoreMessageCoalitionChangePenalties~=""then -ScoreMessage=ScoreMessage.."Coalition Penalties: "..ScoreMessageCoalitionChangePenalties -end -end -return ScoreMessage,PlayerScore,PlayerPenalty -end -function SCORING:ReportDetailedPlayerGoals(PlayerName) -local ScoreMessage="" -local PlayerScore=0 -local PlayerPenalty=0 -local PlayerData=self.Players[PlayerName] -if PlayerData then -self:T("Score Player: "..PlayerName) -local InitUnitCoalition=_SCORINGCoalition[PlayerData.UnitCoalition] -local InitUnitCategory=_SCORINGCategory[PlayerData.UnitCategory] -local InitUnitType=PlayerData.UnitType -local InitUnitName=PlayerData.UnitName -local ScoreMessageGoal="" -local ScoreGoal=0 -local ScoreTask=0 -for GoalName,GoalData in pairs(PlayerData.Goals)do -ScoreGoal=ScoreGoal+GoalData.Score -ScoreMessageGoal=ScoreMessageGoal.."'"..GoalName.."':"..GoalData.Score.."; " -end -PlayerScore=PlayerScore+ScoreGoal -if ScoreMessageGoal~=""then -ScoreMessage="Goals: "..ScoreMessageGoal -end -end -return ScoreMessage,PlayerScore,PlayerPenalty -end -function SCORING:ReportDetailedPlayerMissions(PlayerName) -local ScoreMessage="" -local PlayerScore=0 -local PlayerPenalty=0 -local PlayerData=self.Players[PlayerName] -if PlayerData then -self:T("Score Player: "..PlayerName) -local InitUnitCoalition=_SCORINGCoalition[PlayerData.UnitCoalition] -local InitUnitCategory=_SCORINGCategory[PlayerData.UnitCategory] -local InitUnitType=PlayerData.UnitType -local InitUnitName=PlayerData.UnitName -local ScoreMessageMission="" -local ScoreMission=0 -local ScoreTask=0 -for MissionName,MissionData in pairs(PlayerData.Mission)do -ScoreMission=ScoreMission+MissionData.ScoreMission -ScoreTask=ScoreTask+MissionData.ScoreTask -ScoreMessageMission=ScoreMessageMission.."'"..MissionName.."'; " -end -PlayerScore=PlayerScore+ScoreMission+ScoreTask -if ScoreMessageMission~=""then -ScoreMessage="Tasks: "..ScoreTask.." Mission: "..ScoreMission.." ( "..ScoreMessageMission..")" -end -end -return ScoreMessage,PlayerScore,PlayerPenalty -end -function SCORING:ReportScoreGroupSummary(PlayerGroup) -local PlayerMessage="" -self:T("Report Score Group Summary") -local PlayerUnits=PlayerGroup:GetUnits() -for UnitID,PlayerUnit in pairs(PlayerUnits)do -local PlayerUnit=PlayerUnit -local PlayerName=PlayerUnit:GetPlayerName() -if PlayerName then -local ReportHits,ScoreHits,PenaltyHits=self:ReportDetailedPlayerHits(PlayerName) -ReportHits=ReportHits~=""and"\n- "..ReportHits or ReportHits -self:E({ReportHits,ScoreHits,PenaltyHits}) -local ReportDestroys,ScoreDestroys,PenaltyDestroys=self:ReportDetailedPlayerDestroys(PlayerName) -ReportDestroys=ReportDestroys~=""and"\n- "..ReportDestroys or ReportDestroys -self:E({ReportDestroys,ScoreDestroys,PenaltyDestroys}) -local ReportCoalitionChanges,ScoreCoalitionChanges,PenaltyCoalitionChanges=self:ReportDetailedPlayerCoalitionChanges(PlayerName) -ReportCoalitionChanges=ReportCoalitionChanges~=""and"\n- "..ReportCoalitionChanges or ReportCoalitionChanges -self:E({ReportCoalitionChanges,ScoreCoalitionChanges,PenaltyCoalitionChanges}) -local ReportGoals,ScoreGoals,PenaltyGoals=self:ReportDetailedPlayerGoals(PlayerName) -ReportGoals=ReportGoals~=""and"\n- "..ReportGoals or ReportGoals -self:E({ReportGoals,ScoreGoals,PenaltyGoals}) -local ReportMissions,ScoreMissions,PenaltyMissions=self:ReportDetailedPlayerMissions(PlayerName) -ReportMissions=ReportMissions~=""and"\n- "..ReportMissions or ReportMissions -self:E({ReportMissions,ScoreMissions,PenaltyMissions}) -local PlayerScore=ScoreHits+ScoreDestroys+ScoreCoalitionChanges+ScoreGoals+ScoreMissions -local PlayerPenalty=PenaltyHits+PenaltyDestroys+PenaltyCoalitionChanges+ScoreGoals+PenaltyMissions -PlayerMessage= -string.format("Player '%s' Score = %d ( %d Score, -%d Penalties )", -PlayerName, -PlayerScore-PlayerPenalty, -PlayerScore, -PlayerPenalty -) -MESSAGE:NewType(PlayerMessage,MESSAGE.Type.Detailed):ToGroup(PlayerGroup) -end -end -end -function SCORING:ReportScoreGroupDetailed(PlayerGroup) -local PlayerMessage="" -self:T("Report Score Group Detailed") -local PlayerUnits=PlayerGroup:GetUnits() -for UnitID,PlayerUnit in pairs(PlayerUnits)do -local PlayerUnit=PlayerUnit -local PlayerName=PlayerUnit:GetPlayerName() -if PlayerName then -local ReportHits,ScoreHits,PenaltyHits=self:ReportDetailedPlayerHits(PlayerName) -ReportHits=ReportHits~=""and"\n- "..ReportHits or ReportHits -self:E({ReportHits,ScoreHits,PenaltyHits}) -local ReportDestroys,ScoreDestroys,PenaltyDestroys=self:ReportDetailedPlayerDestroys(PlayerName) -ReportDestroys=ReportDestroys~=""and"\n- "..ReportDestroys or ReportDestroys -self:E({ReportDestroys,ScoreDestroys,PenaltyDestroys}) -local ReportCoalitionChanges,ScoreCoalitionChanges,PenaltyCoalitionChanges=self:ReportDetailedPlayerCoalitionChanges(PlayerName) -ReportCoalitionChanges=ReportCoalitionChanges~=""and"\n- "..ReportCoalitionChanges or ReportCoalitionChanges -self:E({ReportCoalitionChanges,ScoreCoalitionChanges,PenaltyCoalitionChanges}) -local ReportGoals,ScoreGoals,PenaltyGoals=self:ReportDetailedPlayerGoals(PlayerName) -ReportGoals=ReportGoals~=""and"\n- "..ReportGoals or ReportGoals -self:E({ReportGoals,ScoreGoals,PenaltyGoals}) -local ReportMissions,ScoreMissions,PenaltyMissions=self:ReportDetailedPlayerMissions(PlayerName) -ReportMissions=ReportMissions~=""and"\n- "..ReportMissions or ReportMissions -self:E({ReportMissions,ScoreMissions,PenaltyMissions}) -local PlayerScore=ScoreHits+ScoreDestroys+ScoreCoalitionChanges+ScoreGoals+ScoreMissions -local PlayerPenalty=PenaltyHits+PenaltyDestroys+PenaltyCoalitionChanges+ScoreGoals+PenaltyMissions -PlayerMessage= -string.format("Player '%s' Score = %d ( %d Score, -%d Penalties )%s%s%s%s%s", -PlayerName, -PlayerScore-PlayerPenalty, -PlayerScore, -PlayerPenalty, -ReportHits, -ReportDestroys, -ReportCoalitionChanges, -ReportGoals, -ReportMissions -) -MESSAGE:NewType(PlayerMessage,MESSAGE.Type.Detailed):ToGroup(PlayerGroup) -end -end -end -function SCORING:ReportScoreAllSummary(PlayerGroup) -local PlayerMessage="" -self:T("Report Score All Players") -for PlayerName,PlayerData in pairs(self.Players)do -if PlayerName then -local ReportHits,ScoreHits,PenaltyHits=self:ReportDetailedPlayerHits(PlayerName) -ReportHits=ReportHits~=""and"\n- "..ReportHits or ReportHits -self:E({ReportHits,ScoreHits,PenaltyHits}) -local ReportDestroys,ScoreDestroys,PenaltyDestroys=self:ReportDetailedPlayerDestroys(PlayerName) -ReportDestroys=ReportDestroys~=""and"\n- "..ReportDestroys or ReportDestroys -self:E({ReportDestroys,ScoreDestroys,PenaltyDestroys}) -local ReportCoalitionChanges,ScoreCoalitionChanges,PenaltyCoalitionChanges=self:ReportDetailedPlayerCoalitionChanges(PlayerName) -ReportCoalitionChanges=ReportCoalitionChanges~=""and"\n- "..ReportCoalitionChanges or ReportCoalitionChanges -self:E({ReportCoalitionChanges,ScoreCoalitionChanges,PenaltyCoalitionChanges}) -local ReportGoals,ScoreGoals,PenaltyGoals=self:ReportDetailedPlayerGoals(PlayerName) -ReportGoals=ReportGoals~=""and"\n- "..ReportGoals or ReportGoals -self:E({ReportGoals,ScoreGoals,PenaltyGoals}) -local ReportMissions,ScoreMissions,PenaltyMissions=self:ReportDetailedPlayerMissions(PlayerName) -ReportMissions=ReportMissions~=""and"\n- "..ReportMissions or ReportMissions -self:E({ReportMissions,ScoreMissions,PenaltyMissions}) -local PlayerScore=ScoreHits+ScoreDestroys+ScoreCoalitionChanges+ScoreGoals+ScoreMissions -local PlayerPenalty=PenaltyHits+PenaltyDestroys+PenaltyCoalitionChanges+ScoreGoals+PenaltyMissions -PlayerMessage= -string.format("Player '%s' Score = %d ( %d Score, -%d Penalties )", -PlayerName, -PlayerScore-PlayerPenalty, -PlayerScore, -PlayerPenalty -) -MESSAGE:NewType(PlayerMessage,MESSAGE.Type.Overview):ToGroup(PlayerGroup) -end -end -end -function SCORING:SecondsToClock(sSeconds) -local nSeconds=sSeconds -if nSeconds==0 then -return"00:00:00"; -else -nHours=string.format("%02.f",math.floor(nSeconds/3600)); -nMins=string.format("%02.f",math.floor(nSeconds/60-(nHours*60))); -nSecs=string.format("%02.f",math.floor(nSeconds-nHours*3600-nMins*60)); -return nHours..":"..nMins..":"..nSecs -end -end -function SCORING:OpenCSV(ScoringCSV) -self:F(ScoringCSV) -if lfs and io and os then -if ScoringCSV then -self.ScoringCSV=ScoringCSV -local fdir=lfs.writedir()..[[Logs\]]..self.ScoringCSV.." "..os.date("%Y-%m-%d %H-%M-%S")..".csv" -self.CSVFile,self.err=io.open(fdir,"w+") -if not self.CSVFile then -error("Error: Cannot open CSV file in "..lfs.writedir()) -end -self.CSVFile:write('"GameName","RunTime","Time","PlayerName","TargetPlayerName","ScoreType","PlayerUnitCoaltion","PlayerUnitCategory","PlayerUnitType","PlayerUnitName","TargetUnitCoalition","TargetUnitCategory","TargetUnitType","TargetUnitName","Times","Score"\n') -self.RunTime=os.date("%y-%m-%d_%H-%M-%S") -else -error("A string containing the CSV file name must be given.") -end -else -self:E("The MissionScripting.lua file has not been changed to allow lfs, io and os modules to be used...") -end -return self -end -function SCORING:ScoreCSV(PlayerName,TargetPlayerName,ScoreType,ScoreTimes,ScoreAmount,PlayerUnitName,PlayerUnitCoalition,PlayerUnitCategory,PlayerUnitType,TargetUnitName,TargetUnitCoalition,TargetUnitCategory,TargetUnitType) -local ScoreTime=self:SecondsToClock(timer.getTime()) -PlayerName=PlayerName:gsub('"','_') -TargetPlayerName=TargetPlayerName or"" -TargetPlayerName=TargetPlayerName:gsub('"','_') -if PlayerUnitName and PlayerUnitName~=''then -local PlayerUnit=Unit.getByName(PlayerUnitName) -if PlayerUnit then -if not PlayerUnitCategory then -PlayerUnitCategory=_SCORINGCategory[PlayerUnit:getDesc().category] -end -if not PlayerUnitCoalition then -PlayerUnitCoalition=_SCORINGCoalition[PlayerUnit:getCoalition()] -end -if not PlayerUnitType then -PlayerUnitType=PlayerUnit:getTypeName() -end -else -PlayerUnitName='' -PlayerUnitCategory='' -PlayerUnitCoalition='' -PlayerUnitType='' -end -else -PlayerUnitName='' -PlayerUnitCategory='' -PlayerUnitCoalition='' -PlayerUnitType='' -end -TargetUnitCoalition=TargetUnitCoalition or"" -TargetUnitCategory=TargetUnitCategory or"" -TargetUnitType=TargetUnitType or"" -TargetUnitName=TargetUnitName or"" -if lfs and io and os then -self.CSVFile:write( -'"'..self.GameName..'"'..','.. -'"'..self.RunTime..'"'..','.. -''..ScoreTime..''..','.. -'"'..PlayerName..'"'..','.. -'"'..TargetPlayerName..'"'..','.. -'"'..ScoreType..'"'..','.. -'"'..PlayerUnitCoalition..'"'..','.. -'"'..PlayerUnitCategory..'"'..','.. -'"'..PlayerUnitType..'"'..','.. -'"'..PlayerUnitName..'"'..','.. -'"'..TargetUnitCoalition..'"'..','.. -'"'..TargetUnitCategory..'"'..','.. -'"'..TargetUnitType..'"'..','.. -'"'..TargetUnitName..'"'..','.. -''..ScoreTimes..''..','.. -''..ScoreAmount -) -self.CSVFile:write("\n") -end -end -function SCORING:CloseCSV() -if lfs and io and os then -self.CSVFile:close() -end -end -CLEANUP_AIRBASE={ -ClassName="CLEANUP_AIRBASE", -TimeInterval=0.2, -CleanUpList={}, -} -CLEANUP_AIRBASE.__={} -CLEANUP_AIRBASE.__.Airbases={} -function CLEANUP_AIRBASE:New(AirbaseNames) -local self=BASE:Inherit(self,BASE:New()) -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 -function CLEANUP_AIRBASE:AddAirbase(AirbaseName) -self.__.Airbases[AirbaseName]=AIRBASE:FindByName(AirbaseName) -self:F({"Airbase:",AirbaseName,self.__.Airbases[AirbaseName]:GetDesc()}) -return self -end -function CLEANUP_AIRBASE:RemoveAirbase(AirbaseName) -self.__.Airbases[AirbaseName]=nil -return self -end -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 -if Airbase:GetZone():IsVec2InZone(Vec2)then -InAirbase=true -break; -end -end -return InAirbase -end -function CLEANUP_AIRBASE.__:DestroyUnit(CleanUpUnit) -self:F({CleanUpUnit}) -if CleanUpUnit then -local CleanUpUnitName=CleanUpUnit:GetName() -local CleanUpGroup=CleanUpUnit:GetGroup() -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 -function CLEANUP_AIRBASE.__:DestroyMissile(MissileObject) -self:F({MissileObject}) -if MissileObject and MissileObject:isExist()then -MissileObject:destroy() -self:T("MissileObject Destroyed") -end -end -function CLEANUP_AIRBASE.__: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 -function CLEANUP_AIRBASE.__:OnEventCrash(Event) -self:F({Event}) -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 -function CLEANUP_AIRBASE.__:OnEventShot(Event) -self:F({Event}) -if self:IsInAirbase(Event.IniUnit:GetVec2())then -self:DestroyMissile(Event.Weapon) -end -end -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()=SpawnWidth then -SpawnXIndex=0 -SpawnYIndex=SpawnYIndex+1 -end -end -local SpawnRootX=self.SpawnGroups[SpawnGroupID].SpawnTemplate.x -local SpawnRootY=self.SpawnGroups[SpawnGroupID].SpawnTemplate.y -self:_TranslateRotate(SpawnGroupID,SpawnRootX,SpawnRootY,SpawnX,SpawnY,SpawnAngle) -self.SpawnGroups[SpawnGroupID].SpawnTemplate.lateActivation=true -self.SpawnGroups[SpawnGroupID].SpawnTemplate.visible=true -self.SpawnGroups[SpawnGroupID].Visible=true -self:HandleEvent(EVENTS.Birth,self._OnBirth) -self:HandleEvent(EVENTS.Dead,self._OnDeadOrCrash) -self:HandleEvent(EVENTS.Crash,self._OnDeadOrCrash) -if self.Repeat then -self:HandleEvent(EVENTS.Takeoff,self._OnTakeOff) -self:HandleEvent(EVENTS.Land,self._OnLand) -end -if self.RepeatOnEngineShutDown then -self:HandleEvent(EVENTS.EngineShutdown,self._OnEngineShutDown) -end -self.SpawnGroups[SpawnGroupID].Group=_DATABASE:Spawn(self.SpawnGroups[SpawnGroupID].SpawnTemplate) -SpawnX=SpawnXIndex*SpawnDeltaX -SpawnY=SpawnYIndex*SpawnDeltaY -end -return self -end -do -function SPAWN:InitAIOnOff(AIOnOff) -self.AIOnOff=AIOnOff -return self -end -function SPAWN:InitAIOn() -return self:InitAIOnOff(true) -end -function SPAWN:InitAIOff() -return self:InitAIOnOff(false) -end -end -do -function SPAWN:InitDelayOnOff(DelayOnOff) -self.DelayOnOff=DelayOnOff -return self -end -function SPAWN:InitDelayOn() -return self:InitDelayOnOff(true) -end -function SPAWN:InitDelayOff() -return self:InitDelayOnOff(false) -end -end -function SPAWN:Spawn() -self:F({self.SpawnTemplatePrefix,self.SpawnIndex,self.AliveUnits}) -return self:SpawnWithIndex(self.SpawnIndex+1) -end -function SPAWN:ReSpawn(SpawnIndex) -self:F({self.SpawnTemplatePrefix,SpawnIndex}) -if not SpawnIndex then -SpawnIndex=1 -end -local SpawnGroup=self:GetGroupFromIndex(SpawnIndex) -local WayPoints=SpawnGroup and SpawnGroup.WayPoints or nil -if SpawnGroup then -local SpawnDCSGroup=SpawnGroup:GetDCSObject() -if SpawnDCSGroup then -SpawnGroup:Destroy() -end -end -local SpawnGroup=self:SpawnWithIndex(SpawnIndex) -if SpawnGroup and WayPoints then -SpawnGroup:WayPointInitialize(WayPoints) -SpawnGroup:WayPointExecute(1,5) -end -if SpawnGroup.ReSpawnFunction then -SpawnGroup:ReSpawnFunction() -end -SpawnGroup:ResetEvents() -return SpawnGroup -end -function SPAWN:SpawnWithIndex(SpawnIndex) -self:F2({SpawnTemplatePrefix=self.SpawnTemplatePrefix,SpawnIndex=SpawnIndex,AliveUnits=self.AliveUnits,SpawnMaxGroups=self.SpawnMaxGroups}) -if self:_GetSpawnIndex(SpawnIndex)then -if self.SpawnGroups[self.SpawnIndex].Visible then -self.SpawnGroups[self.SpawnIndex].Group:Activate() -else -local SpawnTemplate=self.SpawnGroups[self.SpawnIndex].SpawnTemplate -self:T(SpawnTemplate.name) -if SpawnTemplate then -local PointVec3=POINT_VEC3:New(SpawnTemplate.route.points[1].x,SpawnTemplate.route.points[1].alt,SpawnTemplate.route.points[1].y) -self:T({"Current point of ",self.SpawnTemplatePrefix,PointVec3}) -if self.SpawnRandomizePosition then -local RandomVec2=PointVec3:GetRandomVec2InRadius(self.SpawnRandomizePositionOuterRadius,self.SpawnRandomizePositionInnerRadius) -local CurrentX=SpawnTemplate.units[1].x -local CurrentY=SpawnTemplate.units[1].y -SpawnTemplate.x=RandomVec2.x -SpawnTemplate.y=RandomVec2.y -for UnitID=1,#SpawnTemplate.units do -SpawnTemplate.units[UnitID].x=SpawnTemplate.units[UnitID].x+(RandomVec2.x-CurrentX) -SpawnTemplate.units[UnitID].y=SpawnTemplate.units[UnitID].y+(RandomVec2.y-CurrentY) -self:T('SpawnTemplate.units['..UnitID..'].x = '..SpawnTemplate.units[UnitID].x..', SpawnTemplate.units['..UnitID..'].y = '..SpawnTemplate.units[UnitID].y) -end -end -if self.SpawnRandomizeUnits then -for UnitID=1,#SpawnTemplate.units do -local RandomVec2=PointVec3:GetRandomVec2InRadius(self.SpawnOuterRadius,self.SpawnInnerRadius) -SpawnTemplate.units[UnitID].x=RandomVec2.x -SpawnTemplate.units[UnitID].y=RandomVec2.y -self:T('SpawnTemplate.units['..UnitID..'].x = '..SpawnTemplate.units[UnitID].x..', SpawnTemplate.units['..UnitID..'].y = '..SpawnTemplate.units[UnitID].y) -end -end -if SpawnTemplate.CategoryID==Group.Category.HELICOPTER or SpawnTemplate.CategoryID==Group.Category.AIRPLANE then -if SpawnTemplate.route.points[1].type=="TakeOffParking"then -SpawnTemplate.uncontrolled=self.SpawnUnControlled -end -end -end -self:HandleEvent(EVENTS.Birth,self._OnBirth) -self:HandleEvent(EVENTS.Dead,self._OnDeadOrCrash) -self:HandleEvent(EVENTS.Crash,self._OnDeadOrCrash) -if self.Repeat then -self:HandleEvent(EVENTS.Takeoff,self._OnTakeOff) -self:HandleEvent(EVENTS.Land,self._OnLand) -end -if self.RepeatOnEngineShutDown then -self:HandleEvent(EVENTS.EngineShutdown,self._OnEngineShutDown) -end -self.SpawnGroups[self.SpawnIndex].Group=_DATABASE:Spawn(SpawnTemplate) -local SpawnGroup=self.SpawnGroups[self.SpawnIndex].Group -if SpawnGroup then -SpawnGroup:SetAIOnOff(self.AIOnOff) -end -self:T3(SpawnTemplate.name) -if self.SpawnFunctionHook then -self.SpawnHookScheduler=SCHEDULER:New() -self.SpawnHookScheduler:Schedule(nil,self.SpawnFunctionHook,{self.SpawnGroups[self.SpawnIndex].Group,unpack(self.SpawnFunctionArguments)},0.1) -end -end -self.SpawnGroups[self.SpawnIndex].Spawned=true -return self.SpawnGroups[self.SpawnIndex].Group -else -end -return nil -end -function SPAWN:SpawnScheduled(SpawnTime,SpawnTimeVariation) -self:F({SpawnTime,SpawnTimeVariation}) -if SpawnTime~=nil and SpawnTimeVariation~=nil then -local InitialDelay=0 -if self.DelayOnOff==true then -InitialDelay=math.random(SpawnTime-SpawnTime*SpawnTimeVariation,SpawnTime+SpawnTime*SpawnTimeVariation) -end -self.SpawnScheduler=SCHEDULER:New(self,self._Scheduler,{},InitialDelay,SpawnTime,SpawnTimeVariation) -end -return self -end -function SPAWN:SpawnScheduleStart() -self:F({self.SpawnTemplatePrefix}) -self.SpawnScheduler:Start() -return self -end -function SPAWN:SpawnScheduleStop() -self:F({self.SpawnTemplatePrefix}) -self.SpawnScheduler:Stop() -return self -end -function SPAWN:OnSpawnGroup(SpawnCallBackFunction,...) -self:F("OnSpawnGroup") -self.SpawnFunctionHook=SpawnCallBackFunction -self.SpawnFunctionArguments={} -if arg then -self.SpawnFunctionArguments=arg -end -return self -end -function SPAWN:SpawnAtAirbase(SpawnAirbase,Takeoff,TakeoffAltitude) -self:E({self.SpawnTemplatePrefix,SpawnAirbase,Takeoff,TakeoffAltitude}) -local PointVec3=SpawnAirbase:GetPointVec3() -self:T2(PointVec3) -Takeoff=Takeoff or SPAWN.Takeoff.Hot -if self:_GetSpawnIndex(self.SpawnIndex+1)then -local SpawnTemplate=self.SpawnGroups[self.SpawnIndex].SpawnTemplate -if SpawnTemplate then -self:T({"Current point of ",self.SpawnTemplatePrefix,SpawnAirbase}) -local SpawnPoint=SpawnTemplate.route.points[1] -SpawnPoint.linkUnit=nil -SpawnPoint.helipadId=nil -SpawnPoint.airdromeId=nil -local AirbaseID=SpawnAirbase:GetID() -local AirbaseCategory=SpawnAirbase:GetDesc().category -self:F({AirbaseCategory=AirbaseCategory}) -if AirbaseCategory==Airbase.Category.SHIP then -SpawnPoint.linkUnit=AirbaseID -SpawnPoint.helipadId=AirbaseID -elseif AirbaseCategory==Airbase.Category.HELIPAD then -SpawnPoint.linkUnit=AirbaseID -SpawnPoint.helipadId=AirbaseID -elseif AirbaseCategory==Airbase.Category.AIRDROME then -SpawnPoint.airdromeId=AirbaseID -end -SpawnPoint.alt=0 -SpawnPoint.type=GROUPTEMPLATE.Takeoff[Takeoff][1] -SpawnPoint.action=GROUPTEMPLATE.Takeoff[Takeoff][2] -for UnitID=1,#SpawnTemplate.units do -self:T('Before Translation SpawnTemplate.units['..UnitID..'].x = '..SpawnTemplate.units[UnitID].x..', SpawnTemplate.units['..UnitID..'].y = '..SpawnTemplate.units[UnitID].y) -local UnitTemplate=SpawnTemplate.units[UnitID] -UnitTemplate.parking=nil -UnitTemplate.parking_id=nil -UnitTemplate.alt=0 -local SX=UnitTemplate.x -local SY=UnitTemplate.y -local BX=SpawnPoint.x -local BY=SpawnPoint.y -local TX=PointVec3.x+(SX-BX) -local TY=PointVec3.z+(SY-BY) -UnitTemplate.x=TX -UnitTemplate.y=TY -if Takeoff==GROUP.Takeoff.Air then -UnitTemplate.alt=PointVec3.y+(TakeoffAltitude or 200) -end -self:T('After Translation SpawnTemplate.units['..UnitID..'].x = '..UnitTemplate.x..', SpawnTemplate.units['..UnitID..'].y = '..UnitTemplate.y) -end -SpawnPoint.x=PointVec3.x -SpawnPoint.y=PointVec3.z -if Takeoff==GROUP.Takeoff.Air then -SpawnPoint.alt=PointVec3.y+(TakeoffAltitude or 200) -end -SpawnTemplate.x=PointVec3.x -SpawnTemplate.y=PointVec3.z -local GroupSpawned=self:SpawnWithIndex(self.SpawnIndex) -if Takeoff==GROUP.Takeoff.Air then -for UnitID,UnitSpawned in pairs(GroupSpawned:GetUnits())do -SCHEDULER:New(nil,BASE.CreateEventTakeoff,{GroupSpawned,timer.getTime(),UnitSpawned:GetDCSObject()},1) -end -end -return GroupSpawned -end -end -return nil -end -function SPAWN:SpawnFromVec3(Vec3,SpawnIndex) -self:F({self.SpawnTemplatePrefix,Vec3,SpawnIndex}) -local PointVec3=POINT_VEC3:NewFromVec3(Vec3) -self:T2(PointVec3) -if SpawnIndex then -else -SpawnIndex=self.SpawnIndex+1 -end -if self:_GetSpawnIndex(SpawnIndex)then -local SpawnTemplate=self.SpawnGroups[self.SpawnIndex].SpawnTemplate -if SpawnTemplate then -self:T({"Current point of ",self.SpawnTemplatePrefix,Vec3}) -for UnitID=1,#SpawnTemplate.units do -self:T('Before Translation SpawnTemplate.units['..UnitID..'].x = '..SpawnTemplate.units[UnitID].x..', SpawnTemplate.units['..UnitID..'].y = '..SpawnTemplate.units[UnitID].y) -local UnitTemplate=SpawnTemplate.units[UnitID] -local SX=UnitTemplate.x -local SY=UnitTemplate.y -local BX=SpawnTemplate.route.points[1].x -local BY=SpawnTemplate.route.points[1].y -local TX=Vec3.x+(SX-BX) -local TY=Vec3.z+(SY-BY) -SpawnTemplate.units[UnitID].x=TX -SpawnTemplate.units[UnitID].y=TY -SpawnTemplate.units[UnitID].alt=Vec3.y -self:T('After Translation SpawnTemplate.units['..UnitID..'].x = '..SpawnTemplate.units[UnitID].x..', SpawnTemplate.units['..UnitID..'].y = '..SpawnTemplate.units[UnitID].y) -end -SpawnTemplate.route.points[1].x=Vec3.x -SpawnTemplate.route.points[1].y=Vec3.z -SpawnTemplate.route.points[1].alt=Vec3.y -SpawnTemplate.x=Vec3.x -SpawnTemplate.y=Vec3.z -return self:SpawnWithIndex(self.SpawnIndex) -end -end -return nil -end -function SPAWN:SpawnFromVec2(Vec2,SpawnIndex) -self:F({self.SpawnTemplatePrefix,Vec2,SpawnIndex}) -local PointVec2=POINT_VEC2:NewFromVec2(Vec2) -return self:SpawnFromVec3(PointVec2:GetVec3(),SpawnIndex) -end -function SPAWN:SpawnFromUnit(HostUnit,SpawnIndex) -self:F({self.SpawnTemplatePrefix,HostUnit,SpawnIndex}) -if HostUnit and HostUnit:IsAlive()~=nil then -return self:SpawnFromVec3(HostUnit:GetVec3(),SpawnIndex) -end -return nil -end -function SPAWN:SpawnFromStatic(HostStatic,SpawnIndex) -self:F({self.SpawnTemplatePrefix,HostStatic,SpawnIndex}) -if HostStatic and HostStatic:IsAlive()then -return self:SpawnFromVec3(HostStatic:GetVec3(),SpawnIndex) -end -return nil -end -function SPAWN:SpawnInZone(Zone,RandomizeGroup,SpawnIndex) -self:F({self.SpawnTemplatePrefix,Zone,RandomizeGroup,SpawnIndex}) -if Zone then -if RandomizeGroup then -return self:SpawnFromVec2(Zone:GetRandomVec2(),SpawnIndex) -else -return self:SpawnFromVec2(Zone:GetVec2(),SpawnIndex) -end -end -return nil -end -function SPAWN:InitUnControlled(UnControlled) -self:F2({self.SpawnTemplatePrefix,UnControlled}) -self.SpawnUnControlled=UnControlled -for SpawnGroupID=1,self.SpawnMaxGroups do -self.SpawnGroups[SpawnGroupID].UnControlled=UnControlled -end -return self -end -function SPAWN:GetCoordinate() -local LateGroup=GROUP:FindByName(self.SpawnTemplatePrefix) -if LateGroup then -return LateGroup:GetCoordinate() -end -return nil -end -function SPAWN:SpawnGroupName(SpawnIndex) -self:F({self.SpawnTemplatePrefix,SpawnIndex}) -local SpawnPrefix=self.SpawnTemplatePrefix -if self.SpawnAliasPrefix then -SpawnPrefix=self.SpawnAliasPrefix -end -if SpawnIndex then -local SpawnName=string.format('%s#%03d',SpawnPrefix,SpawnIndex) -self:T(SpawnName) -return SpawnName -else -self:T(SpawnPrefix) -return SpawnPrefix -end -end -function SPAWN:GetFirstAliveGroup() -self:F({self.SpawnTemplatePrefix,self.SpawnAliasPrefix}) -for SpawnIndex=1,self.SpawnCount do -local SpawnGroup=self:GetGroupFromIndex(SpawnIndex) -if SpawnGroup and SpawnGroup:IsAlive()then -return SpawnGroup,SpawnIndex -end -end -return nil,nil -end -function SPAWN:GetNextAliveGroup(SpawnIndexStart) -self:F({self.SpawnTemplatePrefix,self.SpawnAliasPrefix,SpawnIndexStart}) -SpawnIndexStart=SpawnIndexStart+1 -for SpawnIndex=SpawnIndexStart,self.SpawnCount do -local SpawnGroup=self:GetGroupFromIndex(SpawnIndex) -if SpawnGroup and SpawnGroup:IsAlive()then -return SpawnGroup,SpawnIndex -end -end -return nil,nil -end -function SPAWN:GetLastAliveGroup() -self:F({self.SpawnTemplatePrefixself.SpawnAliasPrefix}) -self.SpawnIndex=self:_GetLastIndex() -for SpawnIndex=self.SpawnIndex,1,-1 do -local SpawnGroup=self:GetGroupFromIndex(SpawnIndex) -if SpawnGroup and SpawnGroup:IsAlive()then -self.SpawnIndex=SpawnIndex -return SpawnGroup -end -end -self.SpawnIndex=nil -return nil -end -function SPAWN:GetGroupFromIndex(SpawnIndex) -self:F({self.SpawnTemplatePrefix,self.SpawnAliasPrefix,SpawnIndex}) -if not SpawnIndex then -SpawnIndex=1 -end -if self.SpawnGroups and self.SpawnGroups[SpawnIndex]then -local SpawnGroup=self.SpawnGroups[SpawnIndex].Group -return SpawnGroup -else -return nil -end -end -function SPAWN:_GetPrefixFromGroup(SpawnGroup) -self:F3({self.SpawnTemplatePrefix,self.SpawnAliasPrefix,SpawnGroup}) -local GroupName=SpawnGroup:GetName() -if GroupName then -local SpawnPrefix=string.match(GroupName,".*#") -if SpawnPrefix then -SpawnPrefix=SpawnPrefix:sub(1,-2) -end -return SpawnPrefix -end -return nil -end -function SPAWN:GetSpawnIndexFromGroup(SpawnGroup) -self:F({self.SpawnTemplatePrefix,self.SpawnAliasPrefix,SpawnGroup}) -local IndexString=string.match(SpawnGroup:GetName(),"#(%d*)$"):sub(2) -local Index=tonumber(IndexString) -self:T3(IndexString,Index) -return Index -end -function SPAWN:_GetLastIndex() -self:F({self.SpawnTemplatePrefix,self.SpawnAliasPrefix}) -return self.SpawnMaxGroups -end -function SPAWN:_InitializeSpawnGroups(SpawnIndex) -self:F3({self.SpawnTemplatePrefix,self.SpawnAliasPrefix,SpawnIndex}) -if not self.SpawnGroups[SpawnIndex]then -self.SpawnGroups[SpawnIndex]={} -self.SpawnGroups[SpawnIndex].Visible=false -self.SpawnGroups[SpawnIndex].Spawned=false -self.SpawnGroups[SpawnIndex].UnControlled=false -self.SpawnGroups[SpawnIndex].SpawnTime=0 -self.SpawnGroups[SpawnIndex].SpawnTemplatePrefix=self.SpawnTemplatePrefix -self.SpawnGroups[SpawnIndex].SpawnTemplate=self:_Prepare(self.SpawnGroups[SpawnIndex].SpawnTemplatePrefix,SpawnIndex) -end -self:_RandomizeTemplate(SpawnIndex) -self:_RandomizeRoute(SpawnIndex) -return self.SpawnGroups[SpawnIndex] -end -function SPAWN:_GetGroupCategoryID(SpawnPrefix) -local TemplateGroup=Group.getByName(SpawnPrefix) -if TemplateGroup then -return TemplateGroup:getCategory() -else -return nil -end -end -function SPAWN:_GetGroupCoalitionID(SpawnPrefix) -local TemplateGroup=Group.getByName(SpawnPrefix) -if TemplateGroup then -return TemplateGroup:getCoalition() -else -return nil -end -end -function SPAWN:_GetGroupCountryID(SpawnPrefix) -self:F({self.SpawnTemplatePrefix,self.SpawnAliasPrefix,SpawnPrefix}) -local TemplateGroup=Group.getByName(SpawnPrefix) -if TemplateGroup then -local TemplateUnits=TemplateGroup:getUnits() -return TemplateUnits[1]:getCountry() -else -return nil -end -end -function SPAWN:_GetTemplate(SpawnTemplatePrefix) -self:F({self.SpawnTemplatePrefix,self.SpawnAliasPrefix,SpawnTemplatePrefix}) -local SpawnTemplate=nil -SpawnTemplate=routines.utils.deepCopy(_DATABASE.Templates.Groups[SpawnTemplatePrefix].Template) -if SpawnTemplate==nil then -error('No Template returned for SpawnTemplatePrefix = '..SpawnTemplatePrefix) -end -self:T3({SpawnTemplate}) -return SpawnTemplate -end -function SPAWN:_Prepare(SpawnTemplatePrefix,SpawnIndex) -self:F({self.SpawnTemplatePrefix,self.SpawnAliasPrefix}) -local SpawnTemplate=self:_GetTemplate(SpawnTemplatePrefix) -SpawnTemplate.name=self:SpawnGroupName(SpawnIndex) -SpawnTemplate.groupId=nil -SpawnTemplate.lateActivation=false -if SpawnTemplate.CategoryID==Group.Category.GROUND then -self:T3("For ground units, visible needs to be false...") -SpawnTemplate.visible=false -end -if self.SpawnGrouping then -local UnitAmount=#SpawnTemplate.units -self:F({UnitAmount=UnitAmount,SpawnGrouping=self.SpawnGrouping}) -if UnitAmount>self.SpawnGrouping then -for UnitID=self.SpawnGrouping+1,UnitAmount do -SpawnTemplate.units[UnitID]=nil -end -else -if UnitAmount0 then -local MoveProbability=(self.MoveMaximum*100)/self.AliveUnits -self:T('Move Probability = '..MoveProbability) -for MovementUnitName,MovementGroupName in pairs(self.MoveUnits)do -local MovementGroup=Group.getByName(MovementGroupName) -if MovementGroup and MovementGroup:isExist()then -local MoveOrStop=math.random(1,100) -self:T('MoveOrStop = '..MoveOrStop) -if MoveOrStop<=MoveProbability then -self:T('Group continues moving = '..MovementGroupName) -trigger.action.groupContinueMoving(MovementGroup) -else -self:T('Group stops moving = '..MovementGroupName) -trigger.action.groupStopMoving(MovementGroup) -end -else -self.MoveUnits[MovementUnitName]=nil -end -end -end -return true -end -SEAD={ -ClassName="SEAD", -TargetSkill={ -Average={Evade=50,DelayOff={10,25},DelayOn={10,30}}, -Good={Evade=30,DelayOff={8,20},DelayOn={20,40}}, -High={Evade=15,DelayOff={5,17},DelayOn={30,50}}, -Excellent={Evade=10,DelayOff={3,10},DelayOn={30,60}} -}, -SEADGroupPrefixes={} -} -function SEAD:New(SEADGroupPrefixes) -local self=BASE:Inherit(self,BASE:New()) -self:F(SEADGroupPrefixes) -if type(SEADGroupPrefixes)=='table'then -for SEADGroupPrefixID,SEADGroupPrefix in pairs(SEADGroupPrefixes)do -self.SEADGroupPrefixes[SEADGroupPrefix]=SEADGroupPrefix -end -else -self.SEADGroupNames[SEADGroupPrefixes]=SEADGroupPrefixes -end -self:HandleEvent(EVENTS.Shot) -return self -end -function SEAD:OnEventShot(EventData) -self:F({EventData}) -local SEADUnit=EventData.IniDCSUnit -local SEADUnitName=EventData.IniDCSUnitName -local SEADWeapon=EventData.Weapon -local SEADWeaponName=EventData.WeaponName -self:T("Missile Launched = "..SEADWeaponName) -if SEADWeaponName=="KH-58"or SEADWeaponName=="KH-25MPU"or SEADWeaponName=="AGM-88"or SEADWeaponName=="KH-31A"or SEADWeaponName=="KH-31P"then -local _evade=math.random(1,100) -local _targetMim=EventData.Weapon:getTarget() -local _targetMimname=Unit.getName(_targetMim) -local _targetMimgroup=Unit.getGroup(Weapon.getTarget(SEADWeapon)) -local _targetMimgroupName=_targetMimgroup:getName() -local _targetMimcont=_targetMimgroup:getController() -local _targetskill=_DATABASE.Templates.Units[_targetMimname].Template.skill -self:T(self.SEADGroupPrefixes) -self:T(_targetMimgroupName) -local SEADGroupFound=false -for SEADGroupPrefixID,SEADGroupPrefix in pairs(self.SEADGroupPrefixes)do -if string.find(_targetMimgroupName,SEADGroupPrefix,1,true)then -SEADGroupFound=true -self:T('Group Found') -break -end -end -if SEADGroupFound==true then -if _targetskill=="Random"then -local Skills={"Average","Good","High","Excellent"} -_targetskill=Skills[math.random(1,4)] -end -self:T(_targetskill) -if self.TargetSkill[_targetskill]then -if(_evade>self.TargetSkill[_targetskill].Evade)then -self:T(string.format("Evading, target skill "..string.format(_targetskill))) -local _targetMim=Weapon.getTarget(SEADWeapon) -local _targetMimname=Unit.getName(_targetMim) -local _targetMimgroup=Unit.getGroup(Weapon.getTarget(SEADWeapon)) -local _targetMimcont=_targetMimgroup:getController() -routines.groupRandomDistSelf(_targetMimgroup,300,'Diamond',250,20) -local SuppressedGroups1={} -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 -} -Controller.setOption(_targetMimcont,AI.Option.Ground.id.ALARM_STATE,AI.Option.Ground.val.ALARM_STATE.GREEN) -timer.scheduleFunction(SuppressionEnd1,id,SuppressedGroups1[id.groupName].SuppressionEndTime1) -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 -} -timer.scheduleFunction(SuppressionEnd,id,SuppressedGroups[id.groupName].SuppressionEndTime) -end -end -end -end -end -end -ESCORT={ -ClassName="ESCORT", -EscortName=nil, -EscortClient=nil, -EscortGroup=nil, -EscortMode=1, -MODE={ -FOLLOW=1, -MISSION=2, -}, -Targets={}, -FollowScheduler=nil, -ReportTargets=true, -OptionROE=AI.Option.Air.val.ROE.OPEN_FIRE, -OptionReactionOnThreat=AI.Option.Air.val.REACTION_ON_THREAT.ALLOW_ABORT_MISSION, -SmokeDirectionVector=false, -TaskPoints={} -} -function ESCORT:New(EscortClient,EscortGroup,EscortName,EscortBriefing) -local self=BASE:Inherit(self,BASE:New()) -self:F({EscortClient,EscortGroup,EscortName}) -self.EscortClient=EscortClient -self.EscortGroup=EscortGroup -self.EscortName=EscortName -self.EscortBriefing=EscortBriefing -self.EscortSetGroup=SET_GROUP:New() -self.EscortSetGroup:AddObject(self.EscortGroup) -self.EscortSetGroup:Flush() -self.Detection=DETECTION_UNITS:New(self.EscortSetGroup,15000) -self.EscortGroup.Detection=self.Detection -if not self.EscortClient._EscortGroups then -self.EscortClient._EscortGroups={} -end -if not self.EscortClient._EscortGroups[EscortGroup:GetName()]then -self.EscortClient._EscortGroups[EscortGroup:GetName()]={} -self.EscortClient._EscortGroups[EscortGroup:GetName()].EscortGroup=self.EscortGroup -self.EscortClient._EscortGroups[EscortGroup:GetName()].EscortName=self.EscortName -self.EscortClient._EscortGroups[EscortGroup:GetName()].Detection=self.EscortGroup.Detection -end -self.EscortMenu=MENU_CLIENT:New(self.EscortClient,self.EscortName) -self.EscortGroup:WayPointInitialize(1) -self.EscortGroup:OptionROTVertical() -self.EscortGroup:OptionROEOpenFire() -if not EscortBriefing then -EscortGroup:MessageToClient(EscortGroup:GetCategoryName().." '"..EscortName.."' ("..EscortGroup:GetCallsign()..") reporting! ".. -"We're escorting your flight. ".. -"Use the Radio Menu and F10 and use the options under + "..EscortName.."\n", -60,EscortClient -) -else -EscortGroup:MessageToClient(EscortGroup:GetCategoryName().." '"..EscortName.."' ("..EscortGroup:GetCallsign()..") "..EscortBriefing, -60,EscortClient -) -end -self.FollowDistance=100 -self.CT1=0 -self.GT1=0 -self.FollowScheduler,self.FollowSchedule=SCHEDULER:New(self,self._FollowScheduler,{},1,.5,.01) -self.FollowScheduler:Stop(self.FollowSchedule) -self.EscortMode=ESCORT.MODE.MISSION -return self -end -function ESCORT:SetDetection(Detection) -self.Detection=Detection -self.EscortGroup.Detection=self.Detection -self.EscortClient._EscortGroups[self.EscortGroup:GetName()].Detection=self.EscortGroup.Detection -Detection:__Start(1) -end -function ESCORT:TestSmokeDirectionVector(SmokeDirection) -self.SmokeDirectionVector=(SmokeDirection==true)and true or false -end -function ESCORT:Menus() -self:F() -self:MenuFollowAt(100) -self:MenuFollowAt(200) -self:MenuFollowAt(300) -self:MenuFollowAt(400) -self:MenuScanForTargets(100,60) -self:MenuHoldAtEscortPosition(30) -self:MenuHoldAtLeaderPosition(30) -self:MenuFlare() -self:MenuSmoke() -self:MenuReportTargets(60) -self:MenuAssistedAttack() -self:MenuROE() -self:MenuEvasion() -self:MenuResumeMission() -return self -end -function ESCORT:MenuFollowAt(Distance) -self:F(Distance) -if self.EscortGroup:IsAir()then -if not self.EscortMenuReportNavigation then -self.EscortMenuReportNavigation=MENU_CLIENT:New(self.EscortClient,"Navigation",self.EscortMenu) -end -if not self.EscortMenuJoinUpAndFollow then -self.EscortMenuJoinUpAndFollow={} -end -self.EscortMenuJoinUpAndFollow[#self.EscortMenuJoinUpAndFollow+1]=MENU_CLIENT_COMMAND:New(self.EscortClient,"Join-Up and Follow at "..Distance,self.EscortMenuReportNavigation,ESCORT._JoinUpAndFollow,self,Distance) -self.EscortMode=ESCORT.MODE.FOLLOW -end -return self -end -function ESCORT:MenuHoldAtEscortPosition(Height,Seconds,MenuTextFormat) -self:F({Height,Seconds,MenuTextFormat}) -if self.EscortGroup:IsAir()then -if not self.EscortMenuHold then -self.EscortMenuHold=MENU_CLIENT:New(self.EscortClient,"Hold position",self.EscortMenu) -end -if not Height then -Height=30 -end -if not Seconds then -Seconds=0 -end -local MenuText="" -if not MenuTextFormat then -if Seconds==0 then -MenuText=string.format("Hold at %d meter",Height) -else -MenuText=string.format("Hold at %d meter for %d seconds",Height,Seconds) -end -else -if Seconds==0 then -MenuText=string.format(MenuTextFormat,Height) -else -MenuText=string.format(MenuTextFormat,Height,Seconds) -end -end -if not self.EscortMenuHoldPosition then -self.EscortMenuHoldPosition={} -end -self.EscortMenuHoldPosition[#self.EscortMenuHoldPosition+1]=MENU_CLIENT_COMMAND -:New( -self.EscortClient, -MenuText, -self.EscortMenuHold, -ESCORT._HoldPosition, -self, -self.EscortGroup, -Height, -Seconds -) -end -return self -end -function ESCORT:MenuHoldAtLeaderPosition(Height,Seconds,MenuTextFormat) -self:F({Height,Seconds,MenuTextFormat}) -if self.EscortGroup:IsAir()then -if not self.EscortMenuHold then -self.EscortMenuHold=MENU_CLIENT:New(self.EscortClient,"Hold position",self.EscortMenu) -end -if not Height then -Height=30 -end -if not Seconds then -Seconds=0 -end -local MenuText="" -if not MenuTextFormat then -if Seconds==0 then -MenuText=string.format("Rejoin and hold at %d meter",Height) -else -MenuText=string.format("Rejoin and hold at %d meter for %d seconds",Height,Seconds) -end -else -if Seconds==0 then -MenuText=string.format(MenuTextFormat,Height) -else -MenuText=string.format(MenuTextFormat,Height,Seconds) -end -end -if not self.EscortMenuHoldAtLeaderPosition then -self.EscortMenuHoldAtLeaderPosition={} -end -self.EscortMenuHoldAtLeaderPosition[#self.EscortMenuHoldAtLeaderPosition+1]=MENU_CLIENT_COMMAND -:New( -self.EscortClient, -MenuText, -self.EscortMenuHold, -ESCORT._HoldPosition, -{ParamSelf=self, -ParamOrbitGroup=self.EscortClient, -ParamHeight=Height, -ParamSeconds=Seconds -} -) -end -return self -end -function ESCORT:MenuScanForTargets(Height,Seconds,MenuTextFormat) -self:F({Height,Seconds,MenuTextFormat}) -if self.EscortGroup:IsAir()then -if not self.EscortMenuScan then -self.EscortMenuScan=MENU_CLIENT:New(self.EscortClient,"Scan for targets",self.EscortMenu) -end -if not Height then -Height=100 -end -if not Seconds then -Seconds=30 -end -local MenuText="" -if not MenuTextFormat then -if Seconds==0 then -MenuText=string.format("At %d meter",Height) -else -MenuText=string.format("At %d meter for %d seconds",Height,Seconds) -end -else -if Seconds==0 then -MenuText=string.format(MenuTextFormat,Height) -else -MenuText=string.format(MenuTextFormat,Height,Seconds) -end -end -if not self.EscortMenuScanForTargets then -self.EscortMenuScanForTargets={} -end -self.EscortMenuScanForTargets[#self.EscortMenuScanForTargets+1]=MENU_CLIENT_COMMAND -:New( -self.EscortClient, -MenuText, -self.EscortMenuScan, -ESCORT._ScanTargets, -self, -30 -) -end -return self -end -function ESCORT:MenuFlare(MenuTextFormat) -self:F() -if not self.EscortMenuReportNavigation then -self.EscortMenuReportNavigation=MENU_CLIENT:New(self.EscortClient,"Navigation",self.EscortMenu) -end -local MenuText="" -if not MenuTextFormat then -MenuText="Flare" -else -MenuText=MenuTextFormat -end -if not self.EscortMenuFlare then -self.EscortMenuFlare=MENU_CLIENT:New(self.EscortClient,MenuText,self.EscortMenuReportNavigation,ESCORT._Flare,self) -self.EscortMenuFlareGreen=MENU_CLIENT_COMMAND:New(self.EscortClient,"Release green flare",self.EscortMenuFlare,ESCORT._Flare,self,FLARECOLOR.Green,"Released a green flare!") -self.EscortMenuFlareRed=MENU_CLIENT_COMMAND:New(self.EscortClient,"Release red flare",self.EscortMenuFlare,ESCORT._Flare,self,FLARECOLOR.Red,"Released a red flare!") -self.EscortMenuFlareWhite=MENU_CLIENT_COMMAND:New(self.EscortClient,"Release white flare",self.EscortMenuFlare,ESCORT._Flare,self,FLARECOLOR.White,"Released a white flare!") -self.EscortMenuFlareYellow=MENU_CLIENT_COMMAND:New(self.EscortClient,"Release yellow flare",self.EscortMenuFlare,ESCORT._Flare,self,FLARECOLOR.Yellow,"Released a yellow flare!") -end -return self -end -function ESCORT:MenuSmoke(MenuTextFormat) -self:F() -if not self.EscortGroup:IsAir()then -if not self.EscortMenuReportNavigation then -self.EscortMenuReportNavigation=MENU_CLIENT:New(self.EscortClient,"Navigation",self.EscortMenu) -end -local MenuText="" -if not MenuTextFormat then -MenuText="Smoke" -else -MenuText=MenuTextFormat -end -if not self.EscortMenuSmoke then -self.EscortMenuSmoke=MENU_CLIENT:New(self.EscortClient,"Smoke",self.EscortMenuReportNavigation,ESCORT._Smoke,self) -self.EscortMenuSmokeGreen=MENU_CLIENT_COMMAND:New(self.EscortClient,"Release green smoke",self.EscortMenuSmoke,ESCORT._Smoke,self,SMOKECOLOR.Green,"Releasing green smoke!") -self.EscortMenuSmokeRed=MENU_CLIENT_COMMAND:New(self.EscortClient,"Release red smoke",self.EscortMenuSmoke,ESCORT._Smoke,self,SMOKECOLOR.Red,"Releasing red smoke!") -self.EscortMenuSmokeWhite=MENU_CLIENT_COMMAND:New(self.EscortClient,"Release white smoke",self.EscortMenuSmoke,ESCORT._Smoke,self,SMOKECOLOR.White,"Releasing white smoke!") -self.EscortMenuSmokeOrange=MENU_CLIENT_COMMAND:New(self.EscortClient,"Release orange smoke",self.EscortMenuSmoke,ESCORT._Smoke,self,SMOKECOLOR.Orange,"Releasing orange smoke!") -self.EscortMenuSmokeBlue=MENU_CLIENT_COMMAND:New(self.EscortClient,"Release blue smoke",self.EscortMenuSmoke,ESCORT._Smoke,self,SMOKECOLOR.Blue,"Releasing blue smoke!") -end -end -return self -end -function ESCORT:MenuReportTargets(Seconds) -self:F({Seconds}) -if not self.EscortMenuReportNearbyTargets then -self.EscortMenuReportNearbyTargets=MENU_CLIENT:New(self.EscortClient,"Report targets",self.EscortMenu) -end -if not Seconds then -Seconds=30 -end -self.EscortMenuReportNearbyTargetsNow=MENU_CLIENT_COMMAND:New(self.EscortClient,"Report targets now!",self.EscortMenuReportNearbyTargets,ESCORT._ReportNearbyTargetsNow,self) -self.EscortMenuReportNearbyTargetsOn=MENU_CLIENT_COMMAND:New(self.EscortClient,"Report targets on",self.EscortMenuReportNearbyTargets,ESCORT._SwitchReportNearbyTargets,self,true) -self.EscortMenuReportNearbyTargetsOff=MENU_CLIENT_COMMAND:New(self.EscortClient,"Report targets off",self.EscortMenuReportNearbyTargets,ESCORT._SwitchReportNearbyTargets,self,false) -self.EscortMenuAttackNearbyTargets=MENU_CLIENT:New(self.EscortClient,"Attack targets",self.EscortMenu) -self.ReportTargetsScheduler=SCHEDULER:New(self,self._ReportTargetsScheduler,{},1,Seconds) -return self -end -function ESCORT:MenuAssistedAttack() -self:F() -self.EscortMenuTargetAssistance=MENU_CLIENT:New(self.EscortClient,"Request assistance from",self.EscortMenu) -return self -end -function ESCORT:MenuROE(MenuTextFormat) -self:F(MenuTextFormat) -if not self.EscortMenuROE then -self.EscortMenuROE=MENU_CLIENT:New(self.EscortClient,"ROE",self.EscortMenu) -if self.EscortGroup:OptionROEHoldFirePossible()then -self.EscortMenuROEHoldFire=MENU_CLIENT_COMMAND:New(self.EscortClient,"Hold Fire",self.EscortMenuROE,ESCORT._ROE,self,self.EscortGroup:OptionROEHoldFire(),"Holding weapons!") -end -if self.EscortGroup:OptionROEReturnFirePossible()then -self.EscortMenuROEReturnFire=MENU_CLIENT_COMMAND:New(self.EscortClient,"Return Fire",self.EscortMenuROE,ESCORT._ROE,self,self.EscortGroup:OptionROEReturnFire(),"Returning fire!") -end -if self.EscortGroup:OptionROEOpenFirePossible()then -self.EscortMenuROEOpenFire=MENU_CLIENT_COMMAND:New(self.EscortClient,"Open Fire",self.EscortMenuROE,ESCORT._ROE,self,self.EscortGroup:OptionROEOpenFire(),"Opening fire on designated targets!!") -end -if self.EscortGroup:OptionROEWeaponFreePossible()then -self.EscortMenuROEWeaponFree=MENU_CLIENT_COMMAND:New(self.EscortClient,"Weapon Free",self.EscortMenuROE,ESCORT._ROE,self,self.EscortGroup:OptionROEWeaponFree(),"Opening fire on targets of opportunity!") -end -end -return self -end -function ESCORT:MenuEvasion(MenuTextFormat) -self:F(MenuTextFormat) -if self.EscortGroup:IsAir()then -if not self.EscortMenuEvasion then -self.EscortMenuEvasion=MENU_CLIENT:New(self.EscortClient,"Evasion",self.EscortMenu) -if self.EscortGroup:OptionROTNoReactionPossible()then -self.EscortMenuEvasionNoReaction=MENU_CLIENT_COMMAND:New(self.EscortClient,"Fight until death",self.EscortMenuEvasion,ESCORT._ROT,self,self.EscortGroup:OptionROTNoReaction(),"Fighting until death!") -end -if self.EscortGroup:OptionROTPassiveDefensePossible()then -self.EscortMenuEvasionPassiveDefense=MENU_CLIENT_COMMAND:New(self.EscortClient,"Use flares, chaff and jammers",self.EscortMenuEvasion,ESCORT._ROT,self,self.EscortGroup:OptionROTPassiveDefense(),"Defending using jammers, chaff and flares!") -end -if self.EscortGroup:OptionROTEvadeFirePossible()then -self.EscortMenuEvasionEvadeFire=MENU_CLIENT_COMMAND:New(self.EscortClient,"Evade enemy fire",self.EscortMenuEvasion,ESCORT._ROT,self,self.EscortGroup:OptionROTEvadeFire(),"Evading on enemy fire!") -end -if self.EscortGroup:OptionROTVerticalPossible()then -self.EscortMenuOptionEvasionVertical=MENU_CLIENT_COMMAND:New(self.EscortClient,"Go below radar and evade fire",self.EscortMenuEvasion,ESCORT._ROT,self,self.EscortGroup:OptionROTVertical(),"Evading on enemy fire with vertical manoeuvres!") -end -end -end -return self -end -function ESCORT:MenuResumeMission() -self:F() -if not self.EscortMenuResumeMission then -self.EscortMenuResumeMission=MENU_CLIENT:New(self.EscortClient,"Resume mission from",self.EscortMenu) -end -return self -end -function ESCORT:_HoldPosition(OrbitGroup,OrbitHeight,OrbitSeconds) -local EscortGroup=self.EscortGroup -local EscortClient=self.EscortClient -local OrbitUnit=OrbitGroup:GetUnit(1) -self.FollowScheduler:Stop(self.FollowSchedule) -local PointFrom={} -local GroupVec3=EscortGroup:GetUnit(1):GetVec3() -PointFrom={} -PointFrom.x=GroupVec3.x -PointFrom.y=GroupVec3.z -PointFrom.speed=250 -PointFrom.type=AI.Task.WaypointType.TURNING_POINT -PointFrom.alt=GroupVec3.y -PointFrom.alt_type=AI.Task.AltitudeType.BARO -local OrbitPoint=OrbitUnit:GetVec2() -local PointTo={} -PointTo.x=OrbitPoint.x -PointTo.y=OrbitPoint.y -PointTo.speed=250 -PointTo.type=AI.Task.WaypointType.TURNING_POINT -PointTo.alt=OrbitHeight -PointTo.alt_type=AI.Task.AltitudeType.BARO -PointTo.task=EscortGroup:TaskOrbitCircleAtVec2(OrbitPoint,OrbitHeight,0) -local Points={PointFrom,PointTo} -EscortGroup:OptionROEHoldFire() -EscortGroup:OptionROTPassiveDefense() -EscortGroup:SetTask(EscortGroup:TaskRoute(Points)) -EscortGroup:MessageToClient("Orbiting at location.",10,EscortClient) -end -function ESCORT:_JoinUpAndFollow(Distance) -local EscortGroup=self.EscortGroup -local EscortClient=self.EscortClient -self.Distance=Distance -self:JoinUpAndFollow(EscortGroup,EscortClient,self.Distance) -end -function ESCORT:JoinUpAndFollow(EscortGroup,EscortClient,Distance) -self:F({EscortGroup,EscortClient,Distance}) -self.FollowScheduler:Stop(self.FollowSchedule) -EscortGroup:OptionROEHoldFire() -EscortGroup:OptionROTPassiveDefense() -self.EscortMode=ESCORT.MODE.FOLLOW -self.CT1=0 -self.GT1=0 -self.FollowScheduler:Start(self.FollowSchedule) -EscortGroup:MessageToClient("Rejoining and Following at "..Distance.."!",30,EscortClient) -end -function ESCORT:_Flare(Color,Message) -local EscortGroup=self.EscortGroup -local EscortClient=self.EscortClient -EscortGroup:GetUnit(1):Flare(Color) -EscortGroup:MessageToClient(Message,10,EscortClient) -end -function ESCORT:_Smoke(Color,Message) -local EscortGroup=self.EscortGroup -local EscortClient=self.EscortClient -EscortGroup:GetUnit(1):Smoke(Color) -EscortGroup:MessageToClient(Message,10,EscortClient) -end -function ESCORT:_ReportNearbyTargetsNow() -local EscortGroup=self.EscortGroup -local EscortClient=self.EscortClient -self:_ReportTargetsScheduler() -end -function ESCORT:_SwitchReportNearbyTargets(ReportTargets) -local EscortGroup=self.EscortGroup -local EscortClient=self.EscortClient -self.ReportTargets=ReportTargets -if self.ReportTargets then -if not self.ReportTargetsScheduler then -self.ReportTargetsScheduler:Schedule(self,self._ReportTargetsScheduler,{},1,30) -end -else -routines.removeFunction(self.ReportTargetsScheduler) -self.ReportTargetsScheduler=nil -end -end -function ESCORT:_ScanTargets(ScanDuration) -local EscortGroup=self.EscortGroup -local EscortClient=self.EscortClient -self.FollowScheduler:Stop(self.FollowSchedule) -if EscortGroup:IsHelicopter()then -EscortGroup:PushTask( -EscortGroup:TaskControlled( -EscortGroup:TaskOrbitCircle(200,20), -EscortGroup:TaskCondition(nil,nil,nil,nil,ScanDuration,nil) -),1) -elseif EscortGroup:IsAirPlane()then -EscortGroup:PushTask( -EscortGroup:TaskControlled( -EscortGroup:TaskOrbitCircle(1000,500), -EscortGroup:TaskCondition(nil,nil,nil,nil,ScanDuration,nil) -),1) -end -EscortGroup:MessageToClient("Scanning targets for "..ScanDuration.." seconds.",ScanDuration,EscortClient) -if self.EscortMode==ESCORT.MODE.FOLLOW then -self.FollowScheduler:Start(self.FollowSchedule) -end -end -function _Resume(EscortGroup) -env.info('_Resume') -local Escort=EscortGroup:GetState(EscortGroup,"Escort") -env.info("EscortMode = "..Escort.EscortMode) -if Escort.EscortMode==ESCORT.MODE.FOLLOW then -Escort:JoinUpAndFollow(EscortGroup,Escort.EscortClient,Escort.Distance) -end -end -function ESCORT:_AttackTarget(DetectedItemID) -local EscortGroup=self.EscortGroup -self:E(EscortGroup) -local EscortClient=self.EscortClient -self.FollowScheduler:Stop(self.FollowSchedule) -if EscortGroup:IsAir()then -EscortGroup:OptionROEOpenFire() -EscortGroup:OptionROTPassiveDefense() -EscortGroup:SetState(EscortGroup,"Escort",self) -local DetectedSet=self.Detection:GetDetectedSet(DetectedItemID) -local Tasks={} -DetectedSet:ForEachUnit( -function(DetectedUnit,Tasks) -if DetectedUnit:IsAlive()then -Tasks[#Tasks+1]=EscortGroup:TaskAttackUnit(DetectedUnit) -end -end,Tasks -) -Tasks[#Tasks+1]=EscortGroup:TaskFunction("_Resume",{"''"}) -EscortGroup:SetTask( -EscortGroup:TaskCombo( -Tasks -),1 -) -else -local DetectedSet=self.Detection:GetDetectedSet(DetectedItemID) -local Tasks={} -DetectedSet:ForEachUnit( -function(DetectedUnit,Tasks) -if DetectedUnit:IsAlive()then -Tasks[#Tasks+1]=EscortGroup:TaskFireAtPoint(DetectedUnit:GetVec2(),50) -end -end,Tasks -) -EscortGroup:SetTask( -EscortGroup:TaskCombo( -Tasks -),1 -) -end -EscortGroup:MessageToClient("Engaging Designated Unit!",10,EscortClient) -end -function ESCORT:_AssistTarget(EscortGroupAttack,DetectedItemID) -local EscortGroup=self.EscortGroup -local EscortClient=self.EscortClient -self.FollowScheduler:Stop(self.FollowSchedule) -if EscortGroupAttack:IsAir()then -EscortGroupAttack:OptionROEOpenFire() -EscortGroupAttack:OptionROTVertical() -local DetectedSet=self.Detection:GetDetectedSet(DetectedItemID) -local Tasks={} -DetectedSet:ForEachUnit( -function(DetectedUnit,Tasks) -if DetectedUnit:IsAlive()then -Tasks[#Tasks+1]=EscortGroupAttack:TaskAttackUnit(DetectedUnit) -end -end,Tasks -) -Tasks[#Tasks+1]=EscortGroupAttack:TaskOrbitCircle(500,350) -EscortGroupAttack:SetTask( -EscortGroupAttack:TaskCombo( -Tasks -),1 -) -else -local DetectedSet=self.Detection:GetDetectedSet(DetectedItemID) -local Tasks={} -DetectedSet:ForEachUnit( -function(DetectedUnit,Tasks) -if DetectedUnit:IsAlive()then -Tasks[#Tasks+1]=EscortGroupAttack:TaskFireAtPoint(DetectedUnit:GetVec2(),50) -end -end,Tasks -) -EscortGroupAttack:SetTask( -EscortGroupAttack:TaskCombo( -Tasks -),1 -) -end -EscortGroupAttack:MessageToClient("Assisting with the destroying the enemy unit!",10,EscortClient) -end -function ESCORT:_ROE(EscortROEFunction,EscortROEMessage) -local EscortGroup=self.EscortGroup -local EscortClient=self.EscortClient -pcall(function()EscortROEFunction()end) -EscortGroup:MessageToClient(EscortROEMessage,10,EscortClient) -end -function ESCORT:_ROT(EscortROTFunction,EscortROTMessage) -local EscortGroup=self.EscortGroup -local EscortClient=self.EscortClient -pcall(function()EscortROTFunction()end) -EscortGroup:MessageToClient(EscortROTMessage,10,EscortClient) -end -function ESCORT:_ResumeMission(WayPoint) -local EscortGroup=self.EscortGroup -local EscortClient=self.EscortClient -self.FollowScheduler:Stop(self.FollowSchedule) -local WayPoints=EscortGroup:GetTaskRoute() -self:T(WayPoint,WayPoints) -for WayPointIgnore=1,WayPoint do -table.remove(WayPoints,1) -end -SCHEDULER:New(EscortGroup,EscortGroup.SetTask,{EscortGroup:TaskRoute(WayPoints)},1) -EscortGroup:MessageToClient("Resuming mission from waypoint "..WayPoint..".",10,EscortClient) -end -function ESCORT:RegisterRoute() -self:F() -local EscortGroup=self.EscortGroup -local TaskPoints=EscortGroup:GetTaskRoute() -self:T(TaskPoints) -return TaskPoints -end -function ESCORT:_FollowScheduler() -self:F({self.FollowDistance}) -self:T({self.EscortClient.UnitName,self.EscortGroup.GroupName}) -if self.EscortGroup:IsAlive()and self.EscortClient:IsAlive()then -local ClientUnit=self.EscortClient:GetClientGroupUnit() -local GroupUnit=self.EscortGroup:GetUnit(1) -local FollowDistance=self.FollowDistance -self:T({ClientUnit.UnitName,GroupUnit.UnitName}) -if self.CT1==0 and self.GT1==0 then -self.CV1=ClientUnit:GetVec3() -self:T({"self.CV1",self.CV1}) -self.CT1=timer.getTime() -self.GV1=GroupUnit:GetVec3() -self.GT1=timer.getTime() -else -local CT1=self.CT1 -local CT2=timer.getTime() -local CV1=self.CV1 -local CV2=ClientUnit:GetVec3() -self.CT1=CT2 -self.CV1=CV2 -local CD=((CV2.x-CV1.x)^2+(CV2.y-CV1.y)^2+(CV2.z-CV1.z)^2)^0.5 -local CT=CT2-CT1 -local CS=(3600/CT)*(CD/1000) -self:T2({"Client:",CS,CD,CT,CV2,CV1,CT2,CT1}) -local GT1=self.GT1 -local GT2=timer.getTime() -local GV1=self.GV1 -local GV2=GroupUnit:GetVec3() -self.GT1=GT2 -self.GV1=GV2 -local GD=((GV2.x-GV1.x)^2+(GV2.y-GV1.y)^2+(GV2.z-GV1.z)^2)^0.5 -local GT=GT2-GT1 -local GS=(3600/GT)*(GD/1000) -self:T2({"Group:",GS,GD,GT,GV2,GV1,GT2,GT1}) -local GV={x=GV2.x-CV2.x,y=GV2.y-CV2.y,z=GV2.z-CV2.z} -local GH2={x=GV2.x,y=CV2.y,z=GV2.z} -local alpha=math.atan2(GV.z,GV.x) -local CVI={x=CV2.x+FollowDistance*math.cos(alpha), -y=GH2.y, -z=CV2.z+FollowDistance*math.sin(alpha), -} -local DV={x=CV2.x-CVI.x,y=CV2.y-CVI.y,z=CV2.z-CVI.z} -local DVu={x=DV.x/FollowDistance,y=DV.y/FollowDistance,z=DV.z/FollowDistance} -local GDV={x=DVu.x*CS*8+CVI.x,y=CVI.y,z=DVu.z*CS*8+CVI.z} -if self.SmokeDirectionVector==true then -trigger.action.smoke(GDV,trigger.smokeColor.Red) -end -self:T2({"CV2:",CV2}) -self:T2({"CVI:",CVI}) -self:T2({"GDV:",GDV}) -local CatchUpDistance=((GDV.x-GV2.x)^2+(GDV.y-GV2.y)^2+(GDV.z-GV2.z)^2)^0.5 -local Time=10 -local CatchUpSpeed=(CatchUpDistance-(CS*8.4))/Time -local Speed=CS+CatchUpSpeed -if Speed<0 then -Speed=0 -end -self:T({"Client Speed, Escort Speed, Speed, FollowDistance, Time:",CS,GS,Speed,FollowDistance,Time}) -self.EscortGroup:RouteToVec3(GDV,Speed/3.6) -end -return true -end -return false -end -function ESCORT:_ReportTargetsScheduler() -self:F(self.EscortGroup:GetName()) -if self.EscortGroup:IsAlive()and self.EscortClient:IsAlive()then -if true then -local EscortGroupName=self.EscortGroup:GetName() -self.EscortMenuAttackNearbyTargets:RemoveSubMenus() -if self.EscortMenuTargetAssistance then -self.EscortMenuTargetAssistance:RemoveSubMenus() -end -local DetectedItems=self.Detection:GetDetectedItems() -self:E(DetectedItems) -local DetectedTargets=false -local DetectedMsgs={} -for ClientEscortGroupName,EscortGroupData in pairs(self.EscortClient._EscortGroups)do -local ClientEscortTargets=EscortGroupData.Detection -for DetectedItemID,DetectedItem in pairs(DetectedItems)do -self:E({DetectedItemID,DetectedItem}) -local DetectedItemReportSummary=self.Detection:DetectedItemReportSummary(DetectedItemID,EscortGroupData.EscortGroup,_DATABASE:GetPlayerSettings(self.EscortClient:GetPlayerName())) -if ClientEscortGroupName==EscortGroupName then -local DetectedMsg=DetectedItemReportSummary:Text("\n") -DetectedMsgs[#DetectedMsgs+1]=DetectedMsg -self:T(DetectedMsg) -MENU_CLIENT_COMMAND:New(self.EscortClient, -DetectedMsg, -self.EscortMenuAttackNearbyTargets, -ESCORT._AttackTarget, -self, -DetectedItemID -) -else -if self.EscortMenuTargetAssistance then -local DetectedMsg=DetectedItemReportSummary:Text("\n") -self:T(DetectedMsg) -local MenuTargetAssistance=MENU_CLIENT:New(self.EscortClient,EscortGroupData.EscortName,self.EscortMenuTargetAssistance) -MENU_CLIENT_COMMAND:New(self.EscortClient, -DetectedMsg, -MenuTargetAssistance, -ESCORT._AssistTarget, -self, -EscortGroupData.EscortGroup, -DetectedItemID -) -end -end -DetectedTargets=true -end -end -self:E(DetectedMsgs) -if DetectedTargets then -self.EscortGroup:MessageToClient("Reporting detected targets:\n"..table.concat(DetectedMsgs,"\n"),20,self.EscortClient) -else -self.EscortGroup:MessageToClient("No targets detected.",10,self.EscortClient) -end -return true -else -end -end -return false -end -MISSILETRAINER={ -ClassName="MISSILETRAINER", -TrackingMissiles={}, -} -function MISSILETRAINER._Alive(Client,self) -if self.Briefing then -Client:Message(self.Briefing,15,"Trainer") -end -if self.MenusOnOff==true then -Client:Message("Use the 'Radio Menu' -> 'Other (F10)' -> 'Missile Trainer' menu options to change the Missile Trainer settings (for all players).",15,"Trainer") -Client.MainMenu=MENU_CLIENT:New(Client,"Missile Trainer",nil) -Client.MenuMessages=MENU_CLIENT:New(Client,"Messages",Client.MainMenu) -Client.MenuOn=MENU_CLIENT_COMMAND:New(Client,"Messages On",Client.MenuMessages,self._MenuMessages,{MenuSelf=self,MessagesOnOff=true}) -Client.MenuOff=MENU_CLIENT_COMMAND:New(Client,"Messages Off",Client.MenuMessages,self._MenuMessages,{MenuSelf=self,MessagesOnOff=false}) -Client.MenuTracking=MENU_CLIENT:New(Client,"Tracking",Client.MainMenu) -Client.MenuTrackingToAll=MENU_CLIENT_COMMAND:New(Client,"To All",Client.MenuTracking,self._MenuMessages,{MenuSelf=self,TrackingToAll=true}) -Client.MenuTrackingToTarget=MENU_CLIENT_COMMAND:New(Client,"To Target",Client.MenuTracking,self._MenuMessages,{MenuSelf=self,TrackingToAll=false}) -Client.MenuTrackOn=MENU_CLIENT_COMMAND:New(Client,"Tracking On",Client.MenuTracking,self._MenuMessages,{MenuSelf=self,TrackingOnOff=true}) -Client.MenuTrackOff=MENU_CLIENT_COMMAND:New(Client,"Tracking Off",Client.MenuTracking,self._MenuMessages,{MenuSelf=self,TrackingOnOff=false}) -Client.MenuTrackIncrease=MENU_CLIENT_COMMAND:New(Client,"Frequency Increase",Client.MenuTracking,self._MenuMessages,{MenuSelf=self,TrackingFrequency=-1}) -Client.MenuTrackDecrease=MENU_CLIENT_COMMAND:New(Client,"Frequency Decrease",Client.MenuTracking,self._MenuMessages,{MenuSelf=self,TrackingFrequency=1}) -Client.MenuAlerts=MENU_CLIENT:New(Client,"Alerts",Client.MainMenu) -Client.MenuAlertsToAll=MENU_CLIENT_COMMAND:New(Client,"To All",Client.MenuAlerts,self._MenuMessages,{MenuSelf=self,AlertsToAll=true}) -Client.MenuAlertsToTarget=MENU_CLIENT_COMMAND:New(Client,"To Target",Client.MenuAlerts,self._MenuMessages,{MenuSelf=self,AlertsToAll=false}) -Client.MenuHitsOn=MENU_CLIENT_COMMAND:New(Client,"Hits On",Client.MenuAlerts,self._MenuMessages,{MenuSelf=self,AlertsHitsOnOff=true}) -Client.MenuHitsOff=MENU_CLIENT_COMMAND:New(Client,"Hits Off",Client.MenuAlerts,self._MenuMessages,{MenuSelf=self,AlertsHitsOnOff=false}) -Client.MenuLaunchesOn=MENU_CLIENT_COMMAND:New(Client,"Launches On",Client.MenuAlerts,self._MenuMessages,{MenuSelf=self,AlertsLaunchesOnOff=true}) -Client.MenuLaunchesOff=MENU_CLIENT_COMMAND:New(Client,"Launches Off",Client.MenuAlerts,self._MenuMessages,{MenuSelf=self,AlertsLaunchesOnOff=false}) -Client.MenuDetails=MENU_CLIENT:New(Client,"Details",Client.MainMenu) -Client.MenuDetailsDistanceOn=MENU_CLIENT_COMMAND:New(Client,"Range On",Client.MenuDetails,self._MenuMessages,{MenuSelf=self,DetailsRangeOnOff=true}) -Client.MenuDetailsDistanceOff=MENU_CLIENT_COMMAND:New(Client,"Range Off",Client.MenuDetails,self._MenuMessages,{MenuSelf=self,DetailsRangeOnOff=false}) -Client.MenuDetailsBearingOn=MENU_CLIENT_COMMAND:New(Client,"Bearing On",Client.MenuDetails,self._MenuMessages,{MenuSelf=self,DetailsBearingOnOff=true}) -Client.MenuDetailsBearingOff=MENU_CLIENT_COMMAND:New(Client,"Bearing Off",Client.MenuDetails,self._MenuMessages,{MenuSelf=self,DetailsBearingOnOff=false}) -Client.MenuDistance=MENU_CLIENT:New(Client,"Set distance to plane",Client.MainMenu) -Client.MenuDistance50=MENU_CLIENT_COMMAND:New(Client,"50 meter",Client.MenuDistance,self._MenuMessages,{MenuSelf=self,Distance=50/1000}) -Client.MenuDistance100=MENU_CLIENT_COMMAND:New(Client,"100 meter",Client.MenuDistance,self._MenuMessages,{MenuSelf=self,Distance=100/1000}) -Client.MenuDistance150=MENU_CLIENT_COMMAND:New(Client,"150 meter",Client.MenuDistance,self._MenuMessages,{MenuSelf=self,Distance=150/1000}) -Client.MenuDistance200=MENU_CLIENT_COMMAND:New(Client,"200 meter",Client.MenuDistance,self._MenuMessages,{MenuSelf=self,Distance=200/1000}) -else -if Client.MainMenu then -Client.MainMenu:Remove() -end -end -local ClientID=Client:GetID() -self:T(ClientID) -if not self.TrackingMissiles[ClientID]then -self.TrackingMissiles[ClientID]={} -end -self.TrackingMissiles[ClientID].Client=Client -if not self.TrackingMissiles[ClientID].MissileData then -self.TrackingMissiles[ClientID].MissileData={} -end -end -function MISSILETRAINER:New(Distance,Briefing) -local self=BASE:Inherit(self,BASE:New()) -self:F(Distance) -if Briefing then -self.Briefing=Briefing -end -self.Schedulers={} -self.SchedulerID=0 -self.MessageInterval=2 -self.MessageLastTime=timer.getTime() -self.Distance=Distance/1000 -self:HandleEvent(EVENTS.Shot) -self.DBClients=SET_CLIENT:New():FilterStart() -self.DBClients:ForEachClient( -function(Client) -self:E("ForEach:"..Client.UnitName) -Client:Alive(self._Alive,self) -end -) -self.MessagesOnOff=true -self.TrackingToAll=false -self.TrackingOnOff=true -self.TrackingFrequency=3 -self.AlertsToAll=true -self.AlertsHitsOnOff=true -self.AlertsLaunchesOnOff=true -self.DetailsRangeOnOff=true -self.DetailsBearingOnOff=true -self.MenusOnOff=true -self.TrackingMissiles={} -self.TrackingScheduler=SCHEDULER:New(self,self._TrackMissiles,{},0.5,0.05,0) -return self -end -function MISSILETRAINER:InitMessagesOnOff(MessagesOnOff) -self:F(MessagesOnOff) -self.MessagesOnOff=MessagesOnOff -if self.MessagesOnOff==true then -MESSAGE:New("Messages ON",15,"Menu"):ToAll() -else -MESSAGE:New("Messages OFF",15,"Menu"):ToAll() -end -return self -end -function MISSILETRAINER:InitTrackingToAll(TrackingToAll) -self:F(TrackingToAll) -self.TrackingToAll=TrackingToAll -if self.TrackingToAll==true then -MESSAGE:New("Missile tracking to all players ON",15,"Menu"):ToAll() -else -MESSAGE:New("Missile tracking to all players OFF",15,"Menu"):ToAll() -end -return self -end -function MISSILETRAINER:InitTrackingOnOff(TrackingOnOff) -self:F(TrackingOnOff) -self.TrackingOnOff=TrackingOnOff -if self.TrackingOnOff==true then -MESSAGE:New("Missile tracking ON",15,"Menu"):ToAll() -else -MESSAGE:New("Missile tracking OFF",15,"Menu"):ToAll() -end -return self -end -function MISSILETRAINER:InitTrackingFrequency(TrackingFrequency) -self:F(TrackingFrequency) -self.TrackingFrequency=self.TrackingFrequency+TrackingFrequency -if self.TrackingFrequency<0.5 then -self.TrackingFrequency=0.5 -end -if self.TrackingFrequency then -MESSAGE:New("Missile tracking frequency is "..self.TrackingFrequency.." seconds.",15,"Menu"):ToAll() -end -return self -end -function MISSILETRAINER:InitAlertsToAll(AlertsToAll) -self:F(AlertsToAll) -self.AlertsToAll=AlertsToAll -if self.AlertsToAll==true then -MESSAGE:New("Alerts to all players ON",15,"Menu"):ToAll() -else -MESSAGE:New("Alerts to all players OFF",15,"Menu"):ToAll() -end -return self -end -function MISSILETRAINER:InitAlertsHitsOnOff(AlertsHitsOnOff) -self:F(AlertsHitsOnOff) -self.AlertsHitsOnOff=AlertsHitsOnOff -if self.AlertsHitsOnOff==true then -MESSAGE:New("Alerts Hits ON",15,"Menu"):ToAll() -else -MESSAGE:New("Alerts Hits OFF",15,"Menu"):ToAll() -end -return self -end -function MISSILETRAINER:InitAlertsLaunchesOnOff(AlertsLaunchesOnOff) -self:F(AlertsLaunchesOnOff) -self.AlertsLaunchesOnOff=AlertsLaunchesOnOff -if self.AlertsLaunchesOnOff==true then -MESSAGE:New("Alerts Launches ON",15,"Menu"):ToAll() -else -MESSAGE:New("Alerts Launches OFF",15,"Menu"):ToAll() -end -return self -end -function MISSILETRAINER:InitRangeOnOff(DetailsRangeOnOff) -self:F(DetailsRangeOnOff) -self.DetailsRangeOnOff=DetailsRangeOnOff -if self.DetailsRangeOnOff==true then -MESSAGE:New("Range display ON",15,"Menu"):ToAll() -else -MESSAGE:New("Range display OFF",15,"Menu"):ToAll() -end -return self -end -function MISSILETRAINER:InitBearingOnOff(DetailsBearingOnOff) -self:F(DetailsBearingOnOff) -self.DetailsBearingOnOff=DetailsBearingOnOff -if self.DetailsBearingOnOff==true then -MESSAGE:New("Bearing display OFF",15,"Menu"):ToAll() -else -MESSAGE:New("Bearing display OFF",15,"Menu"):ToAll() -end -return self -end -function MISSILETRAINER:InitMenusOnOff(MenusOnOff) -self:F(MenusOnOff) -self.MenusOnOff=MenusOnOff -if self.MenusOnOff==true then -MESSAGE:New("Menus are ENABLED (only when a player rejoins a slot)",15,"Menu"):ToAll() -else -MESSAGE:New("Menus are DISABLED",15,"Menu"):ToAll() -end -return self -end -function MISSILETRAINER._MenuMessages(MenuParameters) -local self=MenuParameters.MenuSelf -if MenuParameters.MessagesOnOff~=nil then -self:InitMessagesOnOff(MenuParameters.MessagesOnOff) -end -if MenuParameters.TrackingToAll~=nil then -self:InitTrackingToAll(MenuParameters.TrackingToAll) -end -if MenuParameters.TrackingOnOff~=nil then -self:InitTrackingOnOff(MenuParameters.TrackingOnOff) -end -if MenuParameters.TrackingFrequency~=nil then -self:InitTrackingFrequency(MenuParameters.TrackingFrequency) -end -if MenuParameters.AlertsToAll~=nil then -self:InitAlertsToAll(MenuParameters.AlertsToAll) -end -if MenuParameters.AlertsHitsOnOff~=nil then -self:InitAlertsHitsOnOff(MenuParameters.AlertsHitsOnOff) -end -if MenuParameters.AlertsLaunchesOnOff~=nil then -self:InitAlertsLaunchesOnOff(MenuParameters.AlertsLaunchesOnOff) -end -if MenuParameters.DetailsRangeOnOff~=nil then -self:InitRangeOnOff(MenuParameters.DetailsRangeOnOff) -end -if MenuParameters.DetailsBearingOnOff~=nil then -self:InitBearingOnOff(MenuParameters.DetailsBearingOnOff) -end -if MenuParameters.Distance~=nil then -self.Distance=MenuParameters.Distance -MESSAGE:New("Hit detection distance set to "..(self.Distance*1000).." meters",15,"Menu"):ToAll() -end -end -function MISSILETRAINER:OnEventShot(EVentData) -self:F({EVentData}) -local TrainerSourceDCSUnit=EVentData.IniDCSUnit -local TrainerSourceDCSUnitName=EVentData.IniDCSUnitName -local TrainerWeapon=EVentData.Weapon -local TrainerWeaponName=EVentData.WeaponName -self:T("Missile Launched = "..TrainerWeaponName) -local TrainerTargetDCSUnit=TrainerWeapon:getTarget() -if TrainerTargetDCSUnit then -local TrainerTargetDCSUnitName=Unit.getName(TrainerTargetDCSUnit) -local TrainerTargetSkill=_DATABASE.Templates.Units[TrainerTargetDCSUnitName].Template.skill -self:T(TrainerTargetDCSUnitName) -local Client=self.DBClients:FindClient(TrainerTargetDCSUnitName) -if Client then -local TrainerSourceUnit=UNIT:Find(TrainerSourceDCSUnit) -local TrainerTargetUnit=UNIT:Find(TrainerTargetDCSUnit) -if self.MessagesOnOff==true and self.AlertsLaunchesOnOff==true then -local Message=MESSAGE:New( -string.format("%s launched a %s", -TrainerSourceUnit:GetTypeName(), -TrainerWeaponName -)..self:_AddRange(Client,TrainerWeapon)..self:_AddBearing(Client,TrainerWeapon),5,"Launch Alert") -if self.AlertsToAll then -Message:ToAll() -else -Message:ToClient(Client) -end -end -local ClientID=Client:GetID() -self:T(ClientID) -local MissileData={} -MissileData.TrainerSourceUnit=TrainerSourceUnit -MissileData.TrainerWeapon=TrainerWeapon -MissileData.TrainerTargetUnit=TrainerTargetUnit -MissileData.TrainerWeaponTypeName=TrainerWeapon:getTypeName() -MissileData.TrainerWeaponLaunched=true -table.insert(self.TrackingMissiles[ClientID].MissileData,MissileData) -end -else -if(TrainerWeapon:getTypeName()=="9M311")then -SCHEDULER:New(TrainerWeapon,TrainerWeapon.destroy,{},1) -else -end -end -end -function MISSILETRAINER:_AddRange(Client,TrainerWeapon) -local RangeText="" -if self.DetailsRangeOnOff then -local PositionMissile=TrainerWeapon:getPoint() -local TargetVec3=Client:GetVec3() -local Range=((PositionMissile.x-TargetVec3.x)^2+ -(PositionMissile.y-TargetVec3.y)^2+ -(PositionMissile.z-TargetVec3.z)^2 -)^0.5/1000 -RangeText=string.format(", at %4.2fkm",Range) -end -return RangeText -end -function MISSILETRAINER:_AddBearing(Client,TrainerWeapon) -local BearingText="" -if self.DetailsBearingOnOff then -local PositionMissile=TrainerWeapon:getPoint() -local TargetVec3=Client:GetVec3() -self:T2({TargetVec3,PositionMissile}) -local DirectionVector={x=PositionMissile.x-TargetVec3.x,y=PositionMissile.y-TargetVec3.y,z=PositionMissile.z-TargetVec3.z} -local DirectionRadians=math.atan2(DirectionVector.z,DirectionVector.x) -if DirectionRadians<0 then -DirectionRadians=DirectionRadians+2*math.pi -end -local DirectionDegrees=DirectionRadians*180/math.pi -BearingText=string.format(", %d degrees",DirectionDegrees) -end -return BearingText -end -function MISSILETRAINER:_TrackMissiles() -self:F2() -local ShowMessages=false -if self.MessagesOnOff and self.MessageLastTime+self.TrackingFrequency<=timer.getTime()then -self.MessageLastTime=timer.getTime() -ShowMessages=true -end -for ClientDataID,ClientData in pairs(self.TrackingMissiles)do -local Client=ClientData.Client -if Client and Client:IsAlive()then -for MissileDataID,MissileData in pairs(ClientData.MissileData)do -self:T3(MissileDataID) -local TrainerSourceUnit=MissileData.TrainerSourceUnit -local TrainerWeapon=MissileData.TrainerWeapon -local TrainerTargetUnit=MissileData.TrainerTargetUnit -local TrainerWeaponTypeName=MissileData.TrainerWeaponTypeName -local TrainerWeaponLaunched=MissileData.TrainerWeaponLaunched -if Client and Client:IsAlive()and TrainerSourceUnit and TrainerSourceUnit:IsAlive()and TrainerWeapon and TrainerWeapon:isExist()and TrainerTargetUnit and TrainerTargetUnit:IsAlive()then -local PositionMissile=TrainerWeapon:getPosition().p -local TargetVec3=Client:GetVec3() -local Distance=((PositionMissile.x-TargetVec3.x)^2+ -(PositionMissile.y-TargetVec3.y)^2+ -(PositionMissile.z-TargetVec3.z)^2 -)^0.5/1000 -if Distance<=self.Distance then -TrainerWeapon:destroy() -if self.MessagesOnOff==true and self.AlertsHitsOnOff==true then -self:T("killed") -local Message=MESSAGE:New( -string.format("%s launched by %s killed %s", -TrainerWeapon:getTypeName(), -TrainerSourceUnit:GetTypeName(), -TrainerTargetUnit:GetPlayerName() -),15,"Hit Alert") -if self.AlertsToAll==true then -Message:ToAll() -else -Message:ToClient(Client) -end -MissileData=nil -table.remove(ClientData.MissileData,MissileDataID) -self:T(ClientData.MissileData) -end -end -else -if not(TrainerWeapon and TrainerWeapon:isExist())then -if self.MessagesOnOff==true and self.AlertsLaunchesOnOff==true then -local Message=MESSAGE:New( -string.format("%s launched by %s self destructed!", -TrainerWeaponTypeName, -TrainerSourceUnit:GetTypeName() -),5,"Tracking") -if self.AlertsToAll==true then -Message:ToAll() -else -Message:ToClient(Client) -end -end -MissileData=nil -table.remove(ClientData.MissileData,MissileDataID) -self:T(ClientData.MissileData) -end -end -end -else -self.TrackingMissiles[ClientDataID]=nil -end -end -if ShowMessages==true and self.MessagesOnOff==true and self.TrackingOnOff==true then -for ClientDataID,ClientData in pairs(self.TrackingMissiles)do -local Client=ClientData.Client -ClientData.MessageToClient="" -ClientData.MessageToAll="" -for TrackingDataID,TrackingData in pairs(self.TrackingMissiles)do -for MissileDataID,MissileData in pairs(TrackingData.MissileData)do -local TrainerSourceUnit=MissileData.TrainerSourceUnit -local TrainerWeapon=MissileData.TrainerWeapon -local TrainerTargetUnit=MissileData.TrainerTargetUnit -local TrainerWeaponTypeName=MissileData.TrainerWeaponTypeName -local TrainerWeaponLaunched=MissileData.TrainerWeaponLaunched -if Client and Client:IsAlive()and TrainerSourceUnit and TrainerSourceUnit:IsAlive()and TrainerWeapon and TrainerWeapon:isExist()and TrainerTargetUnit and TrainerTargetUnit:IsAlive()then -if ShowMessages==true then -local TrackingTo -TrackingTo=string.format(" -> %s", -TrainerWeaponTypeName -) -if ClientDataID==TrackingDataID then -if ClientData.MessageToClient==""then -ClientData.MessageToClient="Missiles to You:\n" -end -ClientData.MessageToClient=ClientData.MessageToClient..TrackingTo..self:_AddRange(ClientData.Client,TrainerWeapon)..self:_AddBearing(ClientData.Client,TrainerWeapon).."\n" -else -if self.TrackingToAll==true then -if ClientData.MessageToAll==""then -ClientData.MessageToAll="Missiles to other Players:\n" -end -ClientData.MessageToAll=ClientData.MessageToAll..TrackingTo..self:_AddRange(ClientData.Client,TrainerWeapon)..self:_AddBearing(ClientData.Client,TrainerWeapon).." ( "..TrainerTargetUnit:GetPlayerName().." )\n" -end -end -end -end -end -end -if ClientData.MessageToClient~=""or ClientData.MessageToAll~=""then -local Message=MESSAGE:New(ClientData.MessageToClient..ClientData.MessageToAll,1,"Tracking"):ToClient(Client) -end -end -end -return true -end -AIRBASEPOLICE_BASE={ -ClassName="AIRBASEPOLICE_BASE", -SetClient=nil, -Airbases=nil, -AirbaseNames=nil, -} -function AIRBASEPOLICE_BASE:New(SetClient,Airbases) -local self=BASE:Inherit(self,BASE:New()) -self:E({self.ClassName,SetClient,Airbases}) -self.SetClient=SetClient -self.Airbases=Airbases -for AirbaseID,Airbase in pairs(self.Airbases)do -Airbase.ZoneBoundary=ZONE_POLYGON_BASE:New("Boundary",Airbase.PointsBoundary):SmokeZone(SMOKECOLOR.White):Flush() -for PointsRunwayID,PointsRunway in pairs(Airbase.PointsRunways)do -Airbase.ZoneRunways[PointsRunwayID]=ZONE_POLYGON_BASE:New("Runway "..PointsRunwayID,PointsRunway):SmokeZone(SMOKECOLOR.Red):Flush() -end -end -self.SetClient:ForEachClient( -function(Client) -Client:SetState(self,"Speeding",false) -Client:SetState(self,"Warnings",0) -Client:SetState(self,"Taxi",false) -end -) -self.AirbaseMonitor=SCHEDULER:New(self,self._AirbaseMonitor,{},0,2,0.05) -return self -end -function AIRBASEPOLICE_BASE:Monitor(AirbaseNames) -if AirbaseNames then -if type(AirbaseNames)=="table"then -self.AirbaseNames=AirbaseNames -else -self.AirbaseNames={AirbaseNames} -end -end -end -function AIRBASEPOLICE_BASE:_AirbaseMonitor() -for AirbaseID,Airbase in pairs(self.Airbases)do -if not self.AirbaseNames or self.AirbaseNames[AirbaseID]then -self:E(AirbaseID) -self.SetClient:ForEachClientInZone(Airbase.ZoneBoundary, -function(Client) -self:E(Client.UnitName) -if Client:IsAlive()then -local NotInRunwayZone=true -for ZoneRunwayID,ZoneRunway in pairs(Airbase.ZoneRunways)do -NotInRunwayZone=(Client:IsNotInZone(ZoneRunway)==true)and NotInRunwayZone or false -end -if NotInRunwayZone then -local Taxi=self:GetState(self,"Taxi") -self:E(Taxi) -if Taxi==false then -Client:Message("Welcome at "..AirbaseID..". The maximum taxiing speed is "..Airbase.MaximumSpeed" km/h.",20,"ATC") -self:SetState(self,"Taxi",true) -end -local VelocityVec3=Client:GetVelocity() -local Velocity=(VelocityVec3.x^2+VelocityVec3.y^2+VelocityVec3.z^2)^0.5 -local Velocity=Velocity*3.6 -local IsAboveRunway=Client:IsAboveRunway() -local IsOnGround=Client:InAir()==false -self:T(IsAboveRunway,IsOnGround) -if IsAboveRunway and IsOnGround then -if Velocity>Airbase.MaximumSpeed then -local IsSpeeding=Client:GetState(self,"Speeding") -if IsSpeeding==true then -local SpeedingWarnings=Client:GetState(self,"Warnings") -self:T(SpeedingWarnings) -if SpeedingWarnings<=3 then -Client:Message("You are speeding on the taxiway! Slow down or you will be removed from this airbase! Your current velocity is "..string.format("%2.0f km/h",Velocity),5,"Warning "..SpeedingWarnings.." / 3") -Client:SetState(self,"Warnings",SpeedingWarnings+1) -else -MESSAGE:New("Player "..Client:GetPlayerName().." is being damaged at the airbase, due to a speeding violation ...",10,"Airbase Police"):ToAll() -local function DestroyUntilHeavilyDamaged(Client) -local ClientCoord=Client:GetCoordinate() -ClientCoord:Explosion(100) -local Damage=Client:GetLife() -local InitialLife=Client:GetLife0() -MESSAGE:New("Player "..Client:GetPlayerName().." Damage ... "..Damage,5,"Airbase Police"):ToAll() -if(Damage/InitialLife)*100<80 then -Client:ScheduleStop(DestroyUntilHeavilyDamaged) -end -end -Client:ScheduleOnce(1,DestroyUntilHeavilyDamaged,Client) -trigger.action.setUserFlag("AIRCRAFT_"..Client:GetID(),100) -Client:SetState(self,"Speeding",false) -Client:SetState(self,"Warnings",0) -end -else -Client:Message("You are speeding on the taxiway, slow down now! Your current velocity is "..string.format("%2.0f km/h",Velocity),5,"Attention! ") -Client:SetState(self,"Speeding",true) -Client:SetState(self,"Warnings",1) -end -else -Client:SetState(self,"Speeding",false) -Client:SetState(self,"Warnings",0) -end -end -else -Client:SetState(self,"Speeding",false) -Client:SetState(self,"Warnings",0) -local Taxi=self:GetState(self,"Taxi") -if Taxi==true then -Client:Message("You have progressed to the runway ... Await take-off clearance ...",20,"ATC") -self:SetState(self,"Taxi",false) -end -end -end -end -) -end -end -return true -end -AIRBASEPOLICE_CAUCASUS={ -ClassName="AIRBASEPOLICE_CAUCASUS", -Airbases={ -AnapaVityazevo={ -PointsBoundary={ -[1]={["y"]=242234.85714287,["x"]=-6616.5714285726,}, -[2]={["y"]=241060.57142858,["x"]=-5585.142857144,}, -[3]={["y"]=243806.2857143,["x"]=-3962.2857142868,}, -[4]={["y"]=245240.57142858,["x"]=-4816.5714285726,}, -[5]={["y"]=244783.42857144,["x"]=-5630.8571428583,}, -[6]={["y"]=243800.57142858,["x"]=-5065.142857144,}, -[7]={["y"]=242232.00000001,["x"]=-6622.2857142868,}, -}, -PointsRunways={ -[1]={ -[1]={["y"]=242140.57142858,["x"]=-6478.8571428583,}, -[2]={["y"]=242188.57142858,["x"]=-6522.0000000011,}, -[3]={["y"]=244124.2857143,["x"]=-4344.0000000011,}, -[4]={["y"]=244068.2857143,["x"]=-4296.5714285726,}, -[5]={["y"]=242140.57142858,["x"]=-6480.0000000011,} -}, -}, -ZoneBoundary={}, -ZoneRunways={}, -MaximumSpeed=50, -}, -Batumi={ -PointsBoundary={ -[1]={["y"]=617567.14285714,["x"]=-355313.14285715,}, -[2]={["y"]=616181.42857142,["x"]=-354800.28571429,}, -[3]={["y"]=616007.14285714,["x"]=-355128.85714286,}, -[4]={["y"]=618230,["x"]=-356914.57142858,}, -[5]={["y"]=618727.14285714,["x"]=-356166,}, -[6]={["y"]=617572.85714285,["x"]=-355308.85714286,}, -}, -PointsRunways={ -[1]={ -[1]={["y"]=616442.28571429,["x"]=-355090.28571429,}, -[2]={["y"]=618450.57142857,["x"]=-356522,}, -[3]={["y"]=618407.71428571,["x"]=-356584.85714286,}, -[4]={["y"]=618361.99999999,["x"]=-356554.85714286,}, -[5]={["y"]=618324.85714285,["x"]=-356599.14285715,}, -[6]={["y"]=618250.57142856,["x"]=-356543.42857143,}, -[7]={["y"]=618257.7142857,["x"]=-356496.28571429,}, -[8]={["y"]=618237.7142857,["x"]=-356459.14285715,}, -[9]={["y"]=616555.71428571,["x"]=-355258.85714286,}, -[10]={["y"]=616486.28571428,["x"]=-355280.57142858,}, -[11]={["y"]=616410.57142856,["x"]=-355227.71428572,}, -[12]={["y"]=616441.99999999,["x"]=-355179.14285715,}, -[13]={["y"]=616401.99999999,["x"]=-355147.71428572,}, -[14]={["y"]=616441.42857142,["x"]=-355092.57142858,}, -}, -}, -ZoneBoundary={}, -ZoneRunways={}, -MaximumSpeed=50, -}, -Beslan={ -PointsBoundary={ -[1]={["y"]=842082.57142857,["x"]=-148445.14285715,}, -[2]={["y"]=845237.71428572,["x"]=-148639.71428572,}, -[3]={["y"]=845232,["x"]=-148765.42857143,}, -[4]={["y"]=844220.57142857,["x"]=-149168.28571429,}, -[5]={["y"]=843274.85714286,["x"]=-149125.42857143,}, -[6]={["y"]=842077.71428572,["x"]=-148554,}, -[7]={["y"]=842083.42857143,["x"]=-148445.42857143,}, -}, -PointsRunways={ -[1]={ -[1]={["y"]=842104.57142857,["x"]=-148460.57142857,}, -[2]={["y"]=845225.71428572,["x"]=-148656,}, -[3]={["y"]=845220.57142858,["x"]=-148750,}, -[4]={["y"]=842098.85714286,["x"]=-148556.28571429,}, -[5]={["y"]=842104,["x"]=-148460.28571429,}, -}, -}, -ZoneBoundary={}, -ZoneRunways={}, -MaximumSpeed=50, -}, -Gelendzhik={ -PointsBoundary={ -[1]={["y"]=297856.00000001,["x"]=-51151.428571429,}, -[2]={["y"]=299044.57142858,["x"]=-49720.000000001,}, -[3]={["y"]=298861.71428572,["x"]=-49580.000000001,}, -[4]={["y"]=298198.85714286,["x"]=-49842.857142858,}, -[5]={["y"]=297990.28571429,["x"]=-50151.428571429,}, -[6]={["y"]=297696.00000001,["x"]=-51054.285714286,}, -[7]={["y"]=297850.28571429,["x"]=-51160.000000001,}, -}, -PointsRunways={ -[1]={ -[1]={["y"]=297834.00000001,["x"]=-51107.428571429,}, -[2]={["y"]=297786.57142858,["x"]=-51068.857142858,}, -[3]={["y"]=298946.57142858,["x"]=-49686.000000001,}, -[4]={["y"]=298993.14285715,["x"]=-49725.714285715,}, -[5]={["y"]=297835.14285715,["x"]=-51107.714285715,}, -}, -}, -ZoneBoundary={}, -ZoneRunways={}, -MaximumSpeed=50, -}, -Gudauta={ -PointsBoundary={ -[1]={["y"]=517246.57142857,["x"]=-197850.28571429,}, -[2]={["y"]=516749.42857142,["x"]=-198070.28571429,}, -[3]={["y"]=515755.14285714,["x"]=-197598.85714286,}, -[4]={["y"]=515369.42857142,["x"]=-196538.85714286,}, -[5]={["y"]=515623.71428571,["x"]=-195618.85714286,}, -[6]={["y"]=515946.57142857,["x"]=-195510.28571429,}, -[7]={["y"]=517243.71428571,["x"]=-197858.85714286,}, -}, -PointsRunways={ -[1]={ -[1]={["y"]=517096.57142857,["x"]=-197804.57142857,}, -[2]={["y"]=515880.85714285,["x"]=-195590.28571429,}, -[3]={["y"]=515812.28571428,["x"]=-195628.85714286,}, -[4]={["y"]=517036.57142857,["x"]=-197834.57142857,}, -[5]={["y"]=517097.99999999,["x"]=-197807.42857143,}, -}, -}, -ZoneBoundary={}, -ZoneRunways={}, -MaximumSpeed=50, -}, -Kobuleti={ -PointsBoundary={ -[1]={["y"]=634427.71428571,["x"]=-318290.28571429,}, -[2]={["y"]=635033.42857143,["x"]=-317550.2857143,}, -[3]={["y"]=635864.85714286,["x"]=-317333.14285715,}, -[4]={["y"]=636967.71428571,["x"]=-317261.71428572,}, -[5]={["y"]=637144.85714286,["x"]=-317913.14285715,}, -[6]={["y"]=634630.57142857,["x"]=-318687.42857144,}, -[7]={["y"]=634424.85714286,["x"]=-318290.2857143,}, -}, -PointsRunways={ -[1]={ -[1]={["y"]=634509.71428571,["x"]=-318339.42857144,}, -[2]={["y"]=636767.42857143,["x"]=-317516.57142858,}, -[3]={["y"]=636790,["x"]=-317575.71428572,}, -[4]={["y"]=634531.42857143,["x"]=-318398.00000001,}, -[5]={["y"]=634510.28571429,["x"]=-318339.71428572,}, -}, -}, -ZoneBoundary={}, -ZoneRunways={}, -MaximumSpeed=50, -}, -KrasnodarCenter={ -PointsBoundary={ -[1]={["y"]=366680.28571429,["x"]=11699.142857142,}, -[2]={["y"]=366654.28571429,["x"]=11225.142857142,}, -[3]={["y"]=367497.14285715,["x"]=11082.285714285,}, -[4]={["y"]=368025.71428572,["x"]=10396.57142857,}, -[5]={["y"]=369854.28571429,["x"]=11367.999999999,}, -[6]={["y"]=369840.00000001,["x"]=11910.857142856,}, -[7]={["y"]=366682.57142858,["x"]=11697.999999999,}, -}, -PointsRunways={ -[1]={ -[1]={["y"]=369205.42857144,["x"]=11789.142857142,}, -[2]={["y"]=369209.71428572,["x"]=11714.857142856,}, -[3]={["y"]=366699.71428572,["x"]=11581.714285713,}, -[4]={["y"]=366698.28571429,["x"]=11659.142857142,}, -[5]={["y"]=369208.85714286,["x"]=11788.57142857,}, -}, -}, -ZoneBoundary={}, -ZoneRunways={}, -MaximumSpeed=50, -}, -KrasnodarPashkovsky={ -PointsBoundary={ -[1]={["y"]=386754,["x"]=6476.5714285703,}, -[2]={["y"]=389182.57142858,["x"]=8722.2857142846,}, -[3]={["y"]=388832.57142858,["x"]=9086.5714285703,}, -[4]={["y"]=386961.14285715,["x"]=7707.9999999989,}, -[5]={["y"]=385404,["x"]=9179.4285714274,}, -[6]={["y"]=383239.71428572,["x"]=7386.5714285703,}, -[7]={["y"]=383954,["x"]=6486.5714285703,}, -[8]={["y"]=385775.42857143,["x"]=8097.9999999989,}, -[9]={["y"]=386804,["x"]=7319.4285714274,}, -[10]={["y"]=386375.42857143,["x"]=6797.9999999989,}, -[11]={["y"]=386746.85714286,["x"]=6472.2857142846,}, -}, -PointsRunways={ -[1]={ -[1]={["y"]=385891.14285715,["x"]=8416.5714285703,}, -[2]={["y"]=385842.28571429,["x"]=8467.9999999989,}, -[3]={["y"]=384180.85714286,["x"]=6917.1428571417,}, -[4]={["y"]=384228.57142858,["x"]=6867.7142857132,}, -[5]={["y"]=385891.14285715,["x"]=8416.5714285703,}, -}, -[2]={ -[1]={["y"]=386714.85714286,["x"]=6674.857142856,}, -[2]={["y"]=386757.71428572,["x"]=6627.7142857132,}, -[3]={["y"]=389028.57142858,["x"]=8741.4285714275,}, -[4]={["y"]=388981.71428572,["x"]=8790.5714285703,}, -[5]={["y"]=386714.57142858,["x"]=6674.5714285703,}, -}, -}, -ZoneBoundary={}, -ZoneRunways={}, -MaximumSpeed=50, -}, -Krymsk={ -PointsBoundary={ -[1]={["y"]=293338.00000001,["x"]=-7575.4285714297,}, -[2]={["y"]=295199.42857144,["x"]=-5434.0000000011,}, -[3]={["y"]=295595.14285715,["x"]=-6239.7142857154,}, -[4]={["y"]=294152.2857143,["x"]=-8325.4285714297,}, -[5]={["y"]=293345.14285715,["x"]=-7596.8571428582,}, -}, -PointsRunways={ -[1]={ -[1]={["y"]=293522.00000001,["x"]=-7567.4285714297,}, -[2]={["y"]=293578.57142858,["x"]=-7616.0000000011,}, -[3]={["y"]=295246.00000001,["x"]=-5591.142857144,}, -[4]={["y"]=295187.71428573,["x"]=-5546.0000000011,}, -[5]={["y"]=293523.14285715,["x"]=-7568.2857142868,}, -}, -}, -ZoneBoundary={}, -ZoneRunways={}, -MaximumSpeed=50, -}, -Kutaisi={ -PointsBoundary={ -[1]={["y"]=682087.42857143,["x"]=-284512.85714286,}, -[2]={["y"]=685387.42857143,["x"]=-283662.85714286,}, -[3]={["y"]=685294.57142857,["x"]=-284977.14285715,}, -[4]={["y"]=682744.57142857,["x"]=-286505.71428572,}, -[5]={["y"]=682094.57142857,["x"]=-284527.14285715,}, -}, -PointsRunways={ -[1]={ -[1]={["y"]=682638,["x"]=-285202.28571429,}, -[2]={["y"]=685050.28571429,["x"]=-284507.42857144,}, -[3]={["y"]=685068.85714286,["x"]=-284578.85714286,}, -[4]={["y"]=682657.42857143,["x"]=-285264.28571429,}, -[5]={["y"]=682638.28571429,["x"]=-285202.85714286,}, -}, -}, -ZoneBoundary={}, -ZoneRunways={}, -MaximumSpeed=50, -}, -MaykopKhanskaya={ -PointsBoundary={ -[1]={["y"]=456876.28571429,["x"]=-27665.42857143,}, -[2]={["y"]=457800,["x"]=-28392.857142858,}, -[3]={["y"]=459368.57142857,["x"]=-26378.571428573,}, -[4]={["y"]=459425.71428572,["x"]=-25242.857142858,}, -[5]={["y"]=458961.42857143,["x"]=-24964.285714287,}, -[6]={["y"]=456878.57142857,["x"]=-27667.714285715,}, -}, -PointsRunways={ -[1]={ -[1]={["y"]=457005.42857143,["x"]=-27668.000000001,}, -[2]={["y"]=459028.85714286,["x"]=-25168.857142858,}, -[3]={["y"]=459082.57142857,["x"]=-25216.857142858,}, -[4]={["y"]=457060,["x"]=-27714.285714287,}, -[5]={["y"]=457004.57142857,["x"]=-27669.714285715,}, -}, -}, -ZoneBoundary={}, -ZoneRunways={}, -MaximumSpeed=50, -}, -MineralnyeVody={ -PointsBoundary={ -[1]={["y"]=703857.14285714,["x"]=-50226.000000002,}, -[2]={["y"]=707385.71428571,["x"]=-51911.714285716,}, -[3]={["y"]=707595.71428571,["x"]=-51434.857142859,}, -[4]={["y"]=707900,["x"]=-51568.857142859,}, -[5]={["y"]=707542.85714286,["x"]=-52326.000000002,}, -[6]={["y"]=706628.57142857,["x"]=-52568.857142859,}, -[7]={["y"]=705142.85714286,["x"]=-51790.285714288,}, -[8]={["y"]=703678.57142857,["x"]=-50611.714285716,}, -[9]={["y"]=703857.42857143,["x"]=-50226.857142859,}, -}, -PointsRunways={ -[1]={ -[1]={["y"]=703904,["x"]=-50352.571428573,}, -[2]={["y"]=707596.28571429,["x"]=-52094.571428573,}, -[3]={["y"]=707560.57142858,["x"]=-52161.714285716,}, -[4]={["y"]=703871.71428572,["x"]=-50420.571428573,}, -[5]={["y"]=703902,["x"]=-50352.000000002,}, -}, -}, -ZoneBoundary={}, -ZoneRunways={}, -MaximumSpeed=50, -}, -Mozdok={ -PointsBoundary={ -[1]={["y"]=832123.42857143,["x"]=-83608.571428573,}, -[2]={["y"]=835916.28571429,["x"]=-83144.285714288,}, -[3]={["y"]=835474.28571429,["x"]=-84170.571428573,}, -[4]={["y"]=832911.42857143,["x"]=-84470.571428573,}, -[5]={["y"]=832487.71428572,["x"]=-85565.714285716,}, -[6]={["y"]=831573.42857143,["x"]=-85351.42857143,}, -[7]={["y"]=832123.71428572,["x"]=-83610.285714288,}, -}, -PointsRunways={ -[1]={ -[1]={["y"]=832201.14285715,["x"]=-83699.428571431,}, -[2]={["y"]=832212.57142857,["x"]=-83780.571428574,}, -[3]={["y"]=835730.28571429,["x"]=-83335.714285717,}, -[4]={["y"]=835718.85714286,["x"]=-83246.571428574,}, -[5]={["y"]=832200.57142857,["x"]=-83700.000000002,}, -}, -}, -ZoneBoundary={}, -ZoneRunways={}, -MaximumSpeed=50, -}, -Nalchik={ -PointsBoundary={ -[1]={["y"]=759370,["x"]=-125502.85714286,}, -[2]={["y"]=761384.28571429,["x"]=-124177.14285714,}, -[3]={["y"]=761472.85714286,["x"]=-124325.71428572,}, -[4]={["y"]=761092.85714286,["x"]=-125048.57142857,}, -[5]={["y"]=760295.71428572,["x"]=-125685.71428572,}, -[6]={["y"]=759444.28571429,["x"]=-125734.28571429,}, -[7]={["y"]=759375.71428572,["x"]=-125511.42857143,}, -}, -PointsRunways={ -[1]={ -[1]={["y"]=759454.28571429,["x"]=-125551.42857143,}, -[2]={["y"]=759492.85714286,["x"]=-125610.85714286,}, -[3]={["y"]=761406.28571429,["x"]=-124304.28571429,}, -[4]={["y"]=761361.14285714,["x"]=-124239.71428572,}, -[5]={["y"]=759456,["x"]=-125552.57142857,}, -}, -}, -ZoneBoundary={}, -ZoneRunways={}, -MaximumSpeed=50, -}, -Novorossiysk={ -PointsBoundary={ -[1]={["y"]=278677.71428573,["x"]=-41656.571428572,}, -[2]={["y"]=278446.2857143,["x"]=-41453.714285715,}, -[3]={["y"]=278989.14285716,["x"]=-40188.000000001,}, -[4]={["y"]=279717.71428573,["x"]=-39968.000000001,}, -[5]={["y"]=280020.57142859,["x"]=-40208.000000001,}, -[6]={["y"]=278674.85714287,["x"]=-41660.857142858,}, -}, -PointsRunways={ -[1]={ -[1]={["y"]=278673.14285716,["x"]=-41615.142857144,}, -[2]={["y"]=278625.42857144,["x"]=-41570.571428572,}, -[3]={["y"]=279835.42857144,["x"]=-40226.000000001,}, -[4]={["y"]=279882.2857143,["x"]=-40270.000000001,}, -[5]={["y"]=278672.00000001,["x"]=-41614.857142858,}, -}, -}, -ZoneBoundary={}, -ZoneRunways={}, -MaximumSpeed=50, -}, -SenakiKolkhi={ -PointsBoundary={ -[1]={["y"]=646036.57142857,["x"]=-281778.85714286,}, -[2]={["y"]=646045.14285714,["x"]=-281191.71428571,}, -[3]={["y"]=647032.28571429,["x"]=-280598.85714285,}, -[4]={["y"]=647669.42857143,["x"]=-281273.14285714,}, -[5]={["y"]=648323.71428571,["x"]=-281370.28571428,}, -[6]={["y"]=648520.85714286,["x"]=-281978.85714285,}, -[7]={["y"]=646039.42857143,["x"]=-281783.14285714,}, -}, -PointsRunways={ -[1]={ -[1]={["y"]=646060.85714285,["x"]=-281736,}, -[2]={["y"]=646056.57142857,["x"]=-281631.71428571,}, -[3]={["y"]=648442.28571428,["x"]=-281840.28571428,}, -[4]={["y"]=648432.28571428,["x"]=-281918.85714286,}, -[5]={["y"]=646063.71428571,["x"]=-281738.85714286,}, -}, -}, -ZoneBoundary={}, -ZoneRunways={}, -MaximumSpeed=50, -}, -SochiAdler={ -PointsBoundary={ -[1]={["y"]=460642.28571428,["x"]=-164861.71428571,}, -[2]={["y"]=462820.85714285,["x"]=-163368.85714286,}, -[3]={["y"]=463649.42857142,["x"]=-163340.28571429,}, -[4]={["y"]=463835.14285714,["x"]=-164040.28571429,}, -[5]={["y"]=462535.14285714,["x"]=-165654.57142857,}, -[6]={["y"]=460678,["x"]=-165247.42857143,}, -[7]={["y"]=460635.14285714,["x"]=-164876,}, -}, -PointsRunways={ -[1]={ -[1]={["y"]=460831.42857143,["x"]=-165180,}, -[2]={["y"]=460878.57142857,["x"]=-165257.14285714,}, -[3]={["y"]=463663.71428571,["x"]=-163793.14285714,}, -[4]={["y"]=463612.28571428,["x"]=-163697.42857143,}, -[5]={["y"]=460831.42857143,["x"]=-165177.14285714,}, -}, -[2]={ -[1]={["y"]=460831.42857143,["x"]=-165180,}, -[2]={["y"]=460878.57142857,["x"]=-165257.14285714,}, -[3]={["y"]=463663.71428571,["x"]=-163793.14285714,}, -[4]={["y"]=463612.28571428,["x"]=-163697.42857143,}, -[5]={["y"]=460831.42857143,["x"]=-165177.14285714,}, -}, -}, -ZoneBoundary={}, -ZoneRunways={}, -MaximumSpeed=50, -}, -Soganlug={ -PointsBoundary={ -[1]={["y"]=894530.85714286,["x"]=-316928.28571428,}, -[2]={["y"]=896422.28571428,["x"]=-318622.57142857,}, -[3]={["y"]=896090.85714286,["x"]=-318934,}, -[4]={["y"]=894019.42857143,["x"]=-317119.71428571,}, -[5]={["y"]=894533.71428571,["x"]=-316925.42857143,}, -}, -PointsRunways={ -[1]={ -[1]={["y"]=894525.71428571,["x"]=-316964,}, -[2]={["y"]=896363.14285714,["x"]=-318634.28571428,}, -[3]={["y"]=896299.14285714,["x"]=-318702.85714286,}, -[4]={["y"]=894464,["x"]=-317031.71428571,}, -[5]={["y"]=894524.57142857,["x"]=-316963.71428571,}, -}, -}, -ZoneBoundary={}, -ZoneRunways={}, -MaximumSpeed=50, -}, -SukhumiBabushara={ -PointsBoundary={ -[1]={["y"]=562541.14285714,["x"]=-219852.28571429,}, -[2]={["y"]=562691.14285714,["x"]=-219395.14285714,}, -[3]={["y"]=564326.85714286,["x"]=-219523.71428571,}, -[4]={["y"]=566262.57142857,["x"]=-221166.57142857,}, -[5]={["y"]=566069.71428571,["x"]=-221580.85714286,}, -[6]={["y"]=562534,["x"]=-219873.71428571,}, -}, -PointsRunways={ -[1]={ -[1]={["y"]=562684,["x"]=-219779.71428571,}, -[2]={["y"]=562717.71428571,["x"]=-219718,}, -[3]={["y"]=566046.85714286,["x"]=-221376.57142857,}, -[4]={["y"]=566012.28571428,["x"]=-221446.57142857,}, -[5]={["y"]=562684.57142857,["x"]=-219782.57142857,}, -}, -}, -ZoneBoundary={}, -ZoneRunways={}, -MaximumSpeed=50, -}, -TbilisiLochini={ -PointsBoundary={ -[1]={["y"]=895172.85714286,["x"]=-314667.42857143,}, -[2]={["y"]=895337.42857143,["x"]=-314143.14285714,}, -[3]={["y"]=895990.28571429,["x"]=-314036,}, -[4]={["y"]=897730.28571429,["x"]=-315284.57142857,}, -[5]={["y"]=897901.71428571,["x"]=-316284.57142857,}, -[6]={["y"]=897684.57142857,["x"]=-316618.85714286,}, -[7]={["y"]=895173.14285714,["x"]=-314667.42857143,}, -}, -PointsRunways={ -[1]={ -[1]={["y"]=895261.14285715,["x"]=-314652.28571428,}, -[2]={["y"]=897654.57142857,["x"]=-316523.14285714,}, -[3]={["y"]=897711.71428571,["x"]=-316450.28571429,}, -[4]={["y"]=895327.42857143,["x"]=-314568.85714286,}, -[5]={["y"]=895261.71428572,["x"]=-314656,}, -}, -[2]={ -[1]={["y"]=895605.71428572,["x"]=-314724.57142857,}, -[2]={["y"]=897639.71428572,["x"]=-316148,}, -[3]={["y"]=897683.42857143,["x"]=-316087.14285714,}, -[4]={["y"]=895650,["x"]=-314660,}, -[5]={["y"]=895606,["x"]=-314724.85714286,} -}, -}, -ZoneBoundary={}, -ZoneRunways={}, -MaximumSpeed=50, -}, -Vaziani={ -PointsBoundary={ -[1]={["y"]=902122,["x"]=-318163.71428572,}, -[2]={["y"]=902678.57142857,["x"]=-317594,}, -[3]={["y"]=903275.71428571,["x"]=-317405.42857143,}, -[4]={["y"]=903418.57142857,["x"]=-317891.14285714,}, -[5]={["y"]=904292.85714286,["x"]=-318748.28571429,}, -[6]={["y"]=904542,["x"]=-319740.85714286,}, -[7]={["y"]=904042,["x"]=-320166.57142857,}, -[8]={["y"]=902121.42857143,["x"]=-318164.85714286,}, -}, -PointsRunways={ -[1]={ -[1]={["y"]=902239.14285714,["x"]=-318190.85714286,}, -[2]={["y"]=904014.28571428,["x"]=-319994.57142857,}, -[3]={["y"]=904064.85714285,["x"]=-319945.14285715,}, -[4]={["y"]=902294.57142857,["x"]=-318146,}, -[5]={["y"]=902247.71428571,["x"]=-318190.85714286,}, -}, -}, -ZoneBoundary={}, -ZoneRunways={}, -MaximumSpeed=50, -}, -}, -} -function AIRBASEPOLICE_CAUCASUS:New(SetClient) -local self=BASE:Inherit(self,AIRBASEPOLICE_BASE:New(SetClient,self.Airbases)) -return self -end -AIRBASEPOLICE_NEVADA={ -ClassName="AIRBASEPOLICE_NEVADA", -Airbases={ -Nellis={ -PointsBoundary={ -[1]={["y"]=-17814.714285714,["x"]=-399823.14285714,}, -[2]={["y"]=-16875.857142857,["x"]=-398763.14285714,}, -[3]={["y"]=-16251.571428571,["x"]=-398988.85714286,}, -[4]={["y"]=-16163,["x"]=-398693.14285714,}, -[5]={["y"]=-16328.714285714,["x"]=-398034.57142857,}, -[6]={["y"]=-15943,["x"]=-397571.71428571,}, -[7]={["y"]=-15711.571428571,["x"]=-397551.71428571,}, -[8]={["y"]=-15748.714285714,["x"]=-396806,}, -[9]={["y"]=-16288.714285714,["x"]=-396517.42857143,}, -[10]={["y"]=-16751.571428571,["x"]=-396308.85714286,}, -[11]={["y"]=-17263,["x"]=-396234.57142857,}, -[12]={["y"]=-17577.285714286,["x"]=-396640.28571429,}, -[13]={["y"]=-17614.428571429,["x"]=-397400.28571429,}, -[14]={["y"]=-19405.857142857,["x"]=-399428.85714286,}, -[15]={["y"]=-19234.428571429,["x"]=-399683.14285714,}, -[16]={["y"]=-18708.714285714,["x"]=-399408.85714286,}, -[17]={["y"]=-18397.285714286,["x"]=-399657.42857143,}, -[18]={["y"]=-17814.428571429,["x"]=-399823.42857143,}, -}, -PointsRunways={ -[1]={ -[1]={["y"]=-18687,["x"]=-399380.28571429,}, -[2]={["y"]=-18620.714285714,["x"]=-399436.85714286,}, -[3]={["y"]=-16217.857142857,["x"]=-396596.85714286,}, -[4]={["y"]=-16300.142857143,["x"]=-396530,}, -[5]={["y"]=-18687,["x"]=-399380.85714286,}, -}, -[2]={ -[1]={["y"]=-18451.571428572,["x"]=-399580.57142857,}, -[2]={["y"]=-18392.142857143,["x"]=-399628.57142857,}, -[3]={["y"]=-16011,["x"]=-396806.85714286,}, -[4]={["y"]=-16074.714285714,["x"]=-396751.71428572,}, -[5]={["y"]=-18451.571428572,["x"]=-399580.85714285,}, -}, -}, -ZoneBoundary={}, -ZoneRunways={}, -MaximumSpeed=50, -}, -McCarran={ -PointsBoundary={ -[1]={["y"]=-29455.285714286,["x"]=-416277.42857142,}, -[2]={["y"]=-28860.142857143,["x"]=-416492,}, -[3]={["y"]=-25044.428571429,["x"]=-416344.85714285,}, -[4]={["y"]=-24580.142857143,["x"]=-415959.14285714,}, -[5]={["y"]=-25073,["x"]=-415630.57142857,}, -[6]={["y"]=-25087.285714286,["x"]=-415130.57142857,}, -[7]={["y"]=-25830.142857143,["x"]=-414866.28571428,}, -[8]={["y"]=-26658.714285715,["x"]=-414880.57142857,}, -[9]={["y"]=-26973,["x"]=-415273.42857142,}, -[10]={["y"]=-27380.142857143,["x"]=-415187.71428571,}, -[11]={["y"]=-27715.857142857,["x"]=-414144.85714285,}, -[12]={["y"]=-27551.571428572,["x"]=-413473.42857142,}, -[13]={["y"]=-28630.142857143,["x"]=-413201.99999999,}, -[14]={["y"]=-29494.428571429,["x"]=-415437.71428571,}, -[15]={["y"]=-29455.571428572,["x"]=-416277.71428571,}, -}, -PointsRunways={ -[1]={ -[1]={["y"]=-29408.428571429,["x"]=-416016.28571428,}, -[2]={["y"]=-29408.142857144,["x"]=-416105.42857142,}, -[3]={["y"]=-24680.714285715,["x"]=-416003.14285713,}, -[4]={["y"]=-24681.857142858,["x"]=-415926.57142856,}, -[5]={["y"]=-29408.42857143,["x"]=-416016.57142856,}, -}, -[2]={ -[1]={["y"]=-28575.571428572,["x"]=-416303.14285713,}, -[2]={["y"]=-28575.571428572,["x"]=-416382.57142856,}, -[3]={["y"]=-25111.000000001,["x"]=-416309.7142857,}, -[4]={["y"]=-25111.000000001,["x"]=-416249.14285713,}, -[5]={["y"]=-28575.571428572,["x"]=-416303.7142857,}, -}, -[3]={ -[1]={["y"]=-29331.000000001,["x"]=-416275.42857141,}, -[2]={["y"]=-29259.000000001,["x"]=-416306.85714284,}, -[3]={["y"]=-28005.571428572,["x"]=-413449.7142857,}, -[4]={["y"]=-28068.714285715,["x"]=-413422.85714284,}, -[5]={["y"]=-29331.000000001,["x"]=-416275.7142857,}, -}, -[4]={ -[1]={["y"]=-29073.285714286,["x"]=-416386.57142856,}, -[2]={["y"]=-28997.285714286,["x"]=-416417.42857141,}, -[3]={["y"]=-27697.571428572,["x"]=-413464.57142856,}, -[4]={["y"]=-27767.857142858,["x"]=-413434.28571427,}, -[5]={["y"]=-29073.000000001,["x"]=-416386.85714284,}, -}, -}, -ZoneBoundary={}, -ZoneRunways={}, -MaximumSpeed=50, -}, -Creech={ -PointsBoundary={ -[1]={["y"]=-74522.714285715,["x"]=-360887.99999998,}, -[2]={["y"]=-74197,["x"]=-360556.57142855,}, -[3]={["y"]=-74402.714285715,["x"]=-359639.42857141,}, -[4]={["y"]=-74637,["x"]=-359279.42857141,}, -[5]={["y"]=-75759.857142857,["x"]=-359005.14285712,}, -[6]={["y"]=-75834.142857143,["x"]=-359045.14285712,}, -[7]={["y"]=-75902.714285714,["x"]=-359782.28571427,}, -[8]={["y"]=-76099.857142857,["x"]=-360399.42857141,}, -[9]={["y"]=-77314.142857143,["x"]=-360219.42857141,}, -[10]={["y"]=-77728.428571429,["x"]=-360445.14285713,}, -[11]={["y"]=-77585.571428571,["x"]=-360585.14285713,}, -[12]={["y"]=-76471.285714286,["x"]=-360819.42857141,}, -[13]={["y"]=-76325.571428571,["x"]=-360942.28571427,}, -[14]={["y"]=-74671.857142857,["x"]=-360927.7142857,}, -[15]={["y"]=-74522.714285714,["x"]=-360888.85714284,}, -}, -PointsRunways={ -[1]={ -[1]={["y"]=-74237.571428571,["x"]=-360591.7142857,}, -[2]={["y"]=-74234.428571429,["x"]=-360493.71428571,}, -[3]={["y"]=-77605.285714286,["x"]=-360399.14285713,}, -[4]={["y"]=-77608.714285715,["x"]=-360498.85714285,}, -[5]={["y"]=-74237.857142857,["x"]=-360591.7142857,}, -}, -[2]={ -[1]={["y"]=-75807.571428572,["x"]=-359073.42857142,}, -[2]={["y"]=-74770.142857144,["x"]=-360581.71428571,}, -[3]={["y"]=-74641.285714287,["x"]=-360585.42857142,}, -[4]={["y"]=-75734.142857144,["x"]=-359023.14285714,}, -[5]={["y"]=-75807.285714287,["x"]=-359073.42857142,}, -}, -}, -ZoneBoundary={}, -ZoneRunways={}, -MaximumSpeed=50, -}, -GroomLake={ -PointsBoundary={ -[1]={["y"]=-88916.714285714,["x"]=-289102.28571425,}, -[2]={["y"]=-87023.571428572,["x"]=-290388.57142857,}, -[3]={["y"]=-85916.428571429,["x"]=-290674.28571428,}, -[4]={["y"]=-87645.000000001,["x"]=-286567.14285714,}, -[5]={["y"]=-88380.714285715,["x"]=-286388.57142857,}, -[6]={["y"]=-89670.714285715,["x"]=-283524.28571428,}, -[7]={["y"]=-89797.857142858,["x"]=-283567.14285714,}, -[8]={["y"]=-88635.000000001,["x"]=-286749.99999999,}, -[9]={["y"]=-89177.857142858,["x"]=-287207.14285714,}, -[10]={["y"]=-89092.142857144,["x"]=-288892.85714285,}, -[11]={["y"]=-88917.000000001,["x"]=-289102.85714285,}, -}, -PointsRunways={ -[1]={ -[1]={["y"]=-86039.000000001,["x"]=-290606.28571428,}, -[2]={["y"]=-85965.285714287,["x"]=-290573.99999999,}, -[3]={["y"]=-87692.714285715,["x"]=-286634.85714285,}, -[4]={["y"]=-87756.714285715,["x"]=-286663.99999999,}, -[5]={["y"]=-86038.714285715,["x"]=-290606.85714285,}, -}, -[2]={ -[1]={["y"]=-86808.428571429,["x"]=-290375.7142857,}, -[2]={["y"]=-86732.714285715,["x"]=-290344.28571427,}, -[3]={["y"]=-89672.714285714,["x"]=-283546.57142855,}, -[4]={["y"]=-89772.142857143,["x"]=-283587.71428569,}, -[5]={["y"]=-86808.142857143,["x"]=-290375.7142857,}, -}, -}, -ZoneBoundary={}, -ZoneRunways={}, -MaximumSpeed=50, -}, -}, -} -function AIRBASEPOLICE_NEVADA:New(SetClient) -local self=BASE:Inherit(self,AIRBASEPOLICE_BASE:New(SetClient,self.Airbases)) -end -do -DETECTION_BASE={ -ClassName="DETECTION_BASE", -DetectionSetGroup=nil, -DetectionRange=nil, -DetectedObjects={}, -DetectionRun=0, -DetectedObjectsIdentified={}, -DetectedItems={}, -} -function DETECTION_BASE:New(DetectionSetGroup) -local self=BASE:Inherit(self,FSM:New()) -self.DetectedItemCount=0 -self.DetectedItemMax=0 -self.DetectedItems={} -self.DetectionSetGroup=DetectionSetGroup -self.RefreshTimeInterval=30 -self:InitDetectVisual(nil) -self:InitDetectOptical(nil) -self:InitDetectRadar(nil) -self:InitDetectRWR(nil) -self:InitDetectIRST(nil) -self:InitDetectDLINK(nil) -self:FilterCategories({ -Unit.Category.AIRPLANE, -Unit.Category.GROUND_UNIT, -Unit.Category.HELICOPTER, -Unit.Category.SHIP, -Unit.Category.STRUCTURE -}) -self:SetFriendliesRange(6000) -self:SetStartState("Stopped") -self:AddTransition("Stopped","Start","Detecting") -self:AddTransition("Detecting","Detect","Detecting") -self:AddTransition("Detecting","DetectionGroup","Detecting") -self:AddTransition("Detecting","Detected","Detecting") -self:AddTransition("*","Stop","Stopped") -return self -end -do -function DETECTION_BASE:onafterStart(From,Event,To) -self:__Detect(1) -end -function DETECTION_BASE:onafterDetect(From,Event,To) -self:E({From,Event,To}) -local DetectDelay=0.1 -self.DetectionCount=0 -self.DetectionRun=0 -self:UnIdentifyAllDetectedObjects() -local DetectionTimeStamp=timer.getTime() -for DetectionGroupID,DetectionGroupData in pairs(self.DetectionSetGroup:GetSet())do -self:__DetectionGroup(DetectDelay,DetectionGroupData,DetectionTimeStamp) -self.DetectionCount=self.DetectionCount+1 -DetectDelay=DetectDelay+1 -end -end -function DETECTION_BASE:onafterDetectionGroup(From,Event,To,DetectionGroup,DetectionTimeStamp) -self:E({From,Event,To}) -self.DetectionRun=self.DetectionRun+1 -local HasDetectedObjects=false -if DetectionGroup:IsAlive()then -self:T({"DetectionGroup is Alive",DetectionGroup:GetName()}) -local DetectionGroupName=DetectionGroup:GetName() -local DetectionUnit=DetectionGroup:GetUnit(1) -local DetectedUnits={} -local DetectedTargets=DetectionGroup:GetDetectedTargets( -self.DetectVisual, -self.DetectOptical, -self.DetectRadar, -self.DetectIRST, -self.DetectRWR, -self.DetectDLINK -) -self:F(DetectedTargets) -for DetectionObjectID,Detection in pairs(DetectedTargets)do -local DetectedObject=Detection.object -if DetectedObject and DetectedObject:isExist()and DetectedObject.id_<50000000 then -local TargetIsDetected,TargetIsVisible,TargetLastTime,TargetKnowType,TargetKnowDistance,TargetLastPos,TargetLastVelocity=DetectionUnit:IsTargetDetected( -DetectedObject, -self.DetectVisual, -self.DetectOptical, -self.DetectRadar, -self.DetectIRST, -self.DetectRWR, -self.DetectDLINK -) -self:T2({TargetIsDetected=TargetIsDetected,TargetIsVisible=TargetIsVisible,TargetLastTime=TargetLastTime,TargetKnowType=TargetKnowType,TargetKnowDistance=TargetKnowDistance,TargetLastPos=TargetLastPos,TargetLastVelocity=TargetLastVelocity}) -local DetectionAccepted=true -local DetectedObjectName=DetectedObject:getName() -local DetectedObjectType=DetectedObject:getTypeName() -local DetectedObjectVec3=DetectedObject:getPoint() -local DetectedObjectVec2={x=DetectedObjectVec3.x,y=DetectedObjectVec3.z} -local DetectionGroupVec3=DetectionGroup:GetVec3() -local DetectionGroupVec2={x=DetectionGroupVec3.x,y=DetectionGroupVec3.z} -local Distance=((DetectedObjectVec3.x-DetectionGroupVec3.x)^2+ -(DetectedObjectVec3.y-DetectionGroupVec3.y)^2+ -(DetectedObjectVec3.z-DetectionGroupVec3.z)^2 -)^0.5/1000 -local DetectedUnitCategory=DetectedObject:getDesc().category -self:F({"Detected Target:",DetectionGroupName,DetectedObjectName,DetectedObjectType,Distance,DetectedUnitCategory}) -DetectionAccepted=self._.FilterCategories[DetectedUnitCategory]~=nil and DetectionAccepted or false -if self.AcceptRange and Distance>self.AcceptRange then -DetectionAccepted=false -end -if self.AcceptZones then -for AcceptZoneID,AcceptZone in pairs(self.AcceptZones)do -local AcceptZone=AcceptZone -if AcceptZone:IsVec2InZone(DetectedObjectVec2)==false then -DetectionAccepted=false -end -end -end -if self.RejectZones then -for RejectZoneID,RejectZone in pairs(self.RejectZones)do -local RejectZone=RejectZone -if RejectZone:IsPointVec2InZone(DetectedObjectVec2)==true then -DetectionAccepted=false -end -end -end -if not self.DetectedObjects[DetectedObjectName]and Detection.visible and self.DistanceProbability then -local DistanceFactor=Distance/4 -local DistanceProbabilityReversed=(1-self.DistanceProbability)*DistanceFactor -local DistanceProbability=1-DistanceProbabilityReversed -DistanceProbability=DistanceProbability*30/300 -local Probability=math.random() -self:T({Probability,DistanceProbability}) -if Probability>DistanceProbability then -DetectionAccepted=false -end -end -if not self.DetectedObjects[DetectedObjectName]and Detection.visible and self.AlphaAngleProbability then -local NormalVec2={x=DetectedObjectVec2.x-DetectionGroupVec2.x,y=DetectedObjectVec2.y-DetectionGroupVec2.y} -local AlphaAngle=math.atan2(NormalVec2.y,NormalVec2.x) -local Sinus=math.sin(AlphaAngle) -local AlphaAngleProbabilityReversed=(1-self.AlphaAngleProbability)*(1-Sinus) -local AlphaAngleProbability=1-AlphaAngleProbabilityReversed -AlphaAngleProbability=AlphaAngleProbability*30/300 -local Probability=math.random() -self:T({Probability,AlphaAngleProbability}) -if Probability>AlphaAngleProbability then -DetectionAccepted=false -end -end -if not self.DetectedObjects[DetectedObjectName]and Detection.visible and self.ZoneProbability then -for ZoneDataID,ZoneData in pairs(self.ZoneProbability)do -self:E({ZoneData}) -local ZoneObject=ZoneData[1] -local ZoneProbability=ZoneData[2] -ZoneProbability=ZoneProbability*30/300 -if ZoneObject:IsPointVec2InZone(DetectedObjectVec2)==true then -local Probability=math.random() -self:T({Probability,ZoneProbability}) -if Probability>ZoneProbability then -DetectionAccepted=false -break -end -end -end -end -if DetectionAccepted then -HasDetectedObjects=true -self.DetectedObjects[DetectedObjectName]=self.DetectedObjects[DetectedObjectName]or{} -self.DetectedObjects[DetectedObjectName].Name=DetectedObjectName -self.DetectedObjects[DetectedObjectName].IsDetected=TargetIsDetected -self.DetectedObjects[DetectedObjectName].IsVisible=TargetIsVisible -self.DetectedObjects[DetectedObjectName].LastTime=TargetLastTime -self.DetectedObjects[DetectedObjectName].LastPos=TargetLastPos -self.DetectedObjects[DetectedObjectName].LastVelocity=TargetLastVelocity -self.DetectedObjects[DetectedObjectName].KnowType=TargetKnowType -self.DetectedObjects[DetectedObjectName].KnowDistance=Detection.distance -self.DetectedObjects[DetectedObjectName].Distance=Distance -self.DetectedObjects[DetectedObjectName].DetectionTimeStamp=DetectionTimeStamp -self:F({DetectedObject=self.DetectedObjects[DetectedObjectName]}) -local DetectedUnit=UNIT:FindByName(DetectedObjectName) -DetectedUnits[DetectedObjectName]=DetectedUnit -else -if self.DetectedObjects[DetectedObjectName]then -self.DetectedObjects[DetectedObjectName]=nil -end -end -end -self:T2(self.DetectedObjects) -end -if HasDetectedObjects then -self:__Detected(0.1,DetectedUnits) -end -end -if self.DetectionCount>0 and self.DetectionRun==self.DetectionCount then -self:T("--> Create Detection Sets") -for DetectedObjectName,DetectedObject in pairs(self.DetectedObjects)do -if self.DetectedObjects[DetectedObjectName].IsDetected==true and self.DetectedObjects[DetectedObjectName].DetectionTimeStamp+60<=DetectionTimeStamp then -self.DetectedObjects[DetectedObjectName].IsDetected=false -end -end -self:CreateDetectionItems() -for DetectedItemID,DetectedItem in pairs(self.DetectedItems)do -self:UpdateDetectedItemDetection(DetectedItem) -self:CleanDetectionItem(DetectedItem,DetectedItemID) -end -self:__Detect(self.RefreshTimeInterval) -end -end -end -do -function DETECTION_BASE:CleanDetectionItem(DetectedItem,DetectedItemID) -self:F2() -local DetectedSet=DetectedItem.Set -if DetectedSet:Count()==0 then -self:RemoveDetectedItem(DetectedItemID) -end -return self -end -function DETECTION_BASE:ForgetDetectedUnit(UnitName) -self:F2() -local DetectedItems=self:GetDetectedItems() -for DetectedItemIndex,DetectedItem in pairs(DetectedItems)do -local DetectedSet=self:GetDetectedSet(DetectedItemIndex) -if DetectedSet then -DetectedSet:RemoveUnitsByName(UnitName) -end -end -return self -end -function DETECTION_BASE:CreateDetectionItems() -self:F2() -self:E("Error, in DETECTION_BASE class...") -return self -end -end -do -function DETECTION_BASE:InitDetectVisual(DetectVisual) -self.DetectVisual=DetectVisual -return self -end -function DETECTION_BASE:InitDetectOptical(DetectOptical) -self:F2() -self.DetectOptical=DetectOptical -return self -end -function DETECTION_BASE:InitDetectRadar(DetectRadar) -self:F2() -self.DetectRadar=DetectRadar -return self -end -function DETECTION_BASE:InitDetectIRST(DetectIRST) -self:F2() -self.DetectIRST=DetectIRST -return self -end -function DETECTION_BASE:InitDetectRWR(DetectRWR) -self:F2() -self.DetectRWR=DetectRWR -return self -end -function DETECTION_BASE:InitDetectDLINK(DetectDLINK) -self:F2() -self.DetectDLINK=DetectDLINK -return self -end -end -do -function DETECTION_BASE:FilterCategories(FilterCategories) -self:F2() -self._.FilterCategories={} -if type(FilterCategories)=="table"then -for CategoryID,Category in pairs(FilterCategories)do -self._.FilterCategories[Category]=Category -end -else -self._.FilterCategories[FilterCategories]=FilterCategories -end -return self -end -end -do -function DETECTION_BASE:SetRefreshTimeInterval(RefreshTimeInterval) -self:F2() -self.RefreshTimeInterval=RefreshTimeInterval -return self -end -end -do -function DETECTION_BASE:SetFriendliesRange(FriendliesRange) -self:F2() -self.FriendliesRange=FriendliesRange -return self -end -end -do -function DETECTION_BASE:SetIntercept(Intercept,InterceptDelay) -self:F2() -self.Intercept=Intercept -self.InterceptDelay=InterceptDelay -return self -end -end -do -function DETECTION_BASE:SetAcceptRange(AcceptRange) -self:F2() -self.AcceptRange=AcceptRange -return self -end -function DETECTION_BASE:SetAcceptZones(AcceptZones) -self:F2() -if type(AcceptZones)=="table"then -if AcceptZones.ClassName and AcceptZones:IsInstanceOf(ZONE_BASE)then -self.AcceptZones={AcceptZones} -else -self.AcceptZones=AcceptZones -end -else -self:E({"AcceptZones must be a list of ZONE_BASE derived objects or one ZONE_BASE derived object",AcceptZones}) -error() -end -return self -end -function DETECTION_BASE:SetRejectZones(RejectZones) -self:F2() -if type(RejectZones)=="table"then -if RejectZones.ClassName and RejectZones:IsInstanceOf(ZONE_BASE)then -self.RejectZones={RejectZones} -else -self.RejectZones=RejectZones -end -else -self:E({"RejectZones must be a list of ZONE_BASE derived objects or one ZONE_BASE derived object",RejectZones}) -error() -end -return self -end -end -do -function DETECTION_BASE:SetDistanceProbability(DistanceProbability) -self:F2() -self.DistanceProbability=DistanceProbability -return self -end -function DETECTION_BASE:SetAlphaAngleProbability(AlphaAngleProbability) -self:F2() -self.AlphaAngleProbability=AlphaAngleProbability -return self -end -function DETECTION_BASE:SetZoneProbability(ZoneArray) -self:F2() -self.ZoneProbability=ZoneArray -return self -end -end -do -function DETECTION_BASE:AcceptChanges(DetectedItem) -DetectedItem.Changed=false -DetectedItem.Changes={} -return self -end -function DETECTION_BASE:AddChangeItem(DetectedItem,ChangeCode,ItemUnitType) -DetectedItem.Changed=true -local ID=DetectedItem.ID -DetectedItem.Changes=DetectedItem.Changes or{} -DetectedItem.Changes[ChangeCode]=DetectedItem.Changes[ChangeCode]or{} -DetectedItem.Changes[ChangeCode].ID=ID -DetectedItem.Changes[ChangeCode].ItemUnitType=ItemUnitType -self:E({"Change on Detection Item:",DetectedItem.ID,ChangeCode,ItemUnitType}) -return self -end -function DETECTION_BASE:AddChangeUnit(DetectedItem,ChangeCode,ChangeUnitType) -DetectedItem.Changed=true -local ID=DetectedItem.ID -DetectedItem.Changes=DetectedItem.Changes or{} -DetectedItem.Changes[ChangeCode]=DetectedItem.Changes[ChangeCode]or{} -DetectedItem.Changes[ChangeCode][ChangeUnitType]=DetectedItem.Changes[ChangeCode][ChangeUnitType]or 0 -DetectedItem.Changes[ChangeCode][ChangeUnitType]=DetectedItem.Changes[ChangeCode][ChangeUnitType]+1 -DetectedItem.Changes[ChangeCode].ID=ID -self:E({"Change on Detection Item:",DetectedItem.ID,ChangeCode,ChangeUnitType}) -return self -end -end -do -function DETECTION_BASE:SetFriendlyPrefixes(FriendlyPrefixes) -self.FriendlyPrefixes=self.FriendlyPrefixes or{} -if type(FriendlyPrefixes)~="table"then -FriendlyPrefixes={FriendlyPrefixes} -end -for PrefixID,Prefix in pairs(FriendlyPrefixes)do -self:F({FriendlyPrefix=Prefix}) -self.FriendlyPrefixes[Prefix]=Prefix -end -return self -end -function DETECTION_BASE:IsFriendliesNearBy(DetectedItem) -return DetectedItem.FriendliesNearBy~=nil or false -end -function DETECTION_BASE:GetFriendliesNearBy(DetectedItem) -return DetectedItem.FriendliesNearBy -end -function DETECTION_BASE:FilterFriendliesCategory(FriendliesCategory) -self.FriendliesCategory=FriendliesCategory -return self -end -function DETECTION_BASE:IsFriendliesNearIntercept(DetectedItem) -return DetectedItem.FriendliesNearIntercept~=nil or false -end -function DETECTION_BASE:GetFriendliesNearIntercept(DetectedItem) -return DetectedItem.FriendliesNearIntercept -end -function DETECTION_BASE:GetFriendliesDistance(DetectedItem) -return DetectedItem.FriendliesDistance -end -function DETECTION_BASE:IsPlayersNearBy(DetectedItem) -return DetectedItem.PlayersNearBy~=nil -end -function DETECTION_BASE:GetPlayersNearBy(DetectedItem) -return DetectedItem.PlayersNearBy -end -function DETECTION_BASE:ReportFriendliesNearBy(ReportGroupData) -self:F2() -local DetectedItem=ReportGroupData.DetectedItem -local DetectedSet=ReportGroupData.DetectedItem.Set -local DetectedUnit=DetectedSet:GetFirst() -DetectedItem.FriendliesNearBy=nil -if DetectedUnit and DetectedUnit:IsAlive()then -local DetectedUnitCoord=DetectedUnit:GetCoordinate() -local InterceptCoord=ReportGroupData.InterceptCoord or DetectedUnitCoord -local SphereSearch={ -id=world.VolumeType.SPHERE, -params={ -point=InterceptCoord:GetVec3(), -radius=self.FriendliesRange, -} -} -local FindNearByFriendlies=function(FoundDCSUnit,ReportGroupData) -local DetectedItem=ReportGroupData.DetectedItem -local DetectedSet=ReportGroupData.DetectedItem.Set -local DetectedUnit=DetectedSet:GetFirst() -local DetectedUnitCoord=DetectedUnit:GetCoordinate() -local InterceptCoord=ReportGroupData.InterceptCoord or DetectedUnitCoord -local ReportSetGroup=ReportGroupData.ReportSetGroup -local EnemyCoalition=DetectedUnit:GetCoalition() -local FoundUnitCoalition=FoundDCSUnit:getCoalition() -local FoundUnitName=FoundDCSUnit:getName() -local FoundUnitGroupName=FoundDCSUnit:getGroup():getName() -local EnemyUnitName=DetectedUnit:GetName() -local FoundUnitInReportSetGroup=ReportSetGroup:FindGroup(FoundUnitGroupName)~=nil -self:T({"Friendlies search:",FoundUnitName,FoundUnitCoalition,EnemyUnitName,EnemyCoalition,FoundUnitInReportSetGroup}) -if FoundUnitInReportSetGroup==true then -for PrefixID,Prefix in pairs(self.FriendlyPrefixes or{})do -self:F({"FriendlyPrefix:",Prefix}) -if string.find(FoundUnitName,Prefix:gsub("-","%%-"),1)then -FoundUnitInReportSetGroup=false -break -end -end -end -self:F({"Friendlies search:",FoundUnitName,FoundUnitCoalition,EnemyUnitName,EnemyCoalition,FoundUnitInReportSetGroup}) -if FoundUnitCoalition~=EnemyCoalition and FoundUnitInReportSetGroup==false then -local FriendlyUnit=UNIT:Find(FoundDCSUnit) -local FriendlyUnitName=FriendlyUnit:GetName() -local FriendlyUnitCategory=FriendlyUnit:GetDesc().category -self:T({FriendlyUnitCategory=FriendlyUnitCategory,FriendliesCategory=self.FriendliesCategory}) -DetectedItem.FriendliesNearBy=DetectedItem.FriendliesNearBy or{} -DetectedItem.FriendliesNearBy[FriendlyUnitName]=FriendlyUnit -local Distance=DetectedUnitCoord:Get2DDistance(FriendlyUnit:GetCoordinate()) -DetectedItem.FriendliesDistance=DetectedItem.FriendliesDistance or{} -DetectedItem.FriendliesDistance[Distance]=FriendlyUnit -self:T({FriendlyUnitName=FriendlyUnitName,Distance=Distance}) -return true -end -return true -end -world.searchObjects(Object.Category.UNIT,SphereSearch,FindNearByFriendlies,ReportGroupData) -DetectedItem.PlayersNearBy=nil -local DetectionZone=ZONE_UNIT:New("DetectionPlayers",DetectedUnit,self.FriendliesRange) -_DATABASE:ForEachPlayer( -function(PlayerUnitName) -local PlayerUnit=UNIT:FindByName(PlayerUnitName) -if PlayerUnit and PlayerUnit:IsInZone(DetectionZone)then -local PlayerUnitCategory=PlayerUnit:GetDesc().category -if(not self.FriendliesCategory)or(self.FriendliesCategory and(self.FriendliesCategory==PlayerUnitCategory))then -DetectedItem.FriendliesNearBy=DetectedItem.FriendliesNearBy or{} -local PlayerUnitName=PlayerUnit:GetName() -DetectedItem.PlayersNearBy=DetectedItem.PlayersNearBy or{} -DetectedItem.PlayersNearBy[PlayerUnitName]=PlayerUnit -DetectedItem.FriendliesNearBy=DetectedItem.FriendliesNearBy or{} -DetectedItem.FriendliesNearBy[PlayerUnitName]=PlayerUnit -local Distance=DetectedUnitCoord:Get2DDistance(PlayerUnit:GetCoordinate()) -DetectedItem.FriendliesDistance=DetectedItem.FriendliesDistance or{} -DetectedItem.FriendliesDistance[Distance]=PlayerUnit -end -end -end -) -end -end -end -function DETECTION_BASE:IsDetectedObjectIdentified(DetectedObject) -local DetectedObjectName=DetectedObject.Name -if DetectedObjectName then -local DetectedObjectIdentified=self.DetectedObjectsIdentified[DetectedObjectName]==true -self:T3(DetectedObjectIdentified) -return DetectedObjectIdentified -else -return nil -end -end -function DETECTION_BASE:IdentifyDetectedObject(DetectedObject) -local DetectedObjectName=DetectedObject.Name -self.DetectedObjectsIdentified[DetectedObjectName]=true -end -function DETECTION_BASE:UnIdentifyDetectedObject(DetectedObject) -local DetectedObjectName=DetectedObject.Name -self.DetectedObjectsIdentified[DetectedObjectName]=false -end -function DETECTION_BASE:UnIdentifyAllDetectedObjects() -self.DetectedObjectsIdentified={} -end -function DETECTION_BASE:GetDetectedObject(ObjectName) -if ObjectName then -local DetectedObject=self.DetectedObjects[ObjectName] -if DetectedObject then -local DetectedUnit=UNIT:FindByName(ObjectName) -if DetectedUnit and DetectedUnit:IsAlive()then -if self:IsDetectedObjectIdentified(DetectedObject)==false then -return DetectedObject -end -end -end -end -return nil -end -function DETECTION_BASE:GetDetectedUnitTypeName(DetectedUnit) -if DetectedUnit and DetectedUnit:IsAlive()then -local DetectedUnitName=DetectedUnit:GetName() -local DetectedObject=self.DetectedObjects[DetectedUnitName] -if DetectedObject then -if DetectedObject.KnowType then -return DetectedUnit:GetTypeName() -else -return"Unknown" -end -else -return"Unknown" -end -else -return"Dead:"..DetectedUnit:GetName() -end -return"Undetected:"..DetectedUnit:GetName() -end -function DETECTION_BASE:AddDetectedItem(ItemPrefix,DetectedItemIndex,Set) -local DetectedItem={} -self.DetectedItemCount=self.DetectedItemCount+1 -self.DetectedItemMax=self.DetectedItemMax+1 -if DetectedItemIndex then -self.DetectedItems[DetectedItemIndex]=DetectedItem -else -self.DetectedItems[self.DetectedItemCount]=DetectedItem -end -DetectedItem.Set=Set or SET_UNIT:New():FilterDeads():FilterCrashes() -DetectedItem.Index=DetectedItemIndex or self.DetectedItemCount -DetectedItem.ItemID=ItemPrefix.."."..self.DetectedItemMax -DetectedItem.ID=self.DetectedItemMax -DetectedItem.Removed=false -return DetectedItem -end -function DETECTION_BASE:AddDetectedItemZone(DetectedItemIndex,Set,Zone) -local DetectedItem=self:AddDetectedItem("AREA",DetectedItemIndex,Set) -DetectedItem.Zone=Zone -return DetectedItem -end -function DETECTION_BASE:RemoveDetectedItem(DetectedItemIndex) -if self.DetectedItems[DetectedItemIndex]then -self.DetectedItemCount=self.DetectedItemCount-1 -self.DetectedItems[DetectedItemIndex]=nil -end -end -function DETECTION_BASE:GetDetectedItems() -return self.DetectedItems -end -function DETECTION_BASE:GetDetectedItemsCount() -local DetectedCount=self.DetectedItemCount -return DetectedCount -end -function DETECTION_BASE:GetDetectedItem(Index) -local DetectedItem=self.DetectedItems[Index] -if DetectedItem then -return DetectedItem -end -return nil -end -function DETECTION_BASE:GetDetectedItemID(Index) -local DetectedItem=self.DetectedItems[Index] -if DetectedItem then -return DetectedItem.ItemID -end -return"" -end -function DETECTION_BASE:GetDetectedID(Index) -local DetectedItem=self.DetectedItems[Index] -if DetectedItem then -return DetectedItem.ID -end -return"" -end -function DETECTION_BASE:GetDetectedSet(Index) -local DetectedItem=self:GetDetectedItem(Index) -local DetectedSetUnit=DetectedItem.Set -if DetectedSetUnit then -return DetectedSetUnit -end -return nil -end -function DETECTION_BASE:UpdateDetectedItemDetection(DetectedItem) -local IsDetected=false -for UnitName,UnitData in pairs(DetectedItem.Set:GetSet())do -local DetectedObject=self.DetectedObjects[UnitName] -self:F({UnitName=UnitName,IsDetected=DetectedObject.IsDetected}) -if DetectedObject.IsDetected then -IsDetected=true -break -end -end -self:F({IsDetected=DetectedItem.IsDetected}) -DetectedItem.IsDetected=IsDetected -return IsDetected -end -function DETECTION_BASE:IsDetectedItemDetected(DetectedItem) -return DetectedItem.IsDetected -end -do -function DETECTION_BASE:GetDetectedItemZone(Index) -local DetectedZone=self.DetectedItems[Index].Zone -if DetectedZone then -return DetectedZone -end -local Detected -return nil -end -end -function DETECTION_BASE:SetDetectedItemCoordinate(DetectedItem,Coordinate,DetectedItemUnit) -self:F({Coordinate=Coordinate}) -if DetectedItem then -if DetectedItemUnit then -DetectedItem.Coordinate=Coordinate -DetectedItem.Coordinate:SetHeading(DetectedItemUnit:GetHeading()) -DetectedItem.Coordinate.y=DetectedItemUnit:GetAltitude() -DetectedItem.Coordinate:SetVelocity(DetectedItemUnit:GetVelocityMPS()) -end -end -end -function DETECTION_BASE:GetDetectedItemCoordinate(Index) -self:F({Index=Index}) -local DetectedItem=self:GetDetectedItem(Index) -if DetectedItem then -return DetectedItem.Coordinate -end -return nil -end -function DETECTION_BASE:SetDetectedItemThreatLevel(DetectedItem) -local DetectedSet=DetectedItem.Set -if DetectedItem then -DetectedItem.ThreatLevel,DetectedItem.ThreatText=DetectedSet:CalculateThreatLevelA2G() -end -end -function DETECTION_BASE:GetDetectedItemThreatLevel(Index) -self:F({Index=Index}) -local DetectedItem=self:GetDetectedItem(Index) -if DetectedItem then -return DetectedItem.ThreatLevel or 0,DetectedItem.ThreatText or"" -end -return nil,"" -end -function DETECTION_BASE:DetectedItemMenu(Index,AttackGroup) -self:F(Index) -return nil -end -function DETECTION_BASE:DetectedItemReportSummary(Index,AttackGroup,Settings) -self:F(Index) -return nil -end -function DETECTION_BASE:DetectedReportDetailed(AttackGroup) -self:F() -return nil -end -function DETECTION_BASE:GetDetectionSetGroup() -local DetectionSetGroup=self.DetectionSetGroup -return DetectionSetGroup -end -function DETECTION_BASE:Schedule(DelayTime,RepeatInterval) -self:F2() -self.ScheduleDelayTime=DelayTime -self.ScheduleRepeatInterval=RepeatInterval -self.DetectionScheduler=SCHEDULER:New(self,self._DetectionScheduler,{self,"Detection"},DelayTime,RepeatInterval) -return self -end -end -do -DETECTION_UNITS={ -ClassName="DETECTION_UNITS", -DetectionRange=nil, -} -function DETECTION_UNITS:New(DetectionSetGroup) -local self=BASE:Inherit(self,DETECTION_BASE:New(DetectionSetGroup)) -self._SmokeDetectedUnits=false -self._FlareDetectedUnits=false -self._SmokeDetectedZones=false -self._FlareDetectedZones=false -self._BoundDetectedZones=false -return self -end -function DETECTION_UNITS:GetChangeText(DetectedItem) -self:F(DetectedItem) -local MT={} -for ChangeCode,ChangeData in pairs(DetectedItem.Changes)do -if ChangeCode=="AU"then -local MTUT={} -for ChangeUnitType,ChangeUnitCount in pairs(ChangeData)do -if ChangeUnitType~="ID"then -MTUT[#MTUT+1]=ChangeUnitCount.." of "..ChangeUnitType -end -end -MT[#MT+1]=" New target(s) detected: "..table.concat(MTUT,", ").."." -end -if ChangeCode=="RU"then -local MTUT={} -for ChangeUnitType,ChangeUnitCount in pairs(ChangeData)do -if ChangeUnitType~="ID"then -MTUT[#MTUT+1]=ChangeUnitCount.." of "..ChangeUnitType -end -end -MT[#MT+1]=" Invisible or destroyed target(s): "..table.concat(MTUT,", ").."." -end -end -return table.concat(MT,"\n") -end -function DETECTION_UNITS:CreateDetectionItems() -self:F2(#self.DetectedObjects) -for DetectedItemID,DetectedItem in pairs(self.DetectedItems)do -local DetectedItemSet=DetectedItem.Set -for DetectedUnitName,DetectedUnitData in pairs(DetectedItemSet:GetSet())do -local DetectedUnit=DetectedUnitData -local DetectedObject=nil -if DetectedUnit:IsAlive()then -DetectedObject=self:GetDetectedObject(DetectedUnit:GetName()) -end -if DetectedObject then -self:IdentifyDetectedObject(DetectedObject) -DetectedItem.TypeName=DetectedUnit:GetTypeName() -DetectedItem.CategoryName=DetectedUnit:GetCategoryName() -DetectedItem.Name=DetectedObject.Name -DetectedItem.IsVisible=DetectedObject.IsVisible -DetectedItem.LastTime=DetectedObject.LastTime -DetectedItem.LastPos=DetectedObject.LastPos -DetectedItem.LastVelocity=DetectedObject.LastVelocity -DetectedItem.KnowType=DetectedObject.KnowType -DetectedItem.KnowDistance=DetectedObject.KnowDistance -DetectedItem.Distance=DetectedObject.Distance -else -self:AddChangeUnit(DetectedItem,"RU",DetectedUnitName) -DetectedItemSet:Remove(DetectedUnitName) -end -end -end -for DetectedUnitName,DetectedObjectData in pairs(self.DetectedObjects)do -local DetectedObject=self:GetDetectedObject(DetectedUnitName) -if DetectedObject then -self:T({"Detected Unit #",DetectedUnitName}) -local DetectedUnit=UNIT:FindByName(DetectedUnitName) -if DetectedUnit then -local DetectedTypeName=DetectedUnit:GetTypeName() -local DetectedItem=self:GetDetectedItem(DetectedUnitName) -if not DetectedItem then -self:T("Added new DetectedItem") -DetectedItem=self:AddDetectedItem("UNIT",DetectedUnitName) -DetectedItem.TypeName=DetectedUnit:GetTypeName() -DetectedItem.Name=DetectedObject.Name -DetectedItem.IsVisible=DetectedObject.IsVisible -DetectedItem.LastTime=DetectedObject.LastTime -DetectedItem.LastPos=DetectedObject.LastPos -DetectedItem.LastVelocity=DetectedObject.LastVelocity -DetectedItem.KnowType=DetectedObject.KnowType -DetectedItem.KnowDistance=DetectedObject.KnowDistance -DetectedItem.Distance=DetectedObject.Distance -end -DetectedItem.Set:AddUnit(DetectedUnit) -self:AddChangeUnit(DetectedItem,"AU",DetectedTypeName) -end -end -end -for DetectedItemID,DetectedItemData in pairs(self.DetectedItems)do -local DetectedItem=DetectedItemData -local DetectedSet=DetectedItem.Set -local DetectedFirstUnit=DetectedSet:GetFirst() -local DetectedFirstUnitCoord=DetectedFirstUnit:GetCoordinate() -self:SetDetectedItemCoordinate(DetectedItem,DetectedFirstUnitCoord,DetectedFirstUnit) -self:ReportFriendliesNearBy({DetectedItem=DetectedItem,ReportSetGroup=self.DetectionSetGroup}) -end -end -function DETECTION_UNITS:DetectedItemMenu(Index,AttackGroup) -self:F(Index) -local DetectedItem=self:GetDetectedItem(Index) -local DetectedSet=self:GetDetectedSet(Index) -local DetectedItemID=self:GetDetectedItemID(Index) -self:T(DetectedSet) -if DetectedSet then -local ReportSummary="" -local UnitDistanceText="" -local UnitCategoryText="" -local DetectedItemCoordinate=self:GetDetectedItemCoordinate(Index) -local DetectedItemCoordText=DetectedItemCoordinate:ToString(AttackGroup) -ReportSummary=string.format( -"%s - %s", -DetectedItemID, -DetectedItemCoordText -) -self:T(ReportSummary) -return ReportSummary -end -end -function DETECTION_UNITS:DetectedItemReportSummary(Index,AttackGroup,Settings) -self:F({Index,self.DetectedItems}) -local DetectedItem=self:GetDetectedItem(Index) -local DetectedItemID=self:GetDetectedItemID(Index) -if DetectedItem then -local ReportSummary="" -local UnitDistanceText="" -local UnitCategoryText="" -if DetectedItem.KnowType then -local UnitCategoryName=DetectedItem.CategoryName -if UnitCategoryName then -UnitCategoryText=UnitCategoryName -end -if DetectedItem.TypeName then -UnitCategoryText=UnitCategoryText.." ("..DetectedItem.TypeName..")" -end -else -UnitCategoryText="Unknown" -end -if DetectedItem.KnowDistance then -if DetectedItem.IsVisible then -UnitDistanceText=" at "..string.format("%.2f",DetectedItem.Distance).." km" -end -else -if DetectedItem.IsVisible then -UnitDistanceText=" at +/- "..string.format("%.0f",DetectedItem.Distance).." km" -end -end -local DetectedItemCoordinate=self:GetDetectedItemCoordinate(Index) -local DetectedItemCoordText=DetectedItemCoordinate:ToString(AttackGroup,Settings) -local ThreatLevelA2G=self:GetDetectedItemThreatLevel(Index) -local Report=REPORT:New() -Report:Add(DetectedItemID..", "..DetectedItemCoordText) -Report:Add(string.format("Threat: [%s]",string.rep("■",ThreatLevelA2G))) -Report:Add(string.format("Type: %s%s",UnitCategoryText,UnitDistanceText)) -return Report -end -return nil -end -function DETECTION_UNITS:DetectedReportDetailed(AttackGroup) -self:F() -local Report=REPORT:New() -for DetectedItemID,DetectedItem in pairs(self.DetectedItems)do -local DetectedItem=DetectedItem -local ReportSummary=self:DetectedItemReportSummary(DetectedItemID,AttackGroup) -Report:SetTitle("Detected units:") -Report:Add(ReportSummary:Text()) -end -local ReportText=Report:Text() -return ReportText -end -end -do -DETECTION_TYPES={ -ClassName="DETECTION_TYPES", -DetectionRange=nil, -} -function DETECTION_TYPES:New(DetectionSetGroup) -local self=BASE:Inherit(self,DETECTION_BASE:New(DetectionSetGroup)) -self._SmokeDetectedUnits=false -self._FlareDetectedUnits=false -self._SmokeDetectedZones=false -self._FlareDetectedZones=false -self._BoundDetectedZones=false -return self -end -function DETECTION_TYPES:GetChangeText(DetectedItem) -self:F(DetectedItem) -local MT={} -for ChangeCode,ChangeData in pairs(DetectedItem.Changes)do -if ChangeCode=="AU"then -local MTUT={} -for ChangeUnitType,ChangeUnitCount in pairs(ChangeData)do -if ChangeUnitType~="ID"then -MTUT[#MTUT+1]=ChangeUnitCount.." of "..ChangeUnitType -end -end -MT[#MT+1]=" New target(s) detected: "..table.concat(MTUT,", ").."." -end -if ChangeCode=="RU"then -local MTUT={} -for ChangeUnitType,ChangeUnitCount in pairs(ChangeData)do -if ChangeUnitType~="ID"then -MTUT[#MTUT+1]=ChangeUnitCount.." of "..ChangeUnitType -end -end -MT[#MT+1]=" Invisible or destroyed target(s): "..table.concat(MTUT,", ").."." -end -end -return table.concat(MT,"\n") -end -function DETECTION_TYPES:CreateDetectionItems() -self:F2(#self.DetectedObjects) -for DetectedItemID,DetectedItem in pairs(self.DetectedItems)do -local DetectedItemSet=DetectedItem.Set -local DetectedTypeName=DetectedItem.TypeName -for DetectedUnitName,DetectedUnitData in pairs(DetectedItemSet:GetSet())do -local DetectedUnit=DetectedUnitData -local DetectedObject=nil -if DetectedUnit:IsAlive()then -DetectedObject=self:GetDetectedObject(DetectedUnit:GetName()) -end -if DetectedObject then -self:IdentifyDetectedObject(DetectedObject) -else -self:AddChangeUnit(DetectedItem,"RU",DetectedUnitName) -DetectedItemSet:Remove(DetectedUnitName) -end -end -end -for DetectedUnitName,DetectedObjectData in pairs(self.DetectedObjects)do -local DetectedObject=self:GetDetectedObject(DetectedUnitName) -if DetectedObject then -self:T({"Detected Unit #",DetectedUnitName}) -local DetectedUnit=UNIT:FindByName(DetectedUnitName) -if DetectedUnit then -local DetectedTypeName=DetectedUnit:GetTypeName() -local DetectedItem=self:GetDetectedItem(DetectedTypeName) -if not DetectedItem then -DetectedItem=self:AddDetectedItem("TYPE",DetectedTypeName) -DetectedItem.TypeName=DetectedUnit:GetTypeName() -end -DetectedItem.Set:AddUnit(DetectedUnit) -self:AddChangeUnit(DetectedItem,"AU",DetectedTypeName) -end -end -end -for DetectedItemID,DetectedItemData in pairs(self.DetectedItems)do -local DetectedItem=DetectedItemData -local DetectedSet=DetectedItem.Set -local DetectedFirstUnit=DetectedSet:GetFirst() -local DetectedUnitCoord=DetectedFirstUnit:GetCoordinate() -self:SetDetectedItemCoordinate(DetectedItem,DetectedUnitCoord,DetectedFirstUnit) -self:ReportFriendliesNearBy({DetectedItem=DetectedItem,ReportSetGroup=self.DetectionSetGroup}) -end -end -function DETECTION_TYPES:DetectedItemMenu(DetectedTypeName,AttackGroup) -self:F(DetectedTypeName) -local DetectedItem=self:GetDetectedItem(DetectedTypeName) -local DetectedItemID=self:GetDetectedItemID(DetectedTypeName) -if DetectedItem then -local DetectedItemCoordinate=self:GetDetectedItemCoordinate(DetectedTypeName) -local DetectedItemCoordText=DetectedItemCoordinate:ToString(AttackGroup) -local ReportSummary=string.format( -"%s - %s", -DetectedItemID, -DetectedItemCoordText -) -self:T(ReportSummary) -return ReportSummary -end -end -function DETECTION_TYPES:DetectedItemReportSummary(DetectedTypeName,AttackGroup,Settings) -self:F(DetectedTypeName) -local DetectedItem=self:GetDetectedItem(DetectedTypeName) -local DetectedSet=self:GetDetectedSet(DetectedTypeName) -local DetectedItemID=self:GetDetectedItemID(DetectedTypeName) -self:T(DetectedItem) -if DetectedItem then -local ThreatLevelA2G=self:GetDetectedItemThreatLevel(DetectedTypeName) -local DetectedItemsCount=DetectedSet:Count() -local DetectedItemType=DetectedItem.TypeName -local DetectedItemCoordinate=self:GetDetectedItemCoordinate(DetectedTypeName) -local DetectedItemCoordText=DetectedItemCoordinate:ToString(AttackGroup,Settings) -local Report=REPORT:New() -Report:Add(DetectedItemID..", "..DetectedItemCoordText) -Report:Add(string.format("Threat: [%s]",string.rep("■",ThreatLevelA2G))) -Report:Add(string.format("Type: %2d of %s",DetectedItemsCount,DetectedItemType)) -return Report -end -end -function DETECTION_TYPES:DetectedReportDetailed(AttackGroup) -self:F() -local Report=REPORT:New() -for DetectedItemTypeName,DetectedItem in pairs(self.DetectedItems)do -local DetectedItem=DetectedItem -local ReportSummary=self:DetectedItemReportSummary(DetectedItemTypeName,AttackGroup) -Report:SetTitle("Detected types:") -Report:Add(ReportSummary:Text()) -end -local ReportText=Report:Text() -return ReportText -end -end -do -DETECTION_AREAS={ -ClassName="DETECTION_AREAS", -DetectionZoneRange=nil, -} -function DETECTION_AREAS:New(DetectionSetGroup,DetectionZoneRange) -local self=BASE:Inherit(self,DETECTION_BASE:New(DetectionSetGroup)) -self.DetectionZoneRange=DetectionZoneRange -self._SmokeDetectedUnits=false -self._FlareDetectedUnits=false -self._SmokeDetectedZones=false -self._FlareDetectedZones=false -self._BoundDetectedZones=false -return self -end -function DETECTION_AREAS:DetectedItemMenu(Index,AttackGroup) -self:F(Index) -local DetectedItem=self:GetDetectedItem(Index) -local DetectedItemID=self:GetDetectedItemID(Index) -if DetectedItem then -local DetectedSet=self:GetDetectedSet(Index) -local ReportSummaryItem -local DetectedZone=self:GetDetectedItemZone(Index) -local DetectedItemCoordinate=DetectedZone:GetCoordinate() -local DetectedItemCoordText=DetectedItemCoordinate:ToString(AttackGroup) -local ReportSummary=string.format( -"%s - %s", -DetectedItemID, -DetectedItemCoordText -) -return ReportSummary -end -return nil -end -function DETECTION_AREAS:DetectedItemReportSummary(Index,AttackGroup,Settings) -self:F(Index) -local DetectedItem=self:GetDetectedItem(Index) -local DetectedItemID=self:GetDetectedItemID(Index) -if DetectedItem then -local DetectedSet=self:GetDetectedSet(Index) -local ReportSummaryItem -local DetectedZone=self:GetDetectedItemZone(Index) -local DetectedItemCoordinate=DetectedZone:GetCoordinate() -local DetectedItemCoordText=DetectedItemCoordinate:ToString(AttackGroup,Settings) -local ThreatLevelA2G=self:GetDetectedItemThreatLevel(Index) -local DetectedItemsCount=DetectedSet:Count() -local DetectedItemsTypes=DetectedSet:GetTypeNames() -local Report=REPORT:New() -Report:Add(DetectedItemID..", "..DetectedItemCoordText) -Report:Add(string.format("Threat: [%s]",string.rep("■",ThreatLevelA2G))) -Report:Add(string.format("Type: %2d of %s",DetectedItemsCount,DetectedItemsTypes)) -return Report -end -return nil -end -function DETECTION_AREAS:DetectedReportDetailed(AttackGroup) -self:F() -local Report=REPORT:New() -for DetectedItemIndex,DetectedItem in pairs(self.DetectedItems)do -local DetectedItem=DetectedItem -local ReportSummary=self:DetectedItemReportSummary(DetectedItemIndex,AttackGroup) -Report:SetTitle("Detected areas:") -Report:Add(ReportSummary:Text()) -end -local ReportText=Report:Text() -return ReportText -end -function DETECTION_AREAS:CalculateIntercept(DetectedItem) -local DetectedCoord=DetectedItem.Coordinate -local DetectedSpeed=DetectedCoord:GetVelocity() -local DetectedHeading=DetectedCoord:GetHeading() -if self.Intercept then -local DetectedSet=DetectedItem.Set -local TranslateDistance=DetectedSpeed*self.InterceptDelay -local InterceptCoord=DetectedCoord:Translate(TranslateDistance,DetectedHeading) -DetectedItem.InterceptCoord=InterceptCoord -else -DetectedItem.InterceptCoord=DetectedCoord -end -end -function DETECTION_AREAS:NearestFAC(DetectedItem) -local NearestRecce=nil -local DistanceRecce=1000000000 -for RecceGroupName,RecceGroup in pairs(self.DetectionSetGroup:GetSet())do -if RecceGroup and RecceGroup:IsAlive()then -for RecceUnit,RecceUnit in pairs(RecceGroup:GetUnits())do -if RecceUnit:IsActive()then -local RecceUnitCoord=RecceUnit:GetCoordinate() -local Distance=RecceUnitCoord:Get2DDistance(self:GetDetectedItemCoordinate(DetectedItem.Index)) -if Distance=timer.getTime()))then -TargetSetUnit:ForEachUnitPerThreatLevel(10,0, -function(TargetUnit) -self:F({TargetUnit=TargetUnit:GetName()}) -if MarkingCountFLmax then -FLmin=FLmax*0.75 -end -if self.category==RAT.cat.heli then -FLmin=math.max(H_departure,H_destination)+50 -FLmax=math.max(H_departure,H_destination)+1000 -end -FLmax=math.min(FLmax,self.aircraft.ceiling*0.9) -if self.FLminuser then -FLmin=self.FLminuser -end -if self.FLmaxuser then -FLmax=self.FLmaxuser -end -if self.aircraft.FLcruiseFLmax then -self.aircraft.FLcruise=FLmax -end -local FLcruise=self:_Random_Gaussian(self.aircraft.FLcruise,(FLmax-FLmin)/4,FLmin,FLmax) -if self.FLuser then -FLcruise=self.FLuser -end -local h_climb=FLcruise-H_departure -local d_climb=h_climb/math.tan(PhiClimb) -local h_descent=FLcruise-(H_holding+h_holding) -local d_descent=h_descent/math.tan(PhiDescent) -local d_cruise=d_total-d_climb-d_descent -local text=string.format("\n******************************************************\n") -text=text..string.format("Template = %s\n\n",self.SpawnTemplatePrefix) -text=text..string.format("Speeds:\n") -text=text..string.format("VxCruiseMin = %6.1f m/s = %5.1f km/h\n",VxCruiseMin,VxCruiseMin*3.6) -text=text..string.format("VxCruiseMax = %6.1f m/s = %5.1f km/h\n",VxCruiseMax,VxCruiseMax*3.6) -text=text..string.format("VxCruise = %6.1f m/s = %5.1f km/h\n",VxCruise,VxCruise*3.6) -text=text..string.format("VxClimb = %6.1f m/s = %5.1f km/h\n",VxClimb,VxClimb*3.6) -text=text..string.format("VxDescent = %6.1f m/s = %5.1f km/h\n",VxDescent,VxDescent*3.6) -text=text..string.format("VxHolding = %6.1f m/s = %5.1f km/h\n",VxHolding,VxHolding*3.6) -text=text..string.format("VxFinal = %6.1f m/s = %5.1f km/h\n",VxFinal,VxFinal*3.6) -text=text..string.format("VyClimb = %6.1f m/s\n",VyClimb) -text=text..string.format("\nDistances:\n") -text=text..string.format("d_climb = %6.1f km\n",d_climb/1000) -text=text..string.format("d_cruise = %6.1f km\n",d_cruise/1000) -text=text..string.format("d_descent = %6.1f km\n",d_descent/1000) -text=text..string.format("d_holding = %6.1f km\n",d_holding/1000) -text=text..string.format("d_total = %6.1f km\n",d_total/1000) -text=text..string.format("\nHeights:\n") -text=text..string.format("H_departure = %6.1f m ASL\n",H_departure) -text=text..string.format("H_destination = %6.1f m ASL\n",H_destination) -text=text..string.format("H_holding = %6.1f m ASL\n",H_holding) -text=text..string.format("h_climb = %6.1f m\n",h_climb) -text=text..string.format("h_descent = %6.1f m\n",h_descent) -text=text..string.format("h_holding = %6.1f m\n",h_holding) -text=text..string.format("delta H = %6.1f m\n",deltaH) -text=text..string.format("FLmin = %6.1f m ASL = FL%03d\n",FLmin,FLmin/RAT.unit.FL2m) -text=text..string.format("FLcruise = %6.1f m ASL = FL%03d\n",FLcruise,FLcruise/RAT.unit.FL2m) -text=text..string.format("FLmax = %6.1f m ASL = FL%03d\n",FLmax,FLmax/RAT.unit.FL2m) -text=text..string.format("\nAngles:\n") -text=text..string.format("Alpha climb = %6.1f Deg\n",math.deg(AlphaClimb)) -text=text..string.format("Alpha descent = %6.1f Deg\n",math.deg(AlphaDescent)) -text=text..string.format("Phi (slope) = %6.1f Deg\n",math.deg(phi)) -text=text..string.format("Phi climb = %6.1f Deg\n",math.deg(PhiClimb)) -text=text..string.format("Phi descent = %6.1f Deg\n",math.deg(PhiDescent)) -text=text..string.format("Heading = %6.1f Deg\n",heading) -text=text..string.format("******************************************************\n") -env.info(RAT.id..text) -if d_cruise<0 then -d_cruise=100 -end -local c0=Pdeparture -local c1=c0:Translate(d_climb/2,heading) -local c2=c1:Translate(d_climb/2,heading) -local c3=c2:Translate(d_cruise,heading) -local c4=c3:Translate(d_descent/2,heading) -local c5=Pholding -local c6=Pdestination -local wp0=self:_Waypoint(takeoff,c0,VxClimb,H_departure,departure) -local wp1=self:_Waypoint(RAT.wp.climb,c1,VxClimb,H_departure+(FLcruise-H_departure)/2) -local wp2=self:_Waypoint(RAT.wp.cruise,c2,VxCruise,FLcruise) -local wp3=self:_Waypoint(RAT.wp.cruise,c3,VxCruise,FLcruise) -local wp4=self:_Waypoint(RAT.wp.descent,c4,VxDescent,FLcruise-(FLcruise-(h_holding+H_holding))/2) -local wp5=self:_Waypoint(RAT.wp.holding,c5,VxHolding,H_holding+h_holding) -local wp6=self:_Waypoint(RAT.wp.landing,c6,VxFinal,H_destination,destination) -local waypoints={wp0,wp1,wp2,wp3,wp4,wp5,wp6} -if self.placemarkers then -self:_PlaceMarkers(waypoints) -end -self:_Routeinfo(waypoints,"Waypoint info in set_route:") -return departure,destination,waypoints -end -function RAT:_PickDeparture(takeoff) -local departures={} -if takeoff==RAT.wp.air then -if self.random_departure then -for _,airport in pairs(self.airports)do -if not self:_Excluded(airport:GetName())then -table.insert(departures,airport:GetZone()) -end -end -else -for _,name in pairs(self.departure_zones)do -if not self:_Excluded(name)then -table.insert(departures,ZONE:New(name)) -end -end -for _,name in pairs(self.departure_ports)do -if not self:_Excluded(name)then -table.insert(departures,AIRBASE:FindByName(name):GetZone()) -end -end -end -else -if self.random_departure then -for _,airport in pairs(self.airports)do -if not self:_Excluded(airport:GetName())then -table.insert(departures,airport) -end -end -else -for _,name in pairs(self.departure_ports)do -if not self:_Excluded(name)then -table.insert(departures,AIRBASE:FindByName(name)) -end -end -end -end -local departure=departures[math.random(#departures)] -local text -if departure and departure:GetName()then -if takeoff==RAT.wp.air then -text="Chosen departure zone: "..departure:GetName() -else -text="Chosen departure airport: "..departure:GetName().." (ID "..departure:GetID()..")" -end -env.info(RAT.id..text) -if self.debug then -MESSAGE:New(text,30):ToAll() -end -else -departure=nil -end -return departure -end -function RAT:_PickDestination(destinations,_random) -local destination=nil -if destinations and#destinations>0 then -destination=destinations[math.random(#destinations)] -local text="Chosen destination airport: "..destination:GetName().." (ID "..destination:GetID()..")" -env.info(RAT.id..text) -if self.debug then -MESSAGE:New(text,30):ToAll() -end -else -env.error(RAT.id.."No destination airport found.") -end -return destination -end -function RAT:_GetDestinations(departure,q,minrange,maxrange) -minrange=minrange or self.mindist -maxrange=maxrange or self.maxdist -local possible_destinations={} -if self.random_destination then -for _,airport in pairs(self.airports)do -local name=airport:GetName() -if self:_IsFriendly(name)and not self:_Excluded(name)and name~=departure:GetName()then -local distance=q:Get2DDistance(airport:GetCoordinate()) -if distance>=minrange and distance<=maxrange then -table.insert(possible_destinations,airport) -end -end -end -else -for _,name in pairs(self.destination_ports)do -if name~=departure:GetName()then -local airport=AIRBASE:FindByName(name) -table.insert(possible_destinations,airport) -end -end -end -env.info(RAT.id.."Number of possible destination airports = "..#possible_destinations) -if#possible_destinations>0 then -local function compare(a,b) -local qa=q:Get2DDistance(a:GetCoordinate()) -local qb=q:Get2DDistance(b:GetCoordinate()) -return qaself.Tinactive then -if Dg<50 then -stationary=true -end -self.ratcraft[i]["Tlastcheck"]=Tnow -self.ratcraft[i]["Pground"]=coords -end -else -self.ratcraft[i]["Tground"]=Tnow -self.ratcraft[i]["Tlastcheck"]=Tnow -self.ratcraft[i]["Pground"]=coords -end -end -local Pn=coords -local Dtravel=Pn:Get2DDistance(self.ratcraft[i]["Pnow"]) -self.ratcraft[i]["Pnow"]=Pn -self.ratcraft[i]["Distance"]=self.ratcraft[i]["Distance"]+Dtravel -local Ddestination=Pn:Get2DDistance(self.ratcraft[i].destination:GetCoordinate()) -local Hp=COORDINATE:New(self.ratcraft[i].waypoints[6].x,self.ratcraft[i].waypoints[6].alt,self.ratcraft[i].waypoints[6].y) -local Dholding=Pn:Get2DDistance(Hp) -local status=self.ratcraft[i].status -local DRholding -if self.category==RAT.cat.plane then -DRholding=8000 -else -DRholding=2000 -end -if self.ATCswitch and Dholding<=DRholding and string.match(status,"On journey")then -RAT:_ATCRegisterFlight(group:GetName(),Tnow) -self.ratcraft[i].status="Holding" -end -if(forID and i==forID)or(not forID)then -local text=string.format("ID %i of group %s\n",i,prefix) -if self.commute then -text=text..string.format("%s commuting between %s and %s\n",type,departure,destination) -elseif self.continuejourney then -text=text..string.format("%s travelling from %s to %s (and continueing form there)\n",type,departure,destination) -else -text=text..string.format("%s travelling from %s to %s\n",type,departure,destination) -end -text=text..string.format("Status: %s",self.ratcraft[i].status) -if airborne then -text=text.." [airborne]\n" -else -text=text.." [on ground]\n" -end -text=text..string.format("Fuel = %3.0f %%\n",fuel) -text=text..string.format("Life = %3.0f %%\n",life) -text=text..string.format("FL%03d = %i m\n",alt/RAT.unit.FL2m,alt) -text=text..string.format("Distance travelled = %6.1f km\n",self.ratcraft[i]["Distance"]/1000) -text=text..string.format("Distance to destination = %6.1f km",Dholding/1000) -if not airborne then -text=text..string.format("\nTime on ground = %6.0f seconds\n",Tg) -text=text..string.format("Position change = %8.1f m since %3.0f seconds.",Dg,dTlast) -end -if self.debug then -env.info(RAT.id..text) -end -if self.reportstatus or message then -MESSAGE:New(text,20):ToAll() -end -end -if not airborne then -if stationary then -local text=string.format("Group %s is despawned after being %4.0f seconds inaktive on ground.",self.SpawnTemplatePrefix,dTlast) -env.info(RAT.id..text) -self:_Despawn(group) -end -if life<10 and Dtravel<100 then -local text=string.format("Damaged group %s is despawned. Life = %3.0f",self.SpawnTemplatePrefix,life) -self:_Despawn(group) -end -end -end -else -if self.debug then -local text=string.format("Group %i does not exist.",i) -env.info(RAT.id..text) -end -end -end -end -function RAT:_GetLife(group) -local life=0.0 -if group and group:IsAlive()then -local unit=group:GetUnit(1) -if unit then -life=unit:GetLife()/unit:GetLife0()*100 -else -if self.debug then -env.error(RAT.id.."Unit does not exist in RAT_Getlife(). Returning zero.") -end -end -else -if self.debug then -env.error(RAT.id.."Group does not exist in RAT_Getlife(). Returning zero.") -end -end -return life -end -function RAT:_SetStatus(group,status) -local index=self:GetSpawnIndexFromGroup(group) -env.info(RAT.id.."Status for group "..group:GetName()..": "..status) -self.ratcraft[index].status=status -end -function RAT:_OnBirth(EventData) -local SpawnGroup=EventData.IniGroup -if SpawnGroup then -local EventPrefix=self:_GetPrefixFromGroup(SpawnGroup) -if EventPrefix then -if EventPrefix==self.alias then -local text="Event: Group "..SpawnGroup:GetName().." was born." -env.info(RAT.id..text) -local status -if SpawnGroup:InAir()then -status="Just born (after air start)" -else -status="Starting engines (after birth)" -end -self:_SetStatus(SpawnGroup,status) -end -end -else -if self.debug then -env.error("Group does not exist in RAT:_OnBirthDay().") -end -end -end -function RAT:_EngineStartup(EventData) -local SpawnGroup=EventData.IniGroup -if SpawnGroup then -local EventPrefix=self:_GetPrefixFromGroup(SpawnGroup) -if EventPrefix then -if EventPrefix==self.alias then -local text="Event: Group "..SpawnGroup:GetName().." started engines." -env.info(RAT.id..text) -local status -if SpawnGroup:InAir()then -status="On journey (after air start)" -else -status="Taxiing (after engines started)" -end -self:_SetStatus(SpawnGroup,status) -end -end -else -if self.debug then -env.error("Group does not exist in RAT:_EngineStartup().") -end -end -end -function RAT:_OnTakeoff(EventData) -local SpawnGroup=EventData.IniGroup -if SpawnGroup then -local EventPrefix=self:_GetPrefixFromGroup(SpawnGroup) -if EventPrefix then -if EventPrefix==self.alias then -local text="Event: Group "..SpawnGroup:GetName().." is airborne." -env.info(RAT.id..text) -self:_SetStatus(SpawnGroup,"On journey (after takeoff)") -end -end -else -if self.debug then -env.error("Group does not exist in RAT:_OnTakeoff().") -end -end -end -function RAT:_OnLand(EventData) -local SpawnGroup=EventData.IniGroup -if SpawnGroup then -local EventPrefix=self:_GetPrefixFromGroup(SpawnGroup) -if EventPrefix then -if EventPrefix==self.alias then -local text="Event: Group "..SpawnGroup:GetName().." landed." -env.info(RAT.id..text) -self:_SetStatus(SpawnGroup,"Taxiing (after landing)") -if self.ATCswitch then -RAT:_ATCFlightLanded(SpawnGroup:GetName()) -end -if self.respawn_at_landing then -text="Event: Group "..SpawnGroup:GetName().." will be respawned." -env.info(RAT.id..text) -self:_Respawn(SpawnGroup) -end -end -end -else -if self.debug then -env.error("Group does not exist in RAT:_OnLand().") -end -end -end -function RAT:_OnEngineShutdown(EventData) -local SpawnGroup=EventData.IniGroup -if SpawnGroup then -local EventPrefix=self:_GetPrefixFromGroup(SpawnGroup) -if EventPrefix then -if EventPrefix==self.alias then -local text="Event: Group "..SpawnGroup:GetName().." shut down its engines." -env.info(RAT.id..text) -self:_SetStatus(SpawnGroup,"Parking (shutting down engines)") -if not self.respawn_at_landing then -text="Event: Group "..SpawnGroup:GetName().." will be respawned." -env.info(RAT.id..text) -self:_Respawn(SpawnGroup) -end -text="Event: Group "..SpawnGroup:GetName().." will be destroyed now." -env.info(RAT.id..text) -self:_Despawn(SpawnGroup) -end -end -else -if self.debug then -env.error("Group does not exist in RAT:_OnEngineShutdown().") -end -end -end -function RAT:_OnDead(EventData) -local SpawnGroup=EventData.IniGroup -if SpawnGroup then -local EventPrefix=self:_GetPrefixFromGroup(SpawnGroup) -if EventPrefix then -if EventPrefix==self.alias then -local text="Event: Group "..SpawnGroup:GetName().." died." -env.info(RAT.id..text) -self:_SetStatus(SpawnGroup,"Destroyed (after dead)") -end -end -else -if self.debug then -env.error("Group does not exist in RAT:_OnDead().") -end -end -end -function RAT:_OnCrash(EventData) -local SpawnGroup=EventData.IniGroup -env.info(string.format("%sGroup %s crashed!",RAT.id,SpawnGroup:GetName())) -if SpawnGroup then -local EventPrefix=self:_GetPrefixFromGroup(SpawnGroup) -if EventPrefix then -if EventPrefix==self.alias then -local text="Event: Group "..SpawnGroup:GetName().." crashed." -env.info(RAT.id..text) -self:_SetStatus(SpawnGroup,"Crashed") -end -end -else -if self.debug then -env.error("Group does not exist in RAT:_OnCrash().") -end -end -end -function RAT:_Despawn(group) -local index=self:GetSpawnIndexFromGroup(group) -self.ratcraft[index].group:Destroy() -self.ratcraft[index].group=nil -self.alive=self.alive-1 -if self.f10menu then -self.Menu[self.SubMenuName]["groups"][index]:Remove() -end -end -function RAT:_Waypoint(Type,Coord,Speed,Altitude,Airport) -local _Altitude=Altitude or Coord.y -local Hland=Coord:GetLandHeight() -local _Type=nil -local _Action=nil -local _alttype="RADIO" -local _AID=nil -if Type==RAT.wp.cold then -_Type="TakeOffParking" -_Action="From Parking Area" -_Altitude=0 -_alttype="RADIO" -_AID=Airport:GetID() -elseif Type==RAT.wp.hot then -_Type="TakeOffParkingHot" -_Action="From Parking Area Hot" -_Altitude=0 -_alttype="RADIO" -_AID=Airport:GetID() -elseif Type==RAT.wp.runway then -_Type="TakeOff" -_Action="From Parking Area" -_Altitude=0 -_alttype="RADIO" -_AID=Airport:GetID() -elseif Type==RAT.wp.air then -_Type="Turning Point" -_Action="Turning Point" -_alttype="BARO" -elseif Type==RAT.wp.climb then -_Type="Turning Point" -_Action="Turning Point" -_alttype="BARO" -elseif Type==RAT.wp.cruise then -_Type="Turning Point" -_Action="Turning Point" -_alttype="BARO" -elseif Type==RAT.wp.descent then -_Type="Turning Point" -_Action="Turning Point" -_alttype="BARO" -elseif Type==RAT.wp.holding then -_Type="Turning Point" -_Action="Turning Point" -_alttype="BARO" -elseif Type==RAT.wp.landing then -_Type="Land" -_Action="Landing" -_Altitude=0 -_alttype="RADIO" -_AID=Airport:GetID() -else -env.error("Unknown waypoint type in RAT:Waypoint() function!") -_Type="Turning Point" -_Action="Turning Point" -_alttype="RADIO" -end -local text=string.format("\n******************************************************\n") -text=text..string.format("Template = %s\n",self.SpawnTemplatePrefix) -text=text..string.format("Type: %i - %s\n",Type,_Type) -text=text..string.format("Action: %s\n",_Action) -text=text..string.format("Coord: x = %6.1f km, y = %6.1f km, alt = %6.1f m\n",Coord.x/1000,Coord.z/1000,Coord.y) -text=text..string.format("Speed = %6.1f m/s = %6.1f km/h = %6.1f knots\n",Speed,Speed*3.6,Speed*1.94384) -text=text..string.format("Land = %6.1f m ASL\n",Hland) -text=text..string.format("Altitude = %6.1f m (%s)\n",_Altitude,_alttype) -if Airport then -if Type==RAT.wp.air then -text=text..string.format("Zone = %s\n",Airport:GetName()) -else -text=text..string.format("Airport = %s with ID %i\n",Airport:GetName(),Airport:GetID()) -end -else -text=text..string.format("No airport/zone specified\n") -end -text=text.."******************************************************\n" -if self.debug then -env.info(RAT.id..text) -end -local RoutePoint={} -RoutePoint.x=Coord.x -RoutePoint.y=Coord.z -RoutePoint.alt=_Altitude -RoutePoint.alt_type=_alttype -RoutePoint.type=_Type -RoutePoint.action=_Action -RoutePoint.speed=Speed -RoutePoint.speed_locked=true -RoutePoint.ETA=nil -RoutePoint.ETA_locked=false -RoutePoint.name="RAT waypoint" -if(Airport~=nil)and Type~=RAT.wp.air then -local AirbaseID=Airport:GetID() -local AirbaseCategory=Airport:GetDesc().category -if AirbaseCategory==Airbase.Category.SHIP then -RoutePoint.linkUnit=AirbaseID -RoutePoint.helipadId=AirbaseID -elseif AirbaseCategory==Airbase.Category.HELIPAD then -RoutePoint.linkUnit=AirbaseID -RoutePoint.helipadId=AirbaseID -elseif AirbaseCategory==Airbase.Category.AIRDROME then -RoutePoint.airdromeId=AirbaseID -else -end -end -RoutePoint.properties={ -["vnav"]=1, -["scale"]=0, -["angle"]=0, -["vangle"]=0, -["steer"]=2, -} -if Type==RAT.wp.holding then -local Duration=self:_Randomize(90,0.9) -RoutePoint.task=self:_TaskHolding({x=Coord.x,y=Coord.z},Altitude,Speed,Duration) -else -RoutePoint.task={} -RoutePoint.task.id="ComboTask" -RoutePoint.task.params={} -RoutePoint.task.params.tasks={} -end -return RoutePoint -end -function RAT:_Routeinfo(waypoints,comment) -local text=string.format("\n******************************************************\n") -text=text..string.format("Template = %s\n",self.SpawnTemplatePrefix) -if comment then -text=text..comment.."\n" -end -text=text..string.format("Number of waypoints = %i\n",#waypoints) -for i=1,#waypoints do -local p=waypoints[i] -text=text..string.format("WP #%i: x = %6.1f km, y = %6.1f km, alt = %6.1f m\n",i-1,p.x/1000,p.y/1000,p.alt) -end -local total=0.0 -for i=1,#waypoints-1 do -local point1=waypoints[i] -local point2=waypoints[i+1] -local x1=point1.x -local y1=point1.y -local x2=point2.x -local y2=point2.y -local d=math.sqrt((x1-x2)^2+(y1-y2)^2) -local heading=self:_Course(point1,point2) -total=total+d -text=text..string.format("Distance from WP %i-->%i = %6.1f km. Heading = %i.\n",i-1,i,d/1000,heading) -end -text=text..string.format("Total distance = %6.1f km\n",total/1000) -local text=string.format("******************************************************\n") -if self.debug then -env.info(RAT.id..text) -end -return total -end -function RAT:_TaskHolding(P1,Altitude,Speed,Duration) -local dx=3000 -local dy=0 -if self.category==RAT.cat.heli then -dx=200 -dy=0 -end -local P2={} -P2.x=P1.x+dx -P2.y=P1.y+dy -local Task={ -id='Orbit', -params={ -pattern=AI.Task.OrbitPattern.RACE_TRACK, -point=P1, -point2=P2, -speed=Speed, -altitude=Altitude -} -} -local DCSTask={} -DCSTask.id="ControlledTask" -DCSTask.params={} -DCSTask.params.task=Task -if self.ATCswitch then -local userflagname=string.format("%s#%03d",self.alias,self.SpawnIndex+1) -DCSTask.params.stopCondition={userFlag=userflagname,userFlagValue=1,duration=1800} -else -DCSTask.params.stopCondition={duration=Duration} -end -return DCSTask -end -function RAT:_FLmax(alpha,beta,d,phi,h0) -local gamma=math.rad(180)-alpha-beta -local a=d*math.sin(alpha)/math.sin(gamma) -local b=d*math.sin(beta)/math.sin(gamma) -local h1=b*math.sin(alpha) -local h2=a*math.sin(beta) -local h3=b*math.cos(math.pi/2-(alpha+phi)) -local text=string.format("\nFLmax = FL%3.0f = %6.1f m.\n",h1/RAT.unit.FL2m,h1) -text=text..string.format("FLmax = FL%3.0f = %6.1f m.\n",h2/RAT.unit.FL2m,h2) -text=text..string.format("FLmax = FL%3.0f = %6.1f m.",h3/RAT.unit.FL2m,h3) -if self.debug then -env.info(RAT.id..text) -end -return h3+h0 -end -function RAT:_MinDistance(alpha,beta,h) -local d1=h/math.tan(alpha) -local d2=h/math.tan(beta) -return d1+d2 -end -function RAT:_AirportExists(name) -for _,airport in pairs(self.airports_map)do -if airport:GetName()==name then -return true -end -end -return false -end -function RAT:_SetROE(group,roe) -env.info(RAT.id.."Setting ROE to "..roe.." for group "..group:GetName()) -if self.roe==RAT.ROE.returnfire then -group:OptionROEReturnFire() -elseif self.roe==RAT.ROE.weaponfree then -group:OptionROEWeaponFree() -else -group:OptionROEHoldFire() -end -end -function RAT:_SetROT(group,rot) -env.info(RAT.id.."Setting ROT to "..rot.." for group "..group:GetName()) -if self.rot==RAT.ROT.passive then -group:OptionROTPassiveDefense() -elseif self.rot==RAT.ROT.evade then -group:OptionROTEvadeFire() -else -group:OptionROTNoReaction() -end -end -function RAT:_SetCoalitionTable() -if self.friendly==RAT.coal.neutral then -self.ctable={coalition.side.NEUTRAL} -elseif self.friendly==RAT.coal.same then -self.ctable={self.coalition,coalition.side.NEUTRAL} -elseif self.friendly==RAT.coal.sameonly then -self.ctable={self.coalition} -else -env.error("Unknown friendly coalition in _SetCoalitionTable(). Defaulting to NEUTRAL.") -self.ctable={self.coalition,coalition.side.NEUTRAL} -end -end -function RAT:_Course(a,b) -local dx=b.x-a.x -local ay -if a.alt then -ay=a.y -else -ay=a.z -end -local by -if b.alt then -by=b.y -else -by=b.z -end -local dy=by-ay -local angle=math.deg(math.atan2(dy,dx)) -if angle<0 then -angle=360+angle -end -return angle -end -function RAT:_Randomize(value,fac,lower,upper) -local min -if lower then -min=math.max(value-value*fac,lower) -else -min=value-value*fac -end -local max -if upper then -max=math.min(value+value*fac,upper) -else -max=value+value*fac -end -local r=math.random(min,max) -if self.debug then -local text=string.format("Random: value = %6.2f, fac = %4.2f, min = %6.2f, max = %6.2f, r = %6.2f",value,fac,min,max,r) -env.info(RAT.id..text) -end -return r -end -function RAT:_Random_Gaussian(x0,sigma,xmin,xmax) -sigma=sigma or 10 -local r -local gotit=false -local i=0 -while not gotit do -local x1=math.random() -local x2=math.random() -r=math.sqrt(-2*sigma*sigma*math.log(x1))*math.cos(2*math.pi*x2)+x0 -i=i+1 -if(r>=xmin and r<=xmax)or i>100 then -gotit=true -end -end -return r -end -function RAT:_PlaceMarkers(waypoints) -self:_SetMarker("Takeoff",waypoints[1]) -self:_SetMarker("Climb",waypoints[2]) -self:_SetMarker("Begin of Cruise",waypoints[3]) -self:_SetMarker("End of Cruise",waypoints[4]) -self:_SetMarker("Descent",waypoints[5]) -self:_SetMarker("Holding Point",waypoints[6]) -self:_SetMarker("Destination",waypoints[7]) -end -function RAT:_SetMarker(text,wp) -RAT.markerid=RAT.markerid+1 -self.markerids[#self.markerids+1]=RAT.markerid -if self.debug then -env.info(RAT.id..self.SpawnTemplatePrefix..": placing marker with ID "..RAT.markerid..": "..text) -end -local vec={x=wp.x,y=wp.alt,z=wp.y} -local text1=string.format("%s:\n%s",self.alias,text) -trigger.action.markToAll(RAT.markerid,text1,vec) -end -function RAT:_DeleteMarkers() -for k,v in ipairs(self.markerids)do -trigger.action.removeMark(v) -end -for k,v in ipairs(self.markerids)do -self.markerids[k]=nil -end -end -function RAT:_ModifySpawnTemplate(waypoints) -local PointVec3={x=waypoints[1].x,y=waypoints[1].alt,z=waypoints[1].y} -local heading=self:_Course(waypoints[1],waypoints[2]) -if self:_GetSpawnIndex(self.SpawnIndex+1)then -local SpawnTemplate=self.SpawnGroups[self.SpawnIndex].SpawnTemplate -if SpawnTemplate then -self:T(SpawnTemplate) -for UnitID=1,#SpawnTemplate.units do -self:T('Before Translation SpawnTemplate.units['..UnitID..'].x = '..SpawnTemplate.units[UnitID].x..', SpawnTemplate.units['..UnitID..'].y = '..SpawnTemplate.units[UnitID].y) -local UnitTemplate=SpawnTemplate.units[UnitID] -local SX=UnitTemplate.x -local SY=UnitTemplate.y -local BX=SpawnTemplate.route.points[1].x -local BY=SpawnTemplate.route.points[1].y -local TX=PointVec3.x+(SX-BX) -local TY=PointVec3.z+(SY-BY) -SpawnTemplate.units[UnitID].x=TX -SpawnTemplate.units[UnitID].y=TY -SpawnTemplate.units[UnitID].alt=PointVec3.y -SpawnTemplate.units[UnitID].heading=math.rad(heading) -if self.livery then -SpawnTemplate.units[UnitID].livery_id=self.livery[math.random(#self.livery)] -end -SpawnTemplate.units[UnitID]["skill"]=self.skill -SpawnTemplate.units[UnitID]["onboard_num"]=self.SpawnIndex -SpawnTemplate.CoalitionID=self.coalition -if self.country then -SpawnTemplate.CountryID=self.country -end -UnitTemplate.parking=nil -UnitTemplate.parking_id=nil -UnitTemplate.alt=PointVec3.y -self:T('After Translation SpawnTemplate.units['..UnitID..'].x = '..SpawnTemplate.units[UnitID].x..', SpawnTemplate.units['..UnitID..'].y = '..SpawnTemplate.units[UnitID].y) -end -for i,wp in ipairs(waypoints)do -SpawnTemplate.route.points[i]=wp -end -SpawnTemplate.x=PointVec3.x -SpawnTemplate.y=PointVec3.z -self.SpawnGroups[self.SpawnIndex].SpawnTemplate=SpawnTemplate -self:T(SpawnTemplate) -end -end -end -function RAT:_ATCInit(airports_map) -if not RAT.ATC.init then -env.info(RAT.id.."Starting RAT ATC.") -RAT.ATC.init=true -for _,ap in pairs(airports_map)do -local name=ap:GetName() -RAT.ATC.airport[name]={} -RAT.ATC.airport[name].queue={} -RAT.ATC.airport[name].busy=false -RAT.ATC.airport[name].onfinal=nil -RAT.ATC.airport[name].traffic=0 -end -SCHEDULER:New(nil,RAT._ATCCheck,{self},5,15) -SCHEDULER:New(nil,RAT._ATCStatus,{self},5,60) -RAT.ATC.T0=timer.getTime() -end -end -function RAT:_ATCAddFlight(name,dest) -env.info(string.format("%s%s ATC: Adding flight %s with destination %s.",RAT.id,dest,name,dest)) -RAT.ATC.flight[name]={} -RAT.ATC.flight[name].destination=dest -RAT.ATC.flight[name].Tarrive=-1 -RAT.ATC.flight[name].holding=-1 -RAT.ATC.flight[name].Tonfinal=-1 -end -function RAT:_ATCDelFlight(t,entry) -for k,_ in pairs(t)do -if k==entry then -t[entry]=nil -end -end -end -function RAT:_ATCRegisterFlight(name,time) -RAT.ATC.flight[name].Tarrive=time -RAT.ATC.flight[name].holding=0 -end -function RAT:_ATCStatus() -local Tnow=timer.getTime() -for name,_ in pairs(RAT.ATC.flight)do -local hold=RAT.ATC.flight[name].holding -local dest=RAT.ATC.flight[name].destination -if hold>=0 then -local busy="Runway is currently clear" -if RAT.ATC.airport[dest].busy then -if RAT.ATC.airport[dest].onfinal then -busy="Runway is occupied by "..RAT.ATC.airport[dest].onfinal -else -busy="Runway is occupied" -end -end -env.info(string.format("%s%s ATC: Flight %s is holding for %i:%02d. %s.",RAT.id,dest,name,hold/60,hold%60,busy)) -elseif hold==RAT.ATC.onfinal then -local Tfinal=Tnow-RAT.ATC.flight[name].Tonfinal -env.info(string.format("%s%s ATC: Flight %s was cleared for landing. Waiting %i:%02d for landing event.",RAT.id,dest,name,Tfinal/60,Tfinal%60)) -if Tfinal>300 then -end -elseif hold==RAT.ATC.unregistered then -else -env.error(RAT.id.."Unknown holding time in RAT:_ATCStatus().") -end -end -end -function RAT:_ATCCheck() -RAT:_ATCQueue() -local Tnow=timer.getTime() -for name,_ in pairs(RAT.ATC.airport)do -local qw={} -for qID,flight in ipairs(RAT.ATC.airport[name].queue)do -local nqueue=#RAT.ATC.airport[name].queue -if RAT.ATC.airport[name].busy then -RAT.ATC.flight[flight].holding=Tnow-RAT.ATC.flight[flight].Tarrive -local text=string.format("%s ATC: Flight %s runway is busy. You are #%d of %d in landing queue. Your holding time is %i:%02d.",name,flight,qID,nqueue,RAT.ATC.flight[flight].holding/60,RAT.ATC.flight[flight].holding%60) -env.info(text) -else -RAT:_ATCClearForLanding(name,flight) -table.insert(qw,qID) -end -end -for _,i in pairs(qw)do -table.remove(RAT.ATC.airport[name].queue,i) -end -end -end -function RAT:_ATCClearForLanding(airport,flight) -RAT.ATC.flight[flight].holding=RAT.ATC.onfinal -RAT.ATC.airport[airport].busy=true -RAT.ATC.airport[airport].onfinal=flight -RAT.ATC.flight[flight].Tonfinal=timer.getTime() -trigger.action.setUserFlag(flight,1) -local flagvalue=trigger.misc.getUserFlag(flight) -local text1=string.format("%s%s ATC: Flight %s cleared for final approach (flag=%d).",RAT.id,airport,flight,flagvalue) -local text2=string.format("%s ATC: Flight %s you are cleared for landing.",airport,flight) -env.info(text1) -MESSAGE:New(text2,10):ToAll() -end -function RAT:_ATCFlightLanded(name) -if RAT.ATC.flight[name]then -local dest=RAT.ATC.flight[name].destination -local Tnow=timer.getTime() -local Tfinal=Tnow-RAT.ATC.flight[name].Tonfinal -local Thold=RAT.ATC.flight[name].Tonfinal-RAT.ATC.flight[name].Tarrive -RAT.ATC.airport[dest].busy=false -RAT.ATC.airport[dest].onfinal=nil -RAT:_ATCDelFlight(RAT.ATC.flight,name) -RAT.ATC.airport[dest].traffic=RAT.ATC.airport[dest].traffic+1 -local text1=string.format("%s%s ATC: Flight %s landed. Tholding = %i:%02d, Tfinal = %i:%02d.",RAT.id,dest,name,Thold/60,Thold%60,Tfinal/60,Tfinal%60) -local text2=string.format("%s ATC: Flight %s landed. Welcome to %s.",dest,name,dest) -env.info(text1) -env.info(string.format("%s%s ATC: Number of planes landed in total %d.",RAT.id,dest,RAT.ATC.airport[dest].traffic)) -MESSAGE:New(text2,10):ToAll() -end -end -function RAT:_ATCQueue() -for airport,_ in pairs(RAT.ATC.airport)do -local _queue={} -for name,_ in pairs(RAT.ATC.flight)do -local hold=RAT.ATC.flight[name].holding -local dest=RAT.ATC.flight[name].destination -if hold>=0 and airport==dest then -_queue[#_queue+1]={name,hold} -end -end -local function compare(a,b) -return a[2]>b[2] -end -table.sort(_queue,compare) -RAT.ATC.airport[airport].queue={} -for k,v in ipairs(_queue)do -table.insert(RAT.ATC.airport[airport].queue,v[1]) -end -end -end -PROTECT={ -ClassName="PROTECT", -} -function PROTECT:New(ProtectZone) -local self=BASE:Inherit(self,FSM:New()) -self.ProtectZone=ProtectZone -self.ProtectUnitSet=SET_UNIT:New() -self.CaptureUnitSet=SET_UNIT:New() -self:SetStartState("Idle") -self:AddTransition({"Idle","Captured"},"Protect","Protecting") -self:AddTransition("Protecting","Check","Protecting") -self:AddTransition("Protecting","Capture","Captured") -self:AddTransition({"Protecting","Captured"},"Leave","Idle") -return self -end -function PROTECT:AddProtectUnit(ProtectUnit) -self.ProtectUnitSet:AddUnit(ProtectUnit) -end -function PROTECT:AddCaptureUnit(CaptureUnit) -self.CaptureUnitSet:AddUnit(CaptureUnit) -end -function PROTECT:GetCaptureUnitSet() -return self.CaptureUnitSet -end -function PROTECT:AreProtectUnitsAlive() -local IsAlive=false -local UnitSet=self.ProtectUnitSet -UnitSet:Flush() -local UnitList=UnitSet:GetSet() -for UnitID,ProtectUnit in pairs(UnitList)do -local IsUnitAlive=ProtectUnit:IsAlive() -if IsUnitAlive==true then -IsAlive=true -break -end -end -return IsAlive -end -function PROTECT:IsCaptureUnitInZone() -local IsInZone=false -local CaptureUnitSet=self.CaptureUnitSet -CaptureUnitSet:Flush() -local CaptureUnitList=CaptureUnitSet:GetSet() -for UnitID,CaptureUnit in pairs(CaptureUnitList)do -local IsUnitAlive=CaptureUnit:IsAlive() -if IsUnitAlive==true then -if CaptureUnit:IsInZone(self.ProtectZone)then -IsInZone=true -break -end -end -end -return IsInZone -end -function PROTECT:Smoke(SmokeColor) -self.ProtectZone:GetCoordinate():Smoke(SmokeColor) -end -function PROTECT:onafterProtect() -self:Check() -end -function PROTECT:onafterCheck() -if self:AreProtectUnitsAlive()or not self:IsCaptureUnitInZone()then -self:__Check(-1) -else -self:Capture() -end -end -AI_BALANCER={ -ClassName="AI_BALANCER", -PatrolZones={}, -AIGroups={}, -Earliest=5, -Latest=60, -} -function AI_BALANCER:New(SetClient,SpawnAI) -local self=BASE:Inherit(self,FSM_SET:New(SET_GROUP:New())) -self:SetStartState("None") -self:AddTransition("*","Monitor","Monitoring") -self:AddTransition("*","Spawn","Spawning") -self:AddTransition("Spawning","Spawned","Spawned") -self:AddTransition("*","Destroy","Destroying") -self:AddTransition("*","Return","Returning") -self.SetClient=SetClient -self.SetClient:FilterOnce() -self.SpawnAI=SpawnAI -self.SpawnQueue={} -self.ToNearestAirbase=false -self.ToHomeAirbase=false -self:__Monitor(1) -return self -end -function AI_BALANCER:InitSpawnInterval(Earliest,Latest) -self.Earliest=Earliest -self.Latest=Latest -return self -end -function AI_BALANCER:ReturnToNearestAirbases(ReturnThresholdRange,ReturnAirbaseSet) -self.ToNearestAirbase=true -self.ReturnThresholdRange=ReturnThresholdRange -self.ReturnAirbaseSet=ReturnAirbaseSet -end -function AI_BALANCER:ReturnToHomeAirbase(ReturnThresholdRange) -self.ToHomeAirbase=true -self.ReturnThresholdRange=ReturnThresholdRange -end -function AI_BALANCER:onenterSpawning(SetGroup,From,Event,To,ClientName) -local AIGroup=self.SpawnAI:Spawn() -if AIGroup then -AIGroup:E("Spawning new AIGroup") -SetGroup:Add(ClientName,AIGroup) -self.SpawnQueue[ClientName]=nil -self:Spawned(AIGroup) -end -end -function AI_BALANCER:onenterDestroying(SetGroup,From,Event,To,ClientName,AIGroup) -AIGroup:Destroy() -SetGroup:Flush() -SetGroup:Remove(ClientName) -SetGroup:Flush() -end -function AI_BALANCER:onenterReturning(SetGroup,From,Event,To,AIGroup) -local AIGroupTemplate=AIGroup:GetTemplate() -if self.ToHomeAirbase==true then -local WayPointCount=#AIGroupTemplate.route.points -local SwitchWayPointCommand=AIGroup:CommandSwitchWayPoint(1,WayPointCount,1) -AIGroup:SetCommand(SwitchWayPointCommand) -AIGroup:MessageToRed("Returning to home base ...",30) -else -local PointVec2=POINT_VEC2:New(AIGroup:GetVec2().x,AIGroup:GetVec2().y) -local ClosestAirbase=self.ReturnAirbaseSet:FindNearestAirbaseFromPointVec2(PointVec2) -self:T(ClosestAirbase.AirbaseName) -AIGroup:MessageToRed("Returning to "..ClosestAirbase:GetName().." ...",30) -local RTBRoute=AIGroup:RouteReturnToAirbase(ClosestAirbase) -AIGroupTemplate.route=RTBRoute -AIGroup:Respawn(AIGroupTemplate) -end -end -function AI_BALANCER:onenterMonitoring(SetGroup) -self:T2({self.SetClient:Count()}) -self.SetClient:ForEachClient( -function(Client) -self:T3(Client.ClientName) -local AIGroup=self.Set:Get(Client.UnitName) -if Client:IsAlive()then -if AIGroup and AIGroup:IsAlive()==true then -if self.ToNearestAirbase==false and self.ToHomeAirbase==false then -self:Destroy(Client.UnitName,AIGroup) -else -local PlayerInRange={Value=false} -local RangeZone=ZONE_RADIUS:New('RangeZone',AIGroup:GetVec2(),self.ReturnThresholdRange) -self:T2(RangeZone) -_DATABASE:ForEachPlayer( -function(RangeTestUnit,RangeZone,AIGroup,PlayerInRange) -self:T2({PlayerInRange,RangeTestUnit.UnitName,RangeZone.ZoneName}) -if RangeTestUnit:IsInZone(RangeZone)==true then -self:T2("in zone") -if RangeTestUnit:GetCoalition()~=AIGroup:GetCoalition()then -self:T2("in range") -PlayerInRange.Value=true -end -end -end, -function(RangeZone,AIGroup,PlayerInRange) -if PlayerInRange.Value==false then -self:Return(AIGroup) -end -end -,RangeZone,AIGroup,PlayerInRange -) -end -self.Set:Remove(Client.UnitName) -end -else -if not AIGroup or not AIGroup:IsAlive()==true then -self:T("Client "..Client.UnitName.." not alive.") -if not self.SpawnQueue[Client.UnitName]then -self:__Spawn(math.random(self.Earliest,self.Latest),Client.UnitName) -self.SpawnQueue[Client.UnitName]=true -self:E("New AI Spawned for Client "..Client.UnitName) -end -end -end -return true -end -) -self:__Monitor(10) -end -AI_A2A={ -ClassName="AI_A2A", -} -function AI_A2A:New(AIGroup) -local self=BASE:Inherit(self,FSM_CONTROLLABLE:New()) -self:SetControllable(AIGroup) -self:SetFuelThreshold(.2,60) -self:SetDamageThreshold(0.4) -self:SetDisengageRadius(70000) -self:SetStartState("Stopped") -self:AddTransition("*","Start","Started") -self:AddTransition("*","Stop","Stopped") -self:AddTransition("*","Status","*") -self:AddTransition("*","RTB","*") -self:AddTransition("Patrolling","Refuel","Refuelling") -self:AddTransition("*","Takeoff","Airborne") -self:AddTransition("*","Return","Returning") -self:AddTransition("*","Hold","Holding") -self:AddTransition("*","Home","Home") -self:AddTransition("*","LostControl","LostControl") -self:AddTransition("*","Fuel","Fuel") -self:AddTransition("*","Damaged","Damaged") -self:AddTransition("*","Eject","*") -self:AddTransition("*","Crash","Crashed") -self:AddTransition("*","PilotDead","*") -self.IdleCount=0 -return self -end -function GROUP:OnEventTakeoff(EventData,Fsm) -Fsm:Takeoff() -self:UnHandleEvent(EVENTS.Takeoff) -end -function AI_A2A:SetDispatcher(Dispatcher) -self.Dispatcher=Dispatcher -end -function AI_A2A:GetDispatcher() -return self.Dispatcher -end -function AI_A2A:SetTargetDistance(Coordinate) -local CurrentCoord=self.Controllable:GetCoordinate() -self.TargetDistance=CurrentCoord:Get2DDistance(Coordinate) -self.ClosestTargetDistance=(not self.ClosestTargetDistance or self.ClosestTargetDistance>self.TargetDistance)and self.TargetDistance or self.ClosestTargetDistance -end -function AI_A2A:ClearTargetDistance() -self.TargetDistance=nil -self.ClosestTargetDistance=nil -end -function AI_A2A:SetSpeed(PatrolMinSpeed,PatrolMaxSpeed) -self:F2({PatrolMinSpeed,PatrolMaxSpeed}) -self.PatrolMinSpeed=PatrolMinSpeed -self.PatrolMaxSpeed=PatrolMaxSpeed -end -function AI_A2A:SetAltitude(PatrolFloorAltitude,PatrolCeilingAltitude) -self:F2({PatrolFloorAltitude,PatrolCeilingAltitude}) -self.PatrolFloorAltitude=PatrolFloorAltitude -self.PatrolCeilingAltitude=PatrolCeilingAltitude -end -function AI_A2A:SetHomeAirbase(HomeAirbase) -self:F2({HomeAirbase}) -self.HomeAirbase=HomeAirbase -end -function AI_A2A:SetTanker(TankerName) -self:F2({TankerName}) -self.TankerName=TankerName -end -function AI_A2A:SetDisengageRadius(DisengageRadius) -self:F2({DisengageRadius}) -self.DisengageRadius=DisengageRadius -end -function AI_A2A:SetStatusOff() -self:F2() -self.CheckStatus=false -end -function AI_A2A:SetFuelThreshold(PatrolFuelThresholdPercentage,PatrolOutOfFuelOrbitTime) -self.PatrolManageFuel=true -self.PatrolFuelThresholdPercentage=PatrolFuelThresholdPercentage -self.PatrolOutOfFuelOrbitTime=PatrolOutOfFuelOrbitTime -self.Controllable:OptionRTBBingoFuel(false) -return self -end -function AI_A2A:SetDamageThreshold(PatrolDamageThreshold) -self.PatrolManageDamage=true -self.PatrolDamageThreshold=PatrolDamageThreshold -return self -end -function AI_A2A:onafterStart(Controllable,From,Event,To) -self:F2() -self:__Status(10) -self:HandleEvent(EVENTS.PilotDead,self.OnPilotDead) -self:HandleEvent(EVENTS.Crash,self.OnCrash) -self:HandleEvent(EVENTS.Ejection,self.OnEjection) -Controllable:OptionROEHoldFire() -Controllable:OptionROTVertical() -end -function AI_A2A:onbeforeStatus() -return self.CheckStatus -end -function AI_A2A:onafterStatus() -self:F(" Checking Status") -if self.Controllable and self.Controllable:IsAlive()then -local RTB=false -local DistanceFromHomeBase=self.HomeAirbase:GetCoordinate():Get2DDistance(self.Controllable:GetCoordinate()) -if not self:Is("Holding")and not self:Is("Returning")then -local DistanceFromHomeBase=self.HomeAirbase:GetCoordinate():Get2DDistance(self.Controllable:GetCoordinate()) -self:F({DistanceFromHomeBase=DistanceFromHomeBase}) -if DistanceFromHomeBase>self.DisengageRadius then -self:E(self.Controllable:GetName().." is too far from home base, RTB!") -self:Hold(300) -RTB=false -end -end -if self:Is("Fuel")or self:Is("Damaged")or self:Is("LostControl")then -if DistanceFromHomeBase<5000 then -self:E(self.Controllable:GetName().." is too far from home base, RTB!") -self:Home("Destroy") -end -end -if not self:Is("Fuel")and not self:Is("Home")then -local Fuel=self.Controllable:GetFuel() -self:F({Fuel=Fuel}) -if Fuel=2 then -if Damage~=InitialLife then -self:Damaged() -else -self:E(self.Controllable:GetName().." control lost! ") -self:LostControl() -end -else -self.IdleCount=self.IdleCount+1 -end -end -else -self.IdleCount=0 -end -if RTB==true then -self:__RTB(0.5) -end -self:__Status(10) -end -end -function AI_A2A.RTBRoute(AIGroup,Fsm) -AIGroup:F({"AI_A2A.RTBRoute:",AIGroup:GetName()}) -if AIGroup:IsAlive()then -Fsm:__RTB(0.5) -end -end -function AI_A2A.RTBHold(AIGroup,Fsm) -AIGroup:F({"AI_A2A.RTBHold:",AIGroup:GetName()}) -if AIGroup:IsAlive()then -Fsm:__RTB(0.5) -Fsm:Return() -local Task=AIGroup:TaskOrbitCircle(4000,400) -AIGroup:SetTask(Task) -end -end -function AI_A2A:onafterRTB(AIGroup,From,Event,To) -self:F({AIGroup,From,Event,To}) -if AIGroup and AIGroup:IsAlive()then -self:E("Group "..AIGroup:GetName().." ... RTB! ( "..self:GetState().." )") -self:ClearTargetDistance() -AIGroup:ClearTasks() -local EngageRoute={} -local CurrentCoord=AIGroup:GetCoordinate() -local ToTargetCoord=self.HomeAirbase:GetCoordinate() -local ToTargetSpeed=math.random(self.PatrolMinSpeed,self.PatrolMaxSpeed) -local ToAirbaseAngle=CurrentCoord:GetAngleDegrees(CurrentCoord:GetDirectionVec3(ToTargetCoord)) -local Distance=CurrentCoord:Get2DDistance(ToTargetCoord) -local ToAirbaseCoord=CurrentCoord:Translate(5000,ToAirbaseAngle) -if Distance<5000 then -self:E("RTB and near the airbase!") -self:Home() -return -end -local ToRTBRoutePoint=ToAirbaseCoord:WaypointAir( -self.PatrolAltType, -POINT_VEC3.RoutePointType.TurningPoint, -POINT_VEC3.RoutePointAction.TurningPoint, -ToTargetSpeed, -true -) -self:F({Angle=ToAirbaseAngle,ToTargetSpeed=ToTargetSpeed}) -self:T2({self.MinSpeed,self.MaxSpeed,ToTargetSpeed}) -EngageRoute[#EngageRoute+1]=ToRTBRoutePoint -EngageRoute[#EngageRoute+1]=ToRTBRoutePoint -AIGroup:OptionROEHoldFire() -AIGroup:OptionROTEvadeFire() -AIGroup:WayPointInitialize(EngageRoute) -local Tasks={} -Tasks[#Tasks+1]=AIGroup:TaskFunction("AI_A2A.RTBRoute",self) -EngageRoute[#EngageRoute].task=AIGroup:TaskCombo(Tasks) -AIGroup:Route(EngageRoute,0.5) -end -end -function AI_A2A:onafterHome(AIGroup,From,Event,To) -self:F({AIGroup,From,Event,To}) -self:E("Group "..self.Controllable:GetName().." ... Home! ( "..self:GetState().." )") -if AIGroup and AIGroup:IsAlive()then -end -end -function AI_A2A:onafterHold(AIGroup,From,Event,To,HoldTime) -self:F({AIGroup,From,Event,To}) -self:E("Group "..self.Controllable:GetName().." ... Holding! ( "..self:GetState().." )") -if AIGroup and AIGroup:IsAlive()then -local OrbitTask=AIGroup:TaskOrbitCircle(math.random(self.PatrolFloorAltitude,self.PatrolCeilingAltitude),self.PatrolMinSpeed) -local TimedOrbitTask=AIGroup:TaskControlled(OrbitTask,AIGroup:TaskCondition(nil,nil,nil,nil,HoldTime,nil)) -local RTBTask=AIGroup:TaskFunction("AI_A2A.RTBHold",self) -local OrbitHoldTask=AIGroup:TaskOrbitCircle(4000,self.PatrolMinSpeed) -AIGroup:SetTask(AIGroup:TaskCombo({TimedOrbitTask,RTBTask,OrbitHoldTask}),1) -end -end -function AI_A2A.Resume(AIGroup,Fsm) -AIGroup:F({"AI_A2A.Resume:",AIGroup:GetName()}) -if AIGroup:IsAlive()then -Fsm:__RTB(0.5) -end -end -function AI_A2A:onafterRefuel(AIGroup,From,Event,To) -self:F({AIGroup,From,Event,To}) -self:E("Group "..self.Controllable:GetName().." ... Refuelling! ( "..self:GetState().." )") -if AIGroup and AIGroup:IsAlive()then -local Tanker=GROUP:FindByName(self.TankerName) -if Tanker:IsAlive()and Tanker:IsAirPlane()then -local RefuelRoute={} -local CurrentCoord=AIGroup:GetCoordinate() -local ToRefuelCoord=Tanker:GetCoordinate() -local ToRefuelSpeed=math.random(self.PatrolMinSpeed,self.PatrolMaxSpeed) -local ToRefuelRoutePoint=ToRefuelCoord:WaypointAir( -self.PatrolAltType, -POINT_VEC3.RoutePointType.TurningPoint, -POINT_VEC3.RoutePointAction.TurningPoint, -ToRefuelSpeed, -true -) -self:F({ToRefuelSpeed=ToRefuelSpeed}) -RefuelRoute[#RefuelRoute+1]=ToRefuelRoutePoint -RefuelRoute[#RefuelRoute+1]=ToRefuelRoutePoint -AIGroup:OptionROEHoldFire() -AIGroup:OptionROTEvadeFire() -local Tasks={} -Tasks[#Tasks+1]=AIGroup:TaskRefueling() -Tasks[#Tasks+1]=AIGroup:TaskFunction(self:GetClassName()..".Resume",self) -RefuelRoute[#RefuelRoute].task=AIGroup:TaskCombo(Tasks) -AIGroup:Route(RefuelRoute,0.5) -else -self:RTB() -end -end -end -function AI_A2A:onafterDead() -self:SetStatusOff() -end -function AI_A2A:OnCrash(EventData) -if self.Controllable:IsAlive()and EventData.IniDCSGroupName==self.Controllable:GetName()then -self:E(self.Controllable:GetUnits()) -if#self.Controllable:GetUnits()==1 then -self:__Crash(1,EventData) -end -end -end -function AI_A2A:OnEjection(EventData) -if self.Controllable:IsAlive()and EventData.IniDCSGroupName==self.Controllable:GetName()then -self:__Eject(1,EventData) -end -end -function AI_A2A:OnPilotDead(EventData) -if self.Controllable:IsAlive()and EventData.IniDCSGroupName==self.Controllable:GetName()then -self:__PilotDead(1,EventData) -end -end -AI_A2A_PATROL={ -ClassName="AI_A2A_PATROL", -} -function AI_A2A_PATROL:New(AIGroup,PatrolZone,PatrolFloorAltitude,PatrolCeilingAltitude,PatrolMinSpeed,PatrolMaxSpeed,PatrolAltType) -local self=BASE:Inherit(self,AI_A2A:New(AIGroup)) -self.PatrolZone=PatrolZone -self.PatrolFloorAltitude=PatrolFloorAltitude -self.PatrolCeilingAltitude=PatrolCeilingAltitude -self.PatrolMinSpeed=PatrolMinSpeed -self.PatrolMaxSpeed=PatrolMaxSpeed -self.PatrolAltType=PatrolAltType or"RADIO" -self:AddTransition({"Started","Airborne","Refuelling"},"Patrol","Patrolling") -self:AddTransition("Patrolling","Route","Patrolling") -self:AddTransition("*","Reset","Patrolling") -return self -end -function AI_A2A_PATROL:SetSpeed(PatrolMinSpeed,PatrolMaxSpeed) -self:F2({PatrolMinSpeed,PatrolMaxSpeed}) -self.PatrolMinSpeed=PatrolMinSpeed -self.PatrolMaxSpeed=PatrolMaxSpeed -end -function AI_A2A_PATROL:SetAltitude(PatrolFloorAltitude,PatrolCeilingAltitude) -self:F2({PatrolFloorAltitude,PatrolCeilingAltitude}) -self.PatrolFloorAltitude=PatrolFloorAltitude -self.PatrolCeilingAltitude=PatrolCeilingAltitude -end -function AI_A2A_PATROL:onafterPatrol(Controllable,From,Event,To) -self:F2() -self:ClearTargetDistance() -self:__Route(1) -self.Controllable:OnReSpawn( -function(PatrolGroup) -self:E("ReSpawn") -self:__Reset(1) -self:__Route(5) -end -) -end -function AI_A2A_PATROL.PatrolRoute(AIGroup,Fsm) -AIGroup:F({"AI_A2A_PATROL.PatrolRoute:",AIGroup:GetName()}) -if AIGroup:IsAlive()then -Fsm:Route() -end -end -function AI_A2A_PATROL:onafterRoute(AIGroup,From,Event,To) -self:F2() -if From=="RTB"then -return -end -if AIGroup:IsAlive()then -local PatrolRoute={} -local CurrentCoord=AIGroup:GetCoordinate() -local ToTargetCoord=self.PatrolZone:GetRandomPointVec2() -ToTargetCoord:SetAlt(math.random(self.PatrolFloorAltitude,self.PatrolCeilingAltitude)) -self:SetTargetDistance(ToTargetCoord) -local ToTargetSpeed=math.random(self.PatrolMinSpeed,self.PatrolMaxSpeed) -local ToPatrolRoutePoint=ToTargetCoord:WaypointAir( -self.PatrolAltType, -POINT_VEC3.RoutePointType.TurningPoint, -POINT_VEC3.RoutePointAction.TurningPoint, -ToTargetSpeed, -true -) -PatrolRoute[#PatrolRoute+1]=ToPatrolRoutePoint -PatrolRoute[#PatrolRoute+1]=ToPatrolRoutePoint -local Tasks={} -Tasks[#Tasks+1]=AIGroup:TaskFunction("AI_A2A_PATROL.PatrolRoute",self) -PatrolRoute[#PatrolRoute].task=AIGroup:TaskCombo(Tasks) -AIGroup:OptionROEReturnFire() -AIGroup:OptionROTPassiveDefense() -AIGroup:Route(PatrolRoute,0.5) -end -end -function AI_A2A_PATROL.Resume(AIGroup) -AIGroup:F({"AI_A2A_PATROL.Resume:",AIGroup:GetName()}) -if AIGroup:IsAlive()then -local _AI_A2A=AIGroup:GetState(AIGroup,"AI_A2A") -_AI_A2A:__Reset(1) -_AI_A2A:__Route(5) -end -end -AI_A2A_CAP={ -ClassName="AI_A2A_CAP", -} -function AI_A2A_CAP:New(AIGroup,PatrolZone,PatrolFloorAltitude,PatrolCeilingAltitude,PatrolMinSpeed,PatrolMaxSpeed,EngageMinSpeed,EngageMaxSpeed,PatrolAltType) -local self=BASE:Inherit(self,AI_A2A_PATROL:New(AIGroup,PatrolZone,PatrolFloorAltitude,PatrolCeilingAltitude,PatrolMinSpeed,PatrolMaxSpeed,PatrolAltType)) -self.Accomplished=false -self.Engaging=false -self.EngageMinSpeed=EngageMinSpeed -self.EngageMaxSpeed=EngageMaxSpeed -self:AddTransition({"Patrolling","Engaging","Returning","Airborne"},"Engage","Engaging") -self:AddTransition("Engaging","Fired","Engaging") -self:AddTransition("*","Destroy","*") -self:AddTransition("Engaging","Abort","Patrolling") -self:AddTransition("Engaging","Accomplish","Patrolling") -return self -end -function AI_A2A_CAP:onafterStart(AIGroup,From,Event,To) -AIGroup:HandleEvent(EVENTS.Takeoff,nil,self) -end -function AI_A2A_CAP:SetEngageZone(EngageZone) -self:F2() -if EngageZone then -self.EngageZone=EngageZone -else -self.EngageZone=nil -end -end -function AI_A2A_CAP:SetEngageRange(EngageRange) -self:F2() -if EngageRange then -self.EngageRange=EngageRange -else -self.EngageRange=nil -end -end -function AI_A2A_CAP:onafterPatrol(AIGroup,From,Event,To) -self:GetParent(self).onafterPatrol(self,AIGroup,From,Event,To) -self:HandleEvent(EVENTS.Dead) -end -function AI_A2A_CAP.AttackRoute(AIGroup,Fsm) -AIGroup:F({"AI_A2A_CAP.AttackRoute:",AIGroup:GetName()}) -if AIGroup:IsAlive()then -Fsm:__Engage(0.5) -end -end -function AI_A2A_CAP:onbeforeEngage(AIGroup,From,Event,To) -if self.Accomplished==true then -return false -end -end -function AI_A2A_CAP:onafterAbort(AIGroup,From,Event,To) -AIGroup:ClearTasks() -self:__Route(0.5) -end -function AI_A2A_CAP:onafterEngage(AIGroup,From,Event,To,AttackSetUnit) -self:F({AIGroup,From,Event,To,AttackSetUnit}) -self.AttackSetUnit=AttackSetUnit or self.AttackSetUnit -local FirstAttackUnit=self.AttackSetUnit:GetFirst() -if FirstAttackUnit and FirstAttackUnit:IsAlive()then -if AIGroup:IsAlive()then -local EngageRoute={} -local CurrentCoord=AIGroup:GetCoordinate() -local ToTargetCoord=self.AttackSetUnit:GetFirst():GetCoordinate() -local ToTargetSpeed=math.random(self.EngageMinSpeed,self.EngageMaxSpeed) -local ToInterceptAngle=CurrentCoord:GetAngleDegrees(CurrentCoord:GetDirectionVec3(ToTargetCoord)) -local ToPatrolRoutePoint=CurrentCoord:Translate(5000,ToInterceptAngle):WaypointAir( -self.PatrolAltType, -POINT_VEC3.RoutePointType.TurningPoint, -POINT_VEC3.RoutePointAction.TurningPoint, -ToTargetSpeed, -true -) -self:F({Angle=ToInterceptAngle,ToTargetSpeed=ToTargetSpeed}) -self:T2({self.MinSpeed,self.MaxSpeed,ToTargetSpeed}) -EngageRoute[#EngageRoute+1]=ToPatrolRoutePoint -EngageRoute[#EngageRoute+1]=ToPatrolRoutePoint -local AttackTasks={} -for AttackUnitID,AttackUnit in pairs(self.AttackSetUnit:GetSet())do -local AttackUnit=AttackUnit -self:T({"Attacking Unit:",AttackUnit:GetName(),AttackUnit:IsAlive(),AttackUnit:IsAir()}) -if AttackUnit:IsAlive()and AttackUnit:IsAir()then -AttackTasks[#AttackTasks+1]=AIGroup:TaskAttackUnit(AttackUnit) -end -end -if#AttackTasks==0 then -self:E("No targets found -> Going back to Patrolling") -self:__Abort(0.5) -else -AIGroup:OptionROEOpenFire() -AIGroup:OptionROTPassiveDefense() -AttackTasks[#AttackTasks+1]=AIGroup:TaskFunction("AI_A2A_CAP.AttackRoute",self) -EngageRoute[#EngageRoute].task=AIGroup:TaskCombo(AttackTasks) -end -AIGroup:Route(EngageRoute,0.5) -end -else -self:E("No targets found -> Going back to Patrolling") -self:__Abort(0.5) -end -end -function AI_A2A_CAP:onafterAccomplish(Controllable,From,Event,To) -self.Accomplished=true -self:SetDetectionOff() -end -function AI_A2A_CAP:onafterDestroy(Controllable,From,Event,To,EventData) -if EventData.IniUnit then -self.AttackUnits[EventData.IniUnit]=nil -end -end -function AI_A2A_CAP:OnEventDead(EventData) -self:F({"EventDead",EventData}) -if EventData.IniDCSUnit then -if self.AttackUnits and self.AttackUnits[EventData.IniUnit]then -self:__Destroy(1,EventData) -end -end -end -function AI_A2A_CAP.Resume(AIGroup) -AIGroup:F({"AI_A2A_CAP.Resume:",AIGroup:GetName()}) -if AIGroup:IsAlive()then -local _AI_A2A=AIGroup:GetState(AIGroup,"AI_A2A") -_AI_A2A:__Reset(1) -_AI_A2A:__Route(5) -end -end -AI_A2A_GCI={ -ClassName="AI_A2A_GCI", -} -function AI_A2A_GCI:New(AIGroup,EngageMinSpeed,EngageMaxSpeed) -local self=BASE:Inherit(self,AI_A2A:New(AIGroup)) -self.Accomplished=false -self.Engaging=false -self.EngageMinSpeed=EngageMinSpeed -self.EngageMaxSpeed=EngageMaxSpeed -self.PatrolMinSpeed=EngageMinSpeed -self.PatrolMaxSpeed=EngageMaxSpeed -self.PatrolAltType="RADIO" -self:AddTransition({"Started","Engaging","Returning","Airborne"},"Engage","Engaging") -self:AddTransition("Engaging","Fired","Engaging") -self:AddTransition("*","Destroy","*") -self:AddTransition("Engaging","Abort","Patrolling") -self:AddTransition("Engaging","Accomplish","Patrolling") -return self -end -function AI_A2A_GCI:onafterStart(AIGroup,From,Event,To) -AIGroup:HandleEvent(EVENTS.Takeoff,nil,self) -end -function AI_A2A_GCI:onafterEngage(AIGroup,From,Event,To) -self:HandleEvent(EVENTS.Dead) -end -function AI_A2A_GCI.InterceptRoute(AIGroup,Fsm) -AIGroup:F({"AI_A2A_GCI.InterceptRoute:",AIGroup:GetName()}) -if AIGroup:IsAlive()then -Fsm:__Engage(0.5) -end -end -function AI_A2A_GCI:onbeforeEngage(AIGroup,From,Event,To) -if self.Accomplished==true then -return false -end -end -function AI_A2A_GCI:onafterAbort(AIGroup,From,Event,To) -AIGroup:ClearTasks() -self:Return() -self:__RTB(0.5) -end -function AI_A2A_GCI:onafterEngage(AIGroup,From,Event,To,AttackSetUnit) -self:F({AIGroup,From,Event,To,AttackSetUnit}) -self.AttackSetUnit=AttackSetUnit or self.AttackSetUnit -local FirstAttackUnit=self.AttackSetUnit:GetFirst() -if FirstAttackUnit and FirstAttackUnit:IsAlive()then -if AIGroup:IsAlive()then -local EngageRoute={} -local CurrentCoord=AIGroup:GetCoordinate() -local CurrentCoord=AIGroup:GetCoordinate() -local ToTargetCoord=self.AttackSetUnit:GetFirst():GetCoordinate() -self:SetTargetDistance(ToTargetCoord) -local ToTargetSpeed=math.random(self.EngageMinSpeed,self.EngageMaxSpeed) -local ToInterceptAngle=CurrentCoord:GetAngleDegrees(CurrentCoord:GetDirectionVec3(ToTargetCoord)) -local ToPatrolRoutePoint=CurrentCoord:Translate(15000,ToInterceptAngle):WaypointAir( -self.PatrolAltType, -POINT_VEC3.RoutePointType.TurningPoint, -POINT_VEC3.RoutePointAction.TurningPoint, -ToTargetSpeed, -true -) -self:F({Angle=ToInterceptAngle,ToTargetSpeed=ToTargetSpeed}) -self:F({self.EngageMinSpeed,self.EngageMaxSpeed,ToTargetSpeed}) -EngageRoute[#EngageRoute+1]=ToPatrolRoutePoint -EngageRoute[#EngageRoute+1]=ToPatrolRoutePoint -local AttackTasks={} -for AttackUnitID,AttackUnit in pairs(self.AttackSetUnit:GetSet())do -local AttackUnit=AttackUnit -if AttackUnit:IsAlive()and AttackUnit:IsAir()then -self:T({"Intercepting Unit:",AttackUnit:GetName(),AttackUnit:IsAlive(),AttackUnit:IsAir()}) -AttackTasks[#AttackTasks+1]=AIGroup:TaskAttackUnit(AttackUnit) -end -end -if#AttackTasks==0 then -self:E("No targets found -> Going RTB") -self:Return() -self:__RTB(0.5) -else -AIGroup:OptionROEOpenFire() -AIGroup:OptionROTPassiveDefense() -AttackTasks[#AttackTasks+1]=AIGroup:TaskFunction("AI_A2A_GCI.InterceptRoute",self) -EngageRoute[#EngageRoute].task=AIGroup:TaskCombo(AttackTasks) -end -AIGroup:Route(EngageRoute,0.5) -end -else -self:E("No targets found -> Going RTB") -self:Return() -self:__RTB(0.5) -end -end -function AI_A2A_GCI:onafterAccomplish(AIGroup,From,Event,To) -self.Accomplished=true -self:SetDetectionOff() -end -function AI_A2A_GCI:onafterDestroy(AIGroup,From,Event,To,EventData) -if EventData.IniUnit then -self.AttackUnits[EventData.IniUnit]=nil -end -end -function AI_A2A_GCI:OnEventDead(EventData) -self:F({"EventDead",EventData}) -if EventData.IniDCSUnit then -if self.AttackUnits and self.AttackUnits[EventData.IniUnit]then -self:__Destroy(1,EventData) -end -end -end -do -AI_A2A_DISPATCHER={ -ClassName="AI_A2A_DISPATCHER", -Detection=nil, -} -AI_A2A_DISPATCHER.Takeoff=GROUP.Takeoff -AI_A2A_DISPATCHER.Landing={ -NearAirbase=1, -AtRunway=2, -AtEngineShutdown=3, -} -function AI_A2A_DISPATCHER:New(Detection) -local self=BASE:Inherit(self,DETECTION_MANAGER:New(nil,Detection)) -self.Detection=Detection -self.DefenderSquadrons={} -self.DefenderSpawns={} -self.DefenderTasks={} -self.DefenderDefault={} -self.Detection:FilterCategories({Unit.Category.AIRPLANE,Unit.Category.HELICOPTER}) -self.Detection:SetRefreshTimeInterval(30) -self:SetEngageRadius() -self:SetGciRadius() -self:SetIntercept(300) -self:SetDisengageRadius(300000) -self:SetDefaultTakeoff(AI_A2A_DISPATCHER.Takeoff.Air) -self:SetDefaultTakeoffInAirAltitude(500) -self:SetDefaultLanding(AI_A2A_DISPATCHER.Landing.NearAirbase) -self:SetDefaultOverhead(1) -self:SetDefaultGrouping(1) -self:SetDefaultFuelThreshold(0.15,0) -self:SetDefaultDamageThreshold(0.4) -self:SetDefaultCapTimeInterval(180,600) -self:SetDefaultCapLimit(1) -self:AddTransition("Started","Assign","Started") -self:AddTransition("*","CAP","*") -self:AddTransition("*","GCI","*") -self:AddTransition("*","ENGAGE","*") -self:HandleEvent(EVENTS.Crash,self.OnEventCrashOrDead) -self:HandleEvent(EVENTS.Dead,self.OnEventCrashOrDead) -self:HandleEvent(EVENTS.Land) -self:HandleEvent(EVENTS.EngineShutdown) -self:SetTacticalDisplay(false) -self:__Start(5) -return self -end -function AI_A2A_DISPATCHER:OnEventCrashOrDead(EventData) -self.Detection:ForgetDetectedUnit(EventData.IniUnitName) -end -function AI_A2A_DISPATCHER:OnEventLand(EventData) -self:E("Landed") -local DefenderUnit=EventData.IniUnit -local Defender=EventData.IniGroup -local Squadron=self:GetSquadronFromDefender(Defender) -if Squadron then -self:F({SquadronName=Squadron.Name}) -local LandingMethod=self:GetSquadronLanding(Squadron.Name) -if LandingMethod==AI_A2A_DISPATCHER.Landing.AtRunway then -local DefenderSize=Defender:GetSize() -if DefenderSize==1 then -self:RemoveDefenderFromSquadron(Squadron,Defender) -end -DefenderUnit:Destroy() -return -end -if DefenderUnit:GetLife()~=DefenderUnit:GetLife0()then -DefenderUnit:Destroy() -return -end -if DefenderUnit:GetFuel()<=self.DefenderDefault.FuelThreshold then -DefenderUnit:Destroy() -return -end -end -end -function AI_A2A_DISPATCHER:OnEventEngineShutdown(EventData) -local DefenderUnit=EventData.IniUnit -local Defender=EventData.IniGroup -local Squadron=self:GetSquadronFromDefender(Defender) -if Squadron then -self:F({SquadronName=Squadron.Name}) -local LandingMethod=self:GetSquadronLanding(Squadron.Name) -if LandingMethod==AI_A2A_DISPATCHER.Landing.AtEngineShutdown then -local DefenderSize=Defender:GetSize() -if DefenderSize==1 then -self:RemoveDefenderFromSquadron(Squadron,Defender) -end -DefenderUnit:Destroy() -end -end -end -function AI_A2A_DISPATCHER:SetEngageRadius(EngageRadius) -self.Detection:SetFriendliesRange(EngageRadius or 100000) -return self -end -function AI_A2A_DISPATCHER:SetDisengageRadius(DisengageRadius) -self.DisengageRadius=DisengageRadius or 300000 -return self -end -function AI_A2A_DISPATCHER:SetGciRadius(GciRadius) -self.GciRadius=GciRadius or 200000 -return self -end -function AI_A2A_DISPATCHER:SetBorderZone(BorderZone) -self.Detection:SetAcceptZones(BorderZone) -return self -end -function AI_A2A_DISPATCHER:SetTacticalDisplay(TacticalDisplay) -self.TacticalDisplay=TacticalDisplay -return self -end -function AI_A2A_DISPATCHER:SetDefaultDamageThreshold(DamageThreshold) -self.DefenderDefault.DamageThreshold=DamageThreshold -return self -end -function AI_A2A_DISPATCHER:SetDefaultCapTimeInterval(CapMinSeconds,CapMaxSeconds) -self.DefenderDefault.CapMinSeconds=CapMinSeconds -self.DefenderDefault.CapMaxSeconds=CapMaxSeconds -return self -end -function AI_A2A_DISPATCHER:SetDefaultCapLimit(CapLimit) -self.DefenderDefault.CapLimit=CapLimit -return self -end -function AI_A2A_DISPATCHER:SetIntercept(InterceptDelay) -self.DefenderDefault.InterceptDelay=InterceptDelay -local Detection=self.Detection -Detection:SetIntercept(true,InterceptDelay) -return self -end -function AI_A2A_DISPATCHER:GetAIFriendliesNearBy(DetectedItem) -local FriendliesNearBy=self.Detection:GetFriendliesDistance(DetectedItem) -return FriendliesNearBy -end -function AI_A2A_DISPATCHER:GetDefenderTasks() -return self.DefenderTasks or{} -end -function AI_A2A_DISPATCHER:GetDefenderTask(Defender) -return self.DefenderTasks[Defender] -end -function AI_A2A_DISPATCHER:GetDefenderTaskFsm(Defender) -return self:GetDefenderTask(Defender).Fsm -end -function AI_A2A_DISPATCHER:GetDefenderTaskTarget(Defender) -return self:GetDefenderTask(Defender).Target -end -function AI_A2A_DISPATCHER:GetDefenderTaskSquadronName(Defender) -return self:GetDefenderTask(Defender).SquadronName -end -function AI_A2A_DISPATCHER:ClearDefenderTask(Defender) -if Defender:IsAlive()and self.DefenderTasks[Defender]then -local Target=self.DefenderTasks[Defender].Target -local Message="Clearing ("..self.DefenderTasks[Defender].Type..") " -Message=Message..Defender:GetName() -if Target then -Message=Message..(Target and(" from "..Target.Index.." ["..Target.Set:Count().."]"))or"" -end -self:F({Target=Message}) -end -self.DefenderTasks[Defender]=nil -return self -end -function AI_A2A_DISPATCHER:ClearDefenderTaskTarget(Defender) -local DefenderTask=self:GetDefenderTask(Defender) -if Defender:IsAlive()and DefenderTask then -local Target=DefenderTask.Target -local Message="Clearing ("..DefenderTask.Type..") " -Message=Message..Defender:GetName() -if Target then -Message=Message..(Target and(" from "..Target.Index.." ["..Target.Set:Count().."]"))or"" -end -self:F({Target=Message}) -end -if Defender and DefenderTask and DefenderTask.Target then -DefenderTask.Target=nil -end -return self -end -function AI_A2A_DISPATCHER:SetDefenderTask(SquadronName,Defender,Type,Fsm,Target) -self:F({SquadronName=SquadronName,Defender=Defender:GetName()}) -self.DefenderTasks[Defender]=self.DefenderTasks[Defender]or{} -self.DefenderTasks[Defender].Type=Type -self.DefenderTasks[Defender].Fsm=Fsm -self.DefenderTasks[Defender].SquadronName=SquadronName -if Target then -self:SetDefenderTaskTarget(Defender,Target) -end -return self -end -function AI_A2A_DISPATCHER:SetDefenderTaskTarget(Defender,AttackerDetection) -local Message="("..self.DefenderTasks[Defender].Type..") " -Message=Message..Defender:GetName() -Message=Message..(AttackerDetection and(" target "..AttackerDetection.Index.." ["..AttackerDetection.Set:Count().."]"))or"" -self:F({AttackerDetection=Message}) -if AttackerDetection then -self.DefenderTasks[Defender].Target=AttackerDetection -end -return self -end -function AI_A2A_DISPATCHER:SetSquadron(SquadronName,AirbaseName,TemplatePrefixes,Resources) -self.DefenderSquadrons[SquadronName]=self.DefenderSquadrons[SquadronName]or{} -local DefenderSquadron=self.DefenderSquadrons[SquadronName] -DefenderSquadron.Name=SquadronName -DefenderSquadron.Airbase=AIRBASE:FindByName(AirbaseName) -if not DefenderSquadron.Airbase then -error("Cannot find airbase with name:"..AirbaseName) -end -DefenderSquadron.Spawn={} -if type(TemplatePrefixes)=="string"then -local SpawnTemplate=TemplatePrefixes -self.DefenderSpawns[SpawnTemplate]=self.DefenderSpawns[SpawnTemplate]or SPAWN:New(SpawnTemplate) -DefenderSquadron.Spawn[1]=self.DefenderSpawns[SpawnTemplate] -else -for TemplateID,SpawnTemplate in pairs(TemplatePrefixes)do -self.DefenderSpawns[SpawnTemplate]=self.DefenderSpawns[SpawnTemplate]or SPAWN:New(SpawnTemplate) -DefenderSquadron.Spawn[#DefenderSquadron.Spawn+1]=self.DefenderSpawns[SpawnTemplate] -end -end -DefenderSquadron.Resources=Resources -DefenderSquadron.TemplatePrefixes=TemplatePrefixes -self:E({Squadron={SquadronName,AirbaseName,TemplatePrefixes,Resources}}) -return self -end -function AI_A2A_DISPATCHER:GetSquadron(SquadronName) -local DefenderSquadron=self.DefenderSquadrons[SquadronName] -if not DefenderSquadron then -error("Unknown Squadron:"..SquadronName) -end -return DefenderSquadron -end -function AI_A2A_DISPATCHER:SetSquadronCap(SquadronName,Zone,FloorAltitude,CeilingAltitude,PatrolMinSpeed,PatrolMaxSpeed,EngageMinSpeed,EngageMaxSpeed,AltType) -self.DefenderSquadrons[SquadronName]=self.DefenderSquadrons[SquadronName]or{} -self.DefenderSquadrons[SquadronName].Cap=self.DefenderSquadrons[SquadronName].Cap or{} -local DefenderSquadron=self:GetSquadron(SquadronName) -local Cap=self.DefenderSquadrons[SquadronName].Cap -Cap.Name=SquadronName -Cap.Zone=Zone -Cap.FloorAltitude=FloorAltitude -Cap.CeilingAltitude=CeilingAltitude -Cap.PatrolMinSpeed=PatrolMinSpeed -Cap.PatrolMaxSpeed=PatrolMaxSpeed -Cap.EngageMinSpeed=EngageMinSpeed -Cap.EngageMaxSpeed=EngageMaxSpeed -Cap.AltType=AltType -self:SetSquadronCapInterval(SquadronName,self.DefenderDefault.CapLimit,self.DefenderDefault.CapMinSeconds,self.DefenderDefault.CapMaxSeconds,1) -self:E({CAP={SquadronName,Zone,FloorAltitude,CeilingAltitude,PatrolMinSpeed,PatrolMaxSpeed,EngageMinSpeed,EngageMaxSpeed,AltType}}) -local RecceSet=self.Detection:GetDetectionSetGroup() -RecceSet:FilterPrefixes(DefenderSquadron.TemplatePrefixes) -RecceSet:FilterStart() -self.Detection:SetFriendlyPrefixes(DefenderSquadron.TemplatePrefixes) -return self -end -function AI_A2A_DISPATCHER:SetSquadronCapInterval(SquadronName,CapLimit,LowInterval,HighInterval,Probability) -self.DefenderSquadrons[SquadronName]=self.DefenderSquadrons[SquadronName]or{} -self.DefenderSquadrons[SquadronName].Cap=self.DefenderSquadrons[SquadronName].Cap or{} -local DefenderSquadron=self:GetSquadron(SquadronName) -local Cap=self.DefenderSquadrons[SquadronName].Cap -if Cap then -Cap.LowInterval=LowInterval or 180 -Cap.HighInterval=HighInterval or 600 -Cap.Probability=Probability or 1 -Cap.CapLimit=CapLimit or 1 -Cap.Scheduler=Cap.Scheduler or SCHEDULER:New(self) -local Scheduler=Cap.Scheduler -local ScheduleID=Cap.ScheduleID -local Variance=(Cap.HighInterval-Cap.LowInterval)/2 -local Repeat=Cap.LowInterval+Variance -local Randomization=Variance/Repeat -local Start=math.random(1,Cap.HighInterval) -if ScheduleID then -Scheduler:Stop(ScheduleID) -end -Cap.ScheduleID=Scheduler:Schedule(self,self.SchedulerCAP,{SquadronName},Start,Repeat,Randomization) -else -error("This squadron does not exist:"..SquadronName) -end -end -function AI_A2A_DISPATCHER:GetCAPDelay(SquadronName) -self.DefenderSquadrons[SquadronName]=self.DefenderSquadrons[SquadronName]or{} -self.DefenderSquadrons[SquadronName].Cap=self.DefenderSquadrons[SquadronName].Cap or{} -local DefenderSquadron=self:GetSquadron(SquadronName) -local Cap=self.DefenderSquadrons[SquadronName].Cap -if Cap then -return math.random(Cap.LowInterval,Cap.HighInterval) -else -error("This squadron does not exist:"..SquadronName) -end -end -function AI_A2A_DISPATCHER:CanCAP(SquadronName) -self:F({SquadronName=SquadronName}) -self.DefenderSquadrons[SquadronName]=self.DefenderSquadrons[SquadronName]or{} -self.DefenderSquadrons[SquadronName].Cap=self.DefenderSquadrons[SquadronName].Cap or{} -local DefenderSquadron=self:GetSquadron(SquadronName) -if(not DefenderSquadron.Resources)or(DefenderSquadron.Resources and DefenderSquadron.Resources>0)then -local Cap=DefenderSquadron.Cap -if Cap then -local CapCount=self:CountCapAirborne(SquadronName) -self:E({CapCount=CapCount}) -if CapCount0)then -local Gci=DefenderSquadron.Gci -if Gci then -return DefenderSquadron -end -end -return nil -end -function AI_A2A_DISPATCHER:SetSquadronGci(SquadronName,EngageMinSpeed,EngageMaxSpeed) -self.DefenderSquadrons[SquadronName]=self.DefenderSquadrons[SquadronName]or{} -self.DefenderSquadrons[SquadronName].Gci=self.DefenderSquadrons[SquadronName].Gci or{} -local Intercept=self.DefenderSquadrons[SquadronName].Gci -Intercept.Name=SquadronName -Intercept.EngageMinSpeed=EngageMinSpeed -Intercept.EngageMaxSpeed=EngageMaxSpeed -self:E({GCI={SquadronName,EngageMinSpeed,EngageMaxSpeed}}) -end -function AI_A2A_DISPATCHER:SetDefaultOverhead(Overhead) -self.DefenderDefault.Overhead=Overhead -return self -end -function AI_A2A_DISPATCHER:SetSquadronOverhead(SquadronName,Overhead) -local DefenderSquadron=self:GetSquadron(SquadronName) -DefenderSquadron.Overhead=Overhead -return self -end -function AI_A2A_DISPATCHER:SetDefaultGrouping(Grouping) -self.DefenderDefault.Grouping=Grouping -return self -end -function AI_A2A_DISPATCHER:SetSquadronGrouping(SquadronName,Grouping) -local DefenderSquadron=self:GetSquadron(SquadronName) -DefenderSquadron.Grouping=Grouping -return self -end -function AI_A2A_DISPATCHER:SetDefaultTakeoff(Takeoff) -self.DefenderDefault.Takeoff=Takeoff -return self -end -function AI_A2A_DISPATCHER:SetSquadronTakeoff(SquadronName,Takeoff) -local DefenderSquadron=self:GetSquadron(SquadronName) -DefenderSquadron.Takeoff=Takeoff -return self -end -function AI_A2A_DISPATCHER:GetDefaultTakeoff() -return self.DefenderDefault.Takeoff -end -function AI_A2A_DISPATCHER:GetSquadronTakeoff(SquadronName) -local DefenderSquadron=self:GetSquadron(SquadronName) -return DefenderSquadron.Takeoff or self.DefenderDefault.Takeoff -end -function AI_A2A_DISPATCHER:SetDefaultTakeoffInAir() -self:SetDefaultTakeoff(AI_A2A_DISPATCHER.Takeoff.Air) -return self -end -function AI_A2A_DISPATCHER:SetSquadronTakeoffInAir(SquadronName,TakeoffAltitude) -self:SetSquadronTakeoff(SquadronName,AI_A2A_DISPATCHER.Takeoff.Air) -if TakeoffAltitude then -self:SetSquadronTakeoffInAirAltitude(SquadronName,TakeoffAltitude) -end -return self -end -function AI_A2A_DISPATCHER:SetDefaultTakeoffFromRunway() -self:SetDefaultTakeoff(AI_A2A_DISPATCHER.Takeoff.Runway) -return self -end -function AI_A2A_DISPATCHER:SetSquadronTakeoffFromRunway(SquadronName) -self:SetSquadronTakeoff(SquadronName,AI_A2A_DISPATCHER.Takeoff.Runway) -return self -end -function AI_A2A_DISPATCHER:SetDefaultTakeoffFromParkingHot() -self:SetDefaultTakeoff(AI_A2A_DISPATCHER.Takeoff.Hot) -return self -end -function AI_A2A_DISPATCHER:SetSquadronTakeoffFromParkingHot(SquadronName) -self:SetSquadronTakeoff(SquadronName,AI_A2A_DISPATCHER.Takeoff.Hot) -return self -end -function AI_A2A_DISPATCHER:SetDefaultTakeoffFromParkingCold() -self:SetDefaultTakeoff(AI_A2A_DISPATCHER.Takeoff.Cold) -return self -end -function AI_A2A_DISPATCHER:SetSquadronTakeoffFromParkingCold(SquadronName) -self:SetSquadronTakeoff(SquadronName,AI_A2A_DISPATCHER.Takeoff.Cold) -return self -end -function AI_A2A_DISPATCHER:SetDefaultTakeoffInAirAltitude(TakeoffAltitude) -self.DefenderDefault.TakeoffAltitude=TakeoffAltitude -return self -end -function AI_A2A_DISPATCHER:SetSquadronTakeoffInAirAltitude(SquadronName,TakeoffAltitude) -local DefenderSquadron=self:GetSquadron(SquadronName) -DefenderSquadron.TakeoffAltitude=TakeoffAltitude -return self -end -function AI_A2A_DISPATCHER:SetDefaultLanding(Landing) -self.DefenderDefault.Landing=Landing -return self -end -function AI_A2A_DISPATCHER:SetSquadronLanding(SquadronName,Landing) -local DefenderSquadron=self:GetSquadron(SquadronName) -DefenderSquadron.Landing=Landing -return self -end -function AI_A2A_DISPATCHER:GetDefaultLanding() -return self.DefenderDefault.Landing -end -function AI_A2A_DISPATCHER:GetSquadronLanding(SquadronName) -local DefenderSquadron=self:GetSquadron(SquadronName) -return DefenderSquadron.Landing or self.DefenderDefault.Landing -end -function AI_A2A_DISPATCHER:SetDefaultLandingNearAirbase() -self:SetDefaultLanding(AI_A2A_DISPATCHER.Landing.NearAirbase) -return self -end -function AI_A2A_DISPATCHER:SetSquadronLandingNearAirbase(SquadronName) -self:SetSquadronLanding(SquadronName,AI_A2A_DISPATCHER.Landing.NearAirbase) -return self -end -function AI_A2A_DISPATCHER:SetDefaultLandingAtRunway() -self:SetDefaultLanding(AI_A2A_DISPATCHER.Landing.AtRunway) -return self -end -function AI_A2A_DISPATCHER:SetSquadronLandingAtRunway(SquadronName) -self:SetSquadronLanding(SquadronName,AI_A2A_DISPATCHER.Landing.AtRunway) -return self -end -function AI_A2A_DISPATCHER:SetDefaultLandingAtEngineShutdown() -self:SetDefaultLanding(AI_A2A_DISPATCHER.Landing.AtEngineShutdown) -return self -end -function AI_A2A_DISPATCHER:SetSquadronLandingAtEngineShutdown(SquadronName) -self:SetSquadronLanding(SquadronName,AI_A2A_DISPATCHER.Landing.AtEngineShutdown) -return self -end -function AI_A2A_DISPATCHER:SetDefaultFuelThreshold(FuelThreshold) -self.DefenderDefault.FuelThreshold=FuelThreshold -return self -end -function AI_A2A_DISPATCHER:SetSquadronFuelThreshold(SquadronName,FuelThreshold) -local DefenderSquadron=self:GetSquadron(SquadronName) -DefenderSquadron.FuelThreshold=FuelThreshold -return self -end -function AI_A2A_DISPATCHER:SetDefaultTanker(TankerName) -self.DefenderDefault.TankerName=TankerName -return self -end -function AI_A2A_DISPATCHER:SetSquadronTanker(SquadronName,TankerName) -local DefenderSquadron=self:GetSquadron(SquadronName) -DefenderSquadron.TankerName=TankerName -return self -end -function AI_A2A_DISPATCHER:AddDefenderToSquadron(Squadron,Defender,Size) -self.Defenders=self.Defenders or{} -local DefenderName=Defender:GetName() -self.Defenders[DefenderName]=Squadron -if Squadron.Resources then -Squadron.Resources=Squadron.Resources-Size -end -self:E({DefenderName=DefenderName,SquadronResources=Squadron.Resources}) -end -function AI_A2A_DISPATCHER:RemoveDefenderFromSquadron(Squadron,Defender) -self.Defenders=self.Defenders or{} -local DefenderName=Defender:GetName() -if Squadron.Resources then -Squadron.Resources=Squadron.Resources+Defender:GetSize() -end -self.Defenders[DefenderName]=nil -self:F({DefenderName=DefenderName,SquadronResources=Squadron.Resources}) -end -function AI_A2A_DISPATCHER:GetSquadronFromDefender(Defender) -self.Defenders=self.Defenders or{} -local DefenderName=Defender:GetName() -self:F({DefenderName=DefenderName}) -return self.Defenders[DefenderName] -end -function AI_A2A_DISPATCHER:EvaluateSWEEP(DetectedItem) -self:F({DetectedItem.ItemID}) -local DetectedSet=DetectedItem.Set -local DetectedZone=DetectedItem.Zone -if DetectedItem.IsDetected==false then -local TargetSetUnit=SET_UNIT:New() -TargetSetUnit:SetDatabase(DetectedSet) -TargetSetUnit:FilterOnce() -return TargetSetUnit -end -return nil -end -function AI_A2A_DISPATCHER:CountCapAirborne(SquadronName) -local CapCount=0 -local DefenderSquadron=self.DefenderSquadrons[SquadronName] -if DefenderSquadron then -for AIGroup,DefenderTask in pairs(self:GetDefenderTasks())do -if DefenderTask.SquadronName==SquadronName then -if DefenderTask.Type=="CAP"then -if AIGroup:IsAlive()then -if DefenderTask.Fsm:Is("Patrolling")or DefenderTask.Fsm:Is("Engaging")or DefenderTask.Fsm:Is("Refuelling")then -CapCount=CapCount+1 -end -end -end -end -end -end -return CapCount -end -function AI_A2A_DISPATCHER:CountDefendersEngaged(AttackerDetection) -local DefenderCount=0 -self:E("Counting Defenders Engaged for Attacker:") -local DetectedSet=AttackerDetection.Set -DetectedSet:Flush() -local DefenderTasks=self:GetDefenderTasks() -for DefenderGroup,DefenderTask in pairs(DefenderTasks)do -local Defender=DefenderGroup -local DefenderTaskTarget=DefenderTask.Target -local DefenderSquadronName=DefenderTask.SquadronName -if DefenderTaskTarget and DefenderTaskTarget.Index==AttackerDetection.Index then -local Squadron=self:GetSquadron(DefenderSquadronName) -local SquadronOverhead=Squadron.Overhead or self.DefenderDefault.Overhead -local DefenderSize=Defender:GetInitialSize() -DefenderCount=DefenderCount+DefenderSize/SquadronOverhead -self:F("Defender Group Name: "..Defender:GetName()..", Size: "..DefenderSize) -end -end -self:F({DefenderCount=DefenderCount}) -return DefenderCount -end -function AI_A2A_DISPATCHER:CountDefendersToBeEngaged(AttackerDetection,DefenderCount) -local Friendlies=nil -local AttackerSet=AttackerDetection.Set -local AttackerCount=AttackerSet:Count() -local DefenderFriendlies=self:GetAIFriendliesNearBy(AttackerDetection) -for FriendlyDistance,AIFriendly in UTILS.spairs(DefenderFriendlies or{})do -if AttackerCount>DefenderCount then -local Friendly=AIFriendly:GetGroup() -if Friendly and Friendly:IsAlive()then -local DefenderTask=self:GetDefenderTask(Friendly) -if DefenderTask then -if DefenderTask.Type=="CAP"or DefenderTask.Type=="GCI"then -if DefenderTask.Target==nil then -if DefenderTask.Fsm:Is("Returning") -or DefenderTask.Fsm:Is("Patrolling")then -Friendlies=Friendlies or{} -Friendlies[Friendly]=Friendly -DefenderCount=DefenderCount+Friendly:GetSize() -self:F({Friendly=Friendly:GetName(),FriendlyDistance=FriendlyDistance}) -end -end -end -end -end -else -break -end -end -return Friendlies -end -function AI_A2A_DISPATCHER:onafterCAP(From,Event,To,SquadronName) -self:F({SquadronName=SquadronName}) -self.DefenderSquadrons[SquadronName]=self.DefenderSquadrons[SquadronName]or{} -self.DefenderSquadrons[SquadronName].Cap=self.DefenderSquadrons[SquadronName].Cap or{} -local DefenderSquadron=self:CanCAP(SquadronName) -if DefenderSquadron then -local Cap=DefenderSquadron.Cap -if Cap then -local Spawn=DefenderSquadron.Spawn[math.random(1,#DefenderSquadron.Spawn)] -local DefenderGrouping=DefenderSquadron.Grouping or self.DefenderDefault.Grouping -Spawn:InitGrouping(DefenderGrouping) -local TakeoffMethod=self:GetSquadronTakeoff(SquadronName) -local DefenderCAP=Spawn:SpawnAtAirbase(DefenderSquadron.Airbase,TakeoffMethod,DefenderSquadron.TakeoffAltitude or self.DefenderDefault.TakeoffAltitude) -self:AddDefenderToSquadron(DefenderSquadron,DefenderCAP,DefenderGrouping) -if DefenderCAP then -local Fsm=AI_A2A_CAP:New(DefenderCAP,Cap.Zone,Cap.FloorAltitude,Cap.CeilingAltitude,Cap.PatrolMinSpeed,Cap.PatrolMaxSpeed,Cap.EngageMinSpeed,Cap.EngageMaxSpeed,Cap.AltType) -Fsm:SetDispatcher(self) -Fsm:SetHomeAirbase(DefenderSquadron.Airbase) -Fsm:SetFuelThreshold(DefenderSquadron.FuelThreshold or self.DefenderDefault.FuelThreshold,60) -Fsm:SetDamageThreshold(self.DefenderDefault.DamageThreshold) -Fsm:SetDisengageRadius(self.DisengageRadius) -Fsm:SetTanker(DefenderSquadron.TankerName or self.DefenderDefault.TankerName) -Fsm:Start() -self:SetDefenderTask(SquadronName,DefenderCAP,"CAP",Fsm) -function Fsm:onafterTakeoff(Defender,From,Event,To) -self:F({"GCI Birth",Defender:GetName()}) -local Dispatcher=Fsm:GetDispatcher() -local Squadron=Dispatcher:GetSquadronFromDefender(Defender) -if Squadron then -Fsm:__Patrol(2) -end -end -function Fsm:onafterRTB(Defender,From,Event,To) -self:F({"CAP RTB",Defender:GetName()}) -self:GetParent(self).onafterRTB(self,Defender,From,Event,To) -local Dispatcher=self:GetDispatcher() -Dispatcher:ClearDefenderTaskTarget(Defender) -end -function Fsm:onafterHome(Defender,From,Event,To,Action) -self:E({"CAP Home",Defender:GetName()}) -self:GetParent(self).onafterHome(self,Defender,From,Event,To) -local Dispatcher=self:GetDispatcher() -local Squadron=Dispatcher:GetSquadronFromDefender(Defender) -if Action and Action=="Destroy"then -Dispatcher:RemoveDefenderFromSquadron(Squadron,Defender) -Defender:Destroy() -end -if Dispatcher:GetSquadronLanding(Squadron.Name)==AI_A2A_DISPATCHER.Landing.NearAirbase then -Dispatcher:RemoveDefenderFromSquadron(Squadron,Defender) -Defender:Destroy() -end -end -end -end -end -end -function AI_A2A_DISPATCHER:onafterENGAGE(From,Event,To,AttackerDetection,Defenders) -if Defenders then -for DefenderID,Defender in pairs(Defenders)do -local Fsm=self:GetDefenderTaskFsm(Defender) -Fsm:__Engage(1,AttackerDetection.Set) -self:SetDefenderTaskTarget(Defender,AttackerDetection) -end -end -end -function AI_A2A_DISPATCHER:onafterGCI(From,Event,To,AttackerDetection,DefendersMissing,DefenderFriendlies) -self:F({From,Event,To,AttackerDetection.Index,DefendersMissing,DefenderFriendlies}) -local AttackerSet=AttackerDetection.Set -local AttackerUnit=AttackerSet:GetFirst() -if AttackerUnit and AttackerUnit:IsAlive()then -local AttackerCount=AttackerSet:Count() -local DefenderCount=0 -for DefenderID,DefenderGroup in pairs(DefenderFriendlies or{})do -local Fsm=self:GetDefenderTaskFsm(DefenderGroup) -Fsm:__Engage(1,AttackerSet) -self:SetDefenderTaskTarget(DefenderGroup,AttackerDetection) -DefenderCount=DefenderCount+DefenderGroup:GetSize() -end -self:F({DefenderCount=DefenderCount,DefendersMissing=DefendersMissing}) -DefenderCount=DefendersMissing -local ClosestDistance=0 -local ClosestDefenderSquadronName=nil -local BreakLoop=false -while(DefenderCount>0 and not BreakLoop)do -self:F({DefenderSquadrons=self.DefenderSquadrons}) -for SquadronName,DefenderSquadron in pairs(self.DefenderSquadrons or{})do -self:F({GCI=DefenderSquadron.Gci}) -for InterceptID,Intercept in pairs(DefenderSquadron.Gci or{})do -self:F({DefenderSquadron}) -local SpawnCoord=DefenderSquadron.Airbase:GetCoordinate() -local AttackerCoord=AttackerUnit:GetCoordinate() -local InterceptCoord=AttackerDetection.InterceptCoord -self:F({InterceptCoord=InterceptCoord}) -if InterceptCoord then -local InterceptDistance=SpawnCoord:Get2DDistance(InterceptCoord) -local AirbaseDistance=SpawnCoord:Get2DDistance(AttackerCoord) -self:F({InterceptDistance=InterceptDistance,AirbaseDistance=AirbaseDistance,InterceptCoord=InterceptCoord}) -if ClosestDistance==0 or InterceptDistanceDefenderSquadron.Resources then -DefendersNeeded=DefenderSquadron.Resources -BreakLoop=true -end -while(DefendersNeeded>0)do -local Spawn=DefenderSquadron.Spawn[math.random(1,#DefenderSquadron.Spawn)] -local DefenderGrouping=(DefenderGrouping0 then -for PlayerName,PlayerType in pairs(PlayerTypes)do -PlayerTypesReport:Add(string.format('"%s" in %s',PlayerName,PlayerType)) -end -else -PlayerTypesReport:Add("-") -end -return PlayersCount,PlayerTypesReport -end -function AI_A2A_DISPATCHER:GetFriendliesNearBy(Target) -local DetectedSet=Target.Set -local FriendlyUnitsNearBy=self.Detection:GetFriendliesNearBy(Target) -local FriendlyTypes={} -local FriendliesCount=0 -if FriendlyUnitsNearBy then -local DetectedTreatLevel=DetectedSet:CalculateThreatLevelA2G() -for FriendlyUnitName,FriendlyUnitData in pairs(FriendlyUnitsNearBy)do -local FriendlyUnit=FriendlyUnitData -if FriendlyUnit:IsAirPlane()then -local FriendlyUnitThreatLevel=FriendlyUnit:GetThreatLevel() -FriendliesCount=FriendliesCount+1 -local FriendlyType=FriendlyUnit:GetTypeName() -FriendlyTypes[FriendlyType]=FriendlyTypes[FriendlyType]and(FriendlyTypes[FriendlyType]+1)or 1 -if DetectedTreatLevel0 then -for FriendlyType,FriendlyTypeCount in pairs(FriendlyTypes)do -FriendlyTypesReport:Add(string.format("%d of %s",FriendlyTypeCount,FriendlyType)) -end -else -FriendlyTypesReport:Add("-") -end -return FriendliesCount,FriendlyTypesReport -end -function AI_A2A_DISPATCHER:SchedulerCAP(SquadronName) -self:CAP(SquadronName) -end -end -do -AI_A2A_GCICAP={ -ClassName="AI_A2A_GCICAP", -Detection=nil, -} -function AI_A2A_GCICAP:New(EWRPrefixes,TemplatePrefixes,CapPrefixes,CapLimit,GroupingRadius,EngageRadius,GciRadius,Resources) -local EWRSetGroup=SET_GROUP:New() -EWRSetGroup:FilterPrefixes(EWRPrefixes) -EWRSetGroup:FilterStart() -local Detection=DETECTION_AREAS:New(EWRSetGroup,GroupingRadius or 30000) -local self=BASE:Inherit(self,AI_A2A_DISPATCHER:New(Detection)) -self:SetEngageRadius(EngageRadius) -self:SetGciRadius(GciRadius) -local EWRFirst=EWRSetGroup:GetFirst() -local EWRCoalition=EWRFirst:GetCoalition() -local AirbaseNames={} -for AirbaseID,AirbaseData in pairs(_DATABASE.AIRBASES)do -local Airbase=AirbaseData -local AirbaseName=Airbase:GetName() -if Airbase:GetCoalition()==EWRCoalition then -table.insert(AirbaseNames,AirbaseName) -end -end -self.Templates=SET_GROUP -:New() -:FilterPrefixes(TemplatePrefixes) -:FilterOnce() -self:F({Airbases=AirbaseNames}) -self.Templates:Flush() -for AirbaseID,AirbaseName in pairs(AirbaseNames)do -local Airbase=_DATABASE:FindAirbase(AirbaseName) -local AirbaseName=Airbase:GetName() -local AirbaseCoord=Airbase:GetCoordinate() -local AirbaseZone=ZONE_RADIUS:New("Airbase",AirbaseCoord:GetVec2(),3000) -local Templates=nil -for TemplateID,Template in pairs(self.Templates:GetSet())do -local Template=Template -self:F({Template=Template:GetName()}) -local TemplateCoord=Template:GetCoordinate() -if AirbaseZone:IsVec2InZone(TemplateCoord:GetVec2())then -Templates=Templates or{} -table.insert(Templates,Template:GetName()) -end -end -if Templates then -self:SetSquadron(AirbaseName,AirbaseName,Templates,Resources) -end -end -self.CAPTemplates=SET_GROUP:New() -self.CAPTemplates:FilterPrefixes(CapPrefixes) -self.CAPTemplates:FilterOnce() -for CAPID,CAPTemplate in pairs(self.CAPTemplates:GetSet())do -local CAPZone=ZONE_POLYGON:New(CAPTemplate:GetName(),CAPTemplate) -local AirbaseDistance=99999999 -local AirbaseClosest=nil -for AirbaseID,AirbaseName in pairs(AirbaseNames)do -local Airbase=_DATABASE:FindAirbase(AirbaseName) -local AirbaseName=Airbase:GetName() -local AirbaseCoord=Airbase:GetCoordinate() -local Squadron=self.DefenderSquadrons[AirbaseName] -if Squadron then -local Distance=AirbaseCoord:Get2DDistance(CAPZone:GetCoordinate()) -if Distance Engaging') -self:__Engage(1) -end -end -end -function AI_CAP_ZONE:onafterAbort(Controllable,From,Event,To) -Controllable:ClearTasks() -self:__Route(1) -end -function AI_CAP_ZONE:onafterEngage(Controllable,From,Event,To) -if Controllable:IsAlive()then -local EngageRoute={} -local CurrentVec2=self.Controllable:GetVec2() -local CurrentAltitude=self.Controllable:GetUnit(1):GetAltitude() -local CurrentPointVec3=POINT_VEC3:New(CurrentVec2.x,CurrentAltitude,CurrentVec2.y) -local ToEngageZoneSpeed=self.PatrolMaxSpeed -local CurrentRoutePoint=CurrentPointVec3:WaypointAir( -self.PatrolAltType, -POINT_VEC3.RoutePointType.TurningPoint, -POINT_VEC3.RoutePointAction.TurningPoint, -ToEngageZoneSpeed, -true -) -EngageRoute[#EngageRoute+1]=CurrentRoutePoint -local ToTargetVec2=self.PatrolZone:GetRandomVec2() -self:T2(ToTargetVec2) -local ToTargetAltitude=math.random(self.EngageFloorAltitude,self.EngageCeilingAltitude) -local ToTargetSpeed=math.random(self.PatrolMinSpeed,self.PatrolMaxSpeed) -self:T2({self.PatrolMinSpeed,self.PatrolMaxSpeed,ToTargetSpeed}) -local ToTargetPointVec3=POINT_VEC3:New(ToTargetVec2.x,ToTargetAltitude,ToTargetVec2.y) -local ToPatrolRoutePoint=ToTargetPointVec3:WaypointAir( -self.PatrolAltType, -POINT_VEC3.RoutePointType.TurningPoint, -POINT_VEC3.RoutePointAction.TurningPoint, -ToTargetSpeed, -true -) -EngageRoute[#EngageRoute+1]=ToPatrolRoutePoint -Controllable:OptionROEOpenFire() -Controllable:OptionROTPassiveDefense() -local AttackTasks={} -for DetectedUnit,Detected in pairs(self.DetectedUnits)do -local DetectedUnit=DetectedUnit -self:T({DetectedUnit,DetectedUnit:IsAlive(),DetectedUnit:IsAir()}) -if DetectedUnit:IsAlive()and DetectedUnit:IsAir()then -if self.EngageZone then -if DetectedUnit:IsInZone(self.EngageZone)then -self:F({"Within Zone and Engaging ",DetectedUnit}) -AttackTasks[#AttackTasks+1]=Controllable:TaskAttackUnit(DetectedUnit) -end -else -if self.EngageRange then -if DetectedUnit:GetPointVec3():Get2DDistance(Controllable:GetPointVec3())<=self.EngageRange then -self:F({"Within Range and Engaging",DetectedUnit}) -AttackTasks[#AttackTasks+1]=Controllable:TaskAttackUnit(DetectedUnit) -end -else -AttackTasks[#AttackTasks+1]=Controllable:TaskAttackUnit(DetectedUnit) -end -end -else -self.DetectedUnits[DetectedUnit]=nil -end -end -if#AttackTasks==0 then -self:F("No targets found -> Going back to Patrolling") -self:__Abort(1) -self:__Route(1) -self:SetDetectionActivated() -else -AttackTasks[#AttackTasks+1]=Controllable:TaskFunction("AI_CAP_ZONE.EngageRoute",self) -EngageRoute[1].task=Controllable:TaskCombo(AttackTasks) -self:SetDetectionDeactivated() -end -Controllable:Route(EngageRoute,0.5) -end -end -function AI_CAP_ZONE:onafterAccomplish(Controllable,From,Event,To) -self.Accomplished=true -self:SetDetectionOff() -end -function AI_CAP_ZONE:onafterDestroy(Controllable,From,Event,To,EventData) -if EventData.IniUnit then -self.DetectedUnits[EventData.IniUnit]=nil -end -end -function AI_CAP_ZONE:OnEventDead(EventData) -self:F({"EventDead",EventData}) -if EventData.IniDCSUnit then -if self.DetectedUnits and self.DetectedUnits[EventData.IniUnit]then -self:__Destroy(1,EventData) -end -end -end -AI_CAS_ZONE={ -ClassName="AI_CAS_ZONE", -} -function AI_CAS_ZONE:New(PatrolZone,PatrolFloorAltitude,PatrolCeilingAltitude,PatrolMinSpeed,PatrolMaxSpeed,EngageZone,PatrolAltType) -local self=BASE:Inherit(self,AI_PATROL_ZONE:New(PatrolZone,PatrolFloorAltitude,PatrolCeilingAltitude,PatrolMinSpeed,PatrolMaxSpeed,PatrolAltType)) -self.EngageZone=EngageZone -self.Accomplished=false -self:SetDetectionZone(self.EngageZone) -self:AddTransition({"Patrolling","Engaging"},"Engage","Engaging") -self:AddTransition("Engaging","Target","Engaging") -self:AddTransition("Engaging","Fired","Engaging") -self:AddTransition("*","Destroy","*") -self:AddTransition("Engaging","Abort","Patrolling") -self:AddTransition("Engaging","Accomplish","Patrolling") -return self -end -function AI_CAS_ZONE:SetEngageZone(EngageZone) -self:F2() -if EngageZone then -self.EngageZone=EngageZone -else -self.EngageZone=nil -end -end -function AI_CAS_ZONE:onafterStart(Controllable,From,Event,To) -self:GetParent(self).onafterStart(self,Controllable,From,Event,To) -self:HandleEvent(EVENTS.Dead) -self:SetDetectionDeactivated() -end -function AI_CAS_ZONE.EngageRoute(EngageGroup,Fsm) -EngageGroup:F({"AI_CAS_ZONE.EngageRoute:",EngageGroup:GetName()}) -if EngageGroup:IsAlive()then -Fsm:__Engage(1,Fsm.EngageSpeed,Fsm.EngageAltitude,Fsm.EngageWeaponExpend,Fsm.EngageAttackQty,Fsm.EngageDirection) -end -end -function AI_CAS_ZONE:onbeforeEngage(Controllable,From,Event,To) -if self.Accomplished==true then -return false -end -end -function AI_CAS_ZONE:onafterTarget(Controllable,From,Event,To) -self:E("onafterTarget") -if Controllable:IsAlive()then -local AttackTasks={} -for DetectedUnit,Detected in pairs(self.DetectedUnits)do -local DetectedUnit=DetectedUnit -if DetectedUnit:IsAlive()then -if DetectedUnit:IsInZone(self.EngageZone)then -if Detected==true then -self:E({"Target: ",DetectedUnit}) -self.DetectedUnits[DetectedUnit]=false -local AttackTask=Controllable:TaskAttackUnit(DetectedUnit,false,self.EngageWeaponExpend,self.EngageAttackQty,self.EngageDirection,self.EngageAltitude,nil) -self.Controllable:PushTask(AttackTask,1) -end -end -else -self.DetectedUnits[DetectedUnit]=nil -end -end -self:__Target(-10) -end -end -function AI_CAS_ZONE:onafterAbort(Controllable,From,Event,To) -Controllable:ClearTasks() -self:__Route(1) -end -function AI_CAS_ZONE:onafterEngage(Controllable,From,Event,To, -EngageSpeed, -EngageAltitude, -EngageWeaponExpend, -EngageAttackQty, -EngageDirection) -self:F("onafterEngage") -self.EngageSpeed=EngageSpeed or 400 -self.EngageAltitude=EngageAltitude or 2000 -self.EngageWeaponExpend=EngageWeaponExpend -self.EngageAttackQty=EngageAttackQty -self.EngageDirection=EngageDirection -if Controllable:IsAlive()then -Controllable:OptionROEOpenFire() -Controllable:OptionROTVertical() -local EngageRoute={} -local CurrentVec2=self.Controllable:GetVec2() -local CurrentAltitude=self.Controllable:GetUnit(1):GetAltitude() -local CurrentPointVec3=POINT_VEC3:New(CurrentVec2.x,CurrentAltitude,CurrentVec2.y) -local ToEngageZoneSpeed=self.PatrolMaxSpeed -local CurrentRoutePoint=CurrentPointVec3:WaypointAir( -self.PatrolAltType, -POINT_VEC3.RoutePointType.TurningPoint, -POINT_VEC3.RoutePointAction.TurningPoint, -self.EngageSpeed, -true -) -EngageRoute[#EngageRoute+1]=CurrentRoutePoint -local AttackTasks={} -for DetectedUnit,Detected in pairs(self.DetectedUnits)do -local DetectedUnit=DetectedUnit -self:T(DetectedUnit) -if DetectedUnit:IsAlive()then -if DetectedUnit:IsInZone(self.EngageZone)then -self:E({"Engaging ",DetectedUnit}) -AttackTasks[#AttackTasks+1]=Controllable:TaskAttackUnit(DetectedUnit, -true, -EngageWeaponExpend, -EngageAttackQty, -EngageDirection -) -end -else -self.DetectedUnits[DetectedUnit]=nil -end -end -AttackTasks[#AttackTasks+1]=Controllable:TaskFunction("AI_CAS_ZONE.EngageRoute",self) -EngageRoute[#EngageRoute].task=Controllable:TaskCombo(AttackTasks) -local ToTargetVec2=self.EngageZone:GetRandomVec2() -self:T2(ToTargetVec2) -local ToTargetPointVec3=POINT_VEC3:New(ToTargetVec2.x,self.EngageAltitude,ToTargetVec2.y) -local ToTargetRoutePoint=ToTargetPointVec3:WaypointAir( -self.PatrolAltType, -POINT_VEC3.RoutePointType.TurningPoint, -POINT_VEC3.RoutePointAction.TurningPoint, -self.EngageSpeed, -true -) -EngageRoute[#EngageRoute+1]=ToTargetRoutePoint -Controllable:Route(EngageRoute,0.5) -self:SetRefreshTimeInterval(2) -self:SetDetectionActivated() -self:__Target(-2) -end -end -function AI_CAS_ZONE:onafterAccomplish(Controllable,From,Event,To) -self.Accomplished=true -self:SetDetectionDeactivated() -end -function AI_CAS_ZONE:onafterDestroy(Controllable,From,Event,To,EventData) -if EventData.IniUnit then -self.DetectedUnits[EventData.IniUnit]=nil -end -end -function AI_CAS_ZONE:OnEventDead(EventData) -self:F({"EventDead",EventData}) -if EventData.IniDCSUnit then -if self.DetectedUnits and self.DetectedUnits[EventData.IniUnit]then -self:__Destroy(1,EventData) -end -end -end -AI_BAI_ZONE={ -ClassName="AI_BAI_ZONE", -} -function AI_BAI_ZONE:New(PatrolZone,PatrolFloorAltitude,PatrolCeilingAltitude,PatrolMinSpeed,PatrolMaxSpeed,EngageZone,PatrolAltType) -local self=BASE:Inherit(self,AI_PATROL_ZONE:New(PatrolZone,PatrolFloorAltitude,PatrolCeilingAltitude,PatrolMinSpeed,PatrolMaxSpeed,PatrolAltType)) -self.EngageZone=EngageZone -self.Accomplished=false -self:SetDetectionZone(self.EngageZone) -self:SearchOn() -self:AddTransition({"Patrolling","Engaging"},"Engage","Engaging") -self:AddTransition("Engaging","Target","Engaging") -self:AddTransition("Engaging","Fired","Engaging") -self:AddTransition("*","Destroy","*") -self:AddTransition("Engaging","Abort","Patrolling") -self:AddTransition("Engaging","Accomplish","Patrolling") -return self -end -function AI_BAI_ZONE:SetEngageZone(EngageZone) -self:F2() -if EngageZone then -self.EngageZone=EngageZone -else -self.EngageZone=nil -end -end -function AI_BAI_ZONE:SearchOnOff(Search) -self.Search=Search -return self -end -function AI_BAI_ZONE:SearchOff() -self:SearchOnOff(false) -return self -end -function AI_BAI_ZONE:SearchOn() -self:SearchOnOff(true) -return self -end -function AI_BAI_ZONE:onafterStart(Controllable,From,Event,To) -self:GetParent(self).onafterStart(self,Controllable,From,Event,To) -self:HandleEvent(EVENTS.Dead) -self:SetDetectionDeactivated() -end -function _NewEngageRoute(AIControllable) -AIControllable:T("NewEngageRoute") -local EngageZone=AIControllable:GetState(AIControllable,"EngageZone") -EngageZone:__Engage(1,EngageZone.EngageSpeed,EngageZone.EngageAltitude,EngageZone.EngageWeaponExpend,EngageZone.EngageAttackQty,EngageZone.EngageDirection) -end -function AI_BAI_ZONE:onbeforeEngage(Controllable,From,Event,To) -if self.Accomplished==true then -return false -end -end -function AI_BAI_ZONE:onafterTarget(Controllable,From,Event,To) -self:F({"onafterTarget",self.Search,Controllable:IsAlive()}) -if Controllable:IsAlive()then -local AttackTasks={} -if self.Search==true then -for DetectedUnit,Detected in pairs(self.DetectedUnits)do -local DetectedUnit=DetectedUnit -if DetectedUnit:IsAlive()then -if DetectedUnit:IsInZone(self.EngageZone)then -if Detected==true then -self:F({"Target: ",DetectedUnit}) -self.DetectedUnits[DetectedUnit]=false -local AttackTask=Controllable:TaskAttackUnit(DetectedUnit,false,self.EngageWeaponExpend,self.EngageAttackQty,self.EngageDirection,self.EngageAltitude,nil) -self.Controllable:PushTask(AttackTask,1) -end -end -else -self.DetectedUnits[DetectedUnit]=nil -end -end -else -self:F("Attack zone") -local AttackTask=Controllable:TaskAttackMapObject( -self.EngageZone:GetPointVec2():GetVec2(), -true, -self.EngageWeaponExpend, -self.EngageAttackQty, -self.EngageDirection, -self.EngageAltitude -) -self.Controllable:PushTask(AttackTask,1) -end -self:__Target(-10) -end -end -function AI_BAI_ZONE:onafterAbort(Controllable,From,Event,To) -Controllable:ClearTasks() -self:__Route(1) -end -function AI_BAI_ZONE:onafterEngage(Controllable,From,Event,To, -EngageSpeed, -EngageAltitude, -EngageWeaponExpend, -EngageAttackQty, -EngageDirection) -self:F("onafterEngage") -self.EngageSpeed=EngageSpeed or 400 -self.EngageAltitude=EngageAltitude or 2000 -self.EngageWeaponExpend=EngageWeaponExpend -self.EngageAttackQty=EngageAttackQty -self.EngageDirection=EngageDirection -if Controllable:IsAlive()then -local EngageRoute={} -local CurrentVec2=self.Controllable:GetVec2() -local CurrentAltitude=self.Controllable:GetUnit(1):GetAltitude() -local CurrentPointVec3=POINT_VEC3:New(CurrentVec2.x,CurrentAltitude,CurrentVec2.y) -local ToEngageZoneSpeed=self.PatrolMaxSpeed -local CurrentRoutePoint=CurrentPointVec3:WaypointAir( -self.PatrolAltType, -POINT_VEC3.RoutePointType.TurningPoint, -POINT_VEC3.RoutePointAction.TurningPoint, -self.EngageSpeed, -true -) -EngageRoute[#EngageRoute+1]=CurrentRoutePoint -local AttackTasks={} -if self.Search==true then -for DetectedUnitID,DetectedUnitData in pairs(self.DetectedUnits)do -local DetectedUnit=DetectedUnitData -self:T(DetectedUnit) -if DetectedUnit:IsAlive()then -if DetectedUnit:IsInZone(self.EngageZone)then -self:F({"Engaging ",DetectedUnit}) -AttackTasks[#AttackTasks+1]=Controllable:TaskBombing( -DetectedUnit:GetPointVec2():GetVec2(), -true, -EngageWeaponExpend, -EngageAttackQty, -EngageDirection, -EngageAltitude -) -end -else -self.DetectedUnits[DetectedUnit]=nil -end -end -else -self:F("Attack zone") -AttackTasks[#AttackTasks+1]=Controllable:TaskAttackMapObject( -self.EngageZone:GetPointVec2():GetVec2(), -true, -EngageWeaponExpend, -EngageAttackQty, -EngageDirection, -EngageAltitude -) -end -EngageRoute[#EngageRoute].task=Controllable:TaskCombo(AttackTasks) -local ToTargetVec2=self.EngageZone:GetRandomVec2() -self:T2(ToTargetVec2) -local ToTargetPointVec3=POINT_VEC3:New(ToTargetVec2.x,self.EngageAltitude,ToTargetVec2.y) -local ToTargetRoutePoint=ToTargetPointVec3:WaypointAir( -self.PatrolAltType, -POINT_VEC3.RoutePointType.TurningPoint, -POINT_VEC3.RoutePointAction.TurningPoint, -self.EngageSpeed, -true -) -EngageRoute[#EngageRoute+1]=ToTargetRoutePoint -Controllable:OptionROEOpenFire() -Controllable:OptionROTVertical() -Controllable:WayPointInitialize(EngageRoute) -Controllable:SetState(Controllable,"EngageZone",self) -Controllable:WayPointFunction(#EngageRoute,1,"_NewEngageRoute") -Controllable:WayPointExecute(1) -self:SetRefreshTimeInterval(2) -self:SetDetectionActivated() -self:__Target(-2) -end -end -function AI_BAI_ZONE:onafterAccomplish(Controllable,From,Event,To) -self.Accomplished=true -self:SetDetectionDeactivated() -end -function AI_BAI_ZONE:onafterDestroy(Controllable,From,Event,To,EventData) -if EventData.IniUnit then -self.DetectedUnits[EventData.IniUnit]=nil -end -end -function AI_BAI_ZONE:OnEventDead(EventData) -self:F({"EventDead",EventData}) -if EventData.IniDCSUnit then -if self.DetectedUnits and self.DetectedUnits[EventData.IniUnit]then -self:__Destroy(1,EventData) -end -end -end -AI_FORMATION={ -ClassName="AI_FORMATION", -FollowName=nil, -FollowUnit=nil, -FollowGroupSet=nil, -FollowMode=1, -MODE={ -FOLLOW=1, -MISSION=2, -}, -FollowScheduler=nil, -OptionROE=AI.Option.Air.val.ROE.OPEN_FIRE, -OptionReactionOnThreat=AI.Option.Air.val.REACTION_ON_THREAT.ALLOW_ABORT_MISSION, -} -function AI_FORMATION:New(FollowUnit,FollowGroupSet,FollowName,FollowBriefing) -local self=BASE:Inherit(self,FSM_SET:New(FollowGroupSet)) -self:F({FollowUnit,FollowGroupSet,FollowName}) -self.FollowUnit=FollowUnit -self.FollowGroupSet=FollowGroupSet -self:SetFlightRandomization(2) -self:SetStartState("None") -self:AddTransition("*","Stop","Stopped") -self:AddTransition("None","Start","Following") -self:AddTransition("*","FormationLine","*") -self:AddTransition("*","FormationTrail","*") -self:AddTransition("*","FormationStack","*") -self:AddTransition("*","FormationLeftLine","*") -self:AddTransition("*","FormationRightLine","*") -self:AddTransition("*","FormationLeftWing","*") -self:AddTransition("*","FormationRightWing","*") -self:AddTransition("*","FormationCenterWing","*") -self:AddTransition("*","FormationVic","*") -self:AddTransition("*","FormationBox","*") -self:AddTransition("*","Follow","Following") -self:FormationLeftLine(500,0,250,250) -self.FollowName=FollowName -self.FollowBriefing=FollowBriefing -self.CT1=0 -self.GT1=0 -self.FollowMode=AI_FORMATION.MODE.MISSION -return self -end -function AI_FORMATION:TestSmokeDirectionVector(SmokeDirection) -self.SmokeDirectionVector=(SmokeDirection==true)and true or false -return self -end -function AI_FORMATION:onafterFormationLine(FollowGroupSet,From,Event,To,XStart,XSpace,YStart,YSpace,ZStart,ZSpace) -self:F({FollowGroupSet,From,Event,To,XStart,XSpace,YStart,YSpace,ZStart,ZSpace}) -FollowGroupSet:Flush() -local FollowSet=FollowGroupSet:GetSet() -local i=0 -for FollowID,FollowGroup in pairs(FollowSet)do -local PointVec3=POINT_VEC3:New() -PointVec3:SetX(XStart+i*XSpace) -PointVec3:SetY(YStart+i*YSpace) -PointVec3:SetZ(ZStart+i*ZSpace) -local Vec3=PointVec3:GetVec3() -FollowGroup:SetState(self,"FormationVec3",Vec3) -i=i+1 -end -return self -end -function AI_FORMATION:onafterFormationTrail(FollowGroupSet,From,Event,To,XStart,XSpace,YStart) -self:onafterFormationLine(FollowGroupSet,From,Event,To,XStart,XSpace,YStart,0,0,0) -return self -end -function AI_FORMATION:onafterFormationStack(FollowGroupSet,From,Event,To,XStart,XSpace,YStart,YSpace) -self:onafterFormationLine(FollowGroupSet,From,Event,To,XStart,XSpace,YStart,YSpace,0,0) -return self -end -function AI_FORMATION:onafterFormationLeftLine(FollowGroupSet,From,Event,To,XStart,YStart,ZStart,ZSpace) -self:onafterFormationLine(FollowGroupSet,From,Event,To,XStart,0,YStart,0,ZStart,ZSpace) -return self -end -function AI_FORMATION:onafterFormationRightLine(FollowGroupSet,From,Event,To,XStart,YStart,ZStart,ZSpace) -self:onafterFormationLine(FollowGroupSet,From,Event,To,XStart,0,YStart,0,-ZStart,-ZSpace) -return self -end -function AI_FORMATION:onafterFormationLeftWing(FollowGroupSet,From,Event,To,XStart,XSpace,YStart,ZStart,ZSpace) -self:onafterFormationLine(FollowGroupSet,From,Event,To,XStart,XSpace,YStart,0,ZStart,ZSpace) -return self -end -function AI_FORMATION:onafterFormationRightWing(FollowGroupSet,From,Event,To,XStart,XSpace,YStart,ZStart,ZSpace) -self:onafterFormationLine(FollowGroupSet,From,Event,To,XStart,XSpace,YStart,0,-ZStart,-ZSpace) -return self -end -function AI_FORMATION:onafterFormationCenterWing(FollowGroupSet,From,Event,To,XStart,XSpace,YStart,YSpace,ZStart,ZSpace) -local FollowSet=FollowGroupSet:GetSet() -local i=0 -for FollowID,FollowGroup in pairs(FollowSet)do -local PointVec3=POINT_VEC3:New() -local Side=(i%2==0)and 1 or-1 -local Row=i/2+1 -PointVec3:SetX(XStart+Row*XSpace) -PointVec3:SetY(YStart) -PointVec3:SetZ(Side*(ZStart+i*ZSpace)) -local Vec3=PointVec3:GetVec3() -FollowGroup:SetState(self,"FormationVec3",Vec3) -i=i+1 -end -return self -end -function AI_FORMATION:onafterFormationVic(FollowGroupSet,From,Event,To,XStart,XSpace,YStart,YSpace,ZStart,ZSpace) -self:onafterFormationCenterWing(FollowGroupSet,From,Event,To,XStart,XSpace,YStart,YSpace,ZStart,ZSpace) -return self -end -function AI_FORMATION:onafterFormationBox(FollowGroupSet,From,Event,To,XStart,XSpace,YStart,YSpace,ZStart,ZSpace,ZLevels) -local FollowSet=FollowGroupSet:GetSet() -local i=0 -for FollowID,FollowGroup in pairs(FollowSet)do -local PointVec3=POINT_VEC3:New() -local ZIndex=i%ZLevels -local XIndex=math.floor(i/ZLevels) -local YIndex=math.floor(i/ZLevels) -PointVec3:SetX(XStart+XIndex*XSpace) -PointVec3:SetY(YStart+YIndex*YSpace) -PointVec3:SetZ(-ZStart-(ZSpace*ZLevels/2)+ZSpace*ZIndex) -local Vec3=PointVec3:GetVec3() -FollowGroup:SetState(self,"FormationVec3",Vec3) -i=i+1 -end -return self -end -function AI_FORMATION:SetFlightRandomization(FlightRandomization) -self.FlightRandomization=FlightRandomization -return self -end -function AI_FORMATION:onenterFollowing(FollowGroupSet) -self:F() -self:T({self.FollowUnit.UnitName,self.FollowUnit:IsAlive()}) -if self.FollowUnit:IsAlive()then -local ClientUnit=self.FollowUnit -self:T({ClientUnit.UnitName}) -local CT1,CT2,CV1,CV2 -CT1=ClientUnit:GetState(self,"CT1") -if CT1==nil or CT1==0 then -ClientUnit:SetState(self,"CV1",ClientUnit:GetPointVec3()) -ClientUnit:SetState(self,"CT1",timer.getTime()) -else -CT1=ClientUnit:GetState(self,"CT1") -CT2=timer.getTime() -CV1=ClientUnit:GetState(self,"CV1") -CV2=ClientUnit:GetPointVec3() -ClientUnit:SetState(self,"CT1",CT2) -ClientUnit:SetState(self,"CV1",CV2) -end -FollowGroupSet:ForEachGroup( -function(FollowGroup,Formation,ClientUnit,CT1,CV1,CT2,CV2) -FollowGroup:OptionROTPassiveDefense() -FollowGroup:OptionROEReturnFire() -local GroupUnit=FollowGroup:GetUnit(1) -local FollowFormation=FollowGroup:GetState(self,"FormationVec3") -if FollowFormation then -local FollowDistance=FollowFormation.x -local GT1=GroupUnit:GetState(self,"GT1") -if CT1==nil or CT1==0 or GT1==nil or GT1==0 then -GroupUnit:SetState(self,"GV1",GroupUnit:GetPointVec3()) -GroupUnit:SetState(self,"GT1",timer.getTime()) -else -local CD=((CV2.x-CV1.x)^2+(CV2.y-CV1.y)^2+(CV2.z-CV1.z)^2)^0.5 -local CT=CT2-CT1 -local CS=(3600/CT)*(CD/1000)/3.6 -local CDv={x=CV2.x-CV1.x,y=CV2.y-CV1.y,z=CV2.z-CV1.z} -local Ca=math.atan2(CDv.x,CDv.z) -local GT1=GroupUnit:GetState(self,"GT1") -local GT2=timer.getTime() -local GV1=GroupUnit:GetState(self,"GV1") -local GV2=GroupUnit:GetPointVec3() -GV2:AddX(math.random(-Formation.FlightRandomization/2,Formation.FlightRandomization/2)) -GV2:AddY(math.random(-Formation.FlightRandomization/2,Formation.FlightRandomization/2)) -GV2:AddZ(math.random(-Formation.FlightRandomization/2,Formation.FlightRandomization/2)) -GroupUnit:SetState(self,"GT1",GT2) -GroupUnit:SetState(self,"GV1",GV2) -local GD=((GV2.x-GV1.x)^2+(GV2.y-GV1.y)^2+(GV2.z-GV1.z)^2)^0.5 -local GT=GT2-GT1 -local GDv={x=GV2.x-CV1.x,y=GV2.y-CV1.y,z=GV2.z-CV1.z} -local Alpha_T=math.atan2(GDv.x,GDv.z)-math.atan2(CDv.x,CDv.z) -local Alpha_R=(Alpha_T<0)and Alpha_T+2*math.pi or Alpha_T -local Position=math.cos(Alpha_R) -local GD=((GDv.x)^2+(GDv.z)^2)^0.5 -local Distance=GD*Position+-CS*0,5 -local GV={x=GV2.x-CV2.x,y=GV2.y-CV2.y,z=GV2.z-CV2.z} -local GH2={x=GV2.x,y=CV2.y+FollowFormation.y,z=GV2.z} -local alpha=math.atan2(GV.x,GV.z) -local GVx=FollowFormation.z*math.cos(Ca)+FollowFormation.x*math.sin(Ca) -local GVz=FollowFormation.x*math.cos(Ca)-FollowFormation.z*math.sin(Ca) -local CVI={x=CV2.x+CS*10*math.sin(Ca), -y=GH2.y-(Distance+FollowFormation.x)/5, -z=CV2.z+CS*10*math.cos(Ca), -} -local DV={x=CV2.x-CVI.x,y=CV2.y-CVI.y,z=CV2.z-CVI.z} -local DVu={x=DV.x/FollowDistance,y=DV.y,z=DV.z/FollowDistance} -local GDV={x=CVI.x,y=CVI.y,z=CVI.z} -local ADDx=FollowFormation.x*math.cos(alpha)-FollowFormation.z*math.sin(alpha) -local ADDz=FollowFormation.z*math.cos(alpha)+FollowFormation.x*math.sin(alpha) -local GDV_Formation={ -x=GDV.x-GVx, -y=GDV.y, -z=GDV.z-GVz -} -if self.SmokeDirectionVector==true then -trigger.action.smoke(GDV,trigger.smokeColor.Green) -trigger.action.smoke(GDV_Formation,trigger.smokeColor.White) -end -local Time=60 -local Speed=-(Distance+FollowFormation.x)/Time -local GS=Speed+CS -if Speed<0 then -Speed=0 -end -FollowGroup:RouteToVec3(GDV_Formation,GS) -end -end -end, -self,ClientUnit,CT1,CV1,CT2,CV2 -) -self:__Follow(-0.5) -end -end -do -ACT_ASSIGN={ -ClassName="ACT_ASSIGN", -} -function ACT_ASSIGN:New() -local self=BASE:Inherit(self,FSM_PROCESS:New("ACT_ASSIGN")) -self:AddTransition("UnAssigned","Start","Waiting") -self:AddTransition("Waiting","Assign","Assigned") -self:AddTransition("Waiting","Reject","Rejected") -self:AddTransition("*","Fail","Failed") -self:AddEndState("Assigned") -self:AddEndState("Rejected") -self:AddEndState("Failed") -self:SetStartState("UnAssigned") -return self -end -end -do -ACT_ASSIGN_ACCEPT={ -ClassName="ACT_ASSIGN_ACCEPT", -} -function ACT_ASSIGN_ACCEPT:New(TaskBriefing) -local self=BASE:Inherit(self,ACT_ASSIGN:New()) -self.TaskBriefing=TaskBriefing -return self -end -function ACT_ASSIGN_ACCEPT:Init(FsmAssign) -self.TaskBriefing=FsmAssign.TaskBriefing -end -function ACT_ASSIGN_ACCEPT:onafterStart(ProcessUnit,From,Event,To) -self:E({ProcessUnit,From,Event,To}) -self:__Assign(1) -end -function ACT_ASSIGN_ACCEPT:onenterAssigned(ProcessUnit,From,Event,To) -env.info("in here") -self:E({ProcessUnit,From,Event,To}) -local ProcessGroup=ProcessUnit:GetGroup() -self.Task:Assign(ProcessUnit,ProcessUnit:GetPlayerName()) -end -end -do -ACT_ASSIGN_MENU_ACCEPT={ -ClassName="ACT_ASSIGN_MENU_ACCEPT", -} -function ACT_ASSIGN_MENU_ACCEPT:New(TaskName,TaskBriefing) -local self=BASE:Inherit(self,ACT_ASSIGN:New()) -self.TaskName=TaskName -self.TaskBriefing=TaskBriefing -return self -end -function ACT_ASSIGN_MENU_ACCEPT:Init(FsmAssign) -self.TaskName=FsmAssign.TaskName -self.TaskBriefing=FsmAssign.TaskBriefing -end -function ACT_ASSIGN_MENU_ACCEPT:Init(TaskName,TaskBriefing) -self.TaskBriefing=TaskBriefing -self.TaskName=TaskName -return self -end -function ACT_ASSIGN_MENU_ACCEPT:onafterStart(ProcessUnit,From,Event,To) -self:E({ProcessUnit,From,Event,To}) -self:GetCommandCenter():MessageTypeToGroup("Access the radio menu to accept the task. You have 30 seconds or the assignment will be cancelled.",ProcessUnit:GetGroup(),MESSAGE.Type.Information) -local ProcessGroup=ProcessUnit:GetGroup() -self.Menu=MENU_GROUP:New(ProcessGroup,"Task "..self.TaskName.." acceptance") -self.MenuAcceptTask=MENU_GROUP_COMMAND:New(ProcessGroup,"Accept task "..self.TaskName,self.Menu,self.MenuAssign,self) -self.MenuRejectTask=MENU_GROUP_COMMAND:New(ProcessGroup,"Reject task "..self.TaskName,self.Menu,self.MenuReject,self) -end -function ACT_ASSIGN_MENU_ACCEPT:MenuAssign() -self:E() -self:__Assign(1) -end -function ACT_ASSIGN_MENU_ACCEPT:MenuReject() -self:E() -self:__Reject(1) -end -function ACT_ASSIGN_MENU_ACCEPT:onafterAssign(ProcessUnit,From,Event,To) -self:E({ProcessUnit.UnitNameFrom,Event,To}) -self.Menu:Remove() -end -function ACT_ASSIGN_MENU_ACCEPT:onafterReject(ProcessUnit,From,Event,To) -self:E({ProcessUnit.UnitName,From,Event,To}) -self.Menu:Remove() -ProcessUnit:Destroy() -end -end -do -ACT_ROUTE={ -ClassName="ACT_ROUTE", -} -function ACT_ROUTE:New() -local self=BASE:Inherit(self,FSM_PROCESS:New("ACT_ROUTE")) -self:AddTransition("*","Reset","None") -self:AddTransition("None","Start","Routing") -self:AddTransition("*","Report","*") -self:AddTransition("Routing","Route","Routing") -self:AddTransition("Routing","Pause","Pausing") -self:AddTransition("Routing","Arrive","Arrived") -self:AddTransition("*","Cancel","Cancelled") -self:AddTransition("Arrived","Success","Success") -self:AddTransition("*","Fail","Failed") -self:AddTransition("","","") -self:AddTransition("","","") -self:AddEndState("Arrived") -self:AddEndState("Failed") -self:AddEndState("Cancelled") -self:SetStartState("None") -self:SetRouteMode("C") -return self -end -function ACT_ROUTE:SetMenuCancel(MenuGroup,MenuText,ParentMenu,MenuTime) -MENU_GROUP_COMMAND:New( -MenuGroup, -MenuText, -ParentMenu, -self.MenuCancel, -self -):SetTime(MenuTime) -return self -end -function ACT_ROUTE:SetRouteMode(RouteMode) -self.RouteMode=RouteMode -return self -end -function ACT_ROUTE:GetRouteText(Controllable) -self:E() -local RouteText="" -local Coordinate=nil -if self.Coordinate then -Coordinate=self.Coordinate -end -if self.Zone then -Coordinate=self.Zone:GetPointVec3(self.Altitude) -Coordinate:SetHeading(self.Heading) -end -local Task=self:GetTask() -local CC=self:GetTask():GetMission():GetCommandCenter() -if CC then -if CC:IsModeWWII()then -local ShortestDistance=0 -local ShortestReferencePoint=nil -local ShortestReferenceName="" -self:E({CC.ReferencePoints}) -for ZoneName,Zone in pairs(CC.ReferencePoints)do -self:E({ZoneName=ZoneName}) -local Zone=Zone -local ZoneCoord=Zone:GetCoordinate() -local ZoneDistance=ZoneCoord:Get2DDistance(self.Coordinate) -self:E({ShortestDistance,ShortestReferenceName}) -if ShortestDistance==0 or ZoneDistance=self.DisplayInterval then -self:T({HasArrived=HasArrived}) -if not HasArrived then -self:Report() -end -self.DisplayCount=1 -else -self.DisplayCount=self.DisplayCount+1 -end -self:T({DisplayCount=self.DisplayCount}) -if HasArrived then -self:__Arrive(1) -else -self:__Route(1) -end -return HasArrived -end -return false -end -end -do -ACT_ROUTE_POINT={ -ClassName="ACT_ROUTE_POINT", -} -function ACT_ROUTE_POINT:New(Coordinate,Range) -local self=BASE:Inherit(self,ACT_ROUTE:New()) -self.Coordinate=Coordinate -self.Range=Range or 0 -self.DisplayInterval=30 -self.DisplayCount=30 -self.DisplayMessage=true -self.DisplayTime=10 -return self -end -function ACT_ROUTE_POINT:Init(FsmRoute) -self.Coordinate=FsmRoute.Coordinate -self.Range=FsmRoute.Range or 0 -self.DisplayInterval=30 -self.DisplayCount=30 -self.DisplayMessage=true -self.DisplayTime=10 -self:SetStartState("None") -end -function ACT_ROUTE_POINT:SetCoordinate(Coordinate) -self:F2({Coordinate}) -self.Coordinate=Coordinate -end -function ACT_ROUTE_POINT:GetCoordinate() -self:F2({self.Coordinate}) -return self.Coordinate -end -function ACT_ROUTE_POINT:SetRange(Range) -self:F2({self.Range}) -self.Range=Range or 10000 -end -function ACT_ROUTE_POINT:GetRange() -return self.Range -end -function ACT_ROUTE_POINT:onfuncHasArrived(ProcessUnit) -if ProcessUnit:IsAlive()then -local Distance=self.Coordinate:Get2DDistance(ProcessUnit:GetCoordinate()) -if Distance<=self.Range then -local RouteText="You have arrived." -self:GetCommandCenter():MessageTypeToGroup(RouteText,ProcessUnit:GetGroup(),MESSAGE.Type.Information) -return true -end -end -return false -end -function ACT_ROUTE_POINT:onafterReport(ProcessUnit,From,Event,To) -local RouteText=self:GetRouteText(ProcessUnit) -self:GetCommandCenter():MessageTypeToGroup(RouteText,ProcessUnit:GetGroup(),MESSAGE.Type.Update) -end -end -do -ACT_ROUTE_ZONE={ -ClassName="ACT_ROUTE_ZONE", -} -function ACT_ROUTE_ZONE:New(Zone) -local self=BASE:Inherit(self,ACT_ROUTE:New()) -self.Zone=Zone -self.DisplayInterval=30 -self.DisplayCount=30 -self.DisplayMessage=true -self.DisplayTime=10 -return self -end -function ACT_ROUTE_ZONE:Init(FsmRoute) -self.Zone=FsmRoute.Zone -self.DisplayInterval=30 -self.DisplayCount=30 -self.DisplayMessage=true -self.DisplayTime=10 -end -function ACT_ROUTE_ZONE:SetZone(Zone,Altitude,Heading) -self.Zone=Zone -self.Altitude=Altitude -self.Heading=Heading -end -function ACT_ROUTE_ZONE:GetZone() -return self.Zone -end -function ACT_ROUTE_ZONE:onfuncHasArrived(ProcessUnit) -if ProcessUnit:IsInZone(self.Zone)then -local RouteText="You have arrived within the zone." -self:GetCommandCenter():MessageTypeToGroup(RouteText,ProcessUnit:GetGroup(),MESSAGE.Type.Information) -end -return ProcessUnit:IsInZone(self.Zone) -end -function ACT_ROUTE_ZONE:onafterReport(ProcessUnit,From,Event,To) -self:E({ProcessUnit=ProcessUnit}) -local RouteText=self:GetRouteText(ProcessUnit) -self:GetCommandCenter():MessageTypeToGroup(RouteText,ProcessUnit:GetGroup(),MESSAGE.Type.Update) -end -end -do -ACT_ACCOUNT={ -ClassName="ACT_ACCOUNT", -TargetSetUnit=nil, -} -function ACT_ACCOUNT:New() -local self=BASE:Inherit(self,FSM_PROCESS:New()) -self:AddTransition("Assigned","Start","Waiting") -self:AddTransition("*","Wait","Waiting") -self:AddTransition("*","Report","Report") -self:AddTransition("*","Event","Account") -self:AddTransition("Account","Player","AccountForPlayer") -self:AddTransition("Account","Other","AccountForOther") -self:AddTransition({"Account","AccountForPlayer","AccountForOther"},"More","Wait") -self:AddTransition({"Account","AccountForPlayer","AccountForOther"},"NoMore","Accounted") -self:AddTransition("*","Fail","Failed") -self:AddEndState("Failed") -self:SetStartState("Assigned") -return self -end -function ACT_ACCOUNT:onafterStart(ProcessUnit,From,Event,To) -self:HandleEvent(EVENTS.Dead,self.onfuncEventDead) -self:HandleEvent(EVENTS.Crash,self.onfuncEventCrash) -self:HandleEvent(EVENTS.Hit) -self:__Wait(1) -end -function ACT_ACCOUNT:onenterWaiting(ProcessUnit,From,Event,To) -if self.DisplayCount>=self.DisplayInterval then -self:Report() -self.DisplayCount=1 -else -self.DisplayCount=self.DisplayCount+1 -end -return true -end -function ACT_ACCOUNT:onafterEvent(ProcessUnit,From,Event,To,Event) -self:__NoMore(1) -end -end -do -ACT_ACCOUNT_DEADS={ -ClassName="ACT_ACCOUNT_DEADS", -} -function ACT_ACCOUNT_DEADS:New() -local self=BASE:Inherit(self,ACT_ACCOUNT:New()) -self.DisplayInterval=30 -self.DisplayCount=30 -self.DisplayMessage=true -self.DisplayTime=10 -self.DisplayCategory="HQ" -return self -end -function ACT_ACCOUNT_DEADS:Init(FsmAccount) -self.Task=self:GetTask() -self.TaskName=self.Task:GetName() -end -function ACT_ACCOUNT_DEADS:onenterReport(ProcessUnit,Task,From,Event,To) -self:E({ProcessUnit,From,Event,To}) -local MessageText="Your group with assigned "..self.TaskName.." task has "..Task.TargetSetUnit:GetUnitTypesText().." targets left to be destroyed." -self:GetCommandCenter():MessageTypeToGroup(MessageText,ProcessUnit:GetGroup(),MESSAGE.Type.Information) -end -function ACT_ACCOUNT_DEADS:onafterEvent(ProcessUnit,Task,From,Event,To,EventData) -self:T({ProcessUnit:GetName(),Task:GetName(),From,Event,To,EventData}) -if Task.TargetSetUnit:FindUnit(EventData.IniUnitName)then -local PlayerName=ProcessUnit:GetPlayerName() -local PlayerHit=self.PlayerHits and self.PlayerHits[EventData.IniUnitName] -if PlayerHit==PlayerName then -self:Player(EventData) -else -self:Other(EventData) -end -end -end -function ACT_ACCOUNT_DEADS:onenterAccountForPlayer(ProcessUnit,Task,From,Event,To,EventData) -self:T({ProcessUnit:GetName(),Task:GetName(),From,Event,To,EventData}) -local TaskGroup=ProcessUnit:GetGroup() -Task.TargetSetUnit:Remove(EventData.IniUnitName) -local MessageText="You have destroyed a target.\nYour group assigned with task "..self.TaskName.." has\n"..Task.TargetSetUnit:Count().." targets ( "..Task.TargetSetUnit:GetUnitTypesText().." ) left to be destroyed." -self:GetCommandCenter():MessageTypeToGroup(MessageText,ProcessUnit:GetGroup(),MESSAGE.Type.Information) -local PlayerName=ProcessUnit:GetPlayerName() -Task:AddProgress(PlayerName,"Destroyed "..EventData.IniTypeName,timer.getTime(),1) -if Task.TargetSetUnit:Count()>0 then -self:__More(1) -else -self:__NoMore(1) -end -end -function ACT_ACCOUNT_DEADS:onenterAccountForOther(ProcessUnit,Task,From,Event,To,EventData) -self:T({ProcessUnit:GetName(),Task:GetName(),From,Event,To,EventData}) -local TaskGroup=ProcessUnit:GetGroup() -Task.TargetSetUnit:Remove(EventData.IniUnitName) -local MessageText="One of the task targets has been destroyed.\nYour group assigned with task "..self.TaskName.." has\n"..Task.TargetSetUnit:Count().." targets ( "..Task.TargetSetUnit:GetUnitTypesText().." ) left to be destroyed." -self:GetCommandCenter():MessageTypeToGroup(MessageText,ProcessUnit:GetGroup(),MESSAGE.Type.Information) -if Task.TargetSetUnit:Count()>0 then -self:__More(1) -else -self:__NoMore(1) -end -end -function ACT_ACCOUNT_DEADS:OnEventHit(EventData) -self:T({"EventDead",EventData}) -if EventData.IniPlayerName and EventData.TgtDCSUnitName then -self.PlayerHits=self.PlayerHits or{} -self.PlayerHits[EventData.TgtDCSUnitName]=EventData.IniPlayerName -end -end -function ACT_ACCOUNT_DEADS:onfuncEventDead(EventData) -self:T({"EventDead",EventData}) -if EventData.IniDCSUnit then -self:Event(EventData) -end -end -function ACT_ACCOUNT_DEADS:onfuncEventCrash(EventData) -self:T({"EventDead",EventData}) -if EventData.IniDCSUnit then -self:Event(EventData) -end -end -end -do -ACT_ASSIST={ -ClassName="ACT_ASSIST", -} -function ACT_ASSIST:New() -local self=BASE:Inherit(self,FSM_PROCESS:New("ACT_ASSIST")) -self:AddTransition("None","Start","AwaitSmoke") -self:AddTransition("AwaitSmoke","Next","Smoking") -self:AddTransition("Smoking","Next","AwaitSmoke") -self:AddTransition("*","Stop","Success") -self:AddTransition("*","Fail","Failed") -self:AddEndState("Failed") -self:AddEndState("Success") -self:SetStartState("None") -return self -end -function ACT_ASSIST:onafterStart(ProcessUnit,From,Event,To) -local ProcessGroup=ProcessUnit:GetGroup() -local MissionMenu=self:GetMission():GetMenu(ProcessGroup) -local function MenuSmoke(MenuParam) -self:E(MenuParam) -local self=MenuParam.self -local SmokeColor=MenuParam.SmokeColor -self.SmokeColor=SmokeColor -self:__Next(1) -end -self.Menu=MENU_GROUP:New(ProcessGroup,"Target acquisition",MissionMenu) -self.MenuSmokeBlue=MENU_GROUP_COMMAND:New(ProcessGroup,"Drop blue smoke on targets",self.Menu,MenuSmoke,{self=self,SmokeColor=SMOKECOLOR.Blue}) -self.MenuSmokeGreen=MENU_GROUP_COMMAND:New(ProcessGroup,"Drop green smoke on targets",self.Menu,MenuSmoke,{self=self,SmokeColor=SMOKECOLOR.Green}) -self.MenuSmokeOrange=MENU_GROUP_COMMAND:New(ProcessGroup,"Drop Orange smoke on targets",self.Menu,MenuSmoke,{self=self,SmokeColor=SMOKECOLOR.Orange}) -self.MenuSmokeRed=MENU_GROUP_COMMAND:New(ProcessGroup,"Drop Red smoke on targets",self.Menu,MenuSmoke,{self=self,SmokeColor=SMOKECOLOR.Red}) -self.MenuSmokeWhite=MENU_GROUP_COMMAND:New(ProcessGroup,"Drop White smoke on targets",self.Menu,MenuSmoke,{self=self,SmokeColor=SMOKECOLOR.White}) -end -function ACT_ASSIST:onafterStop(ProcessUnit,From,Event,To) -self.Menu:Remove() -end -end -do -ACT_ASSIST_SMOKE_TARGETS_ZONE={ -ClassName="ACT_ASSIST_SMOKE_TARGETS_ZONE", -} -function ACT_ASSIST_SMOKE_TARGETS_ZONE:New(TargetSetUnit,TargetZone) -local self=BASE:Inherit(self,ACT_ASSIST:New()) -self.TargetSetUnit=TargetSetUnit -self.TargetZone=TargetZone -return self -end -function ACT_ASSIST_SMOKE_TARGETS_ZONE:Init(FsmSmoke) -self.TargetSetUnit=FsmSmoke.TargetSetUnit -self.TargetZone=FsmSmoke.TargetZone -end -function ACT_ASSIST_SMOKE_TARGETS_ZONE:Init(TargetSetUnit,TargetZone) -self.TargetSetUnit=TargetSetUnit -self.TargetZone=TargetZone -return self -end -function ACT_ASSIST_SMOKE_TARGETS_ZONE:onenterSmoking(ProcessUnit,From,Event,To) -self.TargetSetUnit:ForEachUnit( -function(SmokeUnit) -if math.random(1,(100*self.TargetSetUnit:Count())/4)<=100 then -SCHEDULER:New(self, -function() -if SmokeUnit:IsAlive()then -SmokeUnit:Smoke(self.SmokeColor,150) -end -end,{},math.random(10,60) -) -end -end -) -end -end -COMMANDCENTER={ -ClassName="COMMANDCENTER", -CommandCenterName="", -CommandCenterCoalition=nil, -CommandCenterPositionable=nil, -Name="", -ReferencePoints={}, -ReferenceNames={}, -CommunicationMode="80", -} -function COMMANDCENTER:New(CommandCenterPositionable,CommandCenterName) -local self=BASE:Inherit(self,BASE:New()) -self.CommandCenterPositionable=CommandCenterPositionable -self.CommandCenterName=CommandCenterName or CommandCenterPositionable:GetName() -self.CommandCenterCoalition=CommandCenterPositionable:GetCoalition() -self.Missions={} -self:HandleEvent(EVENTS.Birth, -function(self,EventData) -if EventData.IniObjectCategory==1 then -local EventGroup=GROUP:Find(EventData.IniDCSGroup) -if EventGroup and self:HasGroup(EventGroup)then -local MenuReporting=MENU_GROUP:New(EventGroup,"Missions Reports",self.CommandCenterMenu) -local MenuMissionsSummary=MENU_GROUP_COMMAND:New(EventGroup,"Missions Status Report",MenuReporting,self.ReportMissionsStatus,self,EventGroup) -local MenuMissionsDetails=MENU_GROUP_COMMAND:New(EventGroup,"Missions Players Report",MenuReporting,self.ReportMissionsPlayers,self,EventGroup) -self:ReportSummary(EventGroup) -local PlayerUnit=EventData.IniUnit -for MissionID,Mission in pairs(self:GetMissions())do -local Mission=Mission -local PlayerGroup=EventData.IniGroup -Mission:JoinUnit(PlayerUnit,PlayerGroup) -end -self:SetMenu() -_DATABASE:PlayerSettingsMenu(PlayerUnit) -end -end -end -) -self:HandleEvent(EVENTS.PlayerEnterUnit, -function(self,EventData) -local PlayerUnit=EventData.IniUnit -for MissionID,Mission in pairs(self:GetMissions())do -local Mission=Mission -local PlayerGroup=EventData.IniGroup -Mission:JoinUnit(PlayerUnit,PlayerGroup) -end -self:SetMenu() -end -) -self:HandleEvent(EVENTS.MissionEnd, -function(self,EventData) -local PlayerUnit=EventData.IniUnit -for MissionID,Mission in pairs(self:GetMissions())do -local Mission=Mission -Mission:Stop() -end -end -) -self:HandleEvent(EVENTS.PlayerLeaveUnit, -function(self,EventData) -local PlayerUnit=EventData.IniUnit -for MissionID,Mission in pairs(self:GetMissions())do -local Mission=Mission -if Mission:IsENGAGED()then -Mission:AbortUnit(PlayerUnit) -end -end -end -) -self:HandleEvent(EVENTS.Crash, -function(self,EventData) -local PlayerUnit=EventData.IniUnit -for MissionID,Mission in pairs(self:GetMissions())do -local Mission=Mission -if Mission:IsENGAGED()then -Mission:CrashUnit(PlayerUnit) -end -end -end -) -self:SetMenu() -_SETTINGS:SetSystemMenu(CommandCenterPositionable) -return self -end -function COMMANDCENTER:GetName() -return self.CommandCenterName -end -function COMMANDCENTER:GetPositionable() -return self.CommandCenterPositionable -end -function COMMANDCENTER:GetMissions() -return self.Missions -end -function COMMANDCENTER:AddMission(Mission) -self.Missions[Mission]=Mission -return Mission -end -function COMMANDCENTER:RemoveMission(Mission) -self.Missions[Mission]=nil -return Mission -end -function COMMANDCENTER:SetReferenceZones(ReferenceZonePrefix) -local MatchPattern="(.*)#(.*)" -self:F({MatchPattern=MatchPattern}) -for ReferenceZoneName in pairs(_DATABASE.ZONENAMES)do -local ZoneName,ReferenceName=string.match(ReferenceZoneName,MatchPattern) -self:F({ZoneName=ZoneName,ReferenceName=ReferenceName}) -if ZoneName and ReferenceName and ZoneName==ReferenceZonePrefix then -self.ReferencePoints[ReferenceZoneName]=ZONE:New(ReferenceZoneName) -self.ReferenceNames[ReferenceZoneName]=ReferenceName -end -end -return self -end -function COMMANDCENTER:SetModeWWII() -self.CommunicationMode="WWII" -return self -end -function COMMANDCENTER:IsModeWWII() -return self.CommunicationMode=="WWII" -end -function COMMANDCENTER:SetMenu() -self:F() -self.CommandCenterMenu=self.CommandCenterMenu or MENU_COALITION:New(self.CommandCenterCoalition,"Command Center ("..self:GetName()..")") -local MenuTime=timer.getTime() -for MissionID,Mission in pairs(self:GetMissions()or{})do -local Mission=Mission -Mission:SetMenu(MenuTime) -end -for MissionID,Mission in pairs(self:GetMissions()or{})do -local Mission=Mission -Mission:RemoveMenu(MenuTime) -end -end -function COMMANDCENTER:GetMenu() -return self.CommandCenterMenu -end -function COMMANDCENTER:HasGroup(MissionGroup) -local Has=false -for MissionID,Mission in pairs(self.Missions)do -local Mission=Mission -if Mission:HasGroup(MissionGroup)then -Has=true -break -end -end -return Has -end -function COMMANDCENTER:MessageToAll(Message) -self:GetPositionable():MessageToAll(Message,20,self:GetName()) -end -function COMMANDCENTER:MessageToGroup(Message,TaskGroup) -self:GetPositionable():MessageToGroup(Message,15,TaskGroup,self:GetName()) -end -function COMMANDCENTER:MessageTypeToGroup(Message,TaskGroup,MessageType) -self:GetPositionable():MessageTypeToGroup(Message,MessageType,TaskGroup,self:GetName()) -end -function COMMANDCENTER:MessageToCoalition(Message) -local CCCoalition=self:GetPositionable():GetCoalition() -self:GetPositionable():MessageToCoalition(Message,15,CCCoalition) -end -function COMMANDCENTER:MessageTypeToCoalition(Message,MessageType) -local CCCoalition=self:GetPositionable():GetCoalition() -self:GetPositionable():MessageTypeToCoalition(Message,MessageType,CCCoalition) -end -function COMMANDCENTER:ReportMissionsStatus(ReportGroup) -self:E(ReportGroup) -local Report=REPORT:New() -Report:Add("Status report of all missions.") -for MissionID,Mission in pairs(self.Missions)do -local Mission=Mission -Report:Add(" - "..Mission:ReportStatus()) -end -self:MessageToGroup(Report:Text(),ReportGroup) -end -function COMMANDCENTER:ReportMissionsPlayers(ReportGroup) -self:E(ReportGroup) -local Report=REPORT:New() -Report:Add("Players active in all missions.") -for MissionID,Mission in pairs(self.Missions)do -local Mission=Mission -Report:Add(" - "..Mission:ReportPlayers()) -end -self:MessageToGroup(Report:Text(),ReportGroup) -end -function COMMANDCENTER:ReportDetails(ReportGroup,Task) -self:E(ReportGroup) -local Report=REPORT:New() -for MissionID,Mission in pairs(self.Missions)do -local Mission=Mission -Report:Add(" - "..Mission:ReportDetails()) -end -self:MessageToGroup(Report:Text(),ReportGroup) -end -MISSION={ -ClassName="MISSION", -Name="", -MissionStatus="PENDING", -AssignedGroups={}, -} -function MISSION:New(CommandCenter,MissionName,MissionPriority,MissionBriefing,MissionCoalition) -local self=BASE:Inherit(self,FSM:New()) -self:T({MissionName,MissionPriority,MissionBriefing,MissionCoalition}) -self.CommandCenter=CommandCenter -CommandCenter:AddMission(self) -self.Name=MissionName -self.MissionPriority=MissionPriority -self.MissionBriefing=MissionBriefing -self.MissionCoalition=MissionCoalition -self.Tasks={} -self.PlayerNames={} -self:SetStartState("IDLE") -self:AddTransition("IDLE","Start","ENGAGED") -self:AddTransition("ENGAGED","Stop","IDLE") -self:AddTransition("ENGAGED","Complete","COMPLETED") -self:AddTransition("*","Fail","FAILED") -self:AddTransition("*","MissionGoals","*") -CommandCenter:SetMenu() -return self -end -function MISSION:onenterCOMPLETED(From,Event,To) -self:GetCommandCenter():MessageTypeToCoalition(self:GetName().." has been completed! Good job guys!",MESSAGE.Type.Information) -end -function MISSION:GetName() -return string.format('Mission "%s (%s)"',self.Name,self.MissionPriority) -end -function MISSION:JoinUnit(PlayerUnit,PlayerGroup) -self:F({PlayerUnit=PlayerUnit,PlayerGroup=PlayerGroup}) -local PlayerUnitAdded=false -for TaskID,Task in pairs(self:GetTasks())do -local Task=Task -if Task:JoinUnit(PlayerUnit,PlayerGroup)then -PlayerUnitAdded=true -end -end -return PlayerUnitAdded -end -function MISSION:AbortUnit(PlayerUnit) -self:F({PlayerUnit=PlayerUnit}) -for TaskID,Task in pairs(self:GetTasks())do -local Task=Task -local PlayerGroup=PlayerUnit:GetGroup() -Task:AbortGroup(PlayerGroup) -end -return self -end -function MISSION:CrashUnit(PlayerUnit) -self:F({PlayerUnit=PlayerUnit}) -for TaskID,Task in pairs(self:GetTasks())do -local Task=Task -local PlayerGroup=PlayerUnit:GetGroup() -Task:CrashGroup(PlayerGroup) -end -return self -end -function MISSION:AddScoring(Scoring) -self.Scoring=Scoring -return self -end -function MISSION:GetScoring() -return self.Scoring -end -function MISSION:GetGroups() -local SetGroup=SET_GROUP:New() -for TaskID,Task in pairs(self:GetTasks())do -local Task=Task -local GroupSet=Task:GetGroups() -GroupSet:ForEachGroup( -function(TaskGroup) -SetGroup:Add(TaskGroup,TaskGroup) -end -) -end -return SetGroup -end -function MISSION:SetMenu(MenuTime) -self:F({self:GetName(),MenuTime}) -for _,TaskData in pairs(self:GetTasks())do -local Task=TaskData -Task:SetMenu(MenuTime) -end -end -function MISSION:RemoveMenu(MenuTime) -self:F({self:GetName(),MenuTime}) -for _,Task in pairs(self:GetTasks())do -local Task=Task -Task:RemoveMenu(MenuTime) -end -end -do -function MISSION:IsGroupAssigned(MissionGroup) -local MissionGroupName=MissionGroup:GetName() -if self.AssignedGroups[MissionGroupName]==MissionGroup then -self:T({"Mission is assigned to:",MissionGroup:GetName()}) -return true -end -self:T({"Mission is not assigned to:",MissionGroup:GetName()}) -return false -end -function MISSION:SetGroupAssigned(MissionGroup) -local MissionName=self:GetName() -local MissionGroupName=MissionGroup:GetName() -self.AssignedGroups[MissionGroupName]=MissionGroup -self:E(string.format("Mission %s is assigned to %s",MissionName,MissionGroupName)) -return self -end -function MISSION:ClearGroupAssignment(MissionGroup) -local MissionName=self:GetName() -local MissionGroupName=MissionGroup:GetName() -self.AssignedGroups[MissionGroupName]=nil -return self -end -end -function MISSION:GetCommandCenter() -return self.CommandCenter -end -function MISSION:RemoveTaskMenu(Task) -Task:RemoveMenu() -end -function MISSION:GetRootMenu(TaskGroup) -local CommandCenter=self:GetCommandCenter() -local CommandCenterMenu=CommandCenter:GetMenu() -local MissionName=self:GetName() -self.MissionMenu=self.MissionMenu or MENU_COALITION:New(self.MissionCoalition,self:GetName(),CommandCenterMenu) -return self.MissionMenu -end -function MISSION:GetMenu(TaskGroup) -local CommandCenter=self:GetCommandCenter() -local CommandCenterMenu=CommandCenter:GetMenu() -local MissionName=self:GetName() -self.MissionGroupMenu=self.MissionGroupMenu or{} -self.MissionGroupMenu[TaskGroup]=self.MissionGroupMenu[TaskGroup]or{} -local GroupMenu=self.MissionGroupMenu[TaskGroup] -self.MissionMenu=self.MissionMenu or MENU_COALITION:New(self.MissionCoalition,self:GetName(),CommandCenterMenu) -GroupMenu.BriefingMenu=GroupMenu.BriefingMenu or MENU_GROUP_COMMAND:New(TaskGroup,"Mission Briefing",self.MissionMenu,self.MenuReportBriefing,self,TaskGroup) -GroupMenu.TaskReportsMenu=GroupMenu.TaskReportsMenu or MENU_GROUP:New(TaskGroup,"Task Reports",self.MissionMenu) -GroupMenu.ReportTasksMenu=GroupMenu.ReportTasksMenu or MENU_GROUP_COMMAND:New(TaskGroup,"Report Tasks",GroupMenu.TaskReportsMenu,self.MenuReportTasksSummary,self,TaskGroup) -GroupMenu.ReportPlannedTasksMenu=GroupMenu.ReportPlannedTasksMenu or MENU_GROUP_COMMAND:New(TaskGroup,"Report Planned Tasks",GroupMenu.TaskReportsMenu,self.MenuReportTasksPerStatus,self,TaskGroup,"Planned") -GroupMenu.ReportAssignedTasksMenu=GroupMenu.ReportAssignedTasksMenu or MENU_GROUP_COMMAND:New(TaskGroup,"Report Assigned Tasks",GroupMenu.TaskReportsMenu,self.MenuReportTasksPerStatus,self,TaskGroup,"Assigned") -GroupMenu.ReportSuccessTasksMenu=GroupMenu.ReportSuccessTasksMenu or MENU_GROUP_COMMAND:New(TaskGroup,"Report Successful Tasks",GroupMenu.TaskReportsMenu,self.MenuReportTasksPerStatus,self,TaskGroup,"Success") -GroupMenu.ReportFailedTasksMenu=GroupMenu.ReportFailedTasksMenu or MENU_GROUP_COMMAND:New(TaskGroup,"Report Failed Tasks",GroupMenu.TaskReportsMenu,self.MenuReportTasksPerStatus,self,TaskGroup,"Failed") -GroupMenu.ReportHeldTasksMenu=GroupMenu.ReportHeldTasksMenu or MENU_GROUP_COMMAND:New(TaskGroup,"Report Held Tasks",GroupMenu.TaskReportsMenu,self.MenuReportTasksPerStatus,self,TaskGroup,"Hold") -GroupMenu.PlayerReportsMenu=GroupMenu.PlayerReportsMenu or MENU_GROUP:New(TaskGroup,"Statistics Reports",self.MissionMenu) -GroupMenu.ReportMissionHistory=GroupMenu.ReportPlayersHistory or MENU_GROUP_COMMAND:New(TaskGroup,"Report Mission Progress",GroupMenu.PlayerReportsMenu,self.MenuReportPlayersProgress,self,TaskGroup) -GroupMenu.ReportPlayersPerTaskMenu=GroupMenu.ReportPlayersPerTaskMenu or MENU_GROUP_COMMAND:New(TaskGroup,"Report Players per Task",GroupMenu.PlayerReportsMenu,self.MenuReportPlayersPerTask,self,TaskGroup) -return self.MissionMenu -end -function MISSION:GetTask(TaskName) -self:F({TaskName}) -return self.Tasks[TaskName] -end -function MISSION:AddTask(Task) -local TaskName=Task:GetTaskName() -self:F(TaskName) -self.Tasks[TaskName]=self.Tasks[TaskName]or{n=0} -self.Tasks[TaskName]=Task -self:GetCommandCenter():SetMenu() -return Task -end -function MISSION:RemoveTask(Task) -local TaskName=Task:GetTaskName() -self:F(TaskName) -self.Tasks[TaskName]=self.Tasks[TaskName]or{n=0} -self.Tasks[TaskName]=nil -Task=nil -collectgarbage() -self:GetCommandCenter():SetMenu() -return nil -end -function MISSION:GetNextTaskID(Task) -local TaskName=Task:GetTaskName() -self:F(TaskName) -self.Tasks[TaskName]=self.Tasks[TaskName]or{n=0} -self.Tasks[TaskName].n=self.Tasks[TaskName].n+1 -return self.Tasks[TaskName].n -end -function MISSION:IsCOMPLETED() -return self:Is("COMPLETED") -end -function MISSION:IsIDLE() -return self:Is("IDLE") -end -function MISSION:IsENGAGED() -return self:Is("ENGAGED") -end -function MISSION:IsFAILED() -return self:Is("FAILED") -end -function MISSION:IsHOLD() -return self:Is("HOLD") -end -function MISSION:HasGroup(TaskGroup) -local Has=false -for TaskID,Task in pairs(self:GetTasks())do -local Task=Task -if Task:HasGroup(TaskGroup)then -Has=true -break -end -end -return Has -end -function MISSION:GetTasksRemaining() -local TasksRemaining=0 -for TaskID,Task in pairs(self:GetTasks())do -local Task=Task -if Task:IsStateSuccess()or Task:IsStateFailed()then -else -TasksRemaining=TasksRemaining+1 -end -end -return TasksRemaining -end -function MISSION:GetTaskTypes() -local TaskTypeList={} -local TasksRemaining=0 -for TaskID,Task in pairs(self:GetTasks())do -local Task=Task -local TaskType=Task:GetType() -TaskTypeList[TaskType]=TaskType -end -return TaskTypeList -end -function MISSION:AddPlayerName(PlayerName) -self.PlayerNames=self.PlayerNames or{} -self.PlayerNames[PlayerName]=PlayerName -return self -end -function MISSION:GetPlayerNames() -return self.PlayerNames -end -function MISSION:ReportBriefing() -local Report=REPORT:New() -local Name=self:GetName() -local Status="<"..self:GetState()..">" -Report:Add(string.format('%s - %s - Mission Briefing Report',Name,Status)) -Report:Add(self.MissionBriefing) -return Report:Text() -end -function MISSION:ReportStatus() -local Report=REPORT:New() -local Name=self:GetName() -local Status="<"..self:GetState()..">" -Report:Add(string.format('%s - Status "%s"',Name,Status)) -local TaskTypes=self:GetTaskTypes() -Report:Add(string.format(" - Task Types: %s",table.concat(TaskTypes,", "))) -local TaskStatusList={"Planned","Assigned","Success","Hold","Cancelled","Aborted","Failed"} -for TaskStatusID,TaskStatus in pairs(TaskStatusList)do -local TaskCount=0 -local TaskPlayerCount=0 -for TaskID,Task in pairs(self:GetTasks())do -local Task=Task -if Task:Is(TaskStatus)then -TaskCount=TaskCount+1 -TaskPlayerCount=TaskPlayerCount+Task:GetPlayerCount() -end -end -if TaskCount>0 then -Report:Add(string.format(" - %02d %s Tasks (%dp)",TaskCount,TaskStatus,TaskPlayerCount)) -end -end -return Report:Text() -end -function MISSION:ReportPlayersPerTask(ReportGroup) -local Report=REPORT:New() -local Name=self:GetName() -local Status="<"..self:GetState()..">" -Report:Add(string.format('%s - %s - Players per Task Report',Name,Status)) -local PlayerList={} -for TaskID,Task in pairs(self:GetTasks())do -local Task=Task -local PlayerNames=Task:GetPlayerNames() -for PlayerName,PlayerGroup in pairs(PlayerNames)do -PlayerList[PlayerName]=Task:GetName() -end -end -for PlayerName,TaskName in pairs(PlayerList)do -Report:Add(string.format(' - Player (%s): Task "%s"',PlayerName,TaskName)) -end -return Report:Text() -end -function MISSION:ReportPlayersProgress(ReportGroup) -local Report=REPORT:New() -local Name=self:GetName() -local Status="<"..self:GetState()..">" -Report:Add(string.format('%s - %s - Players per Task Progress Report',Name,Status)) -local PlayerList={} -for TaskID,Task in pairs(self:GetTasks())do -local Task=Task -local TaskGoalTotal=Task:GetGoalTotal()or 0 -local TaskName=Task:GetName() -PlayerList[TaskName]=PlayerList[TaskName]or{} -if TaskGoalTotal~=0 then -local PlayerNames=self:GetPlayerNames() -for PlayerName,PlayerData in pairs(PlayerNames)do -PlayerList[TaskName][PlayerName]=string.format('Player (%s): Task "%s": %d%%',PlayerName,TaskName,Task:GetPlayerProgress(PlayerName)*100/TaskGoalTotal) -end -else -PlayerList[TaskName]["_"]=string.format('Player (---): Task "%s": %d%%',TaskName,0) -end -end -for TaskName,TaskData in pairs(PlayerList)do -for PlayerName,TaskText in pairs(TaskData)do -Report:Add(string.format(' - %s',TaskText)) -end -end -return Report:Text() -end -function MISSION:ReportSummary(ReportGroup) -local Report=REPORT:New() -local Name=self:GetName() -local Status="<"..self:GetState()..">" -Report:Add(string.format('%s - %s - Task Overview Report',Name,Status)) -for TaskID,Task in UTILS.spairs(self:GetTasks(),function(t,a,b)return t[a]:ReportOrder(ReportGroup)" -Report:Add(string.format('%s - %s - %s Tasks Report',Name,Status,TaskStatus)) -local Tasks=0 -for TaskID,Task in UTILS.spairs(self:GetTasks(),function(t,a,b)return t[a]:ReportOrder(ReportGroup)=8 then -break -end -end -return Report:Text() -end -function MISSION:ReportDetails(ReportGroup) -local Report=REPORT:New() -local Name=self:GetName() -local Status="<"..self:GetState()..">" -Report:Add(string.format('%s - %s - Task Detailed Report',Name,Status)) -local TasksRemaining=0 -for TaskID,Task in pairs(self:GetTasks())do -local Task=Task -Report:Add(Task:ReportDetails(ReportGroup)) -end -return Report:Text() -end -function MISSION:GetTasks() -return self.Tasks -end -function MISSION:MenuReportBriefing(ReportGroup) -local Report=self:ReportBriefing() -self:GetCommandCenter():MessageTypeToGroup(Report,ReportGroup,MESSAGE.Type.Briefing) -end -function MISSION:MenuReportTasksSummary(ReportGroup) -local Report=self:ReportSummary(ReportGroup) -self:GetCommandCenter():MessageTypeToGroup(Report,ReportGroup,MESSAGE.Type.Overview) -end -function MISSION:MenuReportTasksPerStatus(ReportGroup,TaskStatus) -local Report=self:ReportOverview(ReportGroup,TaskStatus) -self:GetCommandCenter():MessageTypeToGroup(Report,ReportGroup,MESSAGE.Type.Overview) -end -function MISSION:MenuReportPlayersPerTask(ReportGroup) -local Report=self:ReportPlayersPerTask() -self:GetCommandCenter():MessageTypeToGroup(Report,ReportGroup,MESSAGE.Type.Overview) -end -function MISSION:MenuReportPlayersProgress(ReportGroup) -local Report=self:ReportPlayersProgress() -self:GetCommandCenter():MessageTypeToGroup(Report,ReportGroup,MESSAGE.Type.Overview) -end -TASK={ -ClassName="TASK", -TaskScheduler=nil, -ProcessClasses={}, -Processes={}, -Players=nil, -Scores={}, -Menu={}, -SetGroup=nil, -FsmTemplate=nil, -Mission=nil, -CommandCenter=nil, -TimeOut=0, -AssignedGroups={}, -} -function TASK:New(Mission,SetGroupAssign,TaskName,TaskType,TaskBriefing) -local self=BASE:Inherit(self,FSM_TASK:New()) -self:SetStartState("Planned") -self:AddTransition("Planned","Assign","Assigned") -self:AddTransition("Assigned","AssignUnit","Assigned") -self:AddTransition("Assigned","Success","Success") -self:AddTransition("Assigned","Hold","Hold") -self:AddTransition("Assigned","Fail","Failed") -self:AddTransition("Assigned","Abort","Aborted") -self:AddTransition("Assigned","Cancel","Cancelled") -self:AddTransition("Assigned","Goal","*") -self:AddTransition("*","PlayerCrashed","*") -self:AddTransition("*","PlayerAborted","*") -self:AddTransition("*","PlayerDead","*") -self:AddTransition({"Failed","Aborted","Cancelled"},"Replan","Planned") -self:AddTransition("*","TimeOut","Cancelled") -self:E("New TASK "..TaskName) -self.Processes={} -self.Fsm={} -self.Mission=Mission -self.CommandCenter=Mission:GetCommandCenter() -self.SetGroup=SetGroupAssign -self:SetType(TaskType) -self:SetName(TaskName) -self:SetID(Mission:GetNextTaskID(self)) -self:SetBriefing(TaskBriefing) -self.FsmTemplate=self.FsmTemplate or FSM_PROCESS:New() -self.TaskInfo={} -self.TaskProgress={} -return self -end -function TASK:GetUnitProcess(TaskUnit) -if TaskUnit then -return self:GetStateMachine(TaskUnit) -else -return self.FsmTemplate -end -end -function TASK:SetUnitProcess(FsmTemplate) -self.FsmTemplate=FsmTemplate -end -function TASK:JoinUnit(PlayerUnit,PlayerGroup) -self:F({PlayerUnit=PlayerUnit,PlayerGroup=PlayerGroup}) -local PlayerUnitAdded=false -local PlayerGroups=self:GetGroups() -if PlayerGroups:IsIncludeObject(PlayerGroup)then -if self:IsStatePlanned()or self:IsStateReplanned()then -end -if self:IsStateAssigned()then -local IsGroupAssigned=self:IsGroupAssigned(PlayerGroup) -self:E({IsGroupAssigned=IsGroupAssigned}) -if IsGroupAssigned then -self:AssignToUnit(PlayerUnit) -self:MessageToGroups(PlayerUnit:GetPlayerName().." joined Task "..self:GetName()) -end -end -end -return PlayerUnitAdded -end -function TASK:AbortGroup(PlayerGroup) -self:F({PlayerGroup=PlayerGroup}) -local PlayerGroups=self:GetGroups() -if PlayerGroups:IsIncludeObject(PlayerGroup)then -if self:IsStateAssigned()then -local IsGroupAssigned=self:IsGroupAssigned(PlayerGroup) -self:E({IsGroupAssigned=IsGroupAssigned}) -if IsGroupAssigned then -local PlayerName=PlayerGroup:GetUnit(1):GetPlayerName() -self:UnAssignFromGroup(PlayerGroup) -PlayerGroups:Flush() -local IsRemaining=false -for GroupName,AssignedGroup in pairs(PlayerGroups:GetSet()or{})do -if self:IsGroupAssigned(AssignedGroup)==true then -IsRemaining=true -self:F({Task=self:GetName(),IsRemaining=IsRemaining}) -break -end -end -self:F({Task=self:GetName(),IsRemaining=IsRemaining}) -if IsRemaining==false then -self:Abort() -end -self:PlayerAborted(PlayerGroup:GetUnit(1)) -end -end -end -return self -end -function TASK:CrashGroup(PlayerGroup) -self:F({PlayerGroup=PlayerGroup}) -local PlayerGroups=self:GetGroups() -if PlayerGroups:IsIncludeObject(PlayerGroup)then -if self:IsStateAssigned()then -local IsGroupAssigned=self:IsGroupAssigned(PlayerGroup) -self:E({IsGroupAssigned=IsGroupAssigned}) -if IsGroupAssigned then -local PlayerName=PlayerGroup:GetUnit(1):GetPlayerName() -self:MessageToGroups(PlayerName.." crashed! ") -self:UnAssignFromGroup(PlayerGroup) -PlayerGroups:Flush() -local IsRemaining=false -for GroupName,AssignedGroup in pairs(PlayerGroups:GetSet()or{})do -if self:IsGroupAssigned(AssignedGroup)==true then -IsRemaining=true -self:F({Task=self:GetName(),IsRemaining=IsRemaining}) -break -end -end -self:F({Task=self:GetName(),IsRemaining=IsRemaining}) -if IsRemaining==false then -self:Abort() -end -self:PlayerCrashed(PlayerGroup:GetUnit(1)) -end -end -end -return self -end -function TASK:GetMission() -return self.Mission -end -function TASK:GetGroups() -return self.SetGroup -end -do -function TASK:IsGroupAssigned(TaskGroup) -local TaskGroupName=TaskGroup:GetName() -if self.AssignedGroups[TaskGroupName]then -self:T({"Task is assigned to:",TaskGroup:GetName()}) -return true -end -self:T({"Task is not assigned to:",TaskGroup:GetName()}) -return false -end -function TASK:SetGroupAssigned(TaskGroup) -local TaskName=self:GetName() -local TaskGroupName=TaskGroup:GetName() -self.AssignedGroups[TaskGroupName]=TaskGroup -self:E(string.format("Task %s is assigned to %s",TaskName,TaskGroupName)) -self:GetMission():SetGroupAssigned(TaskGroup) -local SetAssignedGroups=self:GetGroups() -return self -end -function TASK:ClearGroupAssignment(TaskGroup) -local TaskName=self:GetName() -local TaskGroupName=TaskGroup:GetName() -self.AssignedGroups[TaskGroupName]=nil -self:GetMission():ClearGroupAssignment(TaskGroup) -local SetAssignedGroups=self:GetGroups() -SetAssignedGroups:ForEachGroup( -function(AssignedGroup) -if self:IsGroupAssigned(AssignedGroup)then -else -end -end -) -return self -end -end -do -function TASK:AssignToGroup(TaskGroup) -self:F(TaskGroup:GetName()) -local TaskGroupName=TaskGroup:GetName() -local Mission=self:GetMission() -local CommandCenter=Mission:GetCommandCenter() -self:SetGroupAssigned(TaskGroup) -local TaskUnits=TaskGroup:GetUnits() -for UnitID,UnitData in pairs(TaskUnits)do -local TaskUnit=UnitData -local PlayerName=TaskUnit:GetPlayerName() -self:E(PlayerName) -if PlayerName~=nil and PlayerName~=""then -self:AssignToUnit(TaskUnit) -CommandCenter:MessageToGroup( -string.format('Task "%s": Briefing for player (%s):\n%s', -self:GetName(), -PlayerName, -self:GetBriefing() -),TaskGroup -) -end -end -CommandCenter:SetMenu() -return self -end -function TASK:UnAssignFromGroup(TaskGroup) -self:F2({TaskGroup=TaskGroup:GetName()}) -self:ClearGroupAssignment(TaskGroup) -local TaskUnits=TaskGroup:GetUnits() -for UnitID,UnitData in pairs(TaskUnits)do -local TaskUnit=UnitData -local PlayerName=TaskUnit:GetPlayerName() -if PlayerName~=nil and PlayerName~=""then -self:UnAssignFromUnit(TaskUnit) -end -end -local Mission=self:GetMission() -local CommandCenter=Mission:GetCommandCenter() -CommandCenter:SetMenu() -end -end -function TASK:HasGroup(FindGroup) -local SetAttackGroup=self:GetGroups() -return SetAttackGroup:FindGroup(FindGroup) -end -function TASK:AssignToUnit(TaskUnit) -self:F(TaskUnit:GetName()) -local FsmTemplate=self:GetUnitProcess() -local FsmUnit=self:SetStateMachine(TaskUnit,FsmTemplate:Copy(TaskUnit,self)) -FsmUnit:SetStartState("Planned") -FsmUnit:Accept() -return self -end -function TASK:UnAssignFromUnit(TaskUnit) -self:F(TaskUnit:GetName()) -self:RemoveStateMachine(TaskUnit) -return self -end -function TASK:SetTimeOut(Timer) -self:F(Timer) -self.TimeOut=Timer -self:__TimeOut(self.TimeOut) -return self -end -function TASK:MessageToGroups(Message) -self:F({Message=Message}) -local Mission=self:GetMission() -local CC=Mission:GetCommandCenter() -for TaskGroupName,TaskGroup in pairs(self.SetGroup:GetSet())do -local TaskGroup=TaskGroup -CC:MessageToGroup(Message,TaskGroup,TaskGroup:GetName()) -end -end -function TASK:SendBriefingToAssignedGroups() -self:F2() -for TaskGroupName,TaskGroup in pairs(self.SetGroup:GetSet())do -if self:IsGroupAssigned(TaskGroup)then -TaskGroup:Message(self.TaskBriefing,60) -end -end -end -function TASK:UnAssignFromGroups() -self:F2() -for TaskGroupName,TaskGroup in pairs(self.SetGroup:GetSet())do -if self:IsGroupAssigned(TaskGroup)then -self:UnAssignFromGroup(TaskGroup) -end -end -end -function TASK:HasAliveUnits() -self:F() -for TaskGroupID,TaskGroup in pairs(self.SetGroup:GetSet())do -if self:IsStateAssigned()then -if self:IsGroupAssigned(TaskGroup)then -for TaskUnitID,TaskUnit in pairs(TaskGroup:GetUnits())do -if TaskUnit:IsAlive()then -self:T({HasAliveUnits=true}) -return true -end -end -end -end -end -self:T({HasAliveUnits=false}) -return false -end -function TASK:SetMenu(MenuTime) -self:F({self:GetName(),MenuTime}) -for TaskGroupID,TaskGroupData in pairs(self.SetGroup:GetSet())do -local TaskGroup=TaskGroupData -if TaskGroup:IsAlive()and TaskGroup:GetPlayerNames()then -local Mission=self:GetMission() -local MissionMenu=Mission:GetMenu(TaskGroup) -if MissionMenu then -self:SetMenuForGroup(TaskGroup,MenuTime) -end -end -end -end -function TASK:SetMenuForGroup(TaskGroup,MenuTime) -if self:IsStatePlanned()or self:IsStateAssigned()then -self:SetPlannedMenuForGroup(TaskGroup,MenuTime) -if self:IsGroupAssigned(TaskGroup)then -self:SetAssignedMenuForGroup(TaskGroup,MenuTime) -end -end -end -function TASK:SetPlannedMenuForGroup(TaskGroup,MenuTime) -self:F(TaskGroup:GetName()) -local Mission=self:GetMission() -local MissionName=Mission:GetName() -local CommandCenter=Mission:GetCommandCenter() -local CommandCenterMenu=CommandCenter:GetMenu() -local TaskType=self:GetType() -local TaskPlayerCount=self:GetPlayerCount() -local TaskPlayerString=string.format(" (%dp)",TaskPlayerCount) -local TaskText=string.format("%s%s",self:GetName(),TaskPlayerString) -local TaskName=string.format("%s",self:GetName()) -local MissionMenu=Mission:GetMenu(TaskGroup) -self.MenuPlanned=self.MenuPlanned or{} -self.MenuPlanned[TaskGroup]=MENU_GROUP:New(TaskGroup,"Join Planned Task",MissionMenu,Mission.MenuReportTasksPerStatus,Mission,TaskGroup,"Planned"):SetTime(MenuTime):SetTag("Tasking") -local TaskTypeMenu=MENU_GROUP:New(TaskGroup,TaskType,self.MenuPlanned[TaskGroup]):SetTime(MenuTime):SetTag("Tasking"):SetRemoveParent(true) -local TaskTypeMenu=MENU_GROUP:New(TaskGroup,TaskText,TaskTypeMenu):SetTime(MenuTime):SetTag("Tasking"):SetRemoveParent(true) -local ReportTaskMenu=MENU_GROUP_COMMAND:New(TaskGroup,string.format("Report Task Status"),TaskTypeMenu,self.MenuTaskStatus,self,TaskGroup):SetTime(MenuTime):SetTag("Tasking"):SetRemoveParent(true) -if not Mission:IsGroupAssigned(TaskGroup)then -self:F({"Replacing Join Task menu"}) -local JoinTaskMenu=MENU_GROUP_COMMAND:New(TaskGroup,string.format("Join Task"),TaskTypeMenu,self.MenuAssignToGroup,self,TaskGroup):SetTime(MenuTime):SetTag("Tasking"):SetRemoveParent(true) -local MarkTaskMenu=MENU_GROUP_COMMAND:New(TaskGroup,string.format("Mark Task on Map"),TaskTypeMenu,self.MenuMarkToGroup,self,TaskGroup):SetTime(MenuTime):SetTag("Tasking"):SetRemoveParent(true) -end -return self -end -function TASK:SetAssignedMenuForGroup(TaskGroup,MenuTime) -self:F({TaskGroup:GetName(),MenuTime}) -local Mission=self:GetMission() -local MissionName=Mission:GetName() -local CommandCenter=Mission:GetCommandCenter() -local CommandCenterMenu=CommandCenter:GetMenu() -local TaskType=self:GetType() -local TaskPlayerCount=self:GetPlayerCount() -local TaskPlayerString=string.format(" (%dp)",TaskPlayerCount) -local TaskText=string.format("%s%s",self:GetName(),TaskPlayerString) -local TaskName=string.format("%s",self:GetName()) -local MissionMenu=Mission:GetMenu(TaskGroup) -self.MenuAssigned=self.MenuAssigned or{} -self.MenuAssigned[TaskGroup]=MENU_GROUP:New(TaskGroup,string.format("Assigned Task %s",TaskName),MissionMenu):SetTime(MenuTime):SetTag("Tasking") -local TaskTypeMenu=MENU_GROUP_COMMAND:New(TaskGroup,string.format("Report Task Status"),self.MenuAssigned[TaskGroup],self.MenuTaskStatus,self,TaskGroup):SetTime(MenuTime):SetTag("Tasking"):SetRemoveParent(true) -local TaskMenu=MENU_GROUP_COMMAND:New(TaskGroup,string.format("Abort Group from Task"),self.MenuAssigned[TaskGroup],self.MenuTaskAbort,self,TaskGroup):SetTime(MenuTime):SetTag("Tasking"):SetRemoveParent(true) -return self -end -function TASK:RemoveMenu(MenuTime) -self:F({self:GetName(),MenuTime}) -for TaskGroupID,TaskGroup in pairs(self.SetGroup:GetSet())do -local TaskGroup=TaskGroup -self:RefreshMenus(TaskGroup,MenuTime) -end -end -function TASK:RefreshMenus(TaskGroup,MenuTime) -self:F({TaskGroup:GetName(),MenuTime}) -local Mission=self:GetMission() -local MissionName=Mission:GetName() -local CommandCenter=Mission:GetCommandCenter() -local CommandCenterMenu=CommandCenter:GetMenu() -local MissionMenu=Mission:GetMenu(TaskGroup) -local TaskName=self:GetName() -self.MenuPlanned=self.MenuPlanned or{} -local PlannedMenu=self.MenuPlanned[TaskGroup] -self.MenuAssigned=self.MenuAssigned or{} -local AssignedMenu=self.MenuAssigned[TaskGroup] -if PlannedMenu then -PlannedMenu:Remove(MenuTime,"Tasking") -end -if AssignedMenu then -AssignedMenu:Remove(MenuTime,"Tasking") -end -end -function TASK:RemoveAssignedMenuForGroup(TaskGroup) -self:F() -local Mission=self:GetMission() -local MissionName=Mission:GetName() -local MissionMenu=Mission:GetMenu(TaskGroup) -if MissionMenu then -MissionMenu:RemoveSubMenus() -end -end -function TASK:MenuAssignToGroup(TaskGroup) -self:E("Join Task menu selected") -self:AssignToGroup(TaskGroup) -end -function TASK:MenuMarkToGroup(TaskGroup) -self:E("Mark Task menu selected") -self:UpdateTaskInfo() -local Report=REPORT:New():SetIndent(0) -local Name=self:GetName() -Report:Add(Name..": "..self:GetTaskBriefing()) -for TaskInfoID,TaskInfo in pairs(self.TaskInfo,function(t,a,b)return t[a].TaskInfoOrder") -if self.TaskInfo["Coordinates"]then -local TaskInfoIDText=string.format("%s: ","Coordinate") -local TaskCoord=self.TaskInfo["Coordinates"].TaskInfoText -Report:Add(TaskInfoIDText..TaskCoord:ToString(ReportGroup,nil,self)) -end -return Report:Text(', ') -end -function TASK:ReportOverview(ReportGroup) -self:UpdateTaskInfo() -local TaskName=self:GetName() -local Report=REPORT:New() -local Line=0 -local LineReport=REPORT:New() -for TaskInfoID,TaskInfo in UTILS.spairs(self.TaskInfo,function(t,a,b)return t[a].TaskInfoOrder" -Report:Add("Task: "..Name.." - "..Status.." - Detailed Report") -local PlayerNames=self:GetPlayerNames() -local PlayerReport=REPORT:New() -for PlayerName,PlayerGroup in pairs(PlayerNames)do -PlayerReport:Add("Group "..PlayerGroup:GetCallsign()..": "..PlayerName) -end -local Players=PlayerReport:Text() -if Players~=""then -Report:Add(" - Players assigned:") -Report:AddIndent(Players) -end -for TaskInfoID,TaskInfo in pairs(self.TaskInfo,function(t,a,b)return t[a].TaskInfoOrder0 then -local TargetSetUnit=SET_UNIT:New() -TargetSetUnit:SetDatabase(DetectedSet) -TargetSetUnit:FilterHasSEAD() -TargetSetUnit:FilterOnce() -return TargetSetUnit -end -return nil -end -function TASK_A2G_DISPATCHER:EvaluateCAS(DetectedItem) -self:F({DetectedItem.ItemID}) -local DetectedSet=DetectedItem.Set -local DetectedZone=DetectedItem.Zone -local GroundUnitCount=DetectedSet:HasGroundUnits() -local FriendliesNearBy=self.Detection:IsFriendliesNearBy(DetectedItem) -local RadarCount=DetectedSet:HasSEAD() -if RadarCount==0 and GroundUnitCount>0 and FriendliesNearBy==true then -local TargetSetUnit=SET_UNIT:New() -TargetSetUnit:SetDatabase(DetectedSet) -TargetSetUnit:FilterOnce() -return TargetSetUnit -end -return nil -end -function TASK_A2G_DISPATCHER:EvaluateBAI(DetectedItem,FriendlyCoalition) -self:F({DetectedItem.ItemID}) -local DetectedSet=DetectedItem.Set -local DetectedZone=DetectedItem.Zone -local GroundUnitCount=DetectedSet:HasGroundUnits() -local FriendliesNearBy=self.Detection:IsFriendliesNearBy(DetectedItem) -local RadarCount=DetectedSet:HasSEAD() -if RadarCount==0 and GroundUnitCount>0 and FriendliesNearBy==false then -local TargetSetUnit=SET_UNIT:New() -TargetSetUnit:SetDatabase(DetectedSet) -TargetSetUnit:FilterOnce() -return TargetSetUnit -end -return nil -end -function TASK_A2G_DISPATCHER:RemoveTask(TaskIndex) -self.Mission:RemoveTask(self.Tasks[TaskIndex]) -self.Tasks[TaskIndex]=nil -end -function TASK_A2G_DISPATCHER:EvaluateRemoveTask(Mission,Task,TaskIndex,DetectedItemChanged) -if Task then -if(Task:IsStatePlanned()and DetectedItemChanged==true)or Task:IsStateCancelled()then -self:RemoveTask(TaskIndex) -end -end -return Task -end -function TASK_A2G_DISPATCHER:ProcessDetected(Detection) -self:E() -local AreaMsg={} -local TaskMsg={} -local ChangeMsg={} -local Mission=self.Mission -if Mission:IsIDLE()or Mission:IsENGAGED()then -local TaskReport=REPORT:New() -for TaskIndex,TaskData in pairs(self.Tasks)do -local Task=TaskData -if Task:IsStatePlanned()then -local DetectedItem=Detection:GetDetectedItem(TaskIndex) -if not DetectedItem then -local TaskText=Task:GetName() -for TaskGroupID,TaskGroup in pairs(self.SetGroup:GetSet())do -Mission:GetCommandCenter():MessageToGroup(string.format("Obsolete A2G task %s for %s removed.",TaskText,Mission:GetName()),TaskGroup) -end -Task=self:RemoveTask(TaskIndex) -Mission:RemoveTask(Task) -self.Tasks[TaskIndex]=nil -end -end -end -for DetectedItemID,DetectedItem in pairs(Detection:GetDetectedItems())do -local DetectedItem=DetectedItem -local DetectedSet=DetectedItem.Set -local DetectedZone=DetectedItem.Zone -local DetectedItemID=DetectedItem.ID -local TaskIndex=DetectedItem.Index -local DetectedItemChanged=DetectedItem.Changed -self:E({DetectedItemChanged=DetectedItemChanged,DetectedItemID=DetectedItemID,TaskIndex=TaskIndex}) -local Task=self.Tasks[TaskIndex] -if Task then -if Task:IsStateAssigned()then -if DetectedItemChanged==true then -local TargetsReport=REPORT:New() -local TargetSetUnit=self:EvaluateSEAD(DetectedItem) -if TargetSetUnit then -if Task:IsInstanceOf(TASK_A2G_SEAD)then -Task:SetTargetSetUnit(TargetSetUnit) -Task:UpdateTaskInfo() -TargetsReport:Add(Detection:GetChangeText(DetectedItem)) -else -Task:Cancel() -end -else -local TargetSetUnit=self:EvaluateCAS(DetectedItem) -if TargetSetUnit then -if Task:IsInstanceOf(TASK_A2G_CAS)then -Task:SetTargetSetUnit(TargetSetUnit) -Task:SetDetection(Detection,TaskIndex) -Task:UpdateTaskInfo() -TargetsReport:Add(Detection:GetChangeText(DetectedItem)) -else -Task:Cancel() -Task=self:RemoveTask(TaskIndex) -end -else -local TargetSetUnit=self:EvaluateBAI(DetectedItem) -if TargetSetUnit then -if Task:IsInstanceOf(TASK_A2G_BAI)then -Task:SetTargetSetUnit(TargetSetUnit) -Task:SetDetection(Detection,TaskIndex) -Task:UpdateTaskInfo() -TargetsReport:Add(Detection:GetChangeText(DetectedItem)) -else -Task:Cancel() -Task=self:RemoveTask(TaskIndex) -end -end -end -end -for TaskGroupID,TaskGroup in pairs(self.SetGroup:GetSet())do -local TargetsText=TargetsReport:Text(", ") -if(Mission:IsGroupAssigned(TaskGroup))and TargetsText~=""then -Mission:GetCommandCenter():MessageToGroup(string.format("Task %s has change of targets:\n %s",Task:GetName(),TargetsText),TaskGroup) -end -end -end -end -end -if Task then -if Task:IsStatePlanned()then -if DetectedItemChanged==true then -if Task:IsInstanceOf(TASK_A2G_SEAD)then -local TargetSetUnit=self:EvaluateSEAD(DetectedItem) -if TargetSetUnit then -Task:SetTargetSetUnit(TargetSetUnit) -Task:UpdateTaskInfo() -else -Task:Cancel() -Task=self:RemoveTask(TaskIndex) -end -else -if Task:IsInstanceOf(TASK_A2G_CAS)then -local TargetSetUnit=self:EvaluateCAS(DetectedItem) -if TargetSetUnit then -Task:SetTargetSetUnit(TargetSetUnit) -Task:SetDetection(Detection,TaskIndex) -Task:UpdateTaskInfo() -else -Task:Cancel() -Task=self:RemoveTask(TaskIndex) -end -else -if Task:IsInstanceOf(TASK_A2G_BAI)then -local TargetSetUnit=self:EvaluateBAI(DetectedItem) -if TargetSetUnit then -Task:SetTargetSetUnit(TargetSetUnit) -Task:SetDetection(Detection,TaskIndex) -Task:UpdateTaskInfo() -else -Task:Cancel() -Task=self:RemoveTask(TaskIndex) -end -else -Task:Cancel() -Task=self:RemoveTask(TaskIndex) -end -end -end -end -end -end -if not Task then -local TargetSetUnit=self:EvaluateSEAD(DetectedItem) -if TargetSetUnit then -Task=TASK_A2G_SEAD:New(Mission,self.SetGroup,string.format("SEAD.%03d",DetectedItemID),TargetSetUnit) -Task:SetDetection(Detection,TaskIndex) -end -if not Task then -local TargetSetUnit=self:EvaluateCAS(DetectedItem) -if TargetSetUnit then -Task=TASK_A2G_CAS:New(Mission,self.SetGroup,string.format("CAS.%03d",DetectedItemID),TargetSetUnit) -Task:SetDetection(Detection,TaskIndex) -end -if not Task then -local TargetSetUnit=self:EvaluateBAI(DetectedItem,self.Mission:GetCommandCenter():GetPositionable():GetCoalition()) -if TargetSetUnit then -Task=TASK_A2G_BAI:New(Mission,self.SetGroup,string.format("BAI.%03d",DetectedItemID),TargetSetUnit) -Task:SetDetection(Detection,TaskIndex) -end -end -end -if Task then -self.Tasks[TaskIndex]=Task -Task:SetTargetZone(DetectedZone) -Task:SetDispatcher(self) -Task:UpdateTaskInfo() -Mission:AddTask(Task) -TaskReport:Add(Task:GetName()) -else -self:E("This should not happen") -end -end -Detection:AcceptChanges(DetectedItem) -end -Mission:GetCommandCenter():SetMenu() -local TaskText=TaskReport:Text(", ") -for TaskGroupID,TaskGroup in pairs(self.SetGroup:GetSet())do -if(not Mission:IsGroupAssigned(TaskGroup))and TaskText~=""then -Mission:GetCommandCenter():MessageToGroup(string.format("%s has tasks %s. Subscribe to a task using the radio menu.",Mission:GetName(),TaskText),TaskGroup) -end -end -end -return true -end -end -do -TASK_A2G={ -ClassName="TASK_A2G", -} -function TASK_A2G:New(Mission,SetGroup,TaskName,TargetSetUnit,TaskType,TaskBriefing) -local self=BASE:Inherit(self,TASK:New(Mission,SetGroup,TaskName,TaskType,TaskBriefing)) -self:F() -self.TargetSetUnit=TargetSetUnit -self.TaskType=TaskType -local Fsm=self:GetUnitProcess() -Fsm:AddProcess("Planned","Accept",ACT_ASSIGN_ACCEPT:New(self.TaskBriefing),{Assigned="RouteToRendezVous",Rejected="Reject"}) -Fsm:AddTransition("Assigned","RouteToRendezVous","RoutingToRendezVous") -Fsm:AddProcess("RoutingToRendezVous","RouteToRendezVousPoint",ACT_ROUTE_POINT:New(),{Arrived="ArriveAtRendezVous"}) -Fsm:AddProcess("RoutingToRendezVous","RouteToRendezVousZone",ACT_ROUTE_ZONE:New(),{Arrived="ArriveAtRendezVous"}) -Fsm:AddTransition({"Arrived","RoutingToRendezVous"},"ArriveAtRendezVous","ArrivedAtRendezVous") -Fsm:AddTransition({"ArrivedAtRendezVous","HoldingAtRendezVous"},"Engage","Engaging") -Fsm:AddTransition({"ArrivedAtRendezVous","HoldingAtRendezVous"},"HoldAtRendezVous","HoldingAtRendezVous") -Fsm:AddProcess("Engaging","Account",ACT_ACCOUNT_DEADS:New(),{}) -Fsm:AddTransition("Engaging","RouteToTarget","Engaging") -Fsm:AddProcess("Engaging","RouteToTargetZone",ACT_ROUTE_ZONE:New(),{}) -Fsm:AddProcess("Engaging","RouteToTargetPoint",ACT_ROUTE_POINT:New(),{}) -Fsm:AddTransition("Engaging","RouteToTargets","Engaging") -Fsm:AddTransition("Rejected","Reject","Aborted") -Fsm:AddTransition("Failed","Fail","Failed") -function Fsm:onafterRouteToRendezVous(TaskUnit,Task) -self:E({TaskUnit=TaskUnit,Task=Task and Task:GetClassNameAndID()}) -if Task:GetRendezVousZone(TaskUnit)then -self:__RouteToRendezVousZone(0.1) -else -if Task:GetRendezVousCoordinate(TaskUnit)then -self:__RouteToRendezVousPoint(0.1) -else -self:__ArriveAtRendezVous(0.1) -end -end -end -function Fsm:OnAfterArriveAtRendezVous(TaskUnit,Task) -self:E({TaskUnit=TaskUnit,Task=Task and Task:GetClassNameAndID()}) -self:__Engage(0.1) -end -function Fsm:onafterEngage(TaskUnit,Task) -self:E({self}) -self:__Account(0.1) -self:__RouteToTarget(0.1) -self:__RouteToTargets(-10) -end -function Fsm:onafterRouteToTarget(TaskUnit,Task) -self:E({TaskUnit=TaskUnit,Task=Task and Task:GetClassNameAndID()}) -if Task:GetTargetZone(TaskUnit)then -self:__RouteToTargetZone(0.1) -else -local TargetUnit=Task.TargetSetUnit:GetFirst() -if TargetUnit then -local Coordinate=TargetUnit:GetPointVec3() -self:T({TargetCoordinate=Coordinate,Coordinate:GetX(),Coordinate:GetY(),Coordinate:GetZ()}) -Task:SetTargetCoordinate(Coordinate,TaskUnit) -end -self:__RouteToTargetPoint(0.1) -end -end -function Fsm:onafterRouteToTargets(TaskUnit,Task) -self:E({TaskUnit=TaskUnit,Task=Task and Task:GetClassNameAndID()}) -local TargetUnit=Task.TargetSetUnit:GetFirst() -if TargetUnit then -Task:SetTargetCoordinate(TargetUnit:GetCoordinate(),TaskUnit) -end -self:__RouteToTargets(-10) -end -return self -end -function TASK_A2G:SetTargetSetUnit(TargetSetUnit) -self.TargetSetUnit=TargetSetUnit -end -function TASK_A2G:GetPlannedMenuText() -return self:GetStateString().." - "..self:GetTaskName().." ( "..self.TargetSetUnit:GetUnitTypesText().." )" -end -function TASK_A2G:SetRendezVousCoordinate(RendezVousCoordinate,RendezVousRange,TaskUnit) -local ProcessUnit=self:GetUnitProcess(TaskUnit) -local ActRouteRendezVous=ProcessUnit:GetProcess("RoutingToRendezVous","RouteToRendezVousPoint") -ActRouteRendezVous:SetCoordinate(RendezVousCoordinate) -ActRouteRendezVous:SetRange(RendezVousRange) -end -function TASK_A2G:GetRendezVousCoordinate(TaskUnit) -local ProcessUnit=self:GetUnitProcess(TaskUnit) -local ActRouteRendezVous=ProcessUnit:GetProcess("RoutingToRendezVous","RouteToRendezVousPoint") -return ActRouteRendezVous:GetCoordinate(),ActRouteRendezVous:GetRange() -end -function TASK_A2G:SetRendezVousZone(RendezVousZone,TaskUnit) -local ProcessUnit=self:GetUnitProcess(TaskUnit) -local ActRouteRendezVous=ProcessUnit:GetProcess("RoutingToRendezVous","RouteToRendezVousZone") -ActRouteRendezVous:SetZone(RendezVousZone) -end -function TASK_A2G:GetRendezVousZone(TaskUnit) -local ProcessUnit=self:GetUnitProcess(TaskUnit) -local ActRouteRendezVous=ProcessUnit:GetProcess("RoutingToRendezVous","RouteToRendezVousZone") -return ActRouteRendezVous:GetZone() -end -function TASK_A2G:SetTargetCoordinate(TargetCoordinate,TaskUnit) -local ProcessUnit=self:GetUnitProcess(TaskUnit) -local ActRouteTarget=ProcessUnit:GetProcess("Engaging","RouteToTargetPoint") -ActRouteTarget:SetCoordinate(TargetCoordinate) -end -function TASK_A2G:GetTargetCoordinate(TaskUnit) -local ProcessUnit=self:GetUnitProcess(TaskUnit) -local ActRouteTarget=ProcessUnit:GetProcess("Engaging","RouteToTargetPoint") -return ActRouteTarget:GetCoordinate() -end -function TASK_A2G:SetTargetZone(TargetZone,TaskUnit) -local ProcessUnit=self:GetUnitProcess(TaskUnit) -local ActRouteTarget=ProcessUnit:GetProcess("Engaging","RouteToTargetZone") -ActRouteTarget:SetZone(TargetZone) -end -function TASK_A2G:GetTargetZone(TaskUnit) -local ProcessUnit=self:GetUnitProcess(TaskUnit) -local ActRouteTarget=ProcessUnit:GetProcess("Engaging","RouteToTargetZone") -return ActRouteTarget:GetZone() -end -function TASK_A2G:SetGoalTotal() -self.GoalTotal=self.TargetSetUnit:Count() -end -function TASK_A2G:GetGoalTotal() -return self.GoalTotal -end -end -do -TASK_A2G_SEAD={ -ClassName="TASK_A2G_SEAD", -} -function TASK_A2G_SEAD:New(Mission,SetGroup,TaskName,TargetSetUnit,TaskBriefing) -local self=BASE:Inherit(self,TASK_A2G:New(Mission,SetGroup,TaskName,TargetSetUnit,"SEAD",TaskBriefing)) -self:F() -Mission:AddTask(self) -self:SetBriefing( -TaskBriefing or -"Execute a Suppression of Enemy Air Defenses." -) -return self -end -function TASK_A2G_SEAD:UpdateTaskInfo() -local TargetCoordinate=self.Detection and self.Detection:GetDetectedItemCoordinate(self.DetectedItemIndex)or self.TargetSetUnit:GetFirst():GetCoordinate() -self:SetInfo("Coordinates",TargetCoordinate,0) -local ThreatLevel,ThreatText -if self.Detection then -ThreatLevel,ThreatText=self.Detection:GetDetectedItemThreatLevel(self.DetectedItemIndex) -else -ThreatLevel,ThreatText=self.TargetSetUnit:CalculateThreatLevelA2G() -end -self:SetInfo("Threat",ThreatText.." ["..string.rep("■",ThreatLevel).."]",11) -if self.Detection then -local DetectedItemsCount=self.TargetSetUnit:Count() -local ReportTypes=REPORT:New() -local TargetTypes={} -for TargetUnitName,TargetUnit in pairs(self.TargetSetUnit:GetSet())do -local TargetType=self.Detection:GetDetectedUnitTypeName(TargetUnit) -if not TargetTypes[TargetType]then -TargetTypes[TargetType]=TargetType -ReportTypes:Add(TargetType) -end -end -self:SetInfo("Targets",string.format("%d of %s",DetectedItemsCount,ReportTypes:Text(", ")),10) -else -local DetectedItemsCount=self.TargetSetUnit:Count() -local DetectedItemsTypes=self.TargetSetUnit:GetTypeNames() -self:SetInfo("Targets",string.format("%d of %s",DetectedItemsCount,DetectedItemsTypes),10) -end -end -function TASK_A2G_SEAD:ReportOrder(ReportGroup) -local Coordinate=self:GetInfo("Coordinates") -local Distance=ReportGroup:GetCoordinate():Get2DDistance(Coordinate) -return Distance -end -function TASK_A2G_SEAD:onafterGoal(TaskUnit,From,Event,To) -local TargetSetUnit=self.TargetSetUnit -if TargetSetUnit:Count()==0 then -self:Success() -end -self:__Goal(-10) -end -function TASK_A2G_SEAD:SetScoreOnProgress(PlayerName,Score,TaskUnit) -self:F({PlayerName,Score,TaskUnit}) -local ProcessUnit=self:GetUnitProcess(TaskUnit) -ProcessUnit:AddScoreProcess("Engaging","Account","AccountForPlayer","Player "..PlayerName.." has SEADed a target.",Score) -return self -end -function TASK_A2G_SEAD:SetScoreOnSuccess(PlayerName,Score,TaskUnit) -self:F({PlayerName,Score,TaskUnit}) -local ProcessUnit=self:GetUnitProcess(TaskUnit) -ProcessUnit:AddScore("Success","All radar emitting targets have been successfully SEADed!",Score) -return self -end -function TASK_A2G_SEAD:SetScoreOnFail(PlayerName,Penalty,TaskUnit) -self:F({PlayerName,Penalty,TaskUnit}) -local ProcessUnit=self:GetUnitProcess(TaskUnit) -ProcessUnit:AddScore("Failed","The SEADing has failed!",Penalty) -return self -end -end -do -TASK_A2G_BAI={ -ClassName="TASK_A2G_BAI", -} -function TASK_A2G_BAI:New(Mission,SetGroup,TaskName,TargetSetUnit,TaskBriefing) -local self=BASE:Inherit(self,TASK_A2G:New(Mission,SetGroup,TaskName,TargetSetUnit,"BAI",TaskBriefing)) -self:F() -Mission:AddTask(self) -self:SetBriefing( -TaskBriefing or -"Execute a Battlefield Air Interdiction of a group of enemy targets." -) -return self -end -function TASK_A2G_BAI:UpdateTaskInfo() -self:E({self.Detection,self.DetectedItemIndex}) -local TargetCoordinate=self.Detection and self.Detection:GetDetectedItemCoordinate(self.DetectedItemIndex)or self.TargetSetUnit:GetFirst():GetCoordinate() -self:SetInfo("Coordinates",TargetCoordinate,0) -local ThreatLevel,ThreatText -if self.Detection then -ThreatLevel,ThreatText=self.Detection:GetDetectedItemThreatLevel(self.DetectedItemIndex) -else -ThreatLevel,ThreatText=self.TargetSetUnit:CalculateThreatLevelA2G() -end -self:SetInfo("Threat",ThreatText.." ["..string.rep("■",ThreatLevel).."]",11) -if self.Detection then -local DetectedItemsCount=self.TargetSetUnit:Count() -local ReportTypes=REPORT:New() -local TargetTypes={} -for TargetUnitName,TargetUnit in pairs(self.TargetSetUnit:GetSet())do -local TargetType=self.Detection:GetDetectedUnitTypeName(TargetUnit) -if not TargetTypes[TargetType]then -TargetTypes[TargetType]=TargetType -ReportTypes:Add(TargetType) -end -end -self:SetInfo("Targets",string.format("%d of %s",DetectedItemsCount,ReportTypes:Text(", ")),10) -else -local DetectedItemsCount=self.TargetSetUnit:Count() -local DetectedItemsTypes=self.TargetSetUnit:GetTypeNames() -self:SetInfo("Targets",string.format("%d of %s",DetectedItemsCount,DetectedItemsTypes),10) -end -end -function TASK_A2G_BAI:ReportOrder(ReportGroup) -local Coordinate=self:GetInfo("Coordinates") -local Distance=ReportGroup:GetCoordinate():Get2DDistance(Coordinate) -return Distance -end -function TASK_A2G_BAI:onafterGoal(TaskUnit,From,Event,To) -local TargetSetUnit=self.TargetSetUnit -if TargetSetUnit:Count()==0 then -self:Success() -end -self:__Goal(-10) -end -function TASK_A2G_BAI:SetScoreOnProgress(PlayerName,Score,TaskUnit) -self:F({PlayerName,Score,TaskUnit}) -local ProcessUnit=self:GetUnitProcess(TaskUnit) -ProcessUnit:AddScoreProcess("Engaging","Account","AccountForPlayer","Player "..PlayerName.." has destroyed a target in Battlefield Air Interdiction (BAI).",Score) -return self -end -function TASK_A2G_BAI:SetScoreOnSuccess(PlayerName,Score,TaskUnit) -self:F({PlayerName,Score,TaskUnit}) -local ProcessUnit=self:GetUnitProcess(TaskUnit) -ProcessUnit:AddScore("Success","All targets have been successfully destroyed! The Battlefield Air Interdiction (BAI) is a success!",Score) -return self -end -function TASK_A2G_BAI:SetScoreOnFail(PlayerName,Penalty,TaskUnit) -self:F({PlayerName,Penalty,TaskUnit}) -local ProcessUnit=self:GetUnitProcess(TaskUnit) -ProcessUnit:AddScore("Failed","The Battlefield Air Interdiction (BAI) has failed!",Penalty) -return self -end -end -do -TASK_A2G_CAS={ -ClassName="TASK_A2G_CAS", -} -function TASK_A2G_CAS:New(Mission,SetGroup,TaskName,TargetSetUnit,TaskBriefing) -local self=BASE:Inherit(self,TASK_A2G:New(Mission,SetGroup,TaskName,TargetSetUnit,"CAS",TaskBriefing)) -self:F() -Mission:AddTask(self) -self:SetBriefing( -TaskBriefing or -"Execute a Close Air Support for a group of enemy targets. ".. -"Beware of friendlies at the vicinity! " -) -return self -end -function TASK_A2G_CAS:UpdateTaskInfo() -local TargetCoordinate=(self.Detection and self.Detection:GetDetectedItemCoordinate(self.DetectedItemIndex))or self.TargetSetUnit:GetFirst():GetCoordinate() -self:SetInfo("Coordinates",TargetCoordinate,0) -local ThreatLevel,ThreatText -if self.Detection then -ThreatLevel,ThreatText=self.Detection:GetDetectedItemThreatLevel(self.DetectedItemIndex) -else -ThreatLevel,ThreatText=self.TargetSetUnit:CalculateThreatLevelA2G() -end -self:SetInfo("Threat",ThreatText.." ["..string.rep("■",ThreatLevel).."]",11) -if self.Detection then -local DetectedItemsCount=self.TargetSetUnit:Count() -local ReportTypes=REPORT:New() -local TargetTypes={} -for TargetUnitName,TargetUnit in pairs(self.TargetSetUnit:GetSet())do -local TargetType=self.Detection:GetDetectedUnitTypeName(TargetUnit) -if not TargetTypes[TargetType]then -TargetTypes[TargetType]=TargetType -ReportTypes:Add(TargetType) -end -end -self:SetInfo("Targets",string.format("%d of %s",DetectedItemsCount,ReportTypes:Text(", ")),10) -else -local DetectedItemsCount=self.TargetSetUnit:Count() -local DetectedItemsTypes=self.TargetSetUnit:GetTypeNames() -self:SetInfo("Targets",string.format("%d of %s",DetectedItemsCount,DetectedItemsTypes),10) -end -end -function TASK_A2G_CAS:ReportOrder(ReportGroup) -local Coordinate=self:GetInfo("Coordinates") -local Distance=ReportGroup:GetCoordinate():Get2DDistance(Coordinate) -return Distance -end -function TASK_A2G_CAS:onafterGoal(TaskUnit,From,Event,To) -local TargetSetUnit=self.TargetSetUnit -if TargetSetUnit:Count()==0 then -self:Success() -end -self:__Goal(-10) -end -function TASK_A2G_CAS:SetScoreOnProgress(PlayerName,Score,TaskUnit) -self:F({PlayerName,Score,TaskUnit}) -local ProcessUnit=self:GetUnitProcess(TaskUnit) -ProcessUnit:AddScoreProcess("Engaging","Account","AccountForPlayer","Player "..PlayerName.." has destroyed a target in Close Air Support (CAS).",Score) -return self -end -function TASK_A2G_CAS:SetScoreOnSuccess(PlayerName,Score,TaskUnit) -self:F({PlayerName,Score,TaskUnit}) -local ProcessUnit=self:GetUnitProcess(TaskUnit) -ProcessUnit:AddScore("Success","All targets have been successfully destroyed! The Close Air Support (CAS) was a success!",Score) -return self -end -function TASK_A2G_CAS:SetScoreOnFail(PlayerName,Penalty,TaskUnit) -self:F({PlayerName,Penalty,TaskUnit}) -local ProcessUnit=self:GetUnitProcess(TaskUnit) -ProcessUnit:AddScore("Failed","The Close Air Support (CAS) has failed!",Penalty) -return self -end -end -do -TASK_A2A_DISPATCHER={ -ClassName="TASK_A2A_DISPATCHER", -Mission=nil, -Detection=nil, -Tasks={}, -SweepZones={}, -} -function TASK_A2A_DISPATCHER:New(Mission,SetGroup,Detection) -local self=BASE:Inherit(self,DETECTION_MANAGER:New(SetGroup,Detection)) -self.Detection=Detection -self.Mission=Mission -self.Detection:FilterCategories(Unit.Category.AIRPLANE,Unit.Category.HELICOPTER) -self.Detection:InitDetectRadar(true) -self.Detection:SetRefreshTimeInterval(30) -self:AddTransition("Started","Assign","Started") -self:__Start(5) -return self -end -function TASK_A2A_DISPATCHER:SetEngageRadius(EngageRadius) -self.Detection:SetFriendliesRange(EngageRadius or 100000) -return self -end -function TASK_A2A_DISPATCHER:EvaluateINTERCEPT(DetectedItem) -self:F({DetectedItem.ItemID}) -local DetectedSet=DetectedItem.Set -local DetectedZone=DetectedItem.Zone -if DetectedItem.IsDetected==true then -local TargetSetUnit=SET_UNIT:New() -TargetSetUnit:SetDatabase(DetectedSet) -TargetSetUnit:FilterOnce() -return TargetSetUnit -end -return nil -end -function TASK_A2A_DISPATCHER:EvaluateSWEEP(DetectedItem) -self:F({DetectedItem.ItemID}) -local DetectedSet=DetectedItem.Set -local DetectedZone=DetectedItem.Zone -if DetectedItem.IsDetected==false then -local TargetSetUnit=SET_UNIT:New() -TargetSetUnit:SetDatabase(DetectedSet) -TargetSetUnit:FilterOnce() -return TargetSetUnit -end -return nil -end -function TASK_A2A_DISPATCHER:EvaluateENGAGE(DetectedItem) -self:F({DetectedItem.ItemID}) -local DetectedSet=DetectedItem.Set -local DetectedZone=DetectedItem.Zone -local PlayersCount,PlayersReport=self:GetPlayerFriendliesNearBy(DetectedItem) -if PlayersCount>0 and DetectedItem.IsDetected==true then -local TargetSetUnit=SET_UNIT:New() -TargetSetUnit:SetDatabase(DetectedSet) -TargetSetUnit:FilterOnce() -return TargetSetUnit -end -return nil -end -function TASK_A2A_DISPATCHER:EvaluateRemoveTask(Mission,Task,Detection,DetectedItem,DetectedItemIndex,DetectedItemChanged) -if Task then -if Task:IsStatePlanned()then -local TaskName=Task:GetName() -local TaskType=TaskName:match("(%u+)%.%d+") -self:T2({TaskType=TaskType}) -local Remove=false -local IsPlayers=Detection:IsPlayersNearBy(DetectedItem) -if TaskType=="ENGAGE"then -if IsPlayers==false then -Remove=true -end -end -if TaskType=="INTERCEPT"then -if IsPlayers==true then -Remove=true -end -if DetectedItem.IsDetected==false then -Remove=true -end -end -if TaskType=="SWEEP"then -if DetectedItem.IsDetected==true then -Remove=true -end -end -local DetectedSet=DetectedItem.Set -if DetectedSet:Count()==0 then -Remove=true -end -if DetectedItemChanged==true or Remove then -Task=self:RemoveTask(DetectedItemIndex) -end -end -end -return Task -end -function TASK_A2A_DISPATCHER:GetFriendliesNearBy(DetectedItem) -local DetectedSet=DetectedItem.Set -local FriendlyUnitsNearBy=self.Detection:GetFriendliesNearBy(DetectedItem) -local FriendlyTypes={} -local FriendliesCount=0 -if FriendlyUnitsNearBy then -local DetectedTreatLevel=DetectedSet:CalculateThreatLevelA2G() -for FriendlyUnitName,FriendlyUnitData in pairs(FriendlyUnitsNearBy)do -local FriendlyUnit=FriendlyUnitData -if FriendlyUnit:IsAirPlane()then -local FriendlyUnitThreatLevel=FriendlyUnit:GetThreatLevel() -FriendliesCount=FriendliesCount+1 -local FriendlyType=FriendlyUnit:GetTypeName() -FriendlyTypes[FriendlyType]=FriendlyTypes[FriendlyType]and(FriendlyTypes[FriendlyType]+1)or 1 -if DetectedTreatLevel0 then -for FriendlyType,FriendlyTypeCount in pairs(FriendlyTypes)do -FriendlyTypesReport:Add(string.format("%d of %s",FriendlyTypeCount,FriendlyType)) -end -else -FriendlyTypesReport:Add("-") -end -return FriendliesCount,FriendlyTypesReport -end -function TASK_A2A_DISPATCHER:GetPlayerFriendliesNearBy(DetectedItem) -local DetectedSet=DetectedItem.Set -local PlayersNearBy=self.Detection:GetPlayersNearBy(DetectedItem) -local PlayerTypes={} -local PlayersCount=0 -if PlayersNearBy then -local DetectedTreatLevel=DetectedSet:CalculateThreatLevelA2G() -for PlayerUnitName,PlayerUnitData in pairs(PlayersNearBy)do -local PlayerUnit=PlayerUnitData -local PlayerName=PlayerUnit:GetPlayerName() -if PlayerUnit:IsAirPlane()and PlayerName~=nil then -local FriendlyUnitThreatLevel=PlayerUnit:GetThreatLevel() -PlayersCount=PlayersCount+1 -local PlayerType=PlayerUnit:GetTypeName() -PlayerTypes[PlayerName]=PlayerType -if DetectedTreatLevel0 then -for PlayerName,PlayerType in pairs(PlayerTypes)do -PlayerTypesReport:Add(string.format('"%s" in %s',PlayerName,PlayerType)) -end -else -PlayerTypesReport:Add("-") -end -return PlayersCount,PlayerTypesReport -end -function TASK_A2A_DISPATCHER:RemoveTask(TaskIndex) -self.Mission:RemoveTask(self.Tasks[TaskIndex]) -self.Tasks[TaskIndex]=nil -end -function TASK_A2A_DISPATCHER:ProcessDetected(Detection) -self:E() -local AreaMsg={} -local TaskMsg={} -local ChangeMsg={} -local Mission=self.Mission -if Mission:IsIDLE()or Mission:IsENGAGED()then -local TaskReport=REPORT:New() -for TaskIndex,TaskData in pairs(self.Tasks)do -local Task=TaskData -if Task:IsStatePlanned()then -local DetectedItem=Detection:GetDetectedItem(TaskIndex) -if not DetectedItem then -local TaskText=Task:GetName() -for TaskGroupID,TaskGroup in pairs(self.SetGroup:GetSet())do -Mission:GetCommandCenter():MessageToGroup(string.format("Obsolete A2A task %s for %s removed.",TaskText,Mission:GetName()),TaskGroup) -end -Task=self:RemoveTask(TaskIndex) -end -end -end -for DetectedItemID,DetectedItem in pairs(Detection:GetDetectedItems())do -local DetectedItem=DetectedItem -local DetectedSet=DetectedItem.Set -local DetectedCount=DetectedSet:Count() -local DetectedZone=DetectedItem.Zone -local DetectedID=DetectedItem.ID -local TaskIndex=DetectedItem.Index -local DetectedItemChanged=DetectedItem.Changed -local Task=self.Tasks[TaskIndex] -Task=self:EvaluateRemoveTask(Mission,Task,Detection,DetectedItem,TaskIndex,DetectedItemChanged) -if not Task and DetectedCount>0 then -local TargetSetUnit=self:EvaluateENGAGE(DetectedItem) -if TargetSetUnit then -Task=TASK_A2A_ENGAGE:New(Mission,self.SetGroup,string.format("ENGAGE.%03d",DetectedID),TargetSetUnit) -Task:SetDetection(Detection,TaskIndex) -else -local TargetSetUnit=self:EvaluateINTERCEPT(DetectedItem) -if TargetSetUnit then -Task=TASK_A2A_INTERCEPT:New(Mission,self.SetGroup,string.format("INTERCEPT.%03d",DetectedID),TargetSetUnit) -Task:SetDetection(Detection,TaskIndex) -else -local TargetSetUnit=self:EvaluateSWEEP(DetectedItem) -if TargetSetUnit then -Task=TASK_A2A_SWEEP:New(Mission,self.SetGroup,string.format("SWEEP.%03d",DetectedID),TargetSetUnit) -Task:SetDetection(Detection,TaskIndex) -end -end -end -if Task then -self.Tasks[TaskIndex]=Task -Task:SetTargetZone(DetectedZone,DetectedItem.Coordinate.y,DetectedItem.Coordinate.Heading) -Task:SetDispatcher(self) -Mission:AddTask(Task) -TaskReport:Add(Task:GetName()) -else -self:E("This should not happen") -end -end -if Task then -local FriendliesCount,FriendliesReport=self:GetFriendliesNearBy(DetectedItem) -Task:SetInfo("Friendlies",string.format("%d ( %s )",FriendliesCount,FriendliesReport:Text(",")),30) -local PlayersCount,PlayersReport=self:GetPlayerFriendliesNearBy(DetectedItem) -Task:SetInfo("Players",string.format("%d ( %s )",PlayersCount,PlayersReport:Text(",")),31) -end -Detection:AcceptChanges(DetectedItem) -end -Mission:GetCommandCenter():SetMenu() -local TaskText=TaskReport:Text(", ") -for TaskGroupID,TaskGroup in pairs(self.SetGroup:GetSet())do -if(not Mission:IsGroupAssigned(TaskGroup))and TaskText~=""then -Mission:GetCommandCenter():MessageToGroup(string.format("%s has tasks %s. Subscribe to a task using the radio menu.",Mission:GetName(),TaskText),TaskGroup) -end -end -end -return true -end -end -do -TASK_A2A={ -ClassName="TASK_A2A", -} -function TASK_A2A:New(Mission,SetAttack,TaskName,TargetSetUnit,TaskType,TaskBriefing) -local self=BASE:Inherit(self,TASK:New(Mission,SetAttack,TaskName,TaskType,TaskBriefing)) -self:F() -self.TargetSetUnit=TargetSetUnit -self.TaskType=TaskType -local Fsm=self:GetUnitProcess() -Fsm:AddProcess("Planned","Accept",ACT_ASSIGN_ACCEPT:New(self.TaskBriefing),{Assigned="RouteToRendezVous",Rejected="Reject"}) -Fsm:AddTransition("Assigned","RouteToRendezVous","RoutingToRendezVous") -Fsm:AddProcess("RoutingToRendezVous","RouteToRendezVousPoint",ACT_ROUTE_POINT:New(),{Arrived="ArriveAtRendezVous"}) -Fsm:AddProcess("RoutingToRendezVous","RouteToRendezVousZone",ACT_ROUTE_ZONE:New(),{Arrived="ArriveAtRendezVous"}) -Fsm:AddTransition({"Arrived","RoutingToRendezVous"},"ArriveAtRendezVous","ArrivedAtRendezVous") -Fsm:AddTransition({"ArrivedAtRendezVous","HoldingAtRendezVous"},"Engage","Engaging") -Fsm:AddTransition({"ArrivedAtRendezVous","HoldingAtRendezVous"},"HoldAtRendezVous","HoldingAtRendezVous") -Fsm:AddProcess("Engaging","Account",ACT_ACCOUNT_DEADS:New(),{}) -Fsm:AddTransition("Engaging","RouteToTarget","Engaging") -Fsm:AddProcess("Engaging","RouteToTargetZone",ACT_ROUTE_ZONE:New(),{}) -Fsm:AddProcess("Engaging","RouteToTargetPoint",ACT_ROUTE_POINT:New(),{}) -Fsm:AddTransition("Engaging","RouteToTargets","Engaging") -Fsm:AddTransition("Rejected","Reject","Aborted") -Fsm:AddTransition("Failed","Fail","Failed") -function Fsm:onafterRouteToRendezVous(TaskUnit,Task) -self:E({TaskUnit=TaskUnit,Task=Task and Task:GetClassNameAndID()}) -if Task:GetRendezVousZone(TaskUnit)then -self:__RouteToRendezVousZone(0.1) -else -if Task:GetRendezVousCoordinate(TaskUnit)then -self:__RouteToRendezVousPoint(0.1) -else -self:__ArriveAtRendezVous(0.1) -end -end -end -function Fsm:OnAfterArriveAtRendezVous(TaskUnit,Task) -self:E({TaskUnit=TaskUnit,Task=Task and Task:GetClassNameAndID()}) -self:__Engage(0.1) -end -function Fsm:onafterEngage(TaskUnit,Task) -self:E({self}) -self:__Account(0.1) -self:__RouteToTarget(0.1) -self:__RouteToTargets(-10) -end -function Fsm:onafterRouteToTarget(TaskUnit,Task) -self:E({TaskUnit=TaskUnit,Task=Task and Task:GetClassNameAndID()}) -if Task:GetTargetZone(TaskUnit)then -self:__RouteToTargetZone(0.1) -else -local TargetUnit=Task.TargetSetUnit:GetFirst() -if TargetUnit then -local Coordinate=TargetUnit:GetCoordinate() -self:T({TargetCoordinate=Coordinate,Coordinate:GetX(),Coordinate:GetAlt(),Coordinate:GetZ()}) -Task:SetTargetCoordinate(TargetUnit:GetCoordinate(),TaskUnit) -end -self:__RouteToTargetPoint(0.1) -end -end -function Fsm:onafterRouteToTargets(TaskUnit,Task) -self:E({TaskUnit=TaskUnit,Task=Task and Task:GetClassNameAndID()}) -local TargetUnit=Task.TargetSetUnit:GetFirst() -if TargetUnit then -Task:SetTargetCoordinate(TargetUnit:GetCoordinate(),TaskUnit) -end -self:__RouteToTargets(-10) -end -return self -end -function TASK_A2A:GetPlannedMenuText() -return self:GetStateString().." - "..self:GetTaskName().." ( "..self.TargetSetUnit:GetUnitTypesText().." )" -end -function TASK_A2A:SetRendezVousCoordinate(RendezVousCoordinate,RendezVousRange,TaskUnit) -local ProcessUnit=self:GetUnitProcess(TaskUnit) -local ActRouteRendezVous=ProcessUnit:GetProcess("RoutingToRendezVous","RouteToRendezVousPoint") -ActRouteRendezVous:SetCoordinate(RendezVousCoordinate) -ActRouteRendezVous:SetRange(RendezVousRange) -end -function TASK_A2A:GetRendezVousCoordinate(TaskUnit) -local ProcessUnit=self:GetUnitProcess(TaskUnit) -local ActRouteRendezVous=ProcessUnit:GetProcess("RoutingToRendezVous","RouteToRendezVousPoint") -return ActRouteRendezVous:GetCoordinate(),ActRouteRendezVous:GetRange() -end -function TASK_A2A:SetRendezVousZone(RendezVousZone,TaskUnit) -local ProcessUnit=self:GetUnitProcess(TaskUnit) -local ActRouteRendezVous=ProcessUnit:GetProcess("RoutingToRendezVous","RouteToRendezVousZone") -ActRouteRendezVous:SetZone(RendezVousZone) -end -function TASK_A2A:GetRendezVousZone(TaskUnit) -local ProcessUnit=self:GetUnitProcess(TaskUnit) -local ActRouteRendezVous=ProcessUnit:GetProcess("RoutingToRendezVous","RouteToRendezVousZone") -return ActRouteRendezVous:GetZone() -end -function TASK_A2A:SetTargetCoordinate(TargetCoordinate,TaskUnit) -local ProcessUnit=self:GetUnitProcess(TaskUnit) -local ActRouteTarget=ProcessUnit:GetProcess("Engaging","RouteToTargetPoint") -ActRouteTarget:SetCoordinate(TargetCoordinate) -end -function TASK_A2A:GetTargetCoordinate(TaskUnit) -local ProcessUnit=self:GetUnitProcess(TaskUnit) -local ActRouteTarget=ProcessUnit:GetProcess("Engaging","RouteToTargetPoint") -return ActRouteTarget:GetCoordinate() -end -function TASK_A2A:SetTargetZone(TargetZone,Altitude,Heading,TaskUnit) -local ProcessUnit=self:GetUnitProcess(TaskUnit) -local ActRouteTarget=ProcessUnit:GetProcess("Engaging","RouteToTargetZone") -ActRouteTarget:SetZone(TargetZone,Altitude,Heading) -end -function TASK_A2A:GetTargetZone(TaskUnit) -local ProcessUnit=self:GetUnitProcess(TaskUnit) -local ActRouteTarget=ProcessUnit:GetProcess("Engaging","RouteToTargetZone") -return ActRouteTarget:GetZone() -end -function TASK_A2A:SetGoalTotal() -self.GoalTotal=self.TargetSetUnit:Count() -end -function TASK_A2A:GetGoalTotal() -return self.GoalTotal -end -end -do -TASK_A2A_INTERCEPT={ -ClassName="TASK_A2A_INTERCEPT", -} -function TASK_A2A_INTERCEPT:New(Mission,SetGroup,TaskName,TargetSetUnit,TaskBriefing) -local self=BASE:Inherit(self,TASK_A2A:New(Mission,SetGroup,TaskName,TargetSetUnit,"INTERCEPT",TaskBriefing)) -self:F() -Mission:AddTask(self) -self:SetBriefing( -TaskBriefing or -"Intercept incoming intruders.\n" -) -self:UpdateTaskInfo() -return self -end -function TASK_A2A_INTERCEPT:UpdateTaskInfo() -local TargetCoordinate=self.Detection and self.Detection:GetDetectedItemCoordinate(self.DetectedItemIndex)or self.TargetSetUnit:GetFirst():GetCoordinate() -self:SetInfo("Coordinates",TargetCoordinate,0) -self:SetInfo("Threat","["..string.rep("■",self.Detection and self.Detection:GetDetectedItemThreatLevel(self.DetectedItemIndex)or self.TargetSetUnit:CalculateThreatLevelA2G()).."]",11) -if self.Detection then -local DetectedItemsCount=self.TargetSetUnit:Count() -local ReportTypes=REPORT:New() -local TargetTypes={} -for TargetUnitName,TargetUnit in pairs(self.TargetSetUnit:GetSet())do -local TargetType=self.Detection:GetDetectedUnitTypeName(TargetUnit) -if not TargetTypes[TargetType]then -TargetTypes[TargetType]=TargetType -ReportTypes:Add(TargetType) -end -end -self:SetInfo("Targets",string.format("%d of %s",DetectedItemsCount,ReportTypes:Text(", ")),10) -else -local DetectedItemsCount=self.TargetSetUnit:Count() -local DetectedItemsTypes=self.TargetSetUnit:GetTypeNames() -self:SetInfo("Targets",string.format("%d of %s",DetectedItemsCount,DetectedItemsTypes),10) -end -end -function TASK_A2A_INTERCEPT:ReportOrder(ReportGroup) -self:F({TaskInfo=self.TaskInfo}) -local Coordinate=self.TaskInfo.Coordinates.TaskInfoText -local Distance=ReportGroup:GetCoordinate():Get2DDistance(Coordinate) -return Distance -end -function TASK_A2A_INTERCEPT:onafterGoal(TaskUnit,From,Event,To) -local TargetSetUnit=self.TargetSetUnit -if TargetSetUnit:Count()==0 then -self:Success() -end -self:__Goal(-10) -end -function TASK_A2A_INTERCEPT:SetScoreOnProgress(PlayerName,Score,TaskUnit) -self:F({PlayerName,Score,TaskUnit}) -local ProcessUnit=self:GetUnitProcess(TaskUnit) -ProcessUnit:AddScoreProcess("Engaging","Account","AccountForPlayer","Player "..PlayerName.." has intercepted a target.",Score) -return self -end -function TASK_A2A_INTERCEPT:SetScoreOnSuccess(PlayerName,Score,TaskUnit) -self:F({PlayerName,Score,TaskUnit}) -local ProcessUnit=self:GetUnitProcess(TaskUnit) -ProcessUnit:AddScore("Success","All targets have been successfully intercepted!",Score) -return self -end -function TASK_A2A_INTERCEPT:SetScoreOnFail(PlayerName,Penalty,TaskUnit) -self:F({PlayerName,Penalty,TaskUnit}) -local ProcessUnit=self:GetUnitProcess(TaskUnit) -ProcessUnit:AddScore("Failed","The intercept has failed!",Penalty) -return self -end -end -do -TASK_A2A_SWEEP={ -ClassName="TASK_A2A_SWEEP", -} -function TASK_A2A_SWEEP:New(Mission,SetGroup,TaskName,TargetSetUnit,TaskBriefing) -local self=BASE:Inherit(self,TASK_A2A:New(Mission,SetGroup,TaskName,TargetSetUnit,"SWEEP",TaskBriefing)) -self:F() -Mission:AddTask(self) -self:SetBriefing( -TaskBriefing or -"Perform a fighter sweep. Incoming intruders were detected and could be hiding at the location.\n" -) -self:UpdateTaskInfo() -return self -end -function TASK_A2A_SWEEP:UpdateTaskInfo() -local TargetCoordinate=self.Detection and self.Detection:GetDetectedItemCoordinate(self.DetectedItemIndex)or self.TargetSetUnit:GetFirst():GetCoordinate() -self:SetInfo("Coordinates",TargetCoordinate,0) -self:SetInfo("Assumed Threat","["..string.rep("■",self.Detection and self.Detection:GetDetectedItemThreatLevel(self.DetectedItemIndex)or self.TargetSetUnit:CalculateThreatLevelA2G()).."]",11) -if self.Detection then -local DetectedItemsCount=self.TargetSetUnit:Count() -local ReportTypes=REPORT:New() -local TargetTypes={} -for TargetUnitName,TargetUnit in pairs(self.TargetSetUnit:GetSet())do -local TargetType=self.Detection:GetDetectedUnitTypeName(TargetUnit) -if not TargetTypes[TargetType]then -TargetTypes[TargetType]=TargetType -ReportTypes:Add(TargetType) -end -end -self:SetInfo("Lost Targets",string.format("%d of %s",DetectedItemsCount,ReportTypes:Text(", ")),10) -else -local DetectedItemsCount=self.TargetSetUnit:Count() -local DetectedItemsTypes=self.TargetSetUnit:GetTypeNames() -self:SetInfo("Lost Targets",string.format("%d of %s",DetectedItemsCount,DetectedItemsTypes),10) -end -end -function TASK_A2A_SWEEP:ReportOrder(ReportGroup) -local Coordinate=self.TaskInfo.Coordinates.TaskInfoText -local Distance=ReportGroup:GetCoordinate():Get2DDistance(Coordinate) -return Distance -end -function TASK_A2A_SWEEP:onafterGoal(TaskUnit,From,Event,To) -local TargetSetUnit=self.TargetSetUnit -if TargetSetUnit:Count()==0 then -self:Success() -end -self:__Goal(-10) -end -function TASK_A2A_SWEEP:SetScoreOnProgress(PlayerName,Score,TaskUnit) -self:F({PlayerName,Score,TaskUnit}) -local ProcessUnit=self:GetUnitProcess(TaskUnit) -ProcessUnit:AddScoreProcess("Engaging","Account","AccountForPlayer","Player "..PlayerName.." has sweeped a target.",Score) -return self -end -function TASK_A2A_SWEEP:SetScoreOnSuccess(PlayerName,Score,TaskUnit) -self:F({PlayerName,Score,TaskUnit}) -local ProcessUnit=self:GetUnitProcess(TaskUnit) -ProcessUnit:AddScore("Success","All targets have been successfully sweeped!",Score) -return self -end -function TASK_A2A_SWEEP:SetScoreOnFail(PlayerName,Penalty,TaskUnit) -self:F({PlayerName,Penalty,TaskUnit}) -local ProcessUnit=self:GetUnitProcess(TaskUnit) -ProcessUnit:AddScore("Failed","The sweep has failed!",Penalty) -return self -end -end -do -TASK_A2A_ENGAGE={ -ClassName="TASK_A2A_ENGAGE", -} -function TASK_A2A_ENGAGE:New(Mission,SetGroup,TaskName,TargetSetUnit,TaskBriefing) -local self=BASE:Inherit(self,TASK_A2A:New(Mission,SetGroup,TaskName,TargetSetUnit,"ENGAGE",TaskBriefing)) -self:F() -Mission:AddTask(self) -self:SetBriefing( -TaskBriefing or -"Bogeys are nearby! Players close by are ordered to ENGAGE the intruders!\n" -) -self:UpdateTaskInfo() -return self -end -function TASK_A2A_ENGAGE:UpdateTaskInfo() -local TargetCoordinate=self.Detection and self.Detection:GetDetectedItemCoordinate(self.DetectedItemIndex)or self.TargetSetUnit:GetFirst():GetCoordinate() -self:SetInfo("Coordinates",TargetCoordinate,0) -self:SetInfo("Threat","["..string.rep("■",self.Detection and self.Detection:GetDetectedItemThreatLevel(self.DetectedItemIndex)or self.TargetSetUnit:CalculateThreatLevelA2G()).."]",11) -if self.Detection then -local DetectedItemsCount=self.TargetSetUnit:Count() -local ReportTypes=REPORT:New() -local TargetTypes={} -for TargetUnitName,TargetUnit in pairs(self.TargetSetUnit:GetSet())do -local TargetType=self.Detection:GetDetectedUnitTypeName(TargetUnit) -if not TargetTypes[TargetType]then -TargetTypes[TargetType]=TargetType -ReportTypes:Add(TargetType) -end -end -self:SetInfo("Targets",string.format("%d of %s",DetectedItemsCount,ReportTypes:Text(", ")),10) -else -local DetectedItemsCount=self.TargetSetUnit:Count() -local DetectedItemsTypes=self.TargetSetUnit:GetTypeNames() -self:SetInfo("Targets",string.format("%d of %s",DetectedItemsCount,DetectedItemsTypes),10) -end -end -function TASK_A2A_ENGAGE:ReportOrder(ReportGroup) -local Coordinate=self.TaskInfo.Coordinates.TaskInfoText -local Distance=ReportGroup:GetCoordinate():Get2DDistance(Coordinate) -return Distance -end -function TASK_A2A_ENGAGE:onafterGoal(TaskUnit,From,Event,To) -local TargetSetUnit=self.TargetSetUnit -if TargetSetUnit:Count()==0 then -self:Success() -end -self:__Goal(-10) -end -function TASK_A2A_ENGAGE:SetScoreOnProgress(PlayerName,Score,TaskUnit) -self:F({PlayerName,Score,TaskUnit}) -local ProcessUnit=self:GetUnitProcess(TaskUnit) -ProcessUnit:AddScoreProcess("Engaging","Account","AccountForPlayer","Player "..PlayerName.." has engaged and destroyed a target.",Score) -return self -end -function TASK_A2A_ENGAGE:SetScoreOnSuccess(PlayerName,Score,TaskUnit) -self:F({PlayerName,Score,TaskUnit}) -local ProcessUnit=self:GetUnitProcess(TaskUnit) -ProcessUnit:AddScore("Success","All targets have been successfully engaged!",Score) -return self -end -function TASK_A2A_ENGAGE:SetScoreOnFail(PlayerName,Penalty,TaskUnit) -self:F({PlayerName,Penalty,TaskUnit}) -local ProcessUnit=self:GetUnitProcess(TaskUnit) -ProcessUnit:AddScore("Failed","The target engagement has failed!",Penalty) -return self -end -end -do -TASK_CARGO={ -ClassName="TASK_CARGO", -} -function TASK_CARGO:New(Mission,SetGroup,TaskName,SetCargo,TaskType,TaskBriefing) -local self=BASE:Inherit(self,TASK:New(Mission,SetGroup,TaskName,TaskType,TaskBriefing)) -self:F({Mission,SetGroup,TaskName,SetCargo,TaskType}) -self.SetCargo=SetCargo -self.TaskType=TaskType -self.SmokeColor=SMOKECOLOR.Red -self.CargoItemCount={} -self.CargoLimit=2 -self.DeployZones={} -local Fsm=self:GetUnitProcess() -Fsm:SetStartState("Planned") -Fsm:AddProcess("Planned","Accept",ACT_ASSIGN_ACCEPT:New(self.TaskBriefing),{Assigned="SelectAction",Rejected="Reject"}) -Fsm:AddTransition({"Assigned","WaitingForCommand","ArrivedAtPickup","ArrivedAtDeploy","Boarded","UnBoarded","Landed","Boarding"},"SelectAction","*") -Fsm:AddTransition("*","RouteToPickup","RoutingToPickup") -Fsm:AddProcess("RoutingToPickup","RouteToPickupPoint",ACT_ROUTE_POINT:New(),{Arrived="ArriveAtPickup",Cancelled="CancelRouteToPickup"}) -Fsm:AddTransition("Arrived","ArriveAtPickup","ArrivedAtPickup") -Fsm:AddTransition("Cancelled","CancelRouteToPickup","WaitingForCommand") -Fsm:AddTransition("*","RouteToDeploy","RoutingToDeploy") -Fsm:AddProcess("RoutingToDeploy","RouteToDeployZone",ACT_ROUTE_ZONE:New(),{Arrived="ArriveAtDeploy",Cancelled="CancelRouteToDeploy"}) -Fsm:AddTransition("Arrived","ArriveAtDeploy","ArrivedAtDeploy") -Fsm:AddTransition("Cancelled","CancelRouteToDeploy","WaitingForCommand") -Fsm:AddTransition({"ArrivedAtPickup","ArrivedAtDeploy","Landing"},"Land","Landing") -Fsm:AddTransition("Landing","Landed","Landed") -Fsm:AddTransition("*","PrepareBoarding","AwaitBoarding") -Fsm:AddTransition("AwaitBoarding","Board","Boarding") -Fsm:AddTransition("Boarding","Boarded","Boarded") -Fsm:AddTransition("*","PrepareUnBoarding","AwaitUnBoarding") -Fsm:AddTransition("AwaitUnBoarding","UnBoard","UnBoarding") -Fsm:AddTransition("UnBoarding","UnBoarded","UnBoarded") -Fsm:AddTransition("Deployed","Success","Success") -Fsm:AddTransition("Rejected","Reject","Aborted") -Fsm:AddTransition("Failed","Fail","Failed") -function Fsm:onafterSelectAction(TaskUnit,Task) -local TaskUnitName=TaskUnit:GetName() -self:E({TaskUnit=TaskUnitName,Task=Task and Task:GetClassNameAndID()}) -local MenuTime=timer.getTime() -TaskUnit.Menu=MENU_GROUP:New(TaskUnit:GetGroup(),Task:GetName().." @ "..TaskUnit:GetName()):SetTime(MenuTime) -local CargoItemCount=TaskUnit:CargoItemCount() -Task.SetCargo:ForEachCargo( -function(Cargo) -if Cargo:IsAlive()then -if Cargo:IsUnLoaded()then -if CargoItemCount0 and SmokeColor<=5 then -self.SmokeColor=SMOKECOLOR.SmokeColor -end -end -end -function TASK_CARGO:GetSmokeColor() -return self.SmokeColor -end -function TASK_CARGO:GetPlannedMenuText() -return self:GetStateString().." - "..self:GetTaskName().." ( "..self.TargetSetUnit:GetUnitTypesText().." )" -end -function TASK_CARGO:GetCargoSet() -return self.SetCargo -end -function TASK_CARGO:GetDeployZones() -return self.DeployZones -end -function TASK_CARGO:SetCargoPickup(Cargo,TaskUnit) -self:F({Cargo,TaskUnit}) -local ProcessUnit=self:GetUnitProcess(TaskUnit) -local ActRouteCargo=ProcessUnit:GetProcess("RoutingToPickup","RouteToPickupPoint") -ActRouteCargo:Reset() -ActRouteCargo:SetCoordinate(Cargo:GetCoordinate()) -ActRouteCargo:SetRange(Cargo:GetBoardingRange()) -ActRouteCargo:SetMenuCancel(TaskUnit:GetGroup(),"Cancel Routing to Cargo "..Cargo:GetName(),TaskUnit.Menu) -ActRouteCargo:Start() -return self -end -function TASK_CARGO:SetDeployZone(DeployZone,TaskUnit) -local ProcessUnit=self:GetUnitProcess(TaskUnit) -local ActRouteDeployZone=ProcessUnit:GetProcess("RoutingToDeploy","RouteToDeployZone") -ActRouteDeployZone:Reset() -ActRouteDeployZone:SetZone(DeployZone) -ActRouteDeployZone:SetMenuCancel(TaskUnit:GetGroup(),"Cancel Routing to Deploy Zone"..DeployZone:GetName(),TaskUnit.Menu) -ActRouteDeployZone:Start() -return self -end -function TASK_CARGO:AddDeployZone(DeployZone,TaskUnit) -self.DeployZones[DeployZone:GetName()]=DeployZone -return self -end -function TASK_CARGO:RemoveDeployZone(DeployZone,TaskUnit) -self.DeployZones[DeployZone:GetName()]=nil -return self -end -function TASK_CARGO:SetDeployZones(DeployZones,TaskUnit) -for DeployZoneID,DeployZone in pairs(DeployZones)do -self.DeployZones[DeployZone:GetName()]=DeployZone -end -return self -end -function TASK_CARGO:GetTargetZone(TaskUnit) -local ProcessUnit=self:GetUnitProcess(TaskUnit) -local ActRouteTarget=ProcessUnit:GetProcess("Engaging","RouteToTargetZone") -return ActRouteTarget:GetZone() -end -function TASK_CARGO:SetScoreOnProgress(Text,Score,TaskUnit) -self:F({Text,Score,TaskUnit}) -local ProcessUnit=self:GetUnitProcess(TaskUnit) -ProcessUnit:AddScoreProcess("Engaging","Account","Account",Text,Score) -return self -end -function TASK_CARGO:SetScoreOnSuccess(Text,Score,TaskUnit) -self:F({Text,Score,TaskUnit}) -local ProcessUnit=self:GetUnitProcess(TaskUnit) -ProcessUnit:AddScore("Success",Text,Score) -return self -end -function TASK_CARGO:SetScoreOnFail(Text,Penalty,TaskUnit) -self:F({Text,Score,TaskUnit}) -local ProcessUnit=self:GetUnitProcess(TaskUnit) -ProcessUnit:AddScore("Failed",Text,Penalty) -return self -end -function TASK_CARGO:SetGoalTotal() -self.GoalTotal=self.SetCargo:Count() -end -function TASK_CARGO:GetGoalTotal() -return self.GoalTotal -end -end -do -TASK_CARGO_TRANSPORT={ -ClassName="TASK_CARGO_TRANSPORT", -} -function TASK_CARGO_TRANSPORT:New(Mission,SetGroup,TaskName,SetCargo,TaskBriefing) -local self=BASE:Inherit(self,TASK_CARGO:New(Mission,SetGroup,TaskName,SetCargo,"Transport",TaskBriefing)) -self:F() -Mission:AddTask(self) -self:AddTransition("*","CargoPickedUp","*") -self:AddTransition("*","CargoDeployed","*") -self:E({CargoDeployed=self.CargoDeployed~=nil and"true"or"false"}) -local Fsm=self:GetUnitProcess() -local CargoReport=REPORT:New("Transport Cargo. The following cargo needs to be transported including initial positions:") -SetCargo:ForEachCargo( -function(Cargo) -local CargoType=Cargo:GetType() -local CargoName=Cargo:GetName() -local CargoCoordinate=Cargo:GetCoordinate() -CargoReport:Add(string.format('- "%s" (%s) at %s',CargoName,CargoType,CargoCoordinate:ToStringMGRS())) -end -) -self:SetBriefing( -TaskBriefing or -CargoReport:Text() -) -return self -end -function TASK_CARGO_TRANSPORT:ReportOrder(ReportGroup) -return true -end -function TASK_CARGO_TRANSPORT:IsAllCargoTransported() -local CargoSet=self:GetCargoSet() -local Set=CargoSet:GetSet() -local DeployZones=self:GetDeployZones() -local CargoDeployed=true -for CargoID,CargoData in pairs(Set)do -local Cargo=CargoData -if Cargo:IsDeployed()then -for DeployZoneID,DeployZone in pairs(DeployZones)do -self:T({Cargo.CargoObject}) -if Cargo:IsInZone(DeployZone)==false then -CargoDeployed=false -end -end -else -CargoDeployed=false -end -end -return CargoDeployed -end -function TASK_CARGO_TRANSPORT:onafterGoal(TaskUnit,From,Event,To) -local CargoSet=self.CargoSet -if self:IsAllCargoTransported()then -self:Success() -end -self:__Goal(-10) -end -end -_EVENTDISPATCHER=EVENT:New() -_SCHEDULEDISPATCHER=SCHEDULEDISPATCHER:New() -_DATABASE=DATABASE:New() -_SETTINGS=SETTINGS:Set() -BASE:TraceOnOff(false) +env.info('*** MOOSE DYNAMIC INCLUDE START *** ') +env.info('Moose Generation Timestamp: 20170928_1657') +local base=_G +__Moose={} +__Moose.Include=function(IncludeFile) +if not __Moose.Includes[IncludeFile]then +__Moose.Includes[IncludeFile]=IncludeFile +local f=assert(base.loadfile(__Moose.ProgramPath..IncludeFile)) +if f==nil then +error("Moose: Could not load Moose file "..IncludeFile) +else +env.info("Moose: "..IncludeFile.." dynamically loaded from "..__Moose.ProgramPath) +return f() +end +end +end +__Moose.ProgramPath="Scripts/Moose/" +__Moose.Includes={} +__Moose.Include('Utilities/Routines.lua') +__Moose.Include('Utilities/Utils.lua') +__Moose.Include('Core/Base.lua') +__Moose.Include('Core/Report.lua') +__Moose.Include('Core/Scheduler.lua') +__Moose.Include('Core/ScheduleDispatcher.lua') +__Moose.Include('Core/Event.lua') +__Moose.Include('Core/Settings.lua') +__Moose.Include('Core/Menu.lua') +__Moose.Include('Core/Zone.lua') +__Moose.Include('Core/Database.lua') +__Moose.Include('Core/Set.lua') +__Moose.Include('Core/Point.lua') +__Moose.Include('Core/Message.lua') +__Moose.Include('Core/Fsm.lua') +__Moose.Include('Core/Radio.lua') +__Moose.Include('Core/SpawnStatic.lua') +__Moose.Include('Core/Cargo.lua') +__Moose.Include('Core/Spot.lua') +__Moose.Include('Wrapper/Object.lua') +__Moose.Include('Wrapper/Identifiable.lua') +__Moose.Include('Wrapper/Positionable.lua') +__Moose.Include('Wrapper/Controllable.lua') +__Moose.Include('Wrapper/Group.lua') +__Moose.Include('Wrapper/Unit.lua') +__Moose.Include('Wrapper/Client.lua') +__Moose.Include('Wrapper/Static.lua') +__Moose.Include('Wrapper/Airbase.lua') +__Moose.Include('Wrapper/Scenery.lua') +__Moose.Include('Functional/Scoring.lua') +__Moose.Include('Functional/CleanUp.lua') +__Moose.Include('Functional/Spawn.lua') +__Moose.Include('Functional/Movement.lua') +__Moose.Include('Functional/Sead.lua') +__Moose.Include('Functional/Escort.lua') +__Moose.Include('Functional/MissileTrainer.lua') +__Moose.Include('Functional/AirbasePolice.lua') +__Moose.Include('Functional/Detection.lua') +__Moose.Include('Functional/Designate.lua') +__Moose.Include('Functional/RAT.lua') +__Moose.Include('Functional/Protect.lua') +__Moose.Include('AI/AI_Balancer.lua') +__Moose.Include('AI/AI_A2A.lua') +__Moose.Include('AI/AI_A2A_Patrol.lua') +__Moose.Include('AI/AI_A2A_Cap.lua') +__Moose.Include('AI/AI_A2A_Gci.lua') +__Moose.Include('AI/AI_A2A_Dispatcher.lua') +__Moose.Include('AI/AI_Patrol.lua') +__Moose.Include('AI/AI_Cap.lua') +__Moose.Include('AI/AI_Cas.lua') +__Moose.Include('AI/AI_Bai.lua') +__Moose.Include('AI/AI_Formation.lua') +__Moose.Include('Actions/Act_Assign.lua') +__Moose.Include('Actions/Act_Route.lua') +__Moose.Include('Actions/Act_Account.lua') +__Moose.Include('Actions/Act_Assist.lua') +__Moose.Include('Tasking/CommandCenter.lua') +__Moose.Include('Tasking/Mission.lua') +__Moose.Include('Tasking/Task.lua') +__Moose.Include('Tasking/DetectionManager.lua') +__Moose.Include('Tasking/Task_A2G_Dispatcher.lua') +__Moose.Include('Tasking/Task_A2G.lua') +__Moose.Include('Tasking/Task_A2A_Dispatcher.lua') +__Moose.Include('Tasking/Task_A2A.lua') +__Moose.Include('Tasking/Task_Cargo.lua') +__Moose.Include('Moose.lua') +BASE:TraceOnOff(true) env.info('*** MOOSE INCLUDE END *** ')