diff --git a/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua b/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua index fcb65227a..78d340f09 100644 --- a/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua @@ -954,6 +954,9 @@ do -- AI_A2A_DISPATCHER 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( SpawnTemplates ) == "string" then @@ -1718,6 +1721,7 @@ do -- AI_A2A_DISPATCHER for SquadronName, DefenderSquadron in pairs( self.DefenderSquadrons or {} ) do for InterceptID, Intercept in pairs( DefenderSquadron.Gci or {} ) do + self:E( { DefenderSquadron } ) local SpawnCoord = DefenderSquadron.Airbase:GetCoordinate() -- Core.Point#COORDINATE local TargetCoord = Target.Set:GetFirst():GetCoordinate() local Distance = SpawnCoord:Get2DDistance( TargetCoord ) @@ -2069,16 +2073,14 @@ end do - --- AI_A2A_DISPATCHER_GCICAP class. - -- @type AI_A2A_DISPATCHER_GCICAP + --- @type AI_A2A_GCICAP -- @extends #AI_A2A_DISPATCHER - --- # AI\_A2A\_DISPATCHER\_GCICAP class, extends @{AI#AI_A2A_DISPATCHER} + --- # AI\_A2A\_GCICAP class, extends @{AI#AI_A2A_DISPATCHER} -- -- ![Banner Image](..\Presentations\AI_A2A_DISPATCHER\Dia1.JPG) -- - -- The @{#AI_A2A_DISPATCHER} class is designed to create an automatic air defence system for a coalition. - -- + -- The AI_A2A_GCICAP class is designed to create an automatic air defence system for a coalition setting up GCI and CAP air defenses. -- -- ![Banner Image](..\Presentations\AI_A2A_DISPATCHER\Dia3.JPG) -- @@ -2088,18 +2090,18 @@ do -- With a little time and with a little work it provides the mission designer with a convincing and completely automatic air defence system. -- In short it is a plug in very flexible and configurable air defence module for DCS World. -- - -- Note that in order to create a two way A2A defense system, two AI\_A2A\_DISPATCHER_GCICAP defense system may need to be created, for each coalition one. + -- Note that in order to create a two way A2A defense system, two AI\_A2A\_GCICAP defense system may need to be created, for each coalition one. -- This is a good implementation, because maybe in the future, more coalitions may become available in DCS world. -- - -- ## 1. AI\_A2A\_DISPATCHER\_GCICAP constructor: + -- ## 1. AI\_A2A\_GCICAP constructor: -- - -- The @{#AI_A2A_DISPATCHER_GCICAP.New}() method creates a new AI\_A2A\_DISPATCHER\_GCICAP instance. + -- The @{#AI_A2A_GCICAP.New}() method creates a new AI\_A2A\_GCICAP instance. -- There are two parameters required, a list of prefix group names that collects the groups of the EWR network, and a radius in meters, -- that will be used to group the detected targets. -- -- ### 1.1. Define the **EWR network**: -- - -- As part of the AI\_A2A\_DISPATCHER\_GCICAP constructor, a list of prefixes must be given of the group names defined within the mission editor, + -- As part of the AI\_A2A\_GCICAP constructor, a list of prefixes must be given of the group names defined within the mission editor, -- that define the EWR network. -- -- An EWR network, or, Early Warning Radar network, is used to early detect potential airborne targets and to understand the position of patrolling targets of the enemy. @@ -2147,35 +2149,175 @@ do -- so all further documentation needs to be consulted in this class -- for documentation consistency. -- - -- @field #AI_A2A_DISPATCHER_GCICAP - AI_A2A_DISPATCHER_GCICAP = { - ClassName = "AI_A2A_DISPATCHER_GCICAP", + -- @field #AI_A2A_GCICAP + AI_A2A_GCICAP = { + ClassName = "AI_A2A_GCICAP", Detection = nil, } - --- AI_A2A_DISPATCHER_GCICAP constructor. - -- @param #AI_A2A_DISPATCHER_GCICAP self + --- AI_A2A_GCICAP constructor. + -- @param #AI_A2A_GCICAP self -- @param #list<#string> EWRPrefixes A list of prefixes that of groups that setup the Early Warning Radar network. -- @param #number GroupingRadius The radius in meters wherein detected planes are being grouped as one target area. -- For airplanes, 6000 (6km) is recommended, and is also the default value of this parameter. -- @return #AI_A2A_DISPATCHER_GCICAP -- @usage -- - -- -- Set a new AI A2A Dispatcher object, based on an EWR network with a 30 km grouping radius + -- -- Set a new AI A2A GCICAP object, based on an EWR network with a 30 km grouping radius -- -- This for ground and awacs installations. -- - -- A2ADispatcher = AI_A2A_DISPATCHER_GCICAP:New( { "BlueEWRGroundRadars", "BlueEWRAwacs" }, 30000 ) + -- A2ADispatcher = AI_A2A_GCICAP:New( { "BlueEWRGroundRadars", "BlueEWRAwacs" }, 30000 ) -- - function AI_A2A_DISPATCHER_GCICAP:New( EWRPrefixes, GroupingRadius ) + function AI_A2A_GCICAP:New( EWRPrefixes, TemplatePrefixes, CAPPrefixes, CapLimit, GroupingRadius, EngageRadius ) - local SetGroup = SET_GROUP:New() - SetGroup:FilterPrefixes( EWRPrefixes ) - SetGroup:FilterStart() + GroupingRadius = GroupingRadius or 30000 + EngageRadius = EngageRadius or 100000 - local Detection = DETECTION_AREAS:New( SetGroup, GroupingRadius ) + local EWRSetGroup = SET_GROUP:New() + EWRSetGroup:FilterPrefixes( EWRPrefixes ) + EWRSetGroup:FilterStart() - local self = BASE:Inherit( self, AI_A2A_DISPATCHER:New( Detection ) ) -- #AI_A2A_DISPATCHER_GCICAP + local Detection = DETECTION_AREAS:New( EWRSetGroup, GroupingRadius ) + + local self = BASE:Inherit( self, AI_A2A_DISPATCHER:New( Detection ) ) -- #AI_A2A_GCICAP + + self:SetEngageRadius( EngageRadius ) + + -- Determine the coalition of the EWRNetwork, this will be the coalition of the GCICAP. + local EWRFirst = EWRSetGroup:GetFirst() -- Wrapper.Group#GROUP + local EWRCoalition = EWRFirst:GetCoalition() + + + -- Determine the airbases belonging to the coalition. + local AirbaseNames = {} -- #list<#string> + for AirbaseID, AirbaseData in pairs( _DATABASE.AIRBASES ) do + local Airbase = AirbaseData -- Wrapper.Airbase#AIRBASE + local AirbaseName = Airbase:GetName() + if Airbase:GetCoalition() == EWRCoalition then + table.insert( AirbaseNames, AirbaseName ) + end + end + + self.Templates = SET_GROUP + :New() + :FilterPrefixes( TemplatePrefixes ) + :FilterOnce() + + -- Setup squadrons + + for AirbaseID, AirbaseName in pairs( AirbaseNames ) do + local Airbase = _DATABASE:FindAirbase( AirbaseName ) -- Wrapper.Airbase#AIRBASE + local AirbaseName = Airbase:GetName() + local AirbaseCoord = Airbase:GetCoordinate() + local AirbaseZone = ZONE_RADIUS:New( "Airbase", AirbaseCoord:GetVec2(), 10000 ) + local Templates = nil + for TemplateID, Template in pairs( self.Templates:GetSet() ) do + local Template = Template -- Wrapper.Group#GROUP + 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, 30 ) + end + end + + -- Setup CAP. + -- Find for each CAP the nearest airbase to the (start or center) of the zone. + -- CAP will be launched from there. + + 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 ) + -- Now find the closest airbase from the ZONE (start or center) + local AirbaseDistance = 99999999 + local AirbaseClosest = nil -- Wrapper.Airbase#AIRBASE + for AirbaseID, AirbaseName in pairs( AirbaseNames ) do + local Airbase = _DATABASE:FindAirbase( AirbaseName ) -- Wrapper.Airbase#AIRBASE + local AirbaseName = Airbase:GetName() + local AirbaseCoord = Airbase:GetCoordinate() + local Squadron = self.DefenderSquadrons[AirbaseName] + if Squadron then + local Distance = AirbaseCoord:Get2DDistance( CAPZone:GetCoordinate() ) + if Distance < AirbaseDistance then + AirbaseDistance = Distance + AirbaseClosest = Airbase + end + end + end + if AirbaseClosest then + self:SetSquadronCap( AirbaseClosest:GetName(), CAPZone, 6000, 10000, 500, 800, 800, 1200, "RADIO" ) + self:SetSquadronCapInterval( AirbaseClosest:GetName(), CapLimit, 300, 600, 1 ) + end + end + + -- Setup GCI. + -- GCI is setup for all Squadrons. + for AirbaseID, AirbaseName in pairs( AirbaseNames ) do + local Airbase = _DATABASE:FindAirbase( AirbaseName ) -- Wrapper.Airbase#AIRBASE + local AirbaseName = Airbase:GetName() + local Squadron = self.DefenderSquadrons[AirbaseName] + if Squadron then + self:SetSquadronGci( AirbaseName, 800, 1200 ) + end + end + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + self:__Start( 5 ) diff --git a/Moose Development/Moose/Core/Cargo.lua b/Moose Development/Moose/Core/Cargo.lua index 35a04f6e8..4da31341a 100644 --- a/Moose Development/Moose/Core/Cargo.lua +++ b/Moose Development/Moose/Core/Cargo.lua @@ -164,7 +164,7 @@ do -- CARGO -- @field #number Weight A number defining the weight of the cargo. The weight is expressed in kg. -- @field #number NearRadius (optional) A number defining the radius in meters when the cargo is near to a Carrier, so that it can be loaded. -- @field Wrapper.Controllable#CONTROLLABLE CargoObject The alive DCS object representing the cargo. This value can be nil, meaning, that the cargo is not represented anywhere... - -- @field Wrapper.Controllable#CONTROLLABLE CargoCarrier The alive DCS object carrying the cargo. This value can be nil, meaning, that the cargo is not contained anywhere... + -- @field Wrapper.Client#CLIENT CargoCarrier The alive DCS object carrying the cargo. This value can be nil, meaning, that the cargo is not contained anywhere... -- @field #boolean Slingloadable This flag defines if the cargo can be slingloaded. -- @field #boolean Moveable This flag defines if the cargo is moveable. -- @field #boolean Representable This flag defines if the cargo can be represented by a DCS Unit. @@ -210,8 +210,7 @@ do -- CARGO -- The state transition method needs to start with the name **OnEnter + the name of the state**. -- These state transition methods need to provide a return value, which is specified at the function description. -- - -- @field #CARGO CARGO - -- + -- @field #CARGO CARGO = { ClassName = "CARGO", Type = nil, @@ -251,6 +250,7 @@ function CARGO:New( Type, Name, Weight ) --R2.1 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" ) @@ -264,17 +264,26 @@ function CARGO:New( Type, Name, Weight ) --R2.1 self.Slingloadable = false self.Moveable = false self.Containable = false + + self:SetDeployed( false ) self.CargoScheduler = SCHEDULER:New() CARGOS[self.Name] = self - self:SetEventPriority( 5 ) - return self end +--- Destroy the cargo. +-- @param #CARGO self +function CARGO:Destroy() + if self.CargoObject then + self.CargoObject:Destroy() + end + self:Destroyed() +end + --- Get the name of the Cargo. -- @param #CARGO self -- @return #string The name of the Cargo. @@ -307,6 +316,13 @@ function CARGO:GetCoordinate() return self.CargoObject:GetCoordinate() end +--- Check if cargo is destroyed. +-- @param #CARGO self +-- @return #boolean true if destroyed +function CARGO:IsDestroyed() + return self:Is( "Destroyed" ) +end + --- Check if cargo is loaded. -- @param #CARGO self @@ -334,6 +350,19 @@ function CARGO:IsAlive() end end +--- Set the cargo as deployed +-- @param #CARGO self +function CARGO:SetDeployed( Deployed ) + self.Deployed = Deployed +end + +--- Is the cargo deployed +-- @param #CARGO self +-- @return #boolean +function CARGO:IsDeployed() + return self.Deployed +end + @@ -485,8 +514,12 @@ end -- CARGO_REPRESENTABLE local self = BASE:Inherit( self, CARGO:New( Type, Name, Weight ) ) -- #CARGO_REPORTABLE self:F( { Type, Name, Weight, ReportRadius } ) + self.CargoSet = SET_CARGO:New() -- Core.Set#SET_CARGO + self.ReportRadius = ReportRadius or 1000 self.CargoObject = CargoObject + + return self end @@ -516,7 +549,7 @@ end -- CARGO_REPRESENTABLE end --- Send a CC message to a GROUP. - -- @param #COMMANDCENTER self + -- @param #CARGO_REPORTABLE self -- @param #string Message -- @param Wrapper.Group#GROUP TaskGroup -- @param #sring Name (optional) The name of the Group used as a prefix for the message to the Group. If not provided, there will be nothing shown. @@ -529,12 +562,38 @@ end -- CARGO_REPRESENTABLE end --- Get the range till cargo will board. - -- @param #CARGO self + -- @param #CARGO_REPORTABLE self -- @return #number The range till cargo will board. function CARGO_REPORTABLE:GetBoardingRange() return self.ReportRadius end + + --- Respawn the cargo. + -- @param #CARGO_REPORTABLE self + function CARGO_REPORTABLE:Respawn() + self:F({"Respawning"}) + + for CargoID, CargoData in pairs( self.CargoSet:GetSet() ) do + local Cargo = CargoData -- #CARGO + Cargo:Destroy() + Cargo:SetStartState( "UnLoaded" ) + end + + local CargoObject = self.CargoObject -- Wrapper.Group#GROUP + CargoObject:Destroy() + local Template = CargoObject:GetTemplate() + CargoObject:Respawn( Template ) + + self:SetDeployed( false ) + + local WeightGroup = 0 + + self:SetStartState( "UnLoaded" ) + + end + + end do -- CARGO_UNIT @@ -574,16 +633,18 @@ function CARGO_UNIT:New( CargoUnit, Type, Name, Weight, NearRadius ) self:T( self.ClassName ) - self:HandleEvent( EVENTS.Dead, - --- @param #CARGO Cargo - -- @param Core.Event#EVENTDATA EventData - function( Cargo, EventData ) - if Cargo:GetObjectName() == EventData.IniUnit:GetName() then - self:E( { "Cargo destroyed", Cargo } ) - Cargo:Destroyed() - end - end - ) +-- self:HandleEvent( EVENTS.Dead, +-- --- @param #CARGO Cargo +-- -- @param Core.Event#EVENTDATA EventData +-- function( Cargo, EventData ) +-- if Cargo:GetObjectName() == EventData.IniUnit:GetName() then +-- self:E( { "Cargo destroyed", Cargo } ) +-- Cargo:Destroyed() +-- end +-- end +-- ) + + self:SetEventPriority( 5 ) return self end @@ -594,6 +655,7 @@ end function CARGO_UNIT:Destroy() -- Cargo objects are deleted from the _DATABASE and SET_CARGO objects. + self:F( { CargoName = self:GetName() } ) _EVENTDISPATCHER:CreateEventDeleteCargo( self ) return self @@ -921,9 +983,9 @@ function CARGO_GROUP:New( CargoGroup, Type, Name, ReportRadius ) local self = BASE:Inherit( self, CARGO_REPORTABLE:New( CargoGroup, Type, Name, 0, ReportRadius ) ) -- #CARGO_GROUP self:F( { Type, Name, ReportRadius } ) - self.CargoSet = SET_CARGO:New() - self.CargoObject = CargoGroup + self:SetDeployed( false ) + self.CargoGroup = CargoGroup local WeightGroup = 0 @@ -942,9 +1004,45 @@ function CARGO_GROUP:New( CargoGroup, Type, Name, ReportRadius ) -- Cargo objects are added to the _DATABASE and SET_CARGO objects. _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 +--- @param #CARGO Cargo +-- @param Core.Event#EVENTDATA EventData +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 -- #CARGO + if Cargo:IsAlive() then + Destroyed = false + else + Cargo:Destroyed() + end + end + else + if self.CargoCarrier:GetName() == EventData.IniUnitName then + Destroyed = true + self.CargoCarrier:ClearCargo() + end + end + + if Destroyed then + self:Destroyed() + self:E( { "Cargo group destroyed" } ) + end + +end + --- Enter Boarding State. -- @param #CARGO_GROUP self -- @param Wrapper.Unit#UNIT CargoCarrier @@ -986,7 +1084,7 @@ function CARGO_GROUP:onenterLoaded( From, Event, To, CargoCarrier, ... ) end end - self.CargoObject:Destroy() + --self.CargoObject:Destroy() self.CargoCarrier = CargoCarrier end @@ -1042,6 +1140,14 @@ function CARGO_GROUP:onafterBoarding( From, Event, To, CargoCarrier, NearRadius, end +--- Get the amount of cargo units in the group. +-- @param #CARGO_GROUP self +-- @return #CARGO_GROUP +function CARGO_GROUP:GetCount() + return self.CargoSet:Count() +end + + --- Enter UnBoarding State. -- @param #CARGO_GROUP self -- @param Core.Point#POINT_VEC2 ToPointVec2 @@ -1147,6 +1253,23 @@ function CARGO_GROUP:onenterUnLoaded( From, Event, To, ToPointVec2, ... ) end + + --- Respawn the cargo when destroyed + -- @param #CARGO_GROUP self + -- @param #boolean RespawnDestroyed + 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 -- CARGO_GROUP do -- CARGO_PACKAGE diff --git a/Moose Development/Moose/Core/Database.lua b/Moose Development/Moose/Core/Database.lua index b4a9319b9..f537e0cb4 100644 --- a/Moose Development/Moose/Core/Database.lua +++ b/Moose Development/Moose/Core/Database.lua @@ -214,6 +214,16 @@ function DATABASE:FindStatic( StaticName ) return StaticFound end +--- Finds a AIRBASE based on the AirbaseName. +-- @param #DATABASE self +-- @param #string AirbaseName +-- @return Wrapper.Airbase#AIRBASE The found AIRBASE. +function DATABASE:FindAirbase( AirbaseName ) + + local AirbaseFound = self.AIRBASES[AirbaseName] + return AirbaseFound +end + --- Adds a Airbase based on the Airbase Name in the DATABASE. -- @param #DATABASE self -- @param #string AirbaseName The name of the airbase diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index bb36cabe8..9b0dfb64f 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -804,7 +804,7 @@ do -- COORDINATE local IsAir = Controllable and Controllable:IsAirPlane() or false if IsAir then - if Settings:IsA2A_BRA() then + if Settings:IsA2A_BRAA() then local Coordinate = Controllable:GetCoordinate() return self:ToStringBRA( Coordinate, Settings ) end @@ -814,7 +814,7 @@ do -- COORDINATE return self:ToStringBULLS( Coalition, Settings ) end else - if Settings:IsA2G_BRA() then + if Settings:IsA2G_BR() then local Coordinate = Controllable:GetCoordinate() return Controllable and self:ToStringBR( Coordinate, Settings ) or self:ToStringMGRS( Settings ) end diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua index 0152e5cb8..3b8ece2df 100644 --- a/Moose Development/Moose/Core/Set.lua +++ b/Moose Development/Moose/Core/Set.lua @@ -2748,13 +2748,13 @@ SET_CARGO = { --- (R2.1) Creates a new SET_CARGO object, building a set of cargos belonging to a coalitions and categories. -- @param #SET_CARGO self --- @return #SET_CARGO self +-- @return #SET_CARGO -- @usage -- -- Define a new SET_CARGO Object. The DatabaseSet will contain a reference to all Cargos. -- DatabaseSet = SET_CARGO:New() function SET_CARGO:New() --R2.1 -- Inherits from BASE - local self = BASE:Inherit( self, SET_BASE:New( _DATABASE.CARGOS ) ) + local self = BASE:Inherit( self, SET_BASE:New( _DATABASE.CARGOS ) ) -- #SET_CARGO return self end diff --git a/Moose Development/Moose/Core/Settings.lua b/Moose Development/Moose/Core/Settings.lua index dc0926ba5..5bb5db0dc 100644 --- a/Moose Development/Moose/Core/Settings.lua +++ b/Moose Development/Moose/Core/Settings.lua @@ -56,7 +56,7 @@ do -- SETTINGS local self = BASE:Inherit( self, BASE:New() ) -- #SETTINGS self:SetMetric() -- Defaults self:SetA2G_MGRS() -- Defaults - self:SetA2A_BRA() -- Defaults + self:SetA2A_BRAA() -- Defaults self:SetLL_Accuracy( 2 ) -- Defaults self:SetLL_DMS( true ) -- Defaults self:SetMGRS_Accuracy( 5 ) -- Defaults @@ -179,31 +179,31 @@ do -- SETTINGS --- Sets A2G BRA -- @param #SETTINGS self -- @return #SETTINGS - function SETTINGS:SetA2G_BRA() - self.A2GSystem = "BRA" + function SETTINGS:SetA2G_BR() + self.A2GSystem = "BR" end --- Is BRA -- @param #SETTINGS self -- @return #boolean true if BRA - function SETTINGS:IsA2G_BRA() - self:E( { BRA = ( self.A2GSystem and self.A2GSystem == "BRA" ) or ( not self.A2GSystem and _SETTINGS:IsA2G_BRA() ) } ) - return ( self.A2GSystem and self.A2GSystem == "BRA" ) or ( not self.A2GSystem and _SETTINGS:IsA2G_BRA() ) + function SETTINGS:IsA2G_BR() + self:E( { BRA = ( self.A2GSystem and self.A2GSystem == "BR" ) or ( not self.A2GSystem and _SETTINGS:IsA2G_BR() ) } ) + return ( self.A2GSystem and self.A2GSystem == "BR" ) or ( not self.A2GSystem and _SETTINGS:IsA2G_BR() ) end --- Sets A2A BRA -- @param #SETTINGS self -- @return #SETTINGS - function SETTINGS:SetA2A_BRA() - self.A2ASystem = "BRA" + function SETTINGS:SetA2A_BRAA() + self.A2ASystem = "BRAA" end --- Is BRA -- @param #SETTINGS self -- @return #boolean true if BRA - function SETTINGS:IsA2A_BRA() - self:E( { BRA = ( self.A2ASystem and self.A2ASystem == "BRA" ) or ( not self.A2ASystem and _SETTINGS:IsA2A_BRA() ) } ) - return ( self.A2ASystem and self.A2ASystem == "BRA" ) or ( not self.A2ASystem and _SETTINGS:IsA2A_BRA() ) + 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 --- Sets A2A BULLS @@ -222,66 +222,62 @@ do -- SETTINGS --- @param #SETTINGS self -- @return #SETTINGS - function SETTINGS:SetSystemMenu( RootMenu, MenuText ) + function SETTINGS:SetSystemMenu( MenuGroup, RootMenu ) - MenuText = MenuText or "System Settings" - - if not self.SettingsMenu then - self.SettingsMenu = MENU_MISSION:New( MenuText, RootMenu ) - end - - if self.DefaultMenu then - self.DefaultMenu:Remove() - self.DefaultMenu = nil - end - self.DefaultMenu = MENU_MISSION:New( "Default Settings", self.SettingsMenu ) + local MenuText = "System Settings" - local A2GCoordinateMenu = MENU_MISSION:New( "A2G Coordinate System", self.DefaultMenu ) + 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 self:IsA2G_LL() then - MENU_MISSION_COMMAND:New( "Activate BRA", A2GCoordinateMenu, self.A2GMenuSystem, self, "BRA" ) - MENU_MISSION_COMMAND:New( "Activate MGRS", A2GCoordinateMenu, self.A2GMenuSystem, self, "MGRS" ) - MENU_MISSION_COMMAND:New( "LL Accuracy 1", A2GCoordinateMenu, self.MenuLL_Accuracy, self, 1 ) - MENU_MISSION_COMMAND:New( "LL Accuracy 2", A2GCoordinateMenu, self.MenuLL_Accuracy, self, 2 ) - MENU_MISSION_COMMAND:New( "LL Accuracy 3", A2GCoordinateMenu, self.MenuLL_Accuracy, self, 3 ) - MENU_MISSION_COMMAND:New( "LL Decimal On", A2GCoordinateMenu, self.MenuLL_DMS, self, true ) - MENU_MISSION_COMMAND:New( "LL Decimal Off", A2GCoordinateMenu, self.MenuLL_DMS, self, false ) + MENU_GROUP_COMMAND:New( MenuGroup, "Bearing, Range (BR)", A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "BR" ):SetTime( MenuTime ) + MENU_GROUP_COMMAND:New( MenuGroup, "Military Grid (MGRS)", A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "MGRS" ):SetTime( MenuTime ) + MENU_GROUP_COMMAND:New( MenuGroup, "Lattitude Longitude (LL) Accuracy 1", A2GCoordinateMenu, self.MenuLL_Accuracy, self, MenuGroup, RootMenu, 1 ):SetTime( MenuTime ) + MENU_GROUP_COMMAND:New( MenuGroup, "Lattitude Longitude (LL) Accuracy 2", A2GCoordinateMenu, self.MenuLL_Accuracy, self, MenuGroup, RootMenu, 2 ):SetTime( MenuTime ) + MENU_GROUP_COMMAND:New( MenuGroup, "Lattitude Longitude (LL) Accuracy 3", A2GCoordinateMenu, self.MenuLL_Accuracy, self, MenuGroup, RootMenu, 3 ):SetTime( MenuTime ) + MENU_GROUP_COMMAND:New( MenuGroup, "Lattitude Longitude (LL) Decimal On", A2GCoordinateMenu, self.MenuLL_DMS, self, MenuGroup, RootMenu, true ):SetTime( MenuTime ) + MENU_GROUP_COMMAND:New( MenuGroup, "Lattitude Longitude (LL) Decimal Off", A2GCoordinateMenu, self.MenuLL_DMS, self, MenuGroup, RootMenu, false ):SetTime( MenuTime ) end if self:IsA2G_MGRS() then - MENU_MISSION_COMMAND:New( "Activate BRA", A2GCoordinateMenu, self.A2GMenuSystem, self, "BRA" ) - MENU_MISSION_COMMAND:New( "Activate LL", A2GCoordinateMenu, self.A2GMenuSystem, self, "LL" ) - MENU_MISSION_COMMAND:New( "MGRS Accuracy 1", A2GCoordinateMenu, self.MenuMGRS_Accuracy, self, 1 ) - MENU_MISSION_COMMAND:New( "MGRS Accuracy 2", A2GCoordinateMenu, self.MenuMGRS_Accuracy, self, 2 ) - MENU_MISSION_COMMAND:New( "MGRS Accuracy 3", A2GCoordinateMenu, self.MenuMGRS_Accuracy, self, 3 ) - MENU_MISSION_COMMAND:New( "MGRS Accuracy 4", A2GCoordinateMenu, self.MenuMGRS_Accuracy, self, 4 ) - MENU_MISSION_COMMAND:New( "MGRS Accuracy 5", A2GCoordinateMenu, self.MenuMGRS_Accuracy, self, 5 ) + MENU_GROUP_COMMAND:New( MenuGroup, "Bearing, Range (BR)", A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "BR" ):SetTime( MenuTime ) + MENU_GROUP_COMMAND:New( MenuGroup, "Lattitude Longitude (LL)", A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "LL" ):SetTime( MenuTime ) + MENU_GROUP_COMMAND:New( MenuGroup, "Military Grid (MGRS) Accuracy 1", A2GCoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 1 ):SetTime( MenuTime ) + MENU_GROUP_COMMAND:New( MenuGroup, "Military Grid (MGRS) Accuracy 2", A2GCoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 2 ):SetTime( MenuTime ) + MENU_GROUP_COMMAND:New( MenuGroup, "Military Grid (MGRS) Accuracy 3", A2GCoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 3 ):SetTime( MenuTime ) + MENU_GROUP_COMMAND:New( MenuGroup, "Military Grid (MGRS) Accuracy 4", A2GCoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 4 ):SetTime( MenuTime ) + MENU_GROUP_COMMAND:New( MenuGroup, "Military Grid (MGRS) Accuracy 5", A2GCoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 5 ):SetTime( MenuTime ) end - if self:IsA2G_BRA() then - MENU_MISSION_COMMAND:New( "Activate MGRS", A2GCoordinateMenu, self.A2GMenuSystem, self, "MGRS" ) - MENU_MISSION_COMMAND:New( "Activate LL", A2GCoordinateMenu, self.A2GMenuSystem, self, "LL" ) + if self:IsA2G_BR() then + MENU_GROUP_COMMAND:New( MenuGroup, "Military Grid (MGRS)", A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "MGRS" ):SetTime( MenuTime ) + MENU_GROUP_COMMAND:New( MenuGroup, "Lattitude Longitude (LL)", A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "LL" ):SetTime( MenuTime ) end - local A2ACoordinateMenu = MENU_MISSION:New( "A2A Coordinate System", self.DefaultMenu ) + local A2ACoordinateMenu = MENU_GROUP:New( MenuGroup, "A2A Coordinate System", SettingsMenu ):SetTime( MenuTime ) if self:IsA2A_BULLS() then - MENU_MISSION_COMMAND:New( "Activate BRA", A2ACoordinateMenu, self.A2AMenuSystem, self, "BRA" ) + MENU_GROUP_COMMAND:New( MenuGroup, "Bearing Range Altitude Aspect (BRAA)", A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "BRAA" ):SetTime( MenuTime ) end - if self:IsA2A_BRA() then - MENU_MISSION_COMMAND:New( "Activate BULLS", A2ACoordinateMenu, self.A2AMenuSystem, self, "BULLS" ) + if self:IsA2A_BRAA() then + MENU_GROUP_COMMAND:New( MenuGroup, "Bullseye (BULLS)", A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "BULLS" ):SetTime( MenuTime ) end - local MetricsMenu = MENU_MISSION:New( "Measures and Weights System", self.DefaultMenu ) + local MetricsMenu = MENU_GROUP:New( MenuGroup, "Measures and Weights System", SettingsMenu ):SetTime( MenuTime ) if self:IsMetric() then - MENU_MISSION_COMMAND:New( "Activate Imperial", MetricsMenu, self.MenuMWSystem, self, false ) + MENU_GROUP_COMMAND:New( MenuGroup, "Imperial (Miles,Feet)", MetricsMenu, self.MenuMWSystem, self, MenuGroup, RootMenu, false ):SetTime( MenuTime ) end if self:IsImperial() then - MENU_MISSION_COMMAND:New( "Activate Metric", MetricsMenu, self.MenuMWSystem, self, true ) + MENU_GROUP_COMMAND:New( MenuGroup, "Metric (Kilometers,Meters)", MetricsMenu, self.MenuMWSystem, self, MenuGroup, RootMenu, true ):SetTime( MenuTime ) end + + SettingsMenu:Remove( MenuTime ) return self end @@ -293,65 +289,59 @@ do -- SETTINGS -- @return #SETTINGS function SETTINGS:SetPlayerMenu( PlayerUnit ) - local MenuText = "Player Settings" - self.MenuText = MenuText - - local SettingsMenu = _SETTINGS.SettingsMenu - local PlayerGroup = PlayerUnit:GetGroup() local PlayerName = PlayerUnit:GetPlayerName() local PlayerNames = PlayerGroup:GetPlayerNames() - local GroupMenu = MENU_GROUP:New( PlayerGroup, MenuText, SettingsMenu ) - local PlayerMenu = MENU_GROUP:New( PlayerGroup, 'Settings "' .. PlayerName .. '"', GroupMenu ) + local PlayerMenu = MENU_GROUP:New( PlayerGroup, 'Settings "' .. PlayerName .. '"' ) self.PlayerMenu = PlayerMenu local A2GCoordinateMenu = MENU_GROUP:New( PlayerGroup, "A2G Coordinate System", PlayerMenu ) if self:IsA2G_LL() then - MENU_GROUP_COMMAND:New( PlayerGroup, "Activate BRA", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "BRA" ) - MENU_GROUP_COMMAND:New( PlayerGroup, "Activate MGRS", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "MGRS" ) - MENU_GROUP_COMMAND:New( PlayerGroup, "LL Accuracy 1", A2GCoordinateMenu, self.MenuGroupLL_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 1 ) - MENU_GROUP_COMMAND:New( PlayerGroup, "LL Accuracy 2", A2GCoordinateMenu, self.MenuGroupLL_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 2 ) - MENU_GROUP_COMMAND:New( PlayerGroup, "LL Accuracy 3", A2GCoordinateMenu, self.MenuGroupLL_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 3 ) - MENU_GROUP_COMMAND:New( PlayerGroup, "LL Decimal On", A2GCoordinateMenu, self.MenuGroupLL_DMSSystem, self, PlayerUnit, PlayerGroup, PlayerName, true ) - MENU_GROUP_COMMAND:New( PlayerGroup, "LL Decimal Off", A2GCoordinateMenu, self.MenuGroupLL_DMSSystem, self, PlayerUnit, PlayerGroup, PlayerName, false ) + MENU_GROUP_COMMAND:New( PlayerGroup, "Bearing, Range (BR)", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "BR" ) + MENU_GROUP_COMMAND:New( PlayerGroup, "Military Grid (MGRS)", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "MGRS" ) + MENU_GROUP_COMMAND:New( PlayerGroup, "Lattitude Longitude (LL) Accuracy 1", A2GCoordinateMenu, self.MenuGroupLL_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 1 ) + MENU_GROUP_COMMAND:New( PlayerGroup, "Lattitude Longitude (LL) Accuracy 2", A2GCoordinateMenu, self.MenuGroupLL_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 2 ) + MENU_GROUP_COMMAND:New( PlayerGroup, "Lattitude Longitude (LL) Accuracy 3", A2GCoordinateMenu, self.MenuGroupLL_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 3 ) + MENU_GROUP_COMMAND:New( PlayerGroup, "Lattitude Longitude (LL) Decimal On", A2GCoordinateMenu, self.MenuGroupLL_DMSSystem, self, PlayerUnit, PlayerGroup, PlayerName, true ) + MENU_GROUP_COMMAND:New( PlayerGroup, "Lattitude Longitude (LL) Decimal Off", A2GCoordinateMenu, self.MenuGroupLL_DMSSystem, self, PlayerUnit, PlayerGroup, PlayerName, false ) end if self:IsA2G_MGRS() then - MENU_GROUP_COMMAND:New( PlayerGroup, "Activate BRA", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "BRA" ) - MENU_GROUP_COMMAND:New( PlayerGroup, "Activate LL", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL" ) - 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 ) + MENU_GROUP_COMMAND:New( PlayerGroup, "Bearing Range (BR)", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "BR" ) + MENU_GROUP_COMMAND:New( PlayerGroup, "Lattitude Longitude (LL)", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL" ) + MENU_GROUP_COMMAND:New( PlayerGroup, "Military Grid (MGRS) Accuracy 1", A2GCoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 1 ) + MENU_GROUP_COMMAND:New( PlayerGroup, "Military Grid (MGRS) Accuracy 2", A2GCoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 2 ) + MENU_GROUP_COMMAND:New( PlayerGroup, "Military Grid (MGRS) Accuracy 3", A2GCoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 3 ) + MENU_GROUP_COMMAND:New( PlayerGroup, "Military Grid (MGRS) Accuracy 4", A2GCoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 4 ) + MENU_GROUP_COMMAND:New( PlayerGroup, "Military Grid (MGRS) Accuracy 5", A2GCoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 5 ) end - if self:IsA2G_BRA() then - MENU_GROUP_COMMAND:New( PlayerGroup, "Activate MGRS", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "MGRS" ) - MENU_GROUP_COMMAND:New( PlayerGroup, "Activate LL", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL" ) + if self:IsA2G_BR() then + MENU_GROUP_COMMAND:New( PlayerGroup, "Military Grid (MGRS)", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "MGRS" ) + MENU_GROUP_COMMAND:New( PlayerGroup, "Lattitude Longitude (LL)", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL" ) end local A2ACoordinateMenu = MENU_GROUP:New( PlayerGroup, "A2A Coordinate System", PlayerMenu ) if self:IsA2A_BULLS() then - MENU_GROUP_COMMAND:New( PlayerGroup, "Activate BRA", A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "BRA" ) + MENU_GROUP_COMMAND:New( PlayerGroup, "Bearing Range Altitude Aspect (BRAA)", A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "BRAA" ) end - if self:IsA2A_BRA() then - MENU_GROUP_COMMAND:New( PlayerGroup, "Activate BULLS", A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "BULLS" ) + if self:IsA2A_BRAA() then + MENU_GROUP_COMMAND:New( PlayerGroup, "Bullseye (BULLS)", A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "BULLS" ) end local MetricsMenu = MENU_GROUP:New( PlayerGroup, "Measures and Weights System", PlayerMenu ) if self:IsMetric() then - MENU_GROUP_COMMAND:New( PlayerGroup, "Activate Imperial", MetricsMenu, self.MenuGroupMWSystem, self, PlayerUnit, PlayerGroup, PlayerName, false ) + 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, "Activate Metric", MetricsMenu, self.MenuGroupMWSystem, self, PlayerUnit, PlayerGroup, PlayerName, true ) + MENU_GROUP_COMMAND:New( PlayerGroup, "Metric (Kilometers,Meters)", MetricsMenu, self.MenuGroupMWSystem, self, PlayerUnit, PlayerGroup, PlayerName, true ) end return self @@ -372,40 +362,45 @@ do -- SETTINGS --- @param #SETTINGS self - function SETTINGS:A2GMenuSystem( A2GSystem ) + function SETTINGS:A2GMenuSystem( MenuGroup, RootMenu, A2GSystem ) self.A2GSystem = A2GSystem - self:SetSystemMenu() + MESSAGE:New( string.format("Settings: Default A2G coordinate system set to %s for all players!.", A2GSystem ), 5 ):ToAll() + self:SetSystemMenu( MenuGroup, RootMenu ) end --- @param #SETTINGS self - function SETTINGS:A2AMenuSystem( A2ASystem ) + function SETTINGS:A2AMenuSystem( MenuGroup, RootMenu, A2ASystem ) self.A2ASystem = A2ASystem - self:SetSystemMenu() + MESSAGE:New( string.format("Settings: Default A2A coordinate system set to %s for all players!.", A2ASystem ), 5 ):ToAll() + self:SetSystemMenu( MenuGroup, RootMenu ) end --- @param #SETTINGS self - function SETTINGS:MenuLL_Accuracy( LL_Accuracy ) + function SETTINGS:MenuLL_Accuracy( MenuGroup, RootMenu, LL_Accuracy ) self.LL_Accuracy = LL_Accuracy - self:SetSystemMenu() + MESSAGE:New( string.format("Settings: Default LL accuracy set to %s for all players!.", LL_Accuracy ), 5 ):ToAll() + self:SetSystemMenu( MenuGroup, RootMenu ) end --- @param #SETTINGS self - function SETTINGS:MenuLL_DMS( LL_DMS ) + function SETTINGS:MenuLL_DMS( MenuGroup, RootMenu, LL_DMS ) self.LL_DMS = LL_DMS - self:SetSystemMenu() + MESSAGE:New( string.format("Settings: Default LL format set to %s for all players!.", LL_DMS or "Decimal" or "HMS" ), 5 ):ToAll() + self:SetSystemMenu( MenuGroup, RootMenu ) end --- @param #SETTINGS self - function SETTINGS:MenuMGRS_Accuracy( MGRS_Accuracy ) + function SETTINGS:MenuMGRS_Accuracy( MenuGroup, RootMenu, MGRS_Accuracy ) self.MGRS_Accuracy = MGRS_Accuracy - self:SetSystemMenu() + MESSAGE:New( string.format("Settings: Default MGRS accuracy set to %s for all players!.", MGRS_Accuracy ), 5 ):ToAll() + self:SetSystemMenu( MenuGroup, RootMenu ) end --- @param #SETTINGS self - function SETTINGS:MenuMWSystem( MW ) + 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() + self:SetSystemMenu( MenuGroup, RootMenu ) end do @@ -437,7 +432,7 @@ do -- SETTINGS --- @param #SETTINGS self function SETTINGS:MenuGroupLL_DMSSystem( PlayerUnit, PlayerGroup, PlayerName, LL_DMS ) self.LL_DMS = LL_DMS - MESSAGE:New( string.format("Settings: A2G LL format mode set to %s for player %s.", LL_DMS and "DMS" or "HMS", PlayerName ), 5 ):ToGroup( PlayerGroup ) + MESSAGE:New( string.format("Settings: A2G LL format mode set to %s for player %s.", LL_DMS and "Decimal" or "HMS", PlayerName ), 5 ):ToGroup( PlayerGroup ) self:RemovePlayerMenu(PlayerUnit) self:SetPlayerMenu(PlayerUnit) end diff --git a/Moose Development/Moose/Functional/CleanUp.lua b/Moose Development/Moose/Functional/CleanUp.lua index 3f9425ac0..6ba990e96 100644 --- a/Moose Development/Moose/Functional/CleanUp.lua +++ b/Moose Development/Moose/Functional/CleanUp.lua @@ -58,8 +58,14 @@ -- -- ## 2. Add or Remove airbases -- --- The method @{#CLEANUP.AddAirbase} to add an airbase to the cleanup validation process. --- The method @{#CLEANUP.RemoveAirbase} removes an airbase from the cleanup validation process. +-- The method @{#CLEANUP.AddAirbase}() to add an airbase to the cleanup validation process. +-- The method @{#CLEANUP.RemoveAirbase}() removes an airbase from the cleanup validation process. +-- +-- ## 3. Clean missiles and bombs within the airbase zone. +-- +-- When missiles or bombs hit the runway, the airbase operations stop. +-- Use the method @{#CLEANUP.SetCleanMissiles}() to control the cleaning of missiles, which will prevent airbases to stop. +-- Note that this method will not allow anymore airbases to be attacked, so there is a trade-off here to do. -- -- @field #CLEANUP CLEANUP = { @@ -101,6 +107,13 @@ function CLEANUP:New( AirbaseNames ) 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 @@ -125,7 +138,24 @@ function CLEANUP:RemoveAirbase( AirbaseName ) return self end +--- Enables or disables the cleaning of missiles within the airbase zones. +-- Airbase operations stop when a missile or bomb is dropped at a runway. +-- Note that when this method is used, the airbase operations won't stop if +-- the missile or bomb was cleaned within the airbase zone, which is 8km from the center of the airbase. +-- However, there is a trade-off to make. Attacks on airbases won't be possible anymore if this method is used. +-- Note, one can also use the method @{#CLEANUP.RemoveAirbase}() to remove the airbase from the control process as a whole, +-- when an enemy unit is near. That is also an option... +-- @param #CLEANUP self +-- @param #string CleanMissiles (Default=true) If true, missiles fired are immediately destroyed. If false missiles are not controlled. +-- @return #CLEANUP +function CLEANUP:SetCleanMissiles( CleanMissiles ) + if CleanMissiles or true then + self:HandleEvent( EVENTS.Shot, self.__.OnEventShot ) + else + self:UnHandleEvent( EVENTS.Shot ) + end +end function CLEANUP.__:IsInAirbase( Vec2 ) @@ -191,14 +221,6 @@ function CLEANUP.__:OnEventBirth( EventData ) self.CleanUpList[EventData.IniDCSUnitName].CleanUpGroupName = EventData.IniDCSGroupName self.CleanUpList[EventData.IniDCSUnitName].CleanUpUnitName = EventData.IniDCSUnitName - 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 ) - self:HandleEvent( EVENTS.Shot, self.__.OnEventShot ) - end diff --git a/Moose Development/Moose/Functional/Scoring.lua b/Moose Development/Moose/Functional/Scoring.lua index e6350df6e..08289fd79 100644 --- a/Moose Development/Moose/Functional/Scoring.lua +++ b/Moose Development/Moose/Functional/Scoring.lua @@ -634,10 +634,10 @@ function SCORING:_AddPlayerFromUnit( UnitData ) end if self.Players[PlayerName].Penalty > self.Fratricide then - --UnitData:Destroy() MESSAGE:New( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' committed FRATRICIDE, he will be COURT MARTIALED and is DISMISSED from this mission!", 10 ):ToAll() + UnitData:Destroy() end end diff --git a/Moose Development/Moose/Moose.lua b/Moose Development/Moose/Moose.lua index c0484b05f..25308e705 100644 --- a/Moose Development/Moose/Moose.lua +++ b/Moose Development/Moose/Moose.lua @@ -10,4 +10,4 @@ _SCHEDULEDISPATCHER = SCHEDULEDISPATCHER:New() -- Core.Timer#SCHEDULEDISPATCHER _DATABASE = DATABASE:New() -- Core.Database#DATABASE _SETTINGS = SETTINGS:Set() -_SETTINGS:SetSystemMenu( nil ) + diff --git a/Moose Development/Moose/Tasking/CommandCenter.lua b/Moose Development/Moose/Tasking/CommandCenter.lua index 28688a32f..9c9139f9f 100644 --- a/Moose Development/Moose/Tasking/CommandCenter.lua +++ b/Moose Development/Moose/Tasking/CommandCenter.lua @@ -260,6 +260,8 @@ function COMMANDCENTER:New( CommandCenterPositionable, CommandCenterName ) ) self:SetMenu() + + _SETTINGS:SetSystemMenu( CommandCenterPositionable ) return self end diff --git a/Moose Development/Moose/Tasking/Mission.lua b/Moose Development/Moose/Tasking/Mission.lua index 0c5633ea9..832dd9d6c 100644 --- a/Moose Development/Moose/Tasking/Mission.lua +++ b/Moose Development/Moose/Tasking/Mission.lua @@ -450,7 +450,7 @@ do -- Group Assignment local MissionGroupName = MissionGroup:GetName() self.AssignedGroups[MissionGroupName] = nil - self:E( string.format( "Mission %s is unassigned to %s", MissionName, MissionGroupName ) ) + --self:E( string.format( "Mission %s is unassigned to %s", MissionName, MissionGroupName ) ) return self end diff --git a/Moose Development/Moose/Tasking/Task.lua b/Moose Development/Moose/Tasking/Task.lua index 7d16fbf05..93522f3f0 100644 --- a/Moose Development/Moose/Tasking/Task.lua +++ b/Moose Development/Moose/Tasking/Task.lua @@ -309,7 +309,7 @@ function TASK:AbortGroup( PlayerGroup ) self:E( { IsGroupAssigned = IsGroupAssigned } ) if IsGroupAssigned then local PlayerName = PlayerGroup:GetUnit(1):GetPlayerName() - self:MessageToGroups( PlayerName .. " aborted Task " .. self:GetName() ) + --self:MessageToGroups( PlayerName .. " aborted Task " .. self:GetName() ) self:UnAssignFromGroup( PlayerGroup ) --self:Abort() @@ -469,7 +469,7 @@ do -- Group Assignment local TaskGroupName = TaskGroup:GetName() self.AssignedGroups[TaskGroupName] = nil - self:E( string.format( "Task %s is unassigned to %s", TaskName, TaskGroupName ) ) + --self:E( string.format( "Task %s is unassigned to %s", TaskName, TaskGroupName ) ) -- Set the group to be assigned at mission level. This allows to decide the menu options on mission level for this group. self:GetMission():ClearGroupAssignment( TaskGroup ) @@ -1365,8 +1365,8 @@ function TASK:ReportOverview( ReportGroup ) --R2.1 fixed report. Now nicely form -- List the name of the Task. - local Name = self:GetName() - local Report = REPORT:New( Name ) + local TaskName = self:GetName() + local Report = REPORT:New() -- Determine the status of the Task. local Status = "<" .. self:GetState() .. ">" @@ -1379,7 +1379,11 @@ function TASK:ReportOverview( ReportGroup ) --R2.1 fixed report. Now nicely form self:F( { TaskInfo = TaskInfo } ) if Line < math.floor( TaskInfo.TaskInfoOrder / 10 ) then - Report:AddIndent( LineReport:Text( ", " ) ) + if Line ~= 0 then + Report:AddIndent( LineReport:Text( ", " ) ) + else + Report:Add( TaskName .. ":" .. LineReport:Text( ", " )) + end LineReport = REPORT:New() Line = math.floor( TaskInfo.TaskInfoOrder / 10 ) end diff --git a/Moose Development/Moose/Tasking/Task_CARGO.lua b/Moose Development/Moose/Tasking/Task_CARGO.lua index 368bf9d26..77b17c4bc 100644 --- a/Moose Development/Moose/Tasking/Task_CARGO.lua +++ b/Moose Development/Moose/Tasking/Task_CARGO.lua @@ -161,10 +161,15 @@ do -- TASK_CARGO self.TaskType = TaskType self.SmokeColor = SMOKECOLOR.Red + self.CargoItemCount = {} -- Map of Carriers having a cargo item count to check the cargo loading limits. + self.CargoLimit = 2 + self.DeployZones = {} -- setmetatable( {}, { __mode = "v" } ) -- weak table on value local Fsm = self:GetUnitProcess() + + Fsm:SetStartState( "Planned" ) Fsm:AddProcess ( "Planned", "Accept", ACT_ASSIGN_ACCEPT:New( self.TaskBriefing ), { Assigned = "SelectAction", Rejected = "Reject" } ) @@ -202,12 +207,19 @@ do -- TASK_CARGO -- @param Wrapper.Unit#UNIT TaskUnit -- @param Tasking.Task_CARGO#TASK_CARGO Task function Fsm:onafterSelectAction( TaskUnit, Task ) - self:E( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } ) + + 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:GetMission():GetCommandCenter():MessageToGroup( "Cargo in carrier: " .. CargoItemCount, TaskUnit:GetGroup() ) + Task.SetCargo:ForEachCargo( @@ -226,51 +238,35 @@ do -- TASK_CARGO -- Cargo -- ):SetTime(MenuTime) -- end + + if Cargo:IsUnLoaded() then - if Cargo:IsInRadius( TaskUnit:GetPointVec2() ) then - MENU_GROUP_COMMAND:New( - TaskUnit:GetGroup(), - "Board cargo " .. Cargo.Name, - TaskUnit.Menu, - self.MenuBoardCargo, - self, - Cargo - ):SetTime(MenuTime) - else - MENU_GROUP_COMMAND:New( - TaskUnit:GetGroup(), - "Route to Pickup cargo " .. Cargo.Name, - TaskUnit.Menu, - self.MenuRouteToPickup, - self, - Cargo - ):SetTime(MenuTime) + if CargoItemCount < Task.CargoLimit then + if Cargo:IsInRadius( TaskUnit:GetPointVec2() ) then + local NotInDeployZones = true + for DeployZoneName, DeployZone in pairs( Task.DeployZones ) do + if Cargo:IsInZone( DeployZone ) then + NotInDeployZones = false + end + end + if NotInDeployZones then + MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), "Board cargo " .. Cargo.Name, TaskUnit.Menu, self.MenuBoardCargo, self, Cargo ):SetTime(MenuTime) + end + else + MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), "Route to Pickup cargo " .. Cargo.Name, TaskUnit.Menu, self.MenuRouteToPickup, self, Cargo ):SetTime(MenuTime) + end end end if Cargo:IsLoaded() then - MENU_GROUP_COMMAND:New( - TaskUnit:GetGroup(), - "Unboard cargo " .. Cargo.Name, - TaskUnit.Menu, - self.MenuUnBoardCargo, - self, - Cargo - ):SetTime(MenuTime) + MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), "Unboard cargo " .. Cargo.Name, TaskUnit.Menu, self.MenuUnBoardCargo, self, Cargo ):SetTime(MenuTime) -- Deployzones are optional zones that can be selected to request routing information. for DeployZoneName, DeployZone in pairs( Task.DeployZones ) do if not Cargo:IsInZone( DeployZone ) then - MENU_GROUP_COMMAND:New( - TaskUnit:GetGroup(), - "Route to Deploy cargo at " .. DeployZoneName, - TaskUnit.Menu, - self.MenuRouteToDeploy, - self, - DeployZone - ):SetTime(MenuTime) + MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), "Route to Deploy cargo at " .. DeployZoneName, TaskUnit.Menu, self.MenuRouteToDeploy, self, DeployZone ):SetTime(MenuTime) end end end @@ -284,9 +280,9 @@ do -- TASK_CARGO self:__SelectAction( -15 ) - --Task:GetMission():GetCommandCenter():MessageToGroup("Cargo menu is ready ...", TaskUnit:GetGroup() ) end + --- -- @param #FSM_PROCESS self -- @param Wrapper.Unit#UNIT TaskUnit @@ -320,8 +316,7 @@ do -- TASK_CARGO --#Wrapper.Unit#UNIT - --- Route to Cargo - -- @param #FSM_PROCESS self + --- @param #FSM_PROCESS self -- @param Wrapper.Unit#UNIT TaskUnit -- @param Tasking.Task_Cargo#TASK_CARGO Task -- @param From @@ -341,8 +336,7 @@ do -- TASK_CARGO - --- - -- @param #FSM_PROCESS self + --- @param #FSM_PROCESS self -- @param Wrapper.Unit#UNIT TaskUnit -- @param Tasking.Task_Cargo#TASK_CARGO Task function Fsm:onafterArriveAtPickup( TaskUnit, Task ) @@ -350,6 +344,7 @@ do -- TASK_CARGO if self.Cargo:IsAlive() then TaskUnit:Smoke( Task:GetSmokeColor(), 15 ) if TaskUnit:IsAir() then + Task:GetMission():GetCommandCenter():MessageToGroup( "Land", TaskUnit:GetGroup() ) self:__Land( -0.1, "Pickup" ) else self:__SelectAction( -0.1 ) @@ -358,8 +353,7 @@ do -- TASK_CARGO end - --- - -- @param #FSM_PROCESS self + --- @param #FSM_PROCESS self -- @param Wrapper.Unit#UNIT TaskUnit -- @param Tasking.Task_Cargo#TASK_CARGO Task function Fsm:onafterCancelRouteToPickup( TaskUnit, Task ) @@ -369,8 +363,7 @@ do -- TASK_CARGO end - --- Route to DeployZone - -- @param #FSM_PROCESS self + --- @param #FSM_PROCESS self -- @param Wrapper.Unit#UNIT TaskUnit function Fsm:onafterRouteToDeploy( TaskUnit, Task, From, Event, To, DeployZone ) self:E( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } ) @@ -382,14 +375,14 @@ do -- TASK_CARGO end - --- - -- @param #FSM_PROCESS self + --- @param #FSM_PROCESS self -- @param Wrapper.Unit#UNIT TaskUnit -- @param Tasking.Task_Cargo#TASK_CARGO Task function Fsm:onafterArriveAtDeploy( TaskUnit, Task ) self:E( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } ) if TaskUnit:IsAir() then + Task:GetMission():GetCommandCenter():MessageToGroup( "Land", TaskUnit:GetGroup() ) self:__Land( -0.1, "Deploy" ) else self:__SelectAction( -0.1 ) @@ -397,8 +390,7 @@ do -- TASK_CARGO end - --- - -- @param #FSM_PROCESS self + --- @param #FSM_PROCESS self -- @param Wrapper.Unit#UNIT TaskUnit -- @param Tasking.Task_Cargo#TASK_CARGO Task function Fsm:onafterCancelRouteToDeploy( TaskUnit, Task ) @@ -409,7 +401,7 @@ do -- TASK_CARGO - -- @param #FSM_PROCESS self + --- @param #FSM_PROCESS self -- @param Wrapper.Unit#UNIT TaskUnit -- @param Tasking.Task_Cargo#TASK_CARGO Task function Fsm:onafterLand( TaskUnit, Task, From, Event, To, Action ) @@ -418,7 +410,6 @@ do -- TASK_CARGO if self.Cargo:IsAlive() then if self.Cargo:IsInRadius( TaskUnit:GetPointVec2() ) then if TaskUnit:InAir() then - Task:GetMission():GetCommandCenter():MessageToGroup( "Land", TaskUnit:GetGroup() ) self:__Land( -10, Action ) else Task:GetMission():GetCommandCenter():MessageToGroup( "Landed ...", TaskUnit:GetGroup() ) @@ -434,8 +425,7 @@ do -- TASK_CARGO end end - --- - -- @param #FSM_PROCESS self + --- @param #FSM_PROCESS self -- @param Wrapper.Unit#UNIT TaskUnit -- @param Tasking.Task_Cargo#TASK_CARGO Task function Fsm:onafterLanded( TaskUnit, Task, From, Event, To, Action ) @@ -458,8 +448,7 @@ do -- TASK_CARGO end end - --- - -- @param #FSM_PROCESS self + --- @param #FSM_PROCESS self -- @param Wrapper.Unit#UNIT TaskUnit -- @param Tasking.Task_Cargo#TASK_CARGO Task function Fsm:onafterPrepareBoarding( TaskUnit, Task, From, Event, To, Cargo ) @@ -471,8 +460,7 @@ do -- TASK_CARGO end end - --- - -- @param #FSM_PROCESS self + --- @param #FSM_PROCESS self -- @param Wrapper.Unit#UNIT TaskUnit -- @param Tasking.Task_Cargo#TASK_CARGO Task function Fsm:onafterBoard( TaskUnit, Task ) @@ -498,14 +486,18 @@ do -- TASK_CARGO end - --- - -- @param #FSM_PROCESS self + --- @param #FSM_PROCESS self -- @param Wrapper.Unit#UNIT TaskUnit -- @param Tasking.Task_Cargo#TASK_CARGO Task function Fsm:onafterBoarded( TaskUnit, Task ) - self:E( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } ) + + local TaskUnitName = TaskUnit:GetName() + self:E( { TaskUnit = TaskUnitName, Task = Task and Task:GetClassNameAndID() } ) self.Cargo:MessageToGroup( "Boarded ...", TaskUnit:GetGroup() ) + + TaskUnit:AddCargo( self.Cargo ) + self:__SelectAction( 1 ) -- TODO:I need to find a more decent solution for this. @@ -579,12 +571,27 @@ do -- TASK_CARGO -- @param Wrapper.Unit#UNIT TaskUnit -- @param Tasking.Task_Cargo#TASK_CARGO Task function Fsm:onafterUnBoarded( TaskUnit, Task ) - self:E( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } ) + + local TaskUnitName = TaskUnit:GetName() + self:E( { TaskUnit = TaskUnitName, Task = Task and Task:GetClassNameAndID() } ) self.Cargo:MessageToGroup( "UnBoarded ...", TaskUnit:GetGroup() ) + + TaskUnit:RemoveCargo( self.Cargo ) + + local NotInDeployZones = true + for DeployZoneName, DeployZone in pairs( Task.DeployZones ) do + if self.Cargo:IsInZone( DeployZone ) then + NotInDeployZones = false + end + end + if NotInDeployZones == false then + self.Cargo:SetDeployed( true ) + end + -- TODO:I need to find a more decent solution for this. - Task:E( { CargoDeployed = Task.CargoDeployed } ) + Task:E( { CargoDeployed = Task.CargoDeployed and "true" or "false" } ) if self.Cargo:IsAlive() then if Task.CargoDeployed then Task:CargoDeployed( TaskUnit, self.Cargo, self.DeployZone ) @@ -598,7 +605,16 @@ do -- TASK_CARGO return self end - + + --- Set a limit on the amount of cargo items that can be loaded into the Carriers. + -- @param #TASK_CARGO self + -- @param CargoLimit Specifies a number of cargo items that can be loaded in the helicopter. + -- @return #TASK_CARGO + function TASK_CARGO:SetCargoLimit( CargoLimit ) + self.CargoLimit = CargoLimit + return self + end + ---@param Color Might be SMOKECOLOR.Blue, SMOKECOLOR.Red SMOKECOLOR.Orange, SMOKECOLOR.White or SMOKECOLOR.Green function TASK_CARGO:SetSmokeColor(SmokeColor) @@ -813,6 +829,8 @@ do -- TASK_CARGO_TRANSPORT self:AddTransition( "*", "CargoPickedUp", "*" ) self:AddTransition( "*", "CargoDeployed", "*" ) + self:E( { CargoDeployed = self.CargoDeployed ~= nil and "true" or "false" } ) + --- OnBefore Transition Handler for Event CargoPickedUp. -- @function [parent=#TASK_CARGO_TRANSPORT] OnBeforeCargoPickedUp -- @param #TASK_CARGO_TRANSPORT self @@ -914,26 +932,26 @@ do -- TASK_CARGO_TRANSPORT local DeployZones = self:GetDeployZones() - local CargoDeployed = false + local CargoDeployed = true -- Loop the CargoSet (so evaluate each Cargo in the SET_CARGO ). for CargoID, CargoData in pairs( Set ) do local Cargo = CargoData -- Core.Cargo#CARGO - local CargoInDeployZone = false + if Cargo:IsDeployed() then - -- Loop the DeployZones set for the TASK_CARGO_TRANSPORT. - for DeployZoneID, DeployZone in pairs( DeployZones ) do - - -- If there is a Cargo not in one of DeployZones, then not all Cargo is deployed. - self:T( { Cargo.CargoObject } ) - if Cargo:IsInZone( DeployZone ) then - CargoInDeployZone = true + -- Loop the DeployZones set for the TASK_CARGO_TRANSPORT. + for DeployZoneID, DeployZone in pairs( DeployZones ) do + + -- If there is a Cargo not in one of DeployZones, then not all Cargo is deployed. + self:T( { Cargo.CargoObject } ) + if Cargo:IsInZone( DeployZone ) == false then + CargoDeployed = false + end end + else + CargoDeployed = false end - - CargoDeployed = CargoDeployed or CargoInDeployZone - end return CargoDeployed diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index 8e1deed6e..652e13c7e 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -869,25 +869,28 @@ end -- @param #table Template The template of the Group retrieved with GROUP:GetTemplate() function GROUP:Respawn( Template ) - local Vec3 = self:GetVec3() - Template.x = Vec3.x - Template.y = Vec3.z - --Template.x = nil - --Template.y = nil - - self:E( #Template.units ) - for UnitID, UnitData in pairs( self:GetUnits() ) do - local GroupUnit = UnitData -- Wrapper.Unit#UNIT - 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] } ) + if self:IsAlive() then + local Vec3 = self:GetVec3() + Template.x = Vec3.x + Template.y = Vec3.z + --Template.x = nil + --Template.y = nil + + self:E( #Template.units ) + for UnitID, UnitData in pairs( self:GetUnits() ) do + local GroupUnit = UnitData -- Wrapper.Unit#UNIT + 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() diff --git a/Moose Development/Moose/Wrapper/Positionable.lua b/Moose Development/Moose/Wrapper/Positionable.lua index b2054eea2..bca3967cf 100644 --- a/Moose Development/Moose/Wrapper/Positionable.lua +++ b/Moose Development/Moose/Wrapper/Positionable.lua @@ -10,13 +10,11 @@ -- -- @module Positionable - ---- The POSITIONABLE class --- @type POSITIONABLE +--- @type POSITIONABLE.__ Methods which are not intended for mission designers, but which are used interally by the moose designer :-) -- @extends Wrapper.Identifiable#IDENTIFIABLE --- @field #string PositionableName The name of the measurable. --- @field Core.Spot#SPOT Spot The laser Spot. --- @field #number LaserCode The last assigned laser code. + +--- @type POSITIONABLE +-- @extends POSITIONABLE.__ --- # POSITIONABLE class, extends @{Identifiable#IDENTIFIABLE} @@ -49,6 +47,14 @@ POSITIONABLE = { ClassName = "POSITIONABLE", PositionableName = "", } + +--- @field #POSITIONABLE.__ +POSITIONABLE.__ = {} + +--- @field #POSITIONABLE.__.Cargo +POSITIONABLE.__.Cargo = {} + + --- A DCSPositionable -- @type DCSPositionable -- @field id_ The ID of the controllable in DCS @@ -677,5 +683,44 @@ function POSITIONABLE:GetLaserCode() --R2.1 return self.LaserCode end +--- Add cargo. +-- @param #POSITIONABLE self +-- @param Core.Cargo#CARGO Cargo +-- @return #POSITIONABLE +function POSITIONABLE:AddCargo( Cargo ) + self.__.Cargo[Cargo] = Cargo + return self +end +--- Remove cargo. +-- @param #POSITIONABLE self +-- @param Core.Cargo#CARGO Cargo +-- @return #POSITIONABLE +function POSITIONABLE:RemoveCargo( Cargo ) + self.__.Cargo[Cargo] = nil + return self +end +--- Returns if carrier has given cargo. +-- @param #POSITIONABLE self +-- @return Core.Cargo#CARGO Cargo +function POSITIONABLE:HasCargo( Cargo ) + return self.__.Cargo[Cargo] +end + +--- Clear all cargo. +-- @param #POSITIONABLE self +function POSITIONABLE:ClearCargo() + self.__.Cargo = {} +end + +--- Get cargo item count. +-- @param #POSITIONABLE self +-- @return Core.Cargo#CARGO Cargo +function POSITIONABLE:CargoItemCount() + local ItemCount = 0 + for CargoName, Cargo in pairs( self.__.Cargo ) do + ItemCount = ItemCount + Cargo:GetCount() + end + return ItemCount +end diff --git a/docs/Documentation/AI_Patrol.html b/docs/Documentation/AI_Patrol.html index 93a9f8ce6..43392b308 100644 --- a/docs/Documentation/AI_Patrol.html +++ b/docs/Documentation/AI_Patrol.html @@ -926,6 +926,9 @@ Use the method AIPATROLZONE.M + +

This table contains the targets detected during patrol.

+
diff --git a/docs/Documentation/Cargo.html b/docs/Documentation/Cargo.html index 262969991..d774a472f 100644 --- a/docs/Documentation/Cargo.html +++ b/docs/Documentation/Cargo.html @@ -3059,6 +3059,7 @@ The range till cargo will board.

+ #number CARGO_UNIT.RunCount diff --git a/docs/Documentation/CleanUp.html b/docs/Documentation/CleanUp.html index c8e23a470..9066670dd 100644 --- a/docs/Documentation/CleanUp.html +++ b/docs/Documentation/CleanUp.html @@ -149,6 +149,12 @@ CLEANUP:RemoveAirbase(AirbaseName)

Removes an airbase from the airbase validation list.

+ + + + CLEANUP:SetCleanMissiles(CleanMissiles) + +

Enables or disables the cleaning of missiles within the airbase zones.

@@ -229,8 +235,14 @@ But as a result, there is more CPU overload.

2. Add or Remove airbases

-

The method CLEANUP.AddAirbase to add an airbase to the cleanup validation process. -The method CLEANUP.RemoveAirbase removes an airbase from the cleanup validation process.

+

The method CLEANUP.AddAirbase() to add an airbase to the cleanup validation process. +The method CLEANUP.RemoveAirbase() removes an airbase from the cleanup validation process.

+ +

3. Clean missiles and bombs within the airbase zone.

+ +

When missiles or bombs hit the runway, the airbase operations stop. +Use the method CLEANUP.SetCleanMissiles() to control the cleaning of missiles, which will prevent airbases to stop. +Note that this method will not allow anymore airbases to be attacked, so there is a trade-off here to do.

@@ -328,6 +340,41 @@ CleanUpKutaisi = CLEANUP:New( AIRBASE.Caucasus.Kutaisi )

#CLEANUP:

+ +
+
+
+ + +CLEANUP:SetCleanMissiles(CleanMissiles) + +
+
+ +

Enables or disables the cleaning of missiles within the airbase zones.

+ + +

Airbase operations stop when a missile or bomb is dropped at a runway. +Note that when this method is used, the airbase operations won't stop if +the missile or bomb was cleaned within the airbase zone, which is 8km from the center of the airbase. +However, there is a trade-off to make. Attacks on airbases won't be possible anymore if this method is used. +Note, one can also use the method CLEANUP.RemoveAirbase() to remove the airbase from the control process as a whole, +when an enemy unit is near. That is also an option...

+ +

Parameter

+
    +
  • + +

    #string CleanMissiles : +(Default=true) If true, missiles fired are immediately destroyed. If false missiles are not controlled.

    + +
  • +
+

Return value

+ +

#CLEANUP:

+ +
diff --git a/docs/Documentation/Controllable.html b/docs/Documentation/Controllable.html index 30e42f2ca..a07c91687 100644 --- a/docs/Documentation/Controllable.html +++ b/docs/Documentation/Controllable.html @@ -247,6 +247,12 @@ CONTROLLABLE:GetLife0()

Returns the initial health.

+ + + + CONTROLLABLE:GetSize() + + @@ -1526,6 +1532,19 @@ The controllable is not existing or alive.

+ +
+
+
+ + +CONTROLLABLE:GetSize() + +
+
+ + +
diff --git a/docs/Documentation/Designate.html b/docs/Documentation/Designate.html index 70e3562df..c0c7ee573 100644 --- a/docs/Documentation/Designate.html +++ b/docs/Documentation/Designate.html @@ -900,7 +900,6 @@ function below will use the range 1-7 just in case

- DESIGNATE.LaserCodes diff --git a/docs/Documentation/Detection.html b/docs/Documentation/Detection.html index 1754d0aa0..d42c77032 100644 --- a/docs/Documentation/Detection.html +++ b/docs/Documentation/Detection.html @@ -2406,6 +2406,7 @@ The index of the DetectedItem.

+ #number DETECTION_BASE.DetectedItemMax @@ -2563,7 +2564,7 @@ The index of the DetectedItem.

- #number + DETECTION_BASE.DetectionInterval diff --git a/docs/Documentation/Movement.html b/docs/Documentation/Movement.html index be5ce073c..4307c3aaa 100644 --- a/docs/Documentation/Movement.html +++ b/docs/Documentation/Movement.html @@ -227,7 +227,6 @@ on defined intervals (currently every minute).

- #number MOVEMENT.AliveUnits @@ -236,9 +235,6 @@ on defined intervals (currently every minute).

- -

Contains the counter how many units are currently alive

-
diff --git a/docs/Documentation/Settings.html b/docs/Documentation/Settings.html index 4dce02244..7dca37cbf 100644 --- a/docs/Documentation/Settings.html +++ b/docs/Documentation/Settings.html @@ -1073,7 +1073,7 @@ true if metric.

- #boolean + SETTINGS.Metric diff --git a/docs/Documentation/Spawn.html b/docs/Documentation/Spawn.html index 0f27003d1..6161409ef 100644 --- a/docs/Documentation/Spawn.html +++ b/docs/Documentation/Spawn.html @@ -2194,9 +2194,6 @@ The group that was spawned. You can use this group for further actions.

- -

Don't repeat the group from Take-Off till Landing and back Take-Off by ReSpawning.

-
@@ -2746,9 +2743,6 @@ when nothing was spawned.

- -

By default, no InitLimit

-
@@ -2784,7 +2778,7 @@ when nothing was spawned.

- #number + SPAWN.SpawnMaxGroups @@ -2801,7 +2795,7 @@ when nothing was spawned.

- #number + SPAWN.SpawnMaxUnitsAlive @@ -3129,7 +3123,7 @@ Spawn_BE_KA50 = SPAWN:New( 'BE KA-50@RAMP-Ground Defense' ):Schedule( 600, 0.5 )
- #boolean + SPAWN.SpawnUnControlled diff --git a/docs/Documentation/SpawnStatic.html b/docs/Documentation/SpawnStatic.html index d8aa5e633..bc91b9624 100644 --- a/docs/Documentation/SpawnStatic.html +++ b/docs/Documentation/SpawnStatic.html @@ -436,7 +436,6 @@ ptional) The name of the new static.

- #number SPAWNSTATIC.SpawnIndex diff --git a/docs/Documentation/Task.html b/docs/Documentation/Task.html index 5ea8d8586..ce9c5ff8f 100644 --- a/docs/Documentation/Task.html +++ b/docs/Documentation/Task.html @@ -552,7 +552,7 @@ - TASK:SetInfo(TaskInfo, TaskInfoText) + TASK:SetInfo(TaskInfo, TaskInfoText, TaskInfoOrder)

Sets the Information on the Task

@@ -687,6 +687,12 @@ TASK.TaskID + + + + TASK.TaskInfo + + @@ -2472,7 +2478,7 @@ self

-TASK:SetInfo(TaskInfo, TaskInfoText) +TASK:SetInfo(TaskInfo, TaskInfoText, TaskInfoOrder)
@@ -2483,12 +2489,20 @@ self

  • -

    #string TaskInfo :

    +

    #string TaskInfo : +The key and title of the task information.

  • -

    TaskInfoText :

    +

    #string TaskInfoText : +The Task info text.

    + +
  • +
  • + +

    #number TaskInfoOrder : +The ordering, a number between 0 and 99.

@@ -2978,6 +2992,19 @@ Fsm#FSM_PROCESS

+
+
+
+
+ + +TASK.TaskInfo + +
+
+ + +
diff --git a/docs/Documentation/Task_Cargo.html b/docs/Documentation/Task_Cargo.html index 8c17ced64..7d6a582bd 100644 --- a/docs/Documentation/Task_Cargo.html +++ b/docs/Documentation/Task_Cargo.html @@ -195,6 +195,12 @@ and various dedicated deployment zones.

TASK_CARGO:GetDeployZones() + + + + TASK_CARGO:GetGoalTotal() + + @@ -249,6 +255,12 @@ and various dedicated deployment zones.

TASK_CARGO:SetDeployZones(@, TaskUnit, DeployZones) + + + + TASK_CARGO:SetGoalTotal() + + @@ -355,6 +367,12 @@ and various dedicated deployment zones.

TASK_CARGO_TRANSPORT:__CargoPickedUp(Delay, TaskUnit, Cargo)

Asynchronous Event Trigger for Event CargoPickedUp.

+ + + + TASK_CARGO_TRANSPORT:onafterGoal(TaskUnit, From, Event, To) + + @@ -510,7 +528,7 @@ based on the tasking capabilities defined in Task#TA
- + Core.Cargo#CARGO_GROUP FSM_PROCESS.Cargo @@ -524,6 +542,7 @@ based on the tasking capabilities defined in Task#TA
+ FSM_PROCESS.DeployZone @@ -619,6 +638,19 @@ The Cargo Set.

#list: Core.Zone#ZONE_BASE> The Deployment Zones.

+ +
+
+
+ + +TASK_CARGO:GetGoalTotal() + +
+
+ + +
@@ -875,6 +907,19 @@ ist DeployZones

#TASK_CARGO:

+ +
+
+
+ + +TASK_CARGO:SetGoalTotal() + +
+
+ + +
@@ -1480,6 +1525,42 @@ The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Sta +
+
+
+ + +TASK_CARGO_TRANSPORT:onafterGoal(TaskUnit, From, Event, To) + +
+
+ + + +

Parameters

+
    +
  • + +

    TaskUnit :

    + +
  • +
  • + +

    From :

    + +
  • +
  • + +

    Event :

    + +
  • +
  • + +

    To :

    + +
  • +
+

Type list