diff --git a/Moose Development/Moose/AI/.gitignore b/Moose Development/Moose/AI/.gitignore deleted file mode 100644 index 73a72496a..000000000 --- a/Moose Development/Moose/AI/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/AI_Patrol.lua -/AI_BAI.lua diff --git a/Moose Development/Moose/Core/Event.lua b/Moose Development/Moose/Core/Event.lua index 8e80c69c4..b99dbc771 100644 --- a/Moose Development/Moose/Core/Event.lua +++ b/Moose Development/Moose/Core/Event.lua @@ -1063,36 +1063,6 @@ end do -- Event Creation - --- Creation of a New Cargo Event. - -- @param #EVENT self - -- @param AI.AI_Cargo#AI_CARGO Cargo The Cargo created. - function EVENT:CreateEventNewCargo( Cargo ) - self:F( { Cargo } ) - - local Event = { - id = EVENTS.NewCargo, - time = timer.getTime(), - cargo = Cargo, - } - - world.onEvent( Event ) - end - - --- Creation of a Cargo Deletion Event. - -- @param #EVENT self - -- @param AI.AI_Cargo#AI_CARGO Cargo The Cargo created. - function EVENT:CreateEventDeleteCargo( Cargo ) - self:F( { Cargo } ) - - local Event = { - id = EVENTS.DeleteCargo, - time = timer.getTime(), - cargo = Cargo, - } - - world.onEvent( Event ) - end - --- Creation of a New Zone Event. -- @param #EVENT self -- @param Core.Zone#ZONE_BASE Zone The Zone created. diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua index f9134d6a5..b21d13275 100644 --- a/Moose Development/Moose/Core/Set.lua +++ b/Moose Development/Moose/Core/Set.lua @@ -1106,30 +1106,6 @@ do -- --self:F({ GroupObject = GroupObject:GetName() }) -- end -- - -- While this is a good example, there is a catch. - -- Imagine you want to execute the code above, the the self would need to be from the object declared outside (above) the OnAfterDead method. - -- So, the self would need to contain another object. Fortunately, this can be done, but you must use then the **`.`** notation for the method. - -- See the modified example: - -- - -- -- Now we have a constructor of the class AI_CARGO_DISPATCHER, that receives the SetHelicopter as a parameter. - -- -- Within that constructor, we want to set an enclosed event handler OnAfterDead for SetHelicopter. - -- -- But within the OnAfterDead method, we want to refer to the self variable of the AI_CARGO_DISPATCHER. - -- - -- function AI_CARGO_DISPATCHER:New(SetCarrier, SetCargo, SetDeployZones) - -- - -- local self = BASE:Inherit(self, FSM:New()) -- #AI_CARGO_DISPATCHER - -- - -- -- Put a Dead event handler on SetCarrier, to ensure that when a carrier is destroyed, that all internal parameters are reset. - -- -- Note the "." notation, and the explicit declaration of SetHelicopter, which would be using the ":" notation the implicit self variable declaration. - -- - -- function SetHelicopter.OnAfterDead(SetHelicopter, From, Event, To, GroupObject) - -- SetHelicopter:F({ GroupObject = GroupObject:GetName() }) - -- self.PickupCargo[GroupObject] = nil -- So here I clear the PickupCargo table entry of the self object AI_CARGO_DISPATCHER. - -- self.CarrierHome[GroupObject] = nil - -- end - -- - -- end - -- -- === -- @field #SET_GROUP SET_GROUP SET_GROUP = { @@ -2269,28 +2245,6 @@ do -- SET_UNIT -- --self:F({ UnitObject = UnitObject:GetName() }) -- end -- - -- While this is a good example, there is a catch. - -- Imagine you want to execute the code above, the the self would need to be from the object declared outside (above) the OnAfterDead method. - -- So, the self would need to contain another object. Fortunately, this can be done, but you must use then the **`.`** notation for the method. - -- See the modified example: - -- - -- -- Now we have a constructor of the class AI_CARGO_DISPATCHER, that receives the SetHelicopter as a parameter. - -- -- Within that constructor, we want to set an enclosed event handler OnAfterDead for SetHelicopter. - -- -- But within the OnAfterDead method, we want to refer to the self variable of the AI_CARGO_DISPATCHER. - -- - -- function ACLASS:New(SetCarrier, SetCargo, SetDeployZones) - -- - -- local self = BASE:Inherit(self, FSM:New()) -- #AI_CARGO_DISPATCHER - -- - -- -- Put a Dead event handler on SetCarrier, to ensure that when a carrier is destroyed, that all internal parameters are reset. - -- -- Note the "." notation, and the explicit declaration of SetHelicopter, which would be using the ":" notation the implicit self variable declaration. - -- - -- function SetHelicopter.OnAfterDead(SetHelicopter, From, Event, To, UnitObject) - -- SetHelicopter:F({ UnitObject = UnitObject:GetName() }) - -- self.array[UnitObject] = nil -- So here I clear the array table entry of the self object ACLASS. - -- end - -- - -- end -- === -- @field #SET_UNIT SET_UNIT SET_UNIT = { @@ -5781,430 +5735,6 @@ do -- SET_AIRBASE end -do -- SET_CARGO - - --- - -- @type SET_CARGO - -- @extends Core.Set#SET_BASE - - --- Mission designers can use the @{Core.Set#SET_CARGO} class to build sets of cargos optionally belonging to certain: - -- - -- * Coalitions - -- * Types - -- * Name or Prefix - -- - -- ## SET_CARGO constructor - -- - -- Create a new SET_CARGO object with the @{#SET_CARGO.New} method: - -- - -- * @{#SET_CARGO.New}: Creates a new SET_CARGO object. - -- - -- ## Add or Remove CARGOs from SET_CARGO - -- - -- CARGOs can be added and removed using the @{Core.Set#SET_CARGO.AddCargosByName} and @{Core.Set#SET_CARGO.RemoveCargosByName} respectively. - -- These methods take a single CARGO name or an array of CARGO names to be added or removed from SET_CARGO. - -- - -- ## SET_CARGO filter criteria - -- - -- You can set filter criteria to automatically maintain the SET_CARGO contents. - -- Filter criteria are defined by: - -- - -- * @{#SET_CARGO.FilterCoalitions}: Builds the SET_CARGO with the cargos belonging to the coalition(s). - -- * @{#SET_CARGO.FilterPrefixes}: Builds the SET_CARGO with the cargos containing the same string(s). **Attention!** LUA regular expression apply here, so special characters in names like minus, dot, hash (#) etc might lead to unexpected results. - -- Have a read through here to understand the application of regular expressions: [LUA regular expressions](https://riptutorial.com/lua/example/20315/lua-pattern-matching) - -- * @{#SET_CARGO.FilterTypes}: Builds the SET_CARGO with the cargos belonging to the cargo type(s). - -- * @{#SET_CARGO.FilterCountries}: Builds the SET_CARGO with the cargos belonging to the country(ies). - -- - -- Once the filter criteria have been set for the SET_CARGO, you can start filtering using: - -- - -- * @{#SET_CARGO.FilterStart}: Starts the filtering of the cargos within the SET_CARGO. - -- - -- ## SET_CARGO iterators - -- - -- Once the filters have been defined and the SET_CARGO has been built, you can iterate the SET_CARGO with the available iterator methods. - -- The iterator methods will walk the SET_CARGO set, and call for each cargo within the set a function that you provide. - -- The following iterator methods are currently available within the SET_CARGO: - -- - -- * @{#SET_CARGO.ForEachCargo}: Calls a function for each cargo it finds within the SET_CARGO. - -- - -- @field #SET_CARGO SET_CARGO - 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, - }, - }, - } - - --- Creates a new SET_CARGO object, building a set of cargos belonging to a coalitions and categories. - -- @param #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)) -- #SET_CARGO - - return self - end - - --- Add CARGO to SET_CARGO. - -- @param Core.Set#SET_CARGO self - -- @param Cargo.Cargo#CARGO Cargo A single cargo. - -- @return Core.Set#SET_CARGO self - function SET_CARGO:AddCargo(Cargo) -- R2.4 - - self:Add(Cargo:GetName(), Cargo) - - return self - end - - --- Add CARGOs to SET_CARGO. - -- @param Core.Set#SET_CARGO self - -- @param #string AddCargoNames A single name or an array of CARGO names. - -- @return Core.Set#SET_CARGO self - function SET_CARGO:AddCargosByName(AddCargoNames) -- R2.1 - - 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 - - --- Remove CARGOs from SET_CARGO. - -- @param Core.Set#SET_CARGO self - -- @param Cargo.Cargo#CARGO RemoveCargoNames A single name or an array of CARGO names. - -- @return Core.Set#SET_CARGO self - function SET_CARGO:RemoveCargosByName(RemoveCargoNames) -- R2.1 - - local RemoveCargoNamesArray = (type(RemoveCargoNames) == "table") and RemoveCargoNames or { RemoveCargoNames } - - for RemoveCargoID, RemoveCargoName in pairs(RemoveCargoNamesArray) do - self:Remove(RemoveCargoName.CargoName) - end - - return self - end - - --- Finds a Cargo based on the Cargo Name. - -- @param #SET_CARGO self - -- @param #string CargoName - -- @return Cargo.Cargo#CARGO The found Cargo. - function SET_CARGO:FindCargo(CargoName) -- R2.1 - - local CargoFound = self.Set[CargoName] - return CargoFound - end - - --- Builds a set of cargos of coalitions. - -- Possible current coalitions are red, blue and neutral. - -- @param #SET_CARGO self - -- @param #string Coalitions Can take the following values: "red", "blue", "neutral". - -- @return #SET_CARGO self - - --- Builds a set of cargos of defined cargo types. - -- Possible current types are those types known within DCS world. - -- @param #SET_CARGO self - -- @param #string Types Can take those type strings known within DCS world. - -- @return #SET_CARGO self - function SET_CARGO:FilterTypes(Types) -- R2.1 - 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 cargos of defined countries. - -- Possible current countries are those known within DCS world. - -- @param #SET_CARGO self - -- @param #string Countries Can take those country strings known within DCS world. - -- @return #SET_CARGO self - function SET_CARGO:FilterCountries(Countries) -- R2.1 - 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 CARGOs that contain a given string in their name. - -- **Attention!** Bad naming convention as this **does not** filter only **prefixes** but all cargos that **contain** the string. - -- @param #SET_CARGO self - -- @param #string Prefixes The string pattern(s) that need to be in the cargo name. Can also be passed as a `#table` of strings. - -- @return #SET_CARGO self - function SET_CARGO:FilterPrefixes(Prefixes) -- R2.1 - 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 - - --- Starts the filtering. - -- @param #SET_CARGO self - -- @return #SET_CARGO self - function SET_CARGO:FilterStart() -- R2.1 - - if _DATABASE then - self:_FilterStart() - self:HandleEvent(EVENTS.NewCargo) - self:HandleEvent(EVENTS.DeleteCargo) - end - - return self - end - - --- Stops the filtering for the defined collection. - -- @param #SET_CARGO self - -- @return #SET_CARGO self - function SET_CARGO:FilterStop() - - self:UnHandleEvent(EVENTS.NewCargo) - self:UnHandleEvent(EVENTS.DeleteCargo) - - 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_CARGO self - -- @param Core.Event#EVENTDATA Event - -- @return #string The name of the CARGO - -- @return #table The CARGO - function SET_CARGO:AddInDatabase(Event) -- R2.1 - --self:F3({ Event }) - - 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_CARGO self - -- @param Core.Event#EVENTDATA Event - -- @return #string The name of the CARGO - -- @return #table The CARGO - function SET_CARGO:FindInDatabase(Event) -- R2.1 - --self:F3({ Event }) - - return Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName] - end - - --- Iterate the SET_CARGO and call an iterator function for each CARGO, providing the CARGO and optional parameters. - -- @param #SET_CARGO self - -- @param #function IteratorFunction The function that will be called when there is an alive CARGO in the SET_CARGO. The function needs to accept a CARGO parameter. - -- @return #SET_CARGO self - function SET_CARGO:ForEachCargo(IteratorFunction, ...) -- R2.1 - --self:F2(arg) - - self:ForEach(IteratorFunction, arg, self:GetSet()) - - return self - end - - --- Iterate the SET_CARGO while identifying the nearest @{Cargo.Cargo#CARGO} from a @{Core.Point#COORDINATE}. - -- @param #SET_CARGO self - -- @param Core.Point#COORDINATE Coordinate A @{Core.Point#COORDINATE} object from where to evaluate the closest @{Cargo.Cargo#CARGO}. - -- @return Cargo.Cargo#CARGO The closest @{Cargo.Cargo#CARGO}. - function SET_CARGO:FindNearestCargoFromPointVec2(Coordinate) -- R2.1 - --self:F2(Coordinate) - - local NearestCargo = self:FindNearestObjectFromPointVec2(Coordinate) - return NearestCargo - end - - --- - -- @param #SET_CARGO self - function SET_CARGO:FirstCargoWithState(State) - - local FirstCargo = nil - - for CargoName, Cargo in pairs(self.Set) do - if Cargo:Is(State) then - FirstCargo = Cargo - break - end - end - - return FirstCargo - end - - --- - -- @param #SET_CARGO self - function SET_CARGO:FirstCargoWithStateAndNotDeployed(State) - - local FirstCargo = nil - - for CargoName, Cargo in pairs(self.Set) do - if Cargo:Is(State) and not Cargo:IsDeployed() then - FirstCargo = Cargo - break - end - end - - return FirstCargo - end - - --- Iterate the SET_CARGO while identifying the first @{Cargo.Cargo#CARGO} that is UnLoaded. - -- @param #SET_CARGO self - -- @return Cargo.Cargo#CARGO The first @{Cargo.Cargo#CARGO}. - function SET_CARGO:FirstCargoUnLoaded() - local FirstCargo = self:FirstCargoWithState("UnLoaded") - return FirstCargo - end - - --- Iterate the SET_CARGO while identifying the first @{Cargo.Cargo#CARGO} that is UnLoaded and not Deployed. - -- @param #SET_CARGO self - -- @return Cargo.Cargo#CARGO The first @{Cargo.Cargo#CARGO}. - function SET_CARGO:FirstCargoUnLoadedAndNotDeployed() - local FirstCargo = self:FirstCargoWithStateAndNotDeployed("UnLoaded") - return FirstCargo - end - - --- Iterate the SET_CARGO while identifying the first @{Cargo.Cargo#CARGO} that is Loaded. - -- @param #SET_CARGO self - -- @return Cargo.Cargo#CARGO The first @{Cargo.Cargo#CARGO}. - function SET_CARGO:FirstCargoLoaded() - local FirstCargo = self:FirstCargoWithState("Loaded") - return FirstCargo - end - - --- Iterate the SET_CARGO while identifying the first @{Cargo.Cargo#CARGO} that is Deployed. - -- @param #SET_CARGO self - -- @return Cargo.Cargo#CARGO The first @{Cargo.Cargo#CARGO}. - function SET_CARGO:FirstCargoDeployed() - local FirstCargo = self:FirstCargoWithState("Deployed") - return FirstCargo - end - - --- - -- @param #SET_CARGO self - -- @param AI.AI_Cargo#AI_CARGO MCargo - -- @return #SET_CARGO self - function SET_CARGO:IsIncludeObject(MCargo) -- R2.1 - --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:T(3({ "Coalition:", CargoCoalitionID, self.FilterMeta.Coalitions[CoalitionName], CoalitionName }) - if self.FilterMeta.Coalitions[CoalitionName] and self.FilterMeta.Coalitions[CoalitionName] == CargoCoalitionID then - MCargoCoalition = true - end - end - --self:F({ "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:T(3({ "Type:", MCargo:GetType(), TypeName }) - if TypeName == MCargo:GetType() then - MCargoType = true - end - end - --self:F({ "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:T(3({ "Prefix:", string.find(MCargo.Name, CargoPrefix, 1), CargoPrefix }) - if string.find(MCargo.Name, CargoPrefix, 1) then - MCargoPrefix = true - end - end - --self:F({ "Evaluated Prefix", MCargoPrefix }) - MCargoInclude = MCargoInclude and MCargoPrefix - end - end - - if self.Filter.Functions and MCargoInclude then - local MClientFunc = self:_EvalFilterFunctions(MCargo) - MCargoInclude = MCargoInclude and MClientFunc - end - - --self:T(2(MCargoInclude) - return MCargoInclude - end - - --- Handles the OnEventNewCargo event for the Set. - -- @param #SET_CARGO self - -- @param Core.Event#EVENTDATA EventData - function SET_CARGO:OnEventNewCargo(EventData) -- R2.1 - - --self:F({ "New Cargo", EventData }) - - if EventData.Cargo then - if EventData.Cargo and self:IsIncludeObject(EventData.Cargo) then - self:Add(EventData.Cargo.Name, EventData.Cargo) - end - end - end - - --- Handles the OnDead or OnCrash event for alive units set. - -- @param #SET_CARGO self - -- @param Core.Event#EVENTDATA EventData - function SET_CARGO:OnEventDeleteCargo(EventData) -- R2.1 - --self:F3({ EventData }) - - if EventData.Cargo then - local Cargo = _DATABASE:FindCargo(EventData.Cargo.Name) - if Cargo and Cargo.Name then - - -- When cargo was deleted, it may probably be because of an S_EVENT_DEAD. - -- However, in the loading logic, an S_EVENT_DEAD is also generated after a Destroy() call. - -- And this is a problem because it will remove all entries from the SET_CARGOs. - -- To prevent this from happening, the Cargo object has a flag NoDestroy. - -- When true, the SET_CARGO won't Remove the Cargo object from the set. - -- This flag is switched off after the event handlers have been called in the EVENT class. - --self:F({ CargoNoDestroy = Cargo.NoDestroy }) - if Cargo.NoDestroy then - else - self:Remove(Cargo.Name) - end - end - end - end - -end do -- SET_ZONE diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index a9dc78ddb..2f9e96373 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -419,14 +419,6 @@ -- arty set, battery "Mortar Bravo", rearming group "Ammo Truck M939" -- Note that the name of the rearming group has to be given in quotation marks and spelt exactly as the group name defined in the mission editor. -- --- ## Transporting --- --- ARTY groups can be transported to another location as @{Cargo.Cargo} by means of classes such as @{AI.AI_Cargo_APC}, @{AI.AI_Cargo_Dispatcher_APC}, --- @{AI.AI_Cargo_Helicopter}, @{AI.AI_Cargo_Dispatcher_Helicopter} or @{AI.AI_Cargo_Airplane}. --- --- In order to do this, one needs to define an ARTY object via the @{#ARTY.NewFromCargoGroup}(*cargogroup*, *alias*) function. --- The first argument *cargogroup* has to be a @{Cargo.CargoGroup#CARGO_GROUP} object. The second argument *alias* is a string which can be freely chosen by the user. --- -- ## Fine Tuning -- -- The mission designer has a few options to tailor the ARTY object according to his needs. @@ -511,25 +503,6 @@ -- -- Start ARTY process. -- normandy:Start() -- --- ### Transportation as Cargo --- This example demonstates how an ARTY group can be transported to another location as cargo. --- -- Define a group as CARGO_GROUP --- CargoGroupMortars=CARGO_GROUP:New(GROUP:FindByName("Mortars"), "Mortars", "Mortar Platoon Alpha", 100 , 10) --- --- -- Define the mortar CARGO GROUP as ARTY object --- mortars=ARTY:NewFromCargoGroup(CargoGroupMortars, "Mortar Platoon Alpha") --- --- -- Start ARTY process --- mortars:Start() --- --- -- Setup AI cargo dispatcher for e.g. helos --- SetHeloCarriers = SET_GROUP:New():FilterPrefixes("CH-47D"):FilterStart() --- SetCargoMortars = SET_CARGO:New():FilterTypes("Mortars"):FilterStart() --- SetZoneDepoly = SET_ZONE:New():FilterPrefixes("Deploy"):FilterStart() --- CargoHelo=AI_CARGO_DISPATCHER_HELICOPTER:New(SetHeloCarriers, SetCargoMortars, SetZoneDepoly) --- CargoHelo:Start() --- The ARTY group will be transported and resume its normal operation after it has been deployed. New targets can be assigned at any time also during the transportation process. --- -- @field #ARTY ARTY={ ClassName="ARTY", diff --git a/Moose Development/Moose/Functional/Formation.lua b/Moose Development/Moose/Functional/Formation.lua new file mode 100644 index 000000000..9467c1380 --- /dev/null +++ b/Moose Development/Moose/Functional/Formation.lua @@ -0,0 +1,1000 @@ +--- **Functional** - Build large airborne formations of aircraft. +-- +-- **Features:** +-- +-- * Build in-air formations consisting of more than 40 aircraft as one group. +-- * Build different formation types. +-- * Assign a group leader that will guide the large formation path. +-- +-- === +-- +-- ## Additional Material: +-- +-- * **Demo Missions:** [GitHub](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AI/FORMATION) +-- * **YouTube videos:** [Playlist](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl0bFIJ9jIdYM22uaWmIN4oz) +-- * **Guides:** None +-- +-- === +-- +-- ### Author: **FlightControl** +-- ### Contributions: **Applevangelist** +-- +-- === +-- +-- @module Functional.FORMATION +-- @image AI_Large_Formations.JPG + +--- FORMATION class +-- @type FORMATION +-- @extends Core.Fsm#FSM_SET +-- @field Wrapper.Unit#UNIT FollowUnit +-- @field Core.Set#SET_GROUP FollowGroupSet +-- @field #string FollowName +-- @field Core.Scheduler#SCHEDULER FollowScheduler The instance of the SCHEDULER class. +-- @field #number FollowDistance The current follow distance. +-- @field DCS#AI.Option.Air.val.ROE OptionROE Which ROE is set to the FollowGroup. +-- @field DCS#AI.Option.Air.val.REACTION_ON_THREAT OptionReactionOnThreat Which REACTION_ON_THREAT is set to the FollowGroup. +-- @field #number dtFollow Time step between position updates. + + +--- Build (large) formations, make AI follow a @{Wrapper.Client#CLIENT} (player) leader or a @{Wrapper.Unit#UNIT} (AI) leader. +-- +-- FORMATION makes AI @{Wrapper.Group#GROUP}s fly in formation of various compositions. +-- The FORMATION class models formations in a different manner than the internal DCS formation logic!!! +-- The purpose of the class is to: +-- +-- * Make formation building a process that can be managed while in flight, rather than a task. +-- * Human players can guide formations, consisting of larget planes. +-- * Build large formations (like a large bomber field). +-- * Form formations that DCS does not support off-the-shelve. +-- +-- A few remarks: +-- +-- * Depending on the type of plane, the change in direction by the leader may result in the formation getting disentangled while in flight and needs to be rebuild. +-- * Formations are vulnerable to collissions, but is depending on the type of plane, the distance between the planes and the speed and angle executed by the leader. +-- * Formations may take a while to build up. +-- +-- As a result, the FORMATION is not perfect, but is very useful to: +-- +-- * Model large formations when flying straight line. You can build close formations when doing this. +-- * Make humans guide a large formation, when the planes are wide from each other. +-- +-- ## FORMATION construction +-- +-- Create a new SPAWN object with the @{#FORMATION.New} method: +-- +-- * @{#FORMATION.New}(): Creates a new FORMATION object from a @{Wrapper.Group#GROUP} for a @{Wrapper.Client#CLIENT} or a @{Wrapper.Unit#UNIT}, with an optional briefing text. +-- +-- ## Formation methods +-- +-- The following methods can be used to set or change the formation: +-- +-- * @{#FORMATION.FormationLine}(): Form a line formation (core formation function). +-- * @{#FORMATION.FormationTrail}(): Form a trail formation. +-- * @{#FORMATION.FormationLeftLine}(): Form a left line formation. +-- * @{#FORMATION.FormationRightLine}(): Form a right line formation. +-- * @{#FORMATION.FormationRightWing}(): Form a right wing formation. +-- * @{#FORMATION.FormationLeftWing}(): Form a left wing formation. +-- * @{#FORMATION.FormationCenterWing}(): Form a center wing formation. +-- * @{#FORMATION.FormationCenterVic}(): Form a Vic formation (same as CenterWing). +-- * @{#FORMATION.FormationCenterBoxed}(): Form a center boxed formation. +-- +-- ## Randomization +-- +-- Use the method @{FORMATION#FORMATION.SetFlightRandomization}() to simulate the formation flying errors that pilots make while in formation. Is a range set in meters. +-- +-- @usage +-- local FollowGroupSet = SET_GROUP:New():FilterCategories("plane"):FilterCoalitions("blue"):FilterPrefixes("Follow"):FilterStart() +-- local LeaderUnit = UNIT:FindByName( "Leader" ) +-- local LargeFormation = FORMATION:New( LeaderUnit, FollowGroupSet, "Center Wing Formation", "Briefing" ) +-- LargeFormation:FormationCenterWing( 500, 50, 0, 250, 250 ) +-- LargeFormation:__Start( 1 ) +-- +-- @field #FORMATION +FORMATION = { + ClassName = "FORMATION", + FollowName = nil, -- The Follow Name + FollowUnit = nil, + FollowGroupSet = nil, + FollowScheduler = nil, + OptionROE = AI.Option.Air.val.ROE.OPEN_FIRE, + OptionReactionOnThreat = AI.Option.Air.val.REACTION_ON_THREAT.ALLOW_ABORT_MISSION, + dtFollow = 0.5, +} + +--- @type FORMATION.Formation +-- @field #number None +-- @field #number Line +-- @field #number Trail +-- @field #number Stack +-- @field #number LeftLine +-- @field #number RightLine +-- @field #number LeftWing +-- @field #number RightWing +-- @field #number Vic +-- @field #number Box +FORMATION.Formation = { + None = 1, + Line = 2, + Trail = 3, + Stack = 4, + LeftLine = 5, + RightLine = 6, + LeftWing = 7, + RightWing = 8, + Vic = 9, + Box = 10, +} + +--- FORMATION class constructor for an AI group +-- @param #FORMATION self +-- @param Wrapper.Unit#UNIT FollowUnit The UNIT leading the FolllowGroupSet. +-- @param Core.Set#SET_GROUP FollowGroupSet The group AI escorting the FollowUnit. +-- @param #string FollowName Name of the escort. +-- @return #FORMATION self +function FORMATION:New( FollowUnit, FollowGroupSet, FollowName ) + local self = BASE:Inherit( self, FSM_SET:New( FollowGroupSet ) ) + self:F( { FollowUnit, FollowGroupSet, FollowName } ) + + self.FollowUnit = FollowUnit -- Wrapper.Unit#UNIT + self.FollowGroupSet = FollowGroupSet -- Core.Set#SET_GROUP + + self:SetFlightRandomization( 2 ) + + self:SetStartState( "None" ) + + self:AddTransition( "*", "Stop", "Stopped" ) + + self:AddTransition( {"None", "Stopped"}, "Start", "Following" ) + + self:AddTransition( "*", "FormationLine", "*" ) + + --- Start Trigger for FORMATION + -- @function [parent=#FORMATION] Start + -- @param #FORMATION self + + --- Start Asynchronous Trigger for FORMATION + -- @function [parent=#FORMATION] __Start + -- @param #FORMATION self + -- @param #number Delay + + --- Stop Trigger for FORMATION + -- @function [parent=#FORMATION] Stop + -- @param #FORMATION self + + --- Stop Asynchronous Trigger for FORMATION + -- @function [parent=#FORMATION] __Stop + -- @param #FORMATION self + -- @param #number Delay + + --- FormationLine Handler OnAfter for FORMATION + -- @function [parent=#FORMATION] OnAfterFormationLine + -- @param #FORMATION self + -- @param Core.Set#SET_GROUP FollowGroupSet The group AI escorting the FollowUnit. + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #number YStart The start position on the Y-axis in meters for the first group. + -- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group. + -- @param #number ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. + + --- FormationLine Trigger for FORMATION + -- @function [parent=#FORMATION] FormationLine + -- @param #FORMATION self + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #number YStart The start position on the Y-axis in meters for the first group. + -- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group. + -- @param #number ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. + + --- FormationLine Asynchronous Trigger for FORMATION + -- @function [parent=#FORMATION] __FormationLine + -- @param #FORMATION self + -- @param #number Delay + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #number YStart The start position on the Y-axis in meters for the first group. + -- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group. + -- @param #number ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. + + self:AddTransition( "*", "FormationTrail", "*" ) + + --- FormationTrail Handler OnAfter for FORMATION + -- @function [parent=#FORMATION] OnAfterFormationTrail + -- @param #FORMATION self + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #number YStart The start position on the Y-axis in meters for the first group. + + --- FormationTrail Trigger for FORMATION + -- @function [parent=#FORMATION] FormationTrail + -- @param #FORMATION self + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #number YStart The start position on the Y-axis in meters for the first group. + + --- FormationTrail Asynchronous Trigger for FORMATION + -- @function [parent=#FORMATION] __FormationTrail + -- @param #FORMATION self + -- @param #number Delay + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #number YStart The start position on the Y-axis in meters for the first group. + + self:AddTransition( "*", "FormationStack", "*" ) + + --- FormationStack Handler OnAfter for FORMATION + -- @function [parent=#FORMATION] OnAfterFormationStack + -- @param #FORMATION self + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #number YStart The start position on the Y-axis in meters for the first group. + -- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group. + + --- FormationStack Trigger for FORMATION + -- @function [parent=#FORMATION] FormationStack + -- @param #FORMATION self + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #number YStart The start position on the Y-axis in meters for the first group. + -- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group. + + --- FormationStack Asynchronous Trigger for FORMATION + -- @function [parent=#FORMATION] __FormationStack + -- @param #FORMATION self + -- @param #number Delay + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #number YStart The start position on the Y-axis in meters for the first group. + -- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group. + + self:AddTransition( "*", "FormationLeftLine", "*" ) + + --- FormationLeftLine Handler OnAfter for FORMATION + -- @function [parent=#FORMATION] OnAfterFormationLeftLine + -- @param #FORMATION self + -- @param Core.Set#SET_GROUP FollowGroupSet The group AI escorting the FollowUnit. + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number YStart The start position on the Y-axis in meters for the first group. + -- @param #number ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. + + --- FormationLeftLine Trigger for FORMATION + -- @function [parent=#FORMATION] FormationLeftLine + -- @param #FORMATION self + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number YStart The start position on the Y-axis in meters for the first group. + -- @param #number ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. + + --- FormationLeftLine Asynchronous Trigger for FORMATION + -- @function [parent=#FORMATION] __FormationLeftLine + -- @param #FORMATION self + -- @param #number Delay + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number YStart The start position on the Y-axis in meters for the first group. + -- @param #number ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. + + self:AddTransition( "*", "FormationRightLine", "*" ) + + --- FormationRightLine Handler OnAfter for FORMATION + -- @function [parent=#FORMATION] OnAfterFormationRightLine + -- @param #FORMATION self + -- @param Core.Set#SET_GROUP FollowGroupSet The group AI escorting the FollowUnit. + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number YStart The start position on the Y-axis in meters for the first group. + -- @param #number ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. + + --- FormationRightLine Trigger for FORMATION + -- @function [parent=#FORMATION] FormationRightLine + -- @param #FORMATION self + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number YStart The start position on the Y-axis in meters for the first group. + -- @param #number ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. + + --- FormationRightLine Asynchronous Trigger for FORMATION + -- @function [parent=#FORMATION] __FormationRightLine + -- @param #FORMATION self + -- @param #number Delay + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number YStart The start position on the Y-axis in meters for the first group. + -- @param #number ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. + + self:AddTransition( "*", "FormationLeftWing", "*" ) + + --- FormationLeftWing Handler OnAfter for FORMATION + -- @function [parent=#FORMATION] OnAfterFormationLeftWing + -- @param #FORMATION self + -- @param Core.Set#SET_GROUP FollowGroupSet The group AI escorting the FollowUnit. + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #number YStart The start position on the Y-axis in meters for the first group. + -- @param #number ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. + + --- FormationLeftWing Trigger for FORMATION + -- @function [parent=#FORMATION] FormationLeftWing + -- @param #FORMATION self + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #number YStart The start position on the Y-axis in meters for the first group. + -- @param #number ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. + + --- FormationLeftWing Asynchronous Trigger for FORMATION + -- @function [parent=#FORMATION] __FormationLeftWing + -- @param #FORMATION self + -- @param #number Delay + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #number YStart The start position on the Y-axis in meters for the first group. + -- @param #number ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. + + self:AddTransition( "*", "FormationRightWing", "*" ) + + --- FormationRightWing Handler OnAfter for FORMATION + -- @function [parent=#FORMATION] OnAfterFormationRightWing + -- @param #FORMATION self + -- @param Core.Set#SET_GROUP FollowGroupSet The group AI escorting the FollowUnit. + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #number YStart The start position on the Y-axis in meters for the first group. + -- @param #number ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. + + --- FormationRightWing Trigger for FORMATION + -- @function [parent=#FORMATION] FormationRightWing + -- @param #FORMATION self + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #number YStart The start position on the Y-axis in meters for the first group. + -- @param #number ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. + + --- FormationRightWing Asynchronous Trigger for FORMATION + -- @function [parent=#FORMATION] __FormationRightWing + -- @param #FORMATION self + -- @param #number Delay + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #number YStart The start position on the Y-axis in meters for the first group. + -- @param #number ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. + + self:AddTransition( "*", "FormationCenterWing", "*" ) + + --- FormationCenterWing Handler OnAfter for FORMATION + -- @function [parent=#FORMATION] OnAfterFormationCenterWing + -- @param #FORMATION self + -- @param Core.Set#SET_GROUP FollowGroupSet The group AI escorting the FollowUnit. + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #number YStart The start position on the Y-axis in meters for the first group. + -- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group. + -- @param #number ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. + + --- FormationCenterWing Trigger for FORMATION + -- @function [parent=#FORMATION] FormationCenterWing + -- @param #FORMATION self + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #number YStart The start position on the Y-axis in meters for the first group. + -- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group. + -- @param #number ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. + + --- FormationCenterWing Asynchronous Trigger for FORMATION + -- @function [parent=#FORMATION] __FormationCenterWing + -- @param #FORMATION self + -- @param #number Delay + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #number YStart The start position on the Y-axis in meters for the first group. + -- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group. + -- @param #number ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. + + self:AddTransition( "*", "FormationVic", "*" ) + + --- FormationVic Handler OnAfter for FORMATION + -- @function [parent=#FORMATION] OnAfterFormationVic + -- @param #FORMATION self + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #number YStart The start position on the Y-axis in meters for the first group. + -- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group. + -- @param #number ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. + + --- FormationVic Trigger for FORMATION + -- @function [parent=#FORMATION] FormationVic + -- @param #FORMATION self + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #number YStart The start position on the Y-axis in meters for the first group. + -- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group. + -- @param #number ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. + + --- FormationVic Asynchronous Trigger for FORMATION + -- @function [parent=#FORMATION] __FormationVic + -- @param #FORMATION self + -- @param #number Delay + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #number YStart The start position on the Y-axis in meters for the first group. + -- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group. + -- @param #number ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. + + self:AddTransition( "*", "FormationBox", "*" ) + + --- FormationBox Handler OnAfter for FORMATION + -- @function [parent=#FORMATION] OnAfterFormationBox + -- @param #FORMATION self + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #number YStart The start position on the Y-axis in meters for the first group. + -- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group. + -- @param #number ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. + -- @param #number ZLevels The amount of levels on the Z-axis. + + --- FormationBox Trigger for FORMATION + -- @function [parent=#FORMATION] FormationBox + -- @param #FORMATION self + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #number YStart The start position on the Y-axis in meters for the first group. + -- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group. + -- @param #number ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. + -- @param #number ZLevels The amount of levels on the Z-axis. + + --- FormationBox Asynchronous Trigger for FORMATION + -- @function [parent=#FORMATION] __FormationBox + -- @param #FORMATION self + -- @param #number Delay + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #number YStart The start position on the Y-axis in meters for the first group. + -- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group. + -- @param #number ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. + -- @param #number ZLevels The amount of levels on the Z-axis. + + self:AddTransition( "*", "Follow", "Following" ) + + self:FormationLeftLine( 500, 0, 250, 250 ) + + self.FollowName = FollowName + + self.CT1 = 0 + self.GT1 = 0 + + return self +end + + +--- Set time interval between updates of the formation. +-- @param #FORMATION self +-- @param #number dt Time step in seconds between formation updates. Default is every 0.5 seconds. +-- @return #FORMATION +function FORMATION:SetFollowTimeInterval(dt) + self.dtFollow=dt or 0.5 + return self +end + +--- This function is for test, it will put on the frequency of the FollowScheduler a red smoke at the direction vector calculated for the escort to fly to. +-- This allows to visualize where the escort is flying to. +-- @param #FORMATION self +-- @param #boolean SmokeDirection If true, then the direction vector will be smoked. +-- @return #FORMATION +function FORMATION:TestSmokeDirectionVector( SmokeDirection ) + self.SmokeDirectionVector = ( SmokeDirection == true ) and true or false + return self +end + +--- FormationLine Handler OnAfter for FORMATION +-- @param #FORMATION self +-- @param Core.Set#SET_GROUP FollowGroupSet The group AI escorting the FollowUnit. +-- @param #string From +-- @param #string Event +-- @param #string To +-- @param #number XStart The start position on the X-axis in meters for the first group. +-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. +-- @param #number YStart The start position on the Y-axis in meters for the first group. +-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group. +-- @param #number ZStart The start position on the Z-axis in meters for the first group. +-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. +-- @return #FORMATION +function FORMATION:onafterFormationLine( FollowGroupSet, From , Event , To, XStart, XSpace, YStart, YSpace, ZStart, ZSpace, Formation ) + self:F( { FollowGroupSet, From , Event ,To, XStart, XSpace, YStart, YSpace, ZStart, ZSpace, Formation } ) + + XStart = XStart or self.XStart + XSpace = XSpace or self.XSpace + YStart = YStart or self.YStart + YSpace = YSpace or self.YSpace + ZStart = ZStart or self.ZStart + ZSpace = ZSpace or self.ZSpace + + local FollowSet = FollowGroupSet:GetSet() + + local i = 1 --FF i=0 caused first unit to have no XSpace! Probably needs further adjustments. This is just a quick work around. + + for FollowID, FollowGroup in pairs( FollowSet ) do + + local PointVec3 = COORDINATE: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 + + FollowGroup:SetState( FollowGroup, "Formation", Formation ) + end + + return self + +end + +--- FormationTrail Handler OnAfter for FORMATION +-- @param #FORMATION self +-- @param Core.Set#SET_GROUP FollowGroupSet The group AI escorting the FollowUnit. +-- @param #string From +-- @param #string Event +-- @param #string To +-- @param #number XStart The start position on the X-axis in meters for the first group. +-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. +-- @param #number YStart The start position on the Y-axis in meters for the first group. +-- @return #FORMATION +function FORMATION:onafterFormationTrail( FollowGroupSet, From , Event , To, XStart, XSpace, YStart ) + + self:onafterFormationLine(FollowGroupSet,From,Event,To,XStart,XSpace,YStart,0,0,0, self.Formation.Trail ) + + return self +end + + +--- FormationStack Handler OnAfter for FORMATION +-- @param #FORMATION self +-- @param Core.Set#SET_GROUP FollowGroupSet The group AI escorting the FollowUnit. +-- @param #string From +-- @param #string Event +-- @param #string To +-- @param #number XStart The start position on the X-axis in meters for the first group. +-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. +-- @param #number YStart The start position on the Y-axis in meters for the first group. +-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group. +-- @return #FORMATION +function FORMATION:onafterFormationStack( FollowGroupSet, From , Event , To, XStart, XSpace, YStart, YSpace ) + + self:onafterFormationLine(FollowGroupSet,From,Event,To,XStart,XSpace,YStart,YSpace,0,0, self.Formation.Stack ) + + return self +end + +--- FormationLeftLine Handler OnAfter for FORMATION +-- @param #FORMATION self +-- @param Core.Set#SET_GROUP FollowGroupSet The group AI escorting the FollowUnit. +-- @param #string From +-- @param #string Event +-- @param #string To +-- @param #number XStart The start position on the X-axis in meters for the first group. +-- @param #number YStart The start position on the Y-axis in meters for the first group. +-- @param #number ZStart The start position on the Z-axis in meters for the first group. +-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. +-- @return #FORMATION +function FORMATION:onafterFormationLeftLine( FollowGroupSet, From , Event , To, XStart, YStart, ZStart, ZSpace ) + + self:onafterFormationLine(FollowGroupSet,From,Event,To,XStart,0,YStart,0,-ZStart,-ZSpace, self.Formation.LeftLine ) + + return self +end + +--- FormationRightLine Handler OnAfter for FORMATION +-- @param #FORMATION self +-- @param Core.Set#SET_GROUP FollowGroupSet The group AI escorting the FollowUnit. +-- @param #string From +-- @param #string Event +-- @param #string To +-- @param #number XStart The start position on the X-axis in meters for the first group. +-- @param #number YStart The start position on the Y-axis in meters for the first group. +-- @param #number ZStart The start position on the Z-axis in meters for the first group. +-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. +-- @return #FORMATION +function FORMATION:onafterFormationRightLine( FollowGroupSet, From , Event , To, XStart, YStart, ZStart, ZSpace ) + + self:onafterFormationLine(FollowGroupSet,From,Event,To,XStart,0,YStart,0,ZStart,ZSpace,self.Formation.RightLine) + + return self +end + +--- FormationLeftWing Handler OnAfter for FORMATION +-- @param #FORMATION self +-- @param Core.Set#SET_GROUP FollowGroupSet The group AI escorting the FollowUnit. +-- @param #string From +-- @param #string Event +-- @param #string To +-- @param #number XStart The start position on the X-axis in meters for the first group. +-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. +-- @param #number YStart The start position on the Y-axis in meters for the first group. +-- @param #number ZStart The start position on the Z-axis in meters for the first group. +-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. +function FORMATION:onafterFormationLeftWing( FollowGroupSet, From , Event , To, XStart, XSpace, YStart, ZStart, ZSpace ) + + self:onafterFormationLine(FollowGroupSet,From,Event,To,XStart,XSpace,YStart,0,-ZStart,-ZSpace,self.Formation.LeftWing) + + return self +end + +--- FormationRightWing Handler OnAfter for FORMATION +-- @function [parent=#FORMATION] OnAfterFormationRightWing +-- @param #FORMATION self +-- @param Core.Set#SET_GROUP FollowGroupSet The group AI escorting the FollowUnit. +-- @param #string From +-- @param #string Event +-- @param #string To +-- @param #number XStart The start position on the X-axis in meters for the first group. +-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. +-- @param #number YStart The start position on the Y-axis in meters for the first group. +-- @param #number ZStart The start position on the Z-axis in meters for the first group. +-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. +function FORMATION:onafterFormationRightWing( FollowGroupSet, From , Event , To, XStart, XSpace, YStart, ZStart, ZSpace ) + + self:onafterFormationLine(FollowGroupSet,From,Event,To,XStart,XSpace,YStart,0,ZStart,ZSpace,self.Formation.RightWing) + + return self +end + +--- FormationCenterWing Handler OnAfter for FORMATION +-- @param #FORMATION self +-- @param Core.Set#SET_GROUP FollowGroupSet The group AI escorting the FollowUnit. +-- @param #string From +-- @param #string Event +-- @param #string To +-- @param #number XStart The start position on the X-axis in meters for the first group. +-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. +-- @param #number YStart The start position on the Y-axis in meters for the first group. +-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group. +-- @param #number ZStart The start position on the Z-axis in meters for the first group. +-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. +function 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 = COORDINATE: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 + FollowGroup:SetState( FollowGroup, "Formation", self.Formation.Vic ) + end + + return self +end + +--- FormationVic Handle for FORMATION +-- @param #FORMATION self +-- @param #string From +-- @param #string Event +-- @param #string To +-- @param #number XStart The start position on the X-axis in meters for the first group. +-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. +-- @param #number YStart The start position on the Y-axis in meters for the first group. +-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group. +-- @param #number ZStart The start position on the Z-axis in meters for the first group. +-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. +-- @return #FORMATION +function 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 + +--- FormationBox Handler OnAfter for FORMATION +-- @param #FORMATION self +-- @param #string From +-- @param #string Event +-- @param #string To +-- @param #number XStart The start position on the X-axis in meters for the first group. +-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. +-- @param #number YStart The start position on the Y-axis in meters for the first group. +-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group. +-- @param #number ZStart The start position on the Z-axis in meters for the first group. +-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. +-- @param #number ZLevels The amount of levels on the Z-axis. +-- @return #FORMATION +function 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 = COORDINATE: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 + FollowGroup:SetState( FollowGroup, "Formation", self.Formation.Box ) + end + + return self +end + +--- Use the method @{FORMATION#FORMATION.SetFlightRandomization}() to make the air units in your formation randomize their flight a bit while in formation. +-- @param #FORMATION self +-- @param #number FlightRandomization The formation flying errors that pilots can make while in formation. Is a range set in meters. +-- @return #FORMATION +function FORMATION:SetFlightRandomization( FlightRandomization ) + self.FlightRandomization = FlightRandomization + return self +end + +--- Stop function. Formation will not be updated any more. +-- @param #FORMATION self +-- @param Core.Set#SET_GROUP FollowGroupSet The following set of groups. +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To The to state. +function FORMATION:onafterStop(FollowGroupSet, From, Event, To) + self:E("Stopping formation.") +end + +--- Follow event fuction. Check if coming from state "stopped". If so the transition is rejected. +-- @param #FORMATION self +-- @param Core.Set#SET_GROUP FollowGroupSet The following set of groups. +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To The to state. +function FORMATION:onbeforeFollow( FollowGroupSet, From, Event, To ) + if From=="Stopped" then + return false -- Deny transition. + end + return true +end + +--- Enter following state. +-- @param #FORMATION self +-- @param Core.Set#SET_GROUP FollowGroupSet The following set of groups. +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To The to state. +function FORMATION:onenterFollowing( FollowGroupSet ) + + if self.FollowUnit:IsAlive() then + + local ClientUnit = self.FollowUnit + + local CT1, CT2, CV1, CV2 + CT1 = ClientUnit:GetState( self, "CT1" ) + + local CuVec3=ClientUnit:GetVec3() + + if CT1 == nil or CT1 == 0 then + ClientUnit:SetState( self, "CV1", CuVec3) + ClientUnit:SetState( self, "CT1", timer.getTime() ) + else + CT1 = ClientUnit:GetState( self, "CT1" ) + CT2 = timer.getTime() + CV1 = ClientUnit:GetState( self, "CV1" ) + CV2 = CuVec3 + + ClientUnit:SetState( self, "CT1", CT2 ) + ClientUnit:SetState( self, "CV1", CV2 ) + end + + --FollowGroupSet:ForEachGroupAlive( bla, self, ClientUnit, CT1, CV1, CT2, CV2) + + for _,_group in pairs(FollowGroupSet:GetSet()) do + local group=_group --Wrapper.Group#GROUP + if group and group:IsAlive() then + self:FollowMe(group, ClientUnit, CT1, CV1, CT2, CV2) + end + end + + self:__Follow( -self.dtFollow ) + end + +end + +--- Follow me. +-- @param #FORMATION self +-- @param Wrapper.Group#GROUP FollowGroup Follow group. +-- @param Wrapper.Unit#UNIT ClientUnit Client Unit. +-- @param DCS#Time CT1 Time +-- @param DCS#Vec3 CV1 Vec3 +-- @param DCS#Time CT2 Time +-- @param DCS#Vec3 CV2 Vec3 +function FORMATION:FollowMe(FollowGroup, ClientUnit, CT1, CV1, CT2, CV2) + + if not self:Is("Stopped") then + + self:T({Mode=FollowGroup:GetState( FollowGroup, "Mode" )}) + + FollowGroup:OptionROTEvadeFire() + FollowGroup:OptionROEReturnFire() + + local GroupUnit = FollowGroup:GetUnit( 1 ) + + local GuVec3=GroupUnit:GetVec3() + + 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", GuVec3) + 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 = GuVec3 + + GV2.x=GV2.x+math.random( -self.FlightRandomization / 2, self.FlightRandomization / 2 ) + GV2.y=GV2.y+math.random( -self.FlightRandomization / 2, self.FlightRandomization / 2 ) + GV2.z=GV2.z+math.random( -self.FlightRandomization / 2, self.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 + + -- Calculate the distance + 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 + + -- Calculate the group direction vector + local GV = { x = GV2.x - CV2.x, y = GV2.y - CV2.y, z = GV2.z - CV2.z } + + -- Calculate GH2, GH2 with the same height as CV2. + local GH2 = { x = GV2.x, y = CV2.y + FollowFormation.y, z = GV2.z } + + -- Calculate the angle of GV to the orthonormal plane + 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 ) + + -- Now we calculate the intersecting vector between the circle around CV2 with radius FollowDistance and GH2. + -- From the GeoGebra model: CVI = (x(CV2) + FollowDistance cos(alpha), y(GH2) + FollowDistance sin(alpha), z(CV2)) + local Inclination = ( Distance + FollowFormation.x ) / 10 + if Inclination < -30 then + Inclination = - 30 + end + + local CVI = { + x = CV2.x + CS * 10 * math.sin(Ca), + y = GH2.y + Inclination, -- + FollowFormation.y, + z = CV2.z + CS * 10 * math.cos(Ca), + } + + -- Calculate the direction vector DV of the escort group. We use CVI as the base and CV2 as the direction. + local DV = { x = CV2.x - CVI.x, y = CV2.y - CVI.y, z = CV2.z - CVI.z } + + -- We now calculate the unary direction vector DVu, so that we can multiply DVu with the speed, which is expressed in meters / s. + -- We need to calculate this vector to predict the point the escort group needs to fly to according its speed. + -- The distance of the destination point should be far enough not to have the aircraft starting to swipe left to right... + local DVu = { x = DV.x / FollowDistance, y = DV.y, z = DV.z / FollowDistance } + + -- Now we can calculate the group destination vector GDV. + 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 + } + + -- Debug smoke. + if self.SmokeDirectionVector == true then + trigger.action.smoke( GDV, trigger.smokeColor.Green ) + trigger.action.smoke( GDV_Formation, trigger.smokeColor.White ) + end + + local Time = 120 + + local Speed = - ( Distance + FollowFormation.x ) / Time + + if Distance > -10000 then + Speed = - ( Distance + FollowFormation.x ) / 60 + end + + if Distance > -2500 then + Speed = - ( Distance + FollowFormation.x ) / 20 + end + + local GS = Speed + CS + + --self:F( { Distance = Distance, Speed = Speed, CS = CS, GS = GS } ) + + -- Now route the escort to the desired point with the desired speed. + FollowGroup:RouteToVec3( GDV_Formation, GS ) -- DCS models speed in Mps (Miles per second) + + end + end + end +end diff --git a/Moose Development/Moose/Functional/Suppression.lua b/Moose Development/Moose/Functional/Suppression.lua index d93959990..08ff6966c 100644 --- a/Moose Development/Moose/Functional/Suppression.lua +++ b/Moose Development/Moose/Functional/Suppression.lua @@ -308,7 +308,7 @@ SUPPRESSION.version="0.9.4" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---- Creates a new AI_suppression object. +--- Creates a new suppression object. -- @param #SUPPRESSION self -- @param Wrapper.Group#GROUP group The GROUP object for which suppression should be applied. -- @return #SUPPRESSION self diff --git a/Moose Development/Moose/Modules_local.lua b/Moose Development/Moose/Modules_local.lua index a080a6942..44738a244 100644 --- a/Moose Development/Moose/Modules_local.lua +++ b/Moose Development/Moose/Modules_local.lua @@ -31,6 +31,7 @@ __Moose.Include( 'Core\\MarkerOps_Base.lua' ) __Moose.Include( 'Core\\TextAndSound.lua' ) __Moose.Include( 'Core\\Condition.lua' ) __Moose.Include( 'Core\\ClientMenu.lua' ) +__Moose.Include( 'Core\\Vector.lua' ) __Moose.Include( 'Wrapper\\Object.lua' ) __Moose.Include( 'Wrapper\\Identifiable.lua' ) @@ -76,6 +77,12 @@ __Moose.Include( 'Functional\\AmmoTruck.lua' ) __Moose.Include( 'Functional\\Tiresias.lua' ) __Moose.Include( 'Functional\\Stratego.lua' ) __Moose.Include( 'Functional\\ClientWatch.lua' ) +__Moose.Include( 'Functional\\Formation.lua' ) + +__Moose.Include( 'Navigation\\Beacons.lua' ) +__Moose.Include( 'Navigation\\Point.lua' ) +__Moose.Include( 'Navigation\\Radios.lua' ) +__Moose.Include( 'Navigation\\Towns.lua' ) __Moose.Include( 'Ops\\Airboss.lua' ) __Moose.Include( 'Ops\\RecoveryTanker.lua' ) diff --git a/Moose Development/Moose/Ops/OpsGroup.lua b/Moose Development/Moose/Ops/OpsGroup.lua index 08539aa5c..d3d212670 100644 --- a/Moose Development/Moose/Ops/OpsGroup.lua +++ b/Moose Development/Moose/Ops/OpsGroup.lua @@ -4311,7 +4311,7 @@ function OPSGROUP:_UpdateTask(Task, Mission) local followUnit=UNIT:FindByName(param.unitname) -- Define AI Formation object. - Task.formation=AI_FORMATION:New(followUnit, followSet, AUFTRAG.SpecialTask.FORMATION, "Follow X at given parameters.") + Task.formation=FORMATION:New(followUnit, followSet, AUFTRAG.SpecialTask.FORMATION) -- Formation parameters. Task.formation:FormationCenterWing(-param.offsetX, 50, math.abs(param.altitude), 50, param.offsetZ, 50) diff --git a/Moose Development/Moose/Ops/RescueHelo.lua b/Moose Development/Moose/Ops/RescueHelo.lua index 70a1e95f4..954735153 100644 --- a/Moose Development/Moose/Ops/RescueHelo.lua +++ b/Moose Development/Moose/Ops/RescueHelo.lua @@ -20,7 +20,6 @@ -- === -- -- ### Author: **funkyfranky** --- ### Contributions: Flightcontrol (@{AI.AI_Formation} class being used here) -- -- @module Ops.RescueHelo -- @image Ops_RescueHelo.png @@ -37,7 +36,7 @@ -- @field #number takeoff Takeoff type. -- @field Wrapper.Airbase#AIRBASE airbase The airbase object acting as home base of the helo. -- @field Core.Set#SET_GROUP followset Follow group set. --- @field AI.AI_Formation#AI_FORMATION formation AI_FORMATION object. +-- @field Functional.Formation#FORMATION formation FORMATION object. -- @field #number lowfuel Low fuel threshold of helo in percent. -- @field #number altitude Altitude of helo in meters. -- @field #number offsetX Offset in meters to carrier in longitudinal direction. @@ -947,17 +946,13 @@ function RESCUEHELO:onafterStart(From, Event, To) self.HeloFuel0=self.helo:GetFuel() -- Define AI Formation object. - self.formation=AI_FORMATION:New(self.carrier, self.followset, "Helo Formation with Carrier", "Follow Carrier at given parameters.") - + self.formation=FORMATION:New(self.carrier, self.followset, "Helo Formation with Carrier") -- Formation parameters. self.formation:FormationCenterWing(-self.offsetX, 50, math.abs(self.altitude), 50, self.offsetZ, 50) -- Set follow time interval. self.formation:SetFollowTimeInterval(self.dtFollow) - -- Formation mode. - self.formation:SetFlightModeFormation(self.helo) - -- Start formation FSM. self.formation:__Start(delay) diff --git a/Moose Development/Moose/Wrapper/Client.lua b/Moose Development/Moose/Wrapper/Client.lua index d39f0bb30..3fb04ab4a 100644 --- a/Moose Development/Moose/Wrapper/Client.lua +++ b/Moose Development/Moose/Wrapper/Client.lua @@ -516,28 +516,6 @@ function CLIENT:IsTransport() return self.ClientTransport end ---- Shows the @{AI.AI_Cargo#CARGO} contained within the CLIENT to the player as a message. --- The @{AI.AI_Cargo#CARGO} is shown using the @{Core.Message#MESSAGE} distribution system. --- @param #CLIENT self -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 - --- The main message driver for the CLIENT. -- This function displays various messages to the Player logged into the CLIENT through the DCS World Messaging system. -- @param #CLIENT self diff --git a/Moose Development/Moose/Wrapper/Controllable.lua b/Moose Development/Moose/Wrapper/Controllable.lua index 780dc31c8..82ab29432 100644 --- a/Moose Development/Moose/Wrapper/Controllable.lua +++ b/Moose Development/Moose/Wrapper/Controllable.lua @@ -409,7 +409,7 @@ function CONTROLLABLE:SetTask( DCSTask, WaitTime ) local Controller = self:_GetController() -- self:I( "Before SetTask" ) Controller:setTask( DCSTask ) - -- AI_FORMATION class (used by RESCUEHELO) calls SetTask twice per second! hence spamming the DCS log file ==> setting this to trace. + -- RESCUEHELO calls SetTask twice per second! hence spamming the DCS log file ==> setting this to trace. self:T( { ControllableName = self:GetName(), DCSTask = DCSTask } ) else BASE:E( { DCSControllableName .. " is not alive anymore.", DCSTask = DCSTask } ) diff --git a/Moose Setup/Moose.files b/Moose Setup/Moose.files index d1263e908..f7c8be377 100644 --- a/Moose Setup/Moose.files +++ b/Moose Setup/Moose.files @@ -75,6 +75,7 @@ Functional/ZoneGoalCargo.lua Functional/Tiresias.lua Functional/Stratego.lua Functional/ClientWatch.lua +Functional/Formation.lua Ops/Airboss.lua Ops/RecoveryTanker.lua