diff --git a/Moose Development/Moose/Core/Base.lua b/Moose Development/Moose/Core/Base.lua
index 018f2eb02..64bcd30d2 100644
--- a/Moose Development/Moose/Core/Base.lua
+++ b/Moose Development/Moose/Core/Base.lua
@@ -228,7 +228,8 @@ BASE = {
-- @type FORMATION
-- @field Cone A cone formation.
FORMATION = {
- Cone = "Cone"
+ Cone = "Cone",
+ Vee = "Vee"
}
diff --git a/Moose Development/Moose/AI/AI_Cargo.lua b/Moose Development/Moose/Core/Cargo.lua
similarity index 52%
rename from Moose Development/Moose/AI/AI_Cargo.lua
rename to Moose Development/Moose/Core/Cargo.lua
index 2172045f7..f8414b91f 100644
--- a/Moose Development/Moose/AI/AI_Cargo.lua
+++ b/Moose Development/Moose/Core/Cargo.lua
@@ -1,69 +1,31 @@
----Single-Player:**Yes** / Multi-Player:**Yes** / AI:**Yes** / Human:**No** / Types:**Ground** --
--- **Management of logical cargo objects, that can be transported from and to transportation carriers.**
+--- **Core** -- Management of CARGO logistics, that can be transported from and to transportation carriers.
--
--- 
+-- 
--
-- ===
--
-- Cargo can be of various forms, always are composed out of ONE object ( one unit or one static or one slingload crate ):
--
--- * AI_CARGO_UNIT, represented by a @{Unit} in a @{Group}: Cargo can be represented by a Unit in a Group. Destruction of the Unit will mean that the cargo is lost.
--- * CARGO_STATIC, represented by a @{Static}: Cargo can be represented by a Static. Destruction of the Static will mean that the cargo is lost.
--- * AI_CARGO_PACKAGE, contained in a @{Unit} of a @{Group}: Cargo can be contained within a Unit of a Group. The cargo can be **delivered** by the @{Unit}. If the Unit is destroyed, the cargo will be destroyed also.
--- * AI_CARGO_PACKAGE, Contained in a @{Static}: Cargo can be contained within a Static. The cargo can be **collected** from the @Static. If the @{Static} is destroyed, the cargo will be destroyed.
--- * CARGO_SLINGLOAD, represented by a @{Cargo} that is transportable: Cargo can be represented by a Cargo object that is transportable. Destruction of the Cargo will mean that the cargo is lost.
+-- * CARGO_UNIT, represented by a @{Unit} in a singleton @{Group}: Cargo can be represented by a Unit in a Group. a CARGO_UNIT is representable...
+-- * CARGO_GROUP, represented by a @{Group}. A CARGO_GROUP is reportable...
--
--- * AI_CARGO_GROUPED, represented by a Group of CARGO_UNITs.
+-- ====
--
--- # 1) @{#AI_CARGO} class, extends @{Fsm#FSM_PROCESS}
+-- # Demo Missions
--
--- The @{#AI_CARGO} class defines the core functions that defines a cargo object within MOOSE.
--- A cargo is a logical object defined that is available for transport, and has a life status within a simulation.
+-- ### [CARGO Demo Missions source code]()
+--
+-- ### [CARGO Demo Missions, only for beta testers]()
--
--- The AI_CARGO is a state machine: it manages the different events and states of the cargo.
--- All derived classes from AI_CARGO follow the same state machine, expose the same cargo event functions, and provide the same cargo states.
+-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases)
--
--- ## 1.2.1) AI_CARGO Events:
+-- ====
--
--- * @{#AI_CARGO.Board}( ToCarrier ): Boards the cargo to a carrier.
--- * @{#AI_CARGO.Load}( ToCarrier ): Loads the cargo into a carrier, regardless of its position.
--- * @{#AI_CARGO.UnBoard}( ToPointVec2 ): UnBoard the cargo from a carrier. This will trigger a movement of the cargo to the option ToPointVec2.
--- * @{#AI_CARGO.UnLoad}( ToPointVec2 ): UnLoads the cargo from a carrier.
--- * @{#AI_CARGO.Dead}( Controllable ): The cargo is dead. The cargo process will be ended.
+-- # YouTube Channel
--
--- ## 1.2.2) AI_CARGO States:
+-- ### [SPAWNSTATIC YouTube Channel]()
--
--- * **UnLoaded**: The cargo is unloaded from a carrier.
--- * **Boarding**: The cargo is currently boarding (= running) into a carrier.
--- * **Loaded**: The cargo is loaded into a carrier.
--- * **UnBoarding**: The cargo is currently unboarding (=running) from a carrier.
--- * **Dead**: The cargo is dead ...
--- * **End**: The process has come to an end.
---
--- ## 1.2.3) AI_CARGO state transition methods:
---
--- State transition functions can be set **by the mission designer** customizing or improving the behaviour of the state.
--- There are 2 moments when state transition methods will be called by the state machine:
---
--- * **Leaving** the state.
--- The state transition method needs to start with the name **OnLeave + the name of the state**.
--- If the state transition method returns false, then the processing of the state transition will not be done!
--- If you want to change the behaviour of the AIControllable at this event, return false,
--- but then you'll need to specify your own logic using the AIControllable!
---
--- * **Entering** the state.
--- 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.
---
--- # 2) #AI_CARGO_UNIT class
---
--- The AI_CARGO_UNIT class defines a cargo that is represented by a UNIT object within the simulator, and can be transported by a carrier.
--- Use the event functions as described above to Load, UnLoad, Board, UnBoard the AI_CARGO_UNIT objects to and from carriers.
---
--- # 5) #AI_CARGO_GROUPED class
---
--- The AI_CARGO_GROUPED class defines a cargo that is represented by a group of UNIT objects within the simulator, and can be transported by a carrier.
--- Use the event functions as described above to Load, UnLoad, Board, UnBoard the AI_CARGO_UNIT objects to and from carriers.
+-- ====
--
-- This module is still under construction, but is described above works already, and will keep working ...
--
@@ -75,30 +37,32 @@
--- Boards the cargo to a Carrier. The event will create a movement (= running or driving) of the cargo to the Carrier.
-- The cargo must be in the **UnLoaded** state.
--- @function [parent=#AI_CARGO] Board
--- @param #AI_CARGO self
+-- @function [parent=#CARGO] Board
+-- @param #CARGO self
-- @param Wrapper.Controllable#CONTROLLABLE ToCarrier The Carrier that will hold the cargo.
+-- @param #number NearRadius The radius when the cargo will board the Carrier (to avoid collision).
--- Boards the cargo to a Carrier. The event will create a movement (= running or driving) of the cargo to the Carrier.
-- The cargo must be in the **UnLoaded** state.
--- @function [parent=#AI_CARGO] __Board
--- @param #AI_CARGO self
+-- @function [parent=#CARGO] __Board
+-- @param #CARGO self
-- @param #number DelaySeconds The amount of seconds to delay the action.
-- @param Wrapper.Controllable#CONTROLLABLE ToCarrier The Carrier that will hold the cargo.
+-- @param #number NearRadius The radius when the cargo will board the Carrier (to avoid collision).
-- UnBoard
--- UnBoards the cargo to a Carrier. The event will create a movement (= running or driving) of the cargo from the Carrier.
-- The cargo must be in the **Loaded** state.
--- @function [parent=#AI_CARGO] UnBoard
--- @param #AI_CARGO self
+-- @function [parent=#CARGO] UnBoard
+-- @param #CARGO self
-- @param Core.Point#POINT_VEC2 ToPointVec2 (optional) @{Point#POINT_VEC2) to where the cargo should run after onboarding. If not provided, the cargo will run to 60 meters behind the Carrier location.
--- UnBoards the cargo to a Carrier. The event will create a movement (= running or driving) of the cargo from the Carrier.
-- The cargo must be in the **Loaded** state.
--- @function [parent=#AI_CARGO] __UnBoard
--- @param #AI_CARGO self
+-- @function [parent=#CARGO] __UnBoard
+-- @param #CARGO self
-- @param #number DelaySeconds The amount of seconds to delay the action.
-- @param Core.Point#POINT_VEC2 ToPointVec2 (optional) @{Point#POINT_VEC2) to where the cargo should run after onboarding. If not provided, the cargo will run to 60 meters behind the Carrier location.
@@ -107,14 +71,14 @@
--- Loads the cargo to a Carrier. The event will load the cargo into the Carrier regardless of its position. There will be no movement simulated of the cargo loading.
-- The cargo must be in the **UnLoaded** state.
--- @function [parent=#AI_CARGO] Load
--- @param #AI_CARGO self
+-- @function [parent=#CARGO] Load
+-- @param #CARGO self
-- @param Wrapper.Controllable#CONTROLLABLE ToCarrier The Carrier that will hold the cargo.
--- Loads the cargo to a Carrier. The event will load the cargo into the Carrier regardless of its position. There will be no movement simulated of the cargo loading.
-- The cargo must be in the **UnLoaded** state.
--- @function [parent=#AI_CARGO] __Load
--- @param #AI_CARGO self
+-- @function [parent=#CARGO] __Load
+-- @param #CARGO self
-- @param #number DelaySeconds The amount of seconds to delay the action.
-- @param Wrapper.Controllable#CONTROLLABLE ToCarrier The Carrier that will hold the cargo.
@@ -123,14 +87,14 @@
--- UnLoads the cargo to a Carrier. The event will unload the cargo from the Carrier. There will be no movement simulated of the cargo loading.
-- The cargo must be in the **Loaded** state.
--- @function [parent=#AI_CARGO] UnLoad
--- @param #AI_CARGO self
+-- @function [parent=#CARGO] UnLoad
+-- @param #CARGO self
-- @param Core.Point#POINT_VEC2 ToPointVec2 (optional) @{Point#POINT_VEC2) to where the cargo will be placed after unloading. If not provided, the cargo will be placed 60 meters behind the Carrier location.
--- UnLoads the cargo to a Carrier. The event will unload the cargo from the Carrier. There will be no movement simulated of the cargo loading.
-- The cargo must be in the **Loaded** state.
--- @function [parent=#AI_CARGO] __UnLoad
--- @param #AI_CARGO self
+-- @function [parent=#CARGO] __UnLoad
+-- @param #CARGO self
-- @param #number DelaySeconds The amount of seconds to delay the action.
-- @param Core.Point#POINT_VEC2 ToPointVec2 (optional) @{Point#POINT_VEC2) to where the cargo will be placed after unloading. If not provided, the cargo will be placed 60 meters behind the Carrier location.
@@ -138,46 +102,47 @@
-- UnLoaded
---- @function [parent=#AI_CARGO] OnLeaveUnLoaded
--- @param #AI_CARGO self
+--- @function [parent=#CARGO] OnLeaveUnLoaded
+-- @param #CARGO self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
-- @return #boolean
---- @function [parent=#AI_CARGO] OnEnterUnLoaded
--- @param #AI_CARGO self
+--- @function [parent=#CARGO] OnEnterUnLoaded
+-- @param #CARGO self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
-- Loaded
---- @function [parent=#AI_CARGO] OnLeaveLoaded
--- @param #AI_CARGO self
+--- @function [parent=#CARGO] OnLeaveLoaded
+-- @param #CARGO self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
-- @return #boolean
---- @function [parent=#AI_CARGO] OnEnterLoaded
--- @param #AI_CARGO self
+--- @function [parent=#CARGO] OnEnterLoaded
+-- @param #CARGO self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
-- Boarding
---- @function [parent=#AI_CARGO] OnLeaveBoarding
--- @param #AI_CARGO self
+--- @function [parent=#CARGO] OnLeaveBoarding
+-- @param #CARGO self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
-- @return #boolean
---- @function [parent=#AI_CARGO] OnEnterBoarding
--- @param #AI_CARGO self
+--- @function [parent=#CARGO] OnEnterBoarding
+-- @param #CARGO self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
+-- @param #number NearRadius The radius when the cargo will board the Carrier (to avoid collision).
-- UnBoarding
---- @function [parent=#AI_CARGO] OnLeaveUnBoarding
--- @param #AI_CARGO self
+--- @function [parent=#CARGO] OnLeaveUnBoarding
+-- @param #CARGO self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
-- @return #boolean
---- @function [parent=#AI_CARGO] OnEnterUnBoarding
--- @param #AI_CARGO self
+--- @function [parent=#CARGO] OnEnterUnBoarding
+-- @param #CARGO self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
@@ -185,14 +150,13 @@
CARGOS = {}
-do -- AI_CARGO
+do -- CARGO
- --- @type AI_CARGO
+ --- @type CARGO
-- @extends Core.Fsm#FSM_PROCESS
-- @field #string Type A string defining the type of the cargo. eg. Engineers, Equipment, Screwdrivers.
-- @field #string Name A string defining the name of the cargo. The name is the unique identifier of the cargo.
-- @field #number Weight A number defining the weight of the cargo. The weight is expressed in kg.
- -- @field #number ReportRadius (optional) A number defining the radius in meters when the cargo is signalling or reporting to a Carrier.
-- @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...
@@ -200,8 +164,51 @@ do -- AI_CARGO
-- @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.
-- @field #boolean Containable This flag defines if the cargo can be contained within a DCS Unit.
- AI_CARGO = {
- ClassName = "AI_CARGO",
+
+ --- # CARGO class, extends @{Fsm#FSM_PROCESS}
+ --
+ -- The CARGO class defines the core functions that defines a cargo object within MOOSE.
+ -- A cargo is a logical object defined that is available for transport, and has a life status within a simulation.
+ --
+ -- The CARGO is a state machine: it manages the different events and states of the cargo.
+ -- All derived classes from CARGO follow the same state machine, expose the same cargo event functions, and provide the same cargo states.
+ --
+ -- ## CARGO Events:
+ --
+ -- * @{#CARGO.Board}( ToCarrier ): Boards the cargo to a carrier.
+ -- * @{#CARGO.Load}( ToCarrier ): Loads the cargo into a carrier, regardless of its position.
+ -- * @{#CARGO.UnBoard}( ToPointVec2 ): UnBoard the cargo from a carrier. This will trigger a movement of the cargo to the option ToPointVec2.
+ -- * @{#CARGO.UnLoad}( ToPointVec2 ): UnLoads the cargo from a carrier.
+ -- * @{#CARGO.Dead}( Controllable ): The cargo is dead. The cargo process will be ended.
+ --
+ -- ## CARGO States:
+ --
+ -- * **UnLoaded**: The cargo is unloaded from a carrier.
+ -- * **Boarding**: The cargo is currently boarding (= running) into a carrier.
+ -- * **Loaded**: The cargo is loaded into a carrier.
+ -- * **UnBoarding**: The cargo is currently unboarding (=running) from a carrier.
+ -- * **Dead**: The cargo is dead ...
+ -- * **End**: The process has come to an end.
+ --
+ -- ## CARGO state transition methods:
+ --
+ -- State transition functions can be set **by the mission designer** customizing or improving the behaviour of the state.
+ -- There are 2 moments when state transition methods will be called by the state machine:
+ --
+ -- * **Leaving** the state.
+ -- The state transition method needs to start with the name **OnLeave + the name of the state**.
+ -- If the state transition method returns false, then the processing of the state transition will not be done!
+ -- If you want to change the behaviour of the AIControllable at this event, return false,
+ -- but then you'll need to specify your own logic using the AIControllable!
+ --
+ -- * **Entering** the state.
+ -- 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
+ --
+ CARGO = {
+ ClassName = "CARGO",
Type = nil,
Name = nil,
Weight = nil,
@@ -213,22 +220,21 @@ do -- AI_CARGO
Containable = false,
}
---- @type AI_CARGO.CargoObjects
+--- @type CARGO.CargoObjects
-- @map < #string, Wrapper.Positionable#POSITIONABLE > The alive POSITIONABLE objects representing the the cargo.
---- AI_CARGO Constructor. This class is an abstract class and should not be instantiated.
--- @param #AI_CARGO self
+--- CARGO Constructor. This class is an abstract class and should not be instantiated.
+-- @param #CARGO self
-- @param #string Type
-- @param #string Name
-- @param #number Weight
--- @param #number ReportRadius (optional)
-- @param #number NearRadius (optional)
--- @return #AI_CARGO
-function AI_CARGO:New( Type, Name, Weight, ReportRadius, NearRadius )
+-- @return #CARGO
+function CARGO:New( Type, Name, Weight )
- local self = BASE:Inherit( self, FSM:New() ) -- Core.Fsm#FSM_CONTROLLABLE
- self:F( { Type, Name, Weight, ReportRadius, NearRadius } )
+ local self = BASE:Inherit( self, FSM:New() ) -- Core.Fsm#FSM
+ self:F( { Type, Name, Weight } )
self:SetStartState( "UnLoaded" )
self:AddTransition( "UnLoaded", "Board", "Boarding" )
@@ -244,8 +250,6 @@ function AI_CARGO:New( Type, Name, Weight, ReportRadius, NearRadius )
self.Type = Type
self.Name = Name
self.Weight = Weight
- self.ReportRadius = ReportRadius
- self.NearRadius = NearRadius
self.CargoObject = nil
self.CargoCarrier = nil
self.Representable = false
@@ -253,127 +257,291 @@ function AI_CARGO:New( Type, Name, Weight, ReportRadius, NearRadius )
self.Moveable = false
self.Containable = false
-
self.CargoScheduler = SCHEDULER:New()
CARGOS[self.Name] = self
+ self:SetEventPriority( 5 )
+
return self
end
+--- Get the name of the Cargo.
+-- @param #CARGO self
+-- @return #string The name of the Cargo.
+function CARGO:GetName()
+ return self.Name
+end
---- Template method to spawn a new representation of the AI_CARGO in the simulator.
--- @param #AI_CARGO self
--- @return #AI_CARGO
-function AI_CARGO:Spawn( PointVec2 )
+--- Get the type of the Cargo.
+-- @param #CARGO self
+-- @return #string The type of the Cargo.
+function CARGO:GetType()
+ return self.Type
+end
+
+--- Check if cargo is loaded.
+-- @param #CARGO self
+-- @return #boolean true if loaded
+function CARGO:IsLoaded()
+ return self:Is( "Loaded" )
+end
+
+--- Check if cargo is unloaded.
+-- @param #CARGO self
+-- @return #boolean true if unloaded
+function CARGO:IsUnLoaded()
+ return self:Is( "UnLoaded" )
+end
+
+
+--- Template method to spawn a new representation of the CARGO in the simulator.
+-- @param #CARGO self
+-- @return #CARGO
+function CARGO:Spawn( PointVec2 )
self:F()
end
+
+--- Check if Cargo is the given @{Zone}.
+-- @param #CARGO self
+-- @param Core.Zone#ZONE_BASE Zone
+-- @return #boolean **true** if cargo is in the Zone, **false** if cargo is not in the Zone.
+function CARGO:IsInZone( Zone )
+ self:F( { Zone } )
+
+ if self:IsLoaded() then
+ return Zone:IsPointVec2InZone( self.CargoCarrier:GetPointVec2() )
+ else
+ return Zone:IsPointVec2InZone( self.CargoObject:GetPointVec2() )
+ end
+
+ return nil
+
+end
+
+
--- Check if CargoCarrier is near the Cargo to be Loaded.
--- @param #AI_CARGO self
+-- @param #CARGO self
-- @param Core.Point#POINT_VEC2 PointVec2
+-- @param #number NearRadius The radius when the cargo will board the Carrier (to avoid collision).
-- @return #boolean
-function AI_CARGO:IsNear( PointVec2 )
+function CARGO:IsNear( PointVec2, NearRadius )
self:F( { PointVec2 } )
local Distance = PointVec2:DistanceFromPointVec2( self.CargoObject:GetPointVec2() )
self:T( Distance )
- if Distance <= self.NearRadius then
+ if Distance <= NearRadius then
return true
else
return false
end
end
+--- Get the current PointVec2 of the cargo.
+-- @param #CARGO self
+-- @return Core.Point#POINT_VEC2
+function CARGO:GetPointVec2()
+ return self.CargoObject:GetPointVec2()
end
-do -- AI_CARGO_REPRESENTABLE
-
- --- @type AI_CARGO_REPRESENTABLE
- -- @extends #AI_CARGO
- AI_CARGO_REPRESENTABLE = {
- ClassName = "AI_CARGO_REPRESENTABLE"
- }
-
---- AI_CARGO_REPRESENTABLE Constructor.
--- @param #AI_CARGO_REPRESENTABLE self
--- @param Wrapper.Controllable#Controllable CargoObject
--- @param #string Type
--- @param #string Name
--- @param #number Weight
--- @param #number ReportRadius (optional)
--- @param #number NearRadius (optional)
--- @return #AI_CARGO_REPRESENTABLE
-function AI_CARGO_REPRESENTABLE:New( CargoObject, Type, Name, Weight, ReportRadius, NearRadius )
- local self = BASE:Inherit( self, AI_CARGO:New( Type, Name, Weight, ReportRadius, NearRadius ) ) -- #AI_CARGO
- self:F( { Type, Name, Weight, ReportRadius, NearRadius } )
-
+--- Set the weight of the cargo.
+-- @param #CARGO self
+-- @param #number Weight The weight in kg.
+-- @return #CARGO
+function CARGO:SetWeight( Weight )
+ self.Weight = Weight
return self
end
---- Route a cargo unit to a PointVec2.
--- @param #AI_CARGO_REPRESENTABLE self
--- @param Core.Point#POINT_VEC2 ToPointVec2
--- @param #number Speed
--- @return #AI_CARGO_REPRESENTABLE
-function AI_CARGO_REPRESENTABLE:RouteTo( ToPointVec2, Speed )
- self:F2( ToPointVec2 )
-
- local Points = {}
-
- local PointStartVec2 = self.CargoObject:GetPointVec2()
-
- Points[#Points+1] = PointStartVec2:RoutePointGround( Speed )
- Points[#Points+1] = ToPointVec2:RoutePointGround( Speed )
-
- local TaskRoute = self.CargoObject:TaskRoute( Points )
- self.CargoObject:SetTask( TaskRoute, 2 )
- return self
end
-end -- AI_CARGO
-do -- AI_CARGO_UNIT
+do -- CARGO_REPRESENTABLE
- --- @type AI_CARGO_UNIT
- -- @extends #AI_CARGO_REPRESENTABLE
- AI_CARGO_UNIT = {
- ClassName = "AI_CARGO_UNIT"
+ --- @type CARGO_REPRESENTABLE
+ -- @extends #CARGO
+ CARGO_REPRESENTABLE = {
+ ClassName = "CARGO_REPRESENTABLE"
}
---- AI_CARGO_UNIT Constructor.
--- @param #AI_CARGO_UNIT self
+ --- CARGO_REPRESENTABLE Constructor.
+ -- @param #CARGO_REPRESENTABLE self
+ -- @param Wrapper.Controllable#Controllable CargoObject
+ -- @param #string Type
+ -- @param #string Name
+ -- @param #number Weight
+ -- @param #number ReportRadius (optional)
+ -- @param #number NearRadius (optional)
+ -- @return #CARGO_REPRESENTABLE
+ function CARGO_REPRESENTABLE:New( CargoObject, Type, Name, Weight, ReportRadius, NearRadius )
+ local self = BASE:Inherit( self, CARGO:New( Type, Name, Weight, ReportRadius, NearRadius ) ) -- #CARGO
+ self:F( { Type, Name, Weight, ReportRadius, NearRadius } )
+
+ return self
+ end
+
+ --- Route a cargo unit to a PointVec2.
+ -- @param #CARGO_REPRESENTABLE self
+ -- @param Core.Point#POINT_VEC2 ToPointVec2
+ -- @param #number Speed
+ -- @return #CARGO_REPRESENTABLE
+ function CARGO_REPRESENTABLE:RouteTo( ToPointVec2, Speed )
+ self:F2( ToPointVec2 )
+
+ local Points = {}
+
+ local PointStartVec2 = self.CargoObject:GetPointVec2()
+
+ Points[#Points+1] = PointStartVec2:RoutePointGround( Speed )
+ Points[#Points+1] = ToPointVec2:RoutePointGround( Speed )
+
+ local TaskRoute = self.CargoObject:TaskRoute( Points )
+ self.CargoObject:SetTask( TaskRoute, 2 )
+ return self
+ end
+
+
+end -- CARGO_REPRESENTABLE
+
+ do -- CARGO_REPORTABLE
+
+ --- @type CARGO_REPORTABLE
+ -- @extends #CARGO
+ CARGO_REPORTABLE = {
+ ClassName = "CARGO_REPORTABLE"
+ }
+
+ --- CARGO_REPORTABLE Constructor.
+ -- @param #CARGO_REPORTABLE self
+ -- @param Wrapper.Controllable#Controllable CargoObject
+ -- @param #string Type
+ -- @param #string Name
+ -- @param #number Weight
+ -- @param #number ReportRadius (optional)
+ -- @param #number NearRadius (optional)
+ -- @return #CARGO_REPORTABLE
+ function CARGO_REPORTABLE:New( CargoObject, Type, Name, Weight, ReportRadius )
+ local self = BASE:Inherit( self, CARGO:New( Type, Name, Weight ) ) -- #CARGO_REPORTABLE
+ self:F( { Type, Name, Weight, ReportRadius } )
+
+ self.ReportRadius = ReportRadius or 1000
+ self.CargoObject = CargoObject
+
+ return self
+ end
+
+ --- Check if CargoCarrier is in the ReportRadius for the Cargo to be Loaded.
+ -- @param #CARGO_REPORTABLE self
+ -- @param Core.Point#POINT_VEC2 PointVec2
+ -- @return #boolean
+ function CARGO_REPORTABLE:IsInRadius( PointVec2 )
+ self:F( { PointVec2 } )
+
+ local Distance = 0
+ if self:IsLoaded() then
+ Distance = PointVec2:DistanceFromPointVec2( self.CargoCarrier:GetPointVec2() )
+ else
+ Distance = PointVec2:DistanceFromPointVec2( self.CargoObject:GetPointVec2() )
+ end
+ self:T( Distance )
+
+ if Distance <= self.ReportRadius then
+ return true
+ else
+ return false
+ end
+
+
+ end
+
+ --- Send a CC message to a GROUP.
+ -- @param #COMMANDCENTER 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.
+ function CARGO_REPORTABLE:MessageToGroup( Message, TaskGroup, Name )
+
+ local Prefix = Name and "@ " .. Name .. ": " or "@ " .. TaskGroup:GetCallsign() .. ": "
+ Message = Prefix .. Message
+ MESSAGE:New( Message, 20, "Cargo: " .. self:GetName() ):ToGroup( TaskGroup )
+
+ end
+
+ --- Get the range till cargo will board.
+ -- @param #CARGO self
+ -- @return #number The range till cargo will board.
+ function CARGO_REPORTABLE:GetBoardingRange()
+ return self.ReportRadius
+ end
+
+end
+
+do -- CARGO_UNIT
+
+ --- @type CARGO_UNIT
+ -- @extends #CARGO_REPRESENTABLE
+
+ --- # CARGO\_UNIT class, extends @{#CARGO_REPRESENTABLE}
+ --
+ -- The CARGO\_UNIT class defines a cargo that is represented by a UNIT object within the simulator, and can be transported by a carrier.
+ -- Use the event functions as described above to Load, UnLoad, Board, UnBoard the CARGO\_UNIT objects to and from carriers.
+ --
+ -- ===
+ --
+ -- @field #CARGO_UNIT CARGO_UNIT
+ --
+ CARGO_UNIT = {
+ ClassName = "CARGO_UNIT"
+ }
+
+--- CARGO_UNIT Constructor.
+-- @param #CARGO_UNIT self
-- @param Wrapper.Unit#UNIT CargoUnit
-- @param #string Type
-- @param #string Name
-- @param #number Weight
-- @param #number ReportRadius (optional)
-- @param #number NearRadius (optional)
--- @return #AI_CARGO_UNIT
-function AI_CARGO_UNIT:New( CargoUnit, Type, Name, Weight, ReportRadius, NearRadius )
- local self = BASE:Inherit( self, AI_CARGO_REPRESENTABLE:New( CargoUnit, Type, Name, Weight, ReportRadius, NearRadius ) ) -- #AI_CARGO_UNIT
- self:F( { Type, Name, Weight, ReportRadius, NearRadius } )
+-- @return #CARGO_UNIT
+function CARGO_UNIT:New( CargoUnit, Type, Name, Weight, NearRadius )
+ local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoUnit, Type, Name, Weight, NearRadius ) ) -- #CARGO_UNIT
+ self:F( { Type, Name, Weight, NearRadius } )
self:T( CargoUnit )
self.CargoObject = CargoUnit
self:T( self.ClassName )
+
+ return self
+end
+
+--- CARGO_UNIT Destructor.
+-- @param #CARGO_UNIT self
+-- @return #CARGO_UNIT
+function CARGO_UNIT:Destroy()
+
+ -- Cargo objects are deleted from the _DATABASE and SET_CARGO objects.
+ _EVENTDISPATCHER:CreateEventDeleteCargo( self )
+
return self
end
--- Enter UnBoarding State.
--- @param #AI_CARGO_UNIT self
+-- @param #CARGO_UNIT self
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Core.Point#POINT_VEC2 ToPointVec2
-function AI_CARGO_UNIT:onenterUnBoarding( From, Event, To, ToPointVec2 )
+function CARGO_UNIT:onenterUnBoarding( From, Event, To, ToPointVec2, NearRadius )
self:F()
+ NearRadius = NearRadius or 25
+
local Angle = 180
local Speed = 10
local DeployDistance = 5
@@ -404,30 +572,32 @@ function AI_CARGO_UNIT:onenterUnBoarding( From, Event, To, ToPointVec2 )
local TaskRoute = self.CargoObject:TaskRoute( Points )
self.CargoObject:SetTask( TaskRoute, 1 )
- self:__UnBoarding( 1, ToPointVec2 )
+ self:__UnBoarding( -1, ToPointVec2, NearRadius )
end
end
end
--- Leave UnBoarding State.
--- @param #AI_CARGO_UNIT self
+-- @param #CARGO_UNIT self
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Core.Point#POINT_VEC2 ToPointVec2
-function AI_CARGO_UNIT:onleaveUnBoarding( From, Event, To, ToPointVec2 )
+function CARGO_UNIT:onleaveUnBoarding( From, Event, To, ToPointVec2, NearRadius )
self:F( { ToPointVec2, From, Event, To } )
+ NearRadius = NearRadius or 25
+
local Angle = 180
local Speed = 10
local Distance = 5
if From == "UnBoarding" then
- if self:IsNear( ToPointVec2 ) then
+ if self:IsNear( ToPointVec2, NearRadius ) then
return true
else
- self:__UnBoarding( 1, ToPointVec2 )
+ self:__UnBoarding( 1, ToPointVec2, NearRadius )
end
return false
end
@@ -435,14 +605,16 @@ function AI_CARGO_UNIT:onleaveUnBoarding( From, Event, To, ToPointVec2 )
end
--- UnBoard Event.
--- @param #AI_CARGO_UNIT self
+-- @param #CARGO_UNIT self
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Core.Point#POINT_VEC2 ToPointVec2
-function AI_CARGO_UNIT:onafterUnBoarding( From, Event, To, ToPointVec2 )
+function CARGO_UNIT:onafterUnBoarding( From, Event, To, ToPointVec2, NearRadius )
self:F( { ToPointVec2, From, Event, To } )
+ NearRadius = NearRadius or 25
+
self.CargoInAir = self.CargoObject:InAir()
self:T( self.CargoInAir )
@@ -460,12 +632,12 @@ end
--- Enter UnLoaded State.
--- @param #AI_CARGO_UNIT self
+-- @param #CARGO_UNIT self
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Core.Point#POINT_VEC2
-function AI_CARGO_UNIT:onenterUnLoaded( From, Event, To, ToPointVec2 )
+function CARGO_UNIT:onenterUnLoaded( From, Event, To, ToPointVec2 )
self:F( { ToPointVec2, From, Event, To } )
local Angle = 180
@@ -498,17 +670,19 @@ end
--- Enter Boarding State.
--- @param #AI_CARGO_UNIT self
+-- @param #CARGO_UNIT self
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Wrapper.Unit#UNIT CargoCarrier
-function AI_CARGO_UNIT:onenterBoarding( From, Event, To, CargoCarrier )
- self:F( { CargoCarrier.UnitName, From, Event, To } )
+function CARGO_UNIT:onenterBoarding( From, Event, To, CargoCarrier, NearRadius, ... )
+ self:F( { From, Event, To, CargoCarrier.UnitName, NearRadius } )
- local Speed = 10
+ local Speed = 90
local Angle = 180
local Distance = 5
+
+ NearRadius = NearRadius or 25
if From == "UnLoaded" then
local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2()
@@ -522,6 +696,25 @@ function AI_CARGO_UNIT:onenterBoarding( From, Event, To, CargoCarrier )
Points[#Points+1] = PointStartVec2:RoutePointGround( Speed )
Points[#Points+1] = CargoDeployPointVec2:RoutePointGround( Speed )
+
+ -- I need to do this mess, otherwise the units will stop boarding at a point in time...
+ -- This is a DCS bug that i am handling in this way.
+ do
+ local CargoBooardPointVec2 = CargoDeployPointVec2:GetRandomPointVec2InRadius(NearRadius,0)
+ Points[#Points+1] = CargoBooardPointVec2:RoutePointGround( Speed )
+ end
+ do
+ local CargoBooardPointVec2 = CargoDeployPointVec2:GetRandomPointVec2InRadius(NearRadius,0)
+ Points[#Points+1] = CargoBooardPointVec2:RoutePointGround( Speed )
+ end
+ do
+ local CargoBooardPointVec2 = CargoDeployPointVec2:GetRandomPointVec2InRadius(NearRadius,0)
+ Points[#Points+1] = CargoBooardPointVec2:RoutePointGround( Speed )
+ end
+ do
+ local CargoBooardPointVec2 = CargoDeployPointVec2:GetRandomPointVec2InRadius(NearRadius,0)
+ Points[#Points+1] = CargoBooardPointVec2:RoutePointGround( Speed )
+ end
local TaskRoute = self.CargoObject:TaskRoute( Points )
self.CargoObject:SetTask( TaskRoute, 2 )
@@ -530,30 +723,32 @@ function AI_CARGO_UNIT:onenterBoarding( From, Event, To, CargoCarrier )
end
--- Leave Boarding State.
--- @param #AI_CARGO_UNIT self
+-- @param #CARGO_UNIT self
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Wrapper.Unit#UNIT CargoCarrier
-function AI_CARGO_UNIT:onleaveBoarding( From, Event, To, CargoCarrier )
- self:F( { CargoCarrier.UnitName, From, Event, To } )
+function CARGO_UNIT:onleaveBoarding( From, Event, To, CargoCarrier, NearRadius, ... )
+ self:F( { From, Event, To, CargoCarrier.UnitName, NearRadius } )
- if self:IsNear( CargoCarrier:GetPointVec2() ) then
- self:__Load( 1, CargoCarrier )
+ NearRadius = NearRadius or 25
+
+ if self:IsNear( CargoCarrier:GetPointVec2(), NearRadius ) then
+ self:__Load( 1, CargoCarrier, ... )
return true
else
- self:__Boarding( 1, CargoCarrier )
+ self:__Boarding( 1, CargoCarrier, ... )
end
return false
end
--- Loaded State.
--- @param #AI_CARGO_UNIT self
+-- @param #CARGO_UNIT self
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Wrapper.Unit#UNIT CargoCarrier
-function AI_CARGO_UNIT:onenterLoaded( From, Event, To, CargoCarrier )
+function CARGO_UNIT:onenterLoaded( From, Event, To, CargoCarrier )
self:F()
self.CargoCarrier = CargoCarrier
@@ -567,13 +762,15 @@ end
--- Board Event.
--- @param #AI_CARGO_UNIT self
+-- @param #CARGO_UNIT self
-- @param #string Event
-- @param #string From
-- @param #string To
-function AI_CARGO_UNIT:onafterBoard( From, Event, To, CargoCarrier )
+function CARGO_UNIT:onafterBoard( From, Event, To, CargoCarrier, NearRadius, ... )
self:F()
+ NearRadius = NearRadius or 25
+
self.CargoInAir = self.CargoObject:InAir()
self:T( self.CargoInAir )
@@ -581,32 +778,32 @@ function AI_CARGO_UNIT:onafterBoard( From, Event, To, CargoCarrier )
-- Only move the group to the carrier when the cargo is not in the air
-- (eg. cargo can be on a oil derrick, moving the cargo on the oil derrick will drop the cargo on the sea).
if not self.CargoInAir then
- self:Load( CargoCarrier )
+ self:Load( CargoCarrier, ... )
end
end
end
-do -- AI_CARGO_PACKAGE
+do -- CARGO_PACKAGE
- --- @type AI_CARGO_PACKAGE
- -- @extends #AI_CARGO_REPRESENTABLE
- AI_CARGO_PACKAGE = {
- ClassName = "AI_CARGO_PACKAGE"
+ --- @type CARGO_PACKAGE
+ -- @extends #CARGO_REPRESENTABLE
+ CARGO_PACKAGE = {
+ ClassName = "CARGO_PACKAGE"
}
---- AI_CARGO_PACKAGE Constructor.
--- @param #AI_CARGO_PACKAGE self
+--- CARGO_PACKAGE Constructor.
+-- @param #CARGO_PACKAGE self
-- @param Wrapper.Unit#UNIT CargoCarrier The UNIT carrying the package.
-- @param #string Type
-- @param #string Name
-- @param #number Weight
-- @param #number ReportRadius (optional)
-- @param #number NearRadius (optional)
--- @return #AI_CARGO_PACKAGE
-function AI_CARGO_PACKAGE:New( CargoCarrier, Type, Name, Weight, ReportRadius, NearRadius )
- local self = BASE:Inherit( self, AI_CARGO_REPRESENTABLE:New( CargoCarrier, Type, Name, Weight, ReportRadius, NearRadius ) ) -- #AI_CARGO_PACKAGE
+-- @return #CARGO_PACKAGE
+function CARGO_PACKAGE:New( CargoCarrier, Type, Name, Weight, ReportRadius, NearRadius )
+ local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoCarrier, Type, Name, Weight, ReportRadius, NearRadius ) ) -- #CARGO_PACKAGE
self:F( { Type, Name, Weight, ReportRadius, NearRadius } )
self:T( CargoCarrier )
@@ -616,7 +813,7 @@ function AI_CARGO_PACKAGE:New( CargoCarrier, Type, Name, Weight, ReportRadius, N
end
--- Board Event.
--- @param #AI_CARGO_PACKAGE self
+-- @param #CARGO_PACKAGE self
-- @param #string Event
-- @param #string From
-- @param #string To
@@ -624,7 +821,7 @@ end
-- @param #number Speed
-- @param #number BoardDistance
-- @param #number Angle
-function AI_CARGO_PACKAGE:onafterOnBoard( From, Event, To, CargoCarrier, Speed, BoardDistance, LoadDistance, Angle )
+function CARGO_PACKAGE:onafterOnBoard( From, Event, To, CargoCarrier, Speed, BoardDistance, LoadDistance, Angle )
self:F()
self.CargoInAir = self.CargoCarrier:InAir()
@@ -654,10 +851,10 @@ function AI_CARGO_PACKAGE:onafterOnBoard( From, Event, To, CargoCarrier, Speed,
end
--- Check if CargoCarrier is near the Cargo to be Loaded.
--- @param #AI_CARGO_PACKAGE self
+-- @param #CARGO_PACKAGE self
-- @param Wrapper.Unit#UNIT CargoCarrier
-- @return #boolean
-function AI_CARGO_PACKAGE:IsNear( CargoCarrier )
+function CARGO_PACKAGE:IsNear( CargoCarrier )
self:F()
local CargoCarrierPoint = CargoCarrier:GetPointVec2()
@@ -673,12 +870,12 @@ function AI_CARGO_PACKAGE:IsNear( CargoCarrier )
end
--- Boarded Event.
--- @param #AI_CARGO_PACKAGE self
+-- @param #CARGO_PACKAGE self
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Wrapper.Unit#UNIT CargoCarrier
-function AI_CARGO_PACKAGE:onafterOnBoarded( From, Event, To, CargoCarrier, Speed, BoardDistance, LoadDistance, Angle )
+function CARGO_PACKAGE:onafterOnBoarded( From, Event, To, CargoCarrier, Speed, BoardDistance, LoadDistance, Angle )
self:F()
if self:IsNear( CargoCarrier ) then
@@ -689,7 +886,7 @@ function AI_CARGO_PACKAGE:onafterOnBoarded( From, Event, To, CargoCarrier, Speed
end
--- UnBoard Event.
--- @param #AI_CARGO_PACKAGE self
+-- @param #CARGO_PACKAGE self
-- @param #string Event
-- @param #string From
-- @param #string To
@@ -698,7 +895,7 @@ end
-- @param #number UnBoardDistance
-- @param #number Radius
-- @param #number Angle
-function AI_CARGO_PACKAGE:onafterUnBoard( From, Event, To, CargoCarrier, Speed, UnLoadDistance, UnBoardDistance, Radius, Angle )
+function CARGO_PACKAGE:onafterUnBoard( From, Event, To, CargoCarrier, Speed, UnLoadDistance, UnBoardDistance, Radius, Angle )
self:F()
self.CargoInAir = self.CargoCarrier:InAir()
@@ -731,12 +928,12 @@ function AI_CARGO_PACKAGE:onafterUnBoard( From, Event, To, CargoCarrier, Speed,
end
--- UnBoarded Event.
--- @param #AI_CARGO_PACKAGE self
+-- @param #CARGO_PACKAGE self
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Wrapper.Unit#UNIT CargoCarrier
-function AI_CARGO_PACKAGE:onafterUnBoarded( From, Event, To, CargoCarrier, Speed )
+function CARGO_PACKAGE:onafterUnBoarded( From, Event, To, CargoCarrier, Speed )
self:F()
if self:IsNear( CargoCarrier ) then
@@ -747,7 +944,7 @@ function AI_CARGO_PACKAGE:onafterUnBoarded( From, Event, To, CargoCarrier, Speed
end
--- Load Event.
--- @param #AI_CARGO_PACKAGE self
+-- @param #CARGO_PACKAGE self
-- @param #string Event
-- @param #string From
-- @param #string To
@@ -755,7 +952,7 @@ end
-- @param #number Speed
-- @param #number LoadDistance
-- @param #number Angle
-function AI_CARGO_PACKAGE:onafterLoad( From, Event, To, CargoCarrier, Speed, LoadDistance, Angle )
+function CARGO_PACKAGE:onafterLoad( From, Event, To, CargoCarrier, Speed, LoadDistance, Angle )
self:F()
self.CargoCarrier = CargoCarrier
@@ -775,13 +972,13 @@ function AI_CARGO_PACKAGE:onafterLoad( From, Event, To, CargoCarrier, Speed, Loa
end
--- UnLoad Event.
--- @param #AI_CARGO_PACKAGE self
+-- @param #CARGO_PACKAGE self
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param #number Distance
-- @param #number Angle
-function AI_CARGO_PACKAGE:onafterUnLoad( From, Event, To, CargoCarrier, Speed, Distance, Angle )
+function CARGO_PACKAGE:onafterUnLoad( From, Event, To, CargoCarrier, Speed, Distance, Angle )
self:F()
local StartPointVec2 = self.CargoCarrier:GetPointVec2()
@@ -803,162 +1000,170 @@ end
end
-do -- AI_CARGO_GROUP
+do -- CARGO_GROUP
- --- @type AI_CARGO_GROUP
- -- @extends AI.AI_Cargo#AI_CARGO
- -- @field Set#SET_BASE CargoSet A set of cargo objects.
- -- @field #string Name A string defining the name of the cargo group. The name is the unique identifier of the cargo.
- AI_CARGO_GROUP = {
- ClassName = "AI_CARGO_GROUP",
+ --- @type CARGO_GROUP
+ -- @extends #CARGO_REPORTABLE
+
+ --- # CARGO\_GROUP class
+ --
+ -- The CARGO\_GROUP class defines a cargo that is represented by a @{Group} object within the simulator, and can be transported by a carrier.
+ -- Use the event functions as described above to Load, UnLoad, Board, UnBoard the CARGO\_GROUP to and from carrier.
+ --
+ -- @field #CARGO_GROUP CARGO_GROUP
+ --
+ CARGO_GROUP = {
+ ClassName = "CARGO_GROUP",
}
---- AI_CARGO_GROUP constructor.
--- @param #AI_CARGO_GROUP self
--- @param Core.Set#Set_BASE CargoSet
+--- CARGO_GROUP constructor.
+-- @param #CARGO_GROUP self
+-- @param Wrapper.Group#GROUP CargoGroup
-- @param #string Type
-- @param #string Name
--- @param #number Weight
-- @param #number ReportRadius (optional)
-- @param #number NearRadius (optional)
--- @return #AI_CARGO_GROUP
-function AI_CARGO_GROUP:New( CargoSet, Type, Name, ReportRadius, NearRadius )
- local self = BASE:Inherit( self, AI_CARGO:New( Type, Name, 0, ReportRadius, NearRadius ) ) -- #AI_CARGO_GROUP
- self:F( { Type, Name, ReportRadius, NearRadius } )
+-- @return #CARGO_GROUP
+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 = CargoSet
+ self.CargoSet = SET_CARGO:New()
+
+ local WeightGroup = 0
+
+ for UnitID, UnitData in pairs( CargoGroup:GetUnits() ) do
+ local Unit = UnitData -- Wrapper.Unit#UNIT
+ local WeightUnit = Unit:GetDesc().massEmpty
+ WeightGroup = WeightGroup + WeightUnit
+ local CargoUnit = CARGO_UNIT:New( Unit, Type, Unit:GetName(), WeightUnit )
+ self.CargoSet:Add( CargoUnit:GetName(), CargoUnit )
+ end
+ self:SetWeight( WeightGroup )
+
+ self:T( { "Weight Cargo", WeightGroup } )
- return self
-end
-
-end -- AI_CARGO_GROUP
-
-do -- AI_CARGO_GROUPED
-
- --- @type AI_CARGO_GROUPED
- -- @extends AI.AI_Cargo#AI_CARGO_GROUP
- AI_CARGO_GROUPED = {
- ClassName = "AI_CARGO_GROUPED",
- }
-
---- AI_CARGO_GROUPED constructor.
--- @param #AI_CARGO_GROUPED self
--- @param Core.Set#Set_BASE CargoSet
--- @param #string Type
--- @param #string Name
--- @param #number Weight
--- @param #number ReportRadius (optional)
--- @param #number NearRadius (optional)
--- @return #AI_CARGO_GROUPED
-function AI_CARGO_GROUPED:New( CargoSet, Type, Name, ReportRadius, NearRadius )
- local self = BASE:Inherit( self, AI_CARGO_GROUP:New( CargoSet, Type, Name, ReportRadius, NearRadius ) ) -- #AI_CARGO_GROUPED
- self:F( { Type, Name, ReportRadius, NearRadius } )
-
+ -- Cargo objects are added to the _DATABASE and SET_CARGO objects.
+ _EVENTDISPATCHER:CreateEventNewCargo( self )
+
return self
end
--- Enter Boarding State.
--- @param #AI_CARGO_GROUPED self
+-- @param #CARGO_GROUP self
-- @param Wrapper.Unit#UNIT CargoCarrier
-- @param #string Event
-- @param #string From
-- @param #string To
-function AI_CARGO_GROUPED:onenterBoarding( From, Event, To, CargoCarrier )
+function CARGO_GROUP:onenterBoarding( From, Event, To, CargoCarrier, NearRadius, ... )
self:F( { CargoCarrier.UnitName, From, Event, To } )
+ NearRadius = NearRadius or 25
+
if From == "UnLoaded" then
- -- For each Cargo object within the AI_CARGO_GROUPED, route each object to the CargoLoadPointVec2
+ -- For each Cargo object within the CARGO_GROUPED, route each object to the CargoLoadPointVec2
self.CargoSet:ForEach(
function( Cargo )
- Cargo:__Board( 1, CargoCarrier )
+ Cargo:__Board( 1, CargoCarrier, NearRadius )
end
)
- self:__Boarding( 1, CargoCarrier )
+ self:__Boarding( 1, CargoCarrier, NearRadius, ... )
end
end
--- Enter Loaded State.
--- @param #AI_CARGO_GROUPED self
+-- @param #CARGO_GROUP self
-- @param Wrapper.Unit#UNIT CargoCarrier
-- @param #string Event
-- @param #string From
-- @param #string To
-function AI_CARGO_GROUPED:onenterLoaded( From, Event, To, CargoCarrier )
+function CARGO_GROUP:onenterLoaded( From, Event, To, CargoCarrier, ... )
self:F( { CargoCarrier.UnitName, From, Event, To } )
if From == "UnLoaded" then
- -- For each Cargo object within the AI_CARGO_GROUPED, load each cargo to the CargoCarrier.
+ -- For each Cargo object within the CARGO_GROUP, load each cargo to the CargoCarrier.
for CargoID, Cargo in pairs( self.CargoSet:GetSet() ) do
Cargo:Load( CargoCarrier )
end
end
+
+ self.CargoCarrier = CargoCarrier
+
end
--- Leave Boarding State.
--- @param #AI_CARGO_GROUPED self
+-- @param #CARGO_GROUP self
-- @param Wrapper.Unit#UNIT CargoCarrier
-- @param #string Event
-- @param #string From
-- @param #string To
-function AI_CARGO_GROUPED:onleaveBoarding( From, Event, To, CargoCarrier )
+function CARGO_GROUP:onleaveBoarding( From, Event, To, CargoCarrier, NearRadius, ... )
self:F( { CargoCarrier.UnitName, From, Event, To } )
+ NearRadius = NearRadius or 25
+
local Boarded = true
- -- For each Cargo object within the AI_CARGO_GROUPED, route each object to the CargoLoadPointVec2
+ self.CargoSet:Flush()
+
+ -- For each Cargo object within the CARGO_GROUP, route each object to the CargoLoadPointVec2
for CargoID, Cargo in pairs( self.CargoSet:GetSet() ) do
- self:T( Cargo.current )
+ self:T( { Cargo:GetName(), Cargo.current } )
if not Cargo:is( "Loaded" ) then
Boarded = false
end
end
if not Boarded then
- self:__Boarding( 1, CargoCarrier )
+ self:__Boarding( 1, CargoCarrier, NearRadius, ... )
else
- self:__Load( 1, CargoCarrier )
+ self:__Load( 1, CargoCarrier, ... )
end
return Boarded
end
--- Enter UnBoarding State.
--- @param #AI_CARGO_GROUPED self
+-- @param #CARGO_GROUP self
-- @param Core.Point#POINT_VEC2 ToPointVec2
-- @param #string Event
-- @param #string From
-- @param #string To
-function AI_CARGO_GROUPED:onenterUnBoarding( From, Event, To, ToPointVec2 )
- self:F()
+function CARGO_GROUP:onenterUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... )
+ self:F({From, Event, To, ToPointVec2, NearRadius})
+
+ NearRadius = NearRadius or 25
local Timer = 1
if From == "Loaded" then
- -- For each Cargo object within the AI_CARGO_GROUPED, route each object to the CargoLoadPointVec2
+ -- For each Cargo object within the CARGO_GROUP, route each object to the CargoLoadPointVec2
self.CargoSet:ForEach(
function( Cargo )
- Cargo:__UnBoard( Timer, ToPointVec2 )
+ Cargo:__UnBoard( Timer, ToPointVec2, NearRadius )
Timer = Timer + 10
end
)
- self:__UnBoarding( 1, ToPointVec2 )
+ self:__UnBoarding( 1, ToPointVec2, NearRadius, ... )
end
end
--- Leave UnBoarding State.
--- @param #AI_CARGO_GROUPED self
+-- @param #CARGO_GROUP self
-- @param Core.Point#POINT_VEC2 ToPointVec2
-- @param #string Event
-- @param #string From
-- @param #string To
-function AI_CARGO_GROUPED:onleaveUnBoarding( From, Event, To, ToPointVec2 )
- self:F( { ToPointVec2, From, Event, To } )
+function CARGO_GROUP:onleaveUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... )
+ self:F( { From, Event, To, ToPointVec2, NearRadius } )
+
+ NearRadius = NearRadius or 25
local Angle = 180
local Speed = 10
@@ -967,7 +1172,7 @@ function AI_CARGO_GROUPED:onleaveUnBoarding( From, Event, To, ToPointVec2 )
if From == "UnBoarding" then
local UnBoarded = true
- -- For each Cargo object within the AI_CARGO_GROUPED, route each object to the CargoLoadPointVec2
+ -- For each Cargo object within the CARGO_GROUP, route each object to the CargoLoadPointVec2
for CargoID, Cargo in pairs( self.CargoSet:GetSet() ) do
self:T( Cargo.current )
if not Cargo:is( "UnLoaded" ) then
@@ -978,7 +1183,7 @@ function AI_CARGO_GROUPED:onleaveUnBoarding( From, Event, To, ToPointVec2 )
if UnBoarded then
return true
else
- self:__UnBoarding( 1, ToPointVec2 )
+ self:__UnBoarding( 1, ToPointVec2, NearRadius, ... )
end
return false
@@ -987,31 +1192,33 @@ function AI_CARGO_GROUPED:onleaveUnBoarding( From, Event, To, ToPointVec2 )
end
--- UnBoard Event.
--- @param #AI_CARGO_GROUPED self
+-- @param #CARGO_GROUP self
-- @param Core.Point#POINT_VEC2 ToPointVec2
-- @param #string Event
-- @param #string From
-- @param #string To
-function AI_CARGO_GROUPED:onafterUnBoarding( From, Event, To, ToPointVec2 )
- self:F( { ToPointVec2, From, Event, To } )
+function CARGO_GROUP:onafterUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... )
+ self:F( { From, Event, To, ToPointVec2, NearRadius } )
- self:__UnLoad( 1, ToPointVec2 )
+ NearRadius = NearRadius or 25
+
+ self:__UnLoad( 1, ToPointVec2, ... )
end
--- Enter UnLoaded State.
--- @param #AI_CARGO_GROUPED self
+-- @param #CARGO_GROUP self
-- @param Core.Point#POINT_VEC2
-- @param #string Event
-- @param #string From
-- @param #string To
-function AI_CARGO_GROUPED:onenterUnLoaded( From, Event, To, ToPointVec2 )
- self:F( { ToPointVec2, From, Event, To } )
+function CARGO_GROUP:onenterUnLoaded( From, Event, To, ToPointVec2, ... )
+ self:F( { From, Event, To, ToPointVec2 } )
if From == "Loaded" then
- -- For each Cargo object within the AI_CARGO_GROUPED, route each object to the CargoLoadPointVec2
+ -- For each Cargo object within the CARGO_GROUP, route each object to the CargoLoadPointVec2
self.CargoSet:ForEach(
function( Cargo )
Cargo:UnLoad( ToPointVec2 )
@@ -1022,7 +1229,5 @@ function AI_CARGO_GROUPED:onenterUnLoaded( From, Event, To, ToPointVec2 )
end
-end -- AI_CARGO_GROUPED
-
-
+end -- CARGO_GROUP
diff --git a/Moose Development/Moose/Core/Database.lua b/Moose Development/Moose/Core/Database.lua
index bdf743d0d..0b3a3df6c 100644
--- a/Moose Development/Moose/Core/Database.lua
+++ b/Moose Development/Moose/Core/Database.lua
@@ -6,12 +6,14 @@
-- ===================================================
-- Mission designers can use the DATABASE class to refer to:
--
+-- * STATICS
-- * UNITS
-- * GROUPS
-- * CLIENTS
--- * AIRPORTS
+-- * AIRBASES
-- * PLAYERSJOINED
-- * PLAYERS
+-- * CARGOS
--
-- On top, for internal MOOSE administration purposes, the DATBASE administers the Unit and Group TEMPLATES as defined within the Mission Editor.
--
@@ -54,6 +56,7 @@ DATABASE = {
PLAYERS = {},
PLAYERSJOINED = {},
CLIENTS = {},
+ CARGOS = {},
AIRBASES = {},
COUNTRY_ID = {},
COUNTRY_NAME = {},
@@ -85,13 +88,15 @@ local _DATABASECategory =
function DATABASE:New()
-- Inherits from BASE
- local self = BASE:Inherit( self, BASE:New() )
+ local self = BASE:Inherit( self, BASE:New() ) -- #DATABASE
self:SetEventPriority( 1 )
self:HandleEvent( EVENTS.Birth, self._EventOnBirth )
self:HandleEvent( EVENTS.Dead, self._EventOnDeadOrCrash )
self:HandleEvent( EVENTS.Crash, self._EventOnDeadOrCrash )
+ self:HandleEvent( EVENTS.NewCargo )
+ self:HandleEvent( EVENTS.DeleteCargo )
-- Follow alive players and clients
self:HandleEvent( EVENTS.PlayerEnterUnit, self._EventOnPlayerEnterUnit )
@@ -167,22 +172,24 @@ end
--- Adds a Airbase based on the Airbase Name in the DATABASE.
-- @param #DATABASE self
-function DATABASE:AddAirbase( DCSAirbaseName )
+-- @param #string AirbaseName The name of the airbase
+function DATABASE:AddAirbase( AirbaseName )
- if not self.AIRBASES[DCSAirbaseName] then
- self.AIRBASES[DCSAirbaseName] = AIRBASE:Register( DCSAirbaseName )
+ if not self.AIRBASES[AirbaseName] then
+ self.AIRBASES[AirbaseName] = AIRBASE:Register( AirbaseName )
end
end
--- Deletes a Airbase from the DATABASE based on the Airbase Name.
-- @param #DATABASE self
-function DATABASE:DeleteAirbase( DCSAirbaseName )
+-- @param #string AirbaseName The name of the airbase
+function DATABASE:DeleteAirbase( AirbaseName )
- --self.AIRBASES[DCSAirbaseName] = nil
+ self.AIRBASES[AirbaseName] = nil
end
---- Finds a AIRBASE based on the AirbaseName.
+--- Finds an AIRBASE based on the AirbaseName.
-- @param #DATABASE self
-- @param #string AirbaseName
-- @return Wrapper.Airbase#AIRBASE The found AIRBASE.
@@ -192,6 +199,35 @@ function DATABASE:FindAirbase( AirbaseName )
return AirbaseFound
end
+--- Adds a Cargo based on the Cargo Name in the DATABASE.
+-- @param #DATABASE self
+-- @param #string CargoName The name of the airbase
+function DATABASE:AddCargo( Cargo )
+
+ if not self.CARGOS[Cargo.Name] then
+ self.CARGOS[Cargo.Name] = Cargo
+ end
+end
+
+
+--- Deletes a Cargo from the DATABASE based on the Cargo Name.
+-- @param #DATABASE self
+-- @param #string CargoName The name of the airbase
+function DATABASE:DeleteCargo( CargoName )
+
+ self.CARGOS[CargoName] = nil
+end
+
+--- Finds an CARGO based on the CargoName.
+-- @param #DATABASE self
+-- @param #string CargoName
+-- @return Wrapper.Cargo#CARGO The found CARGO.
+function DATABASE:FindCargo( CargoName )
+
+ local CargoFound = self.CARGOS[CargoName]
+ return CargoFound
+end
+
--- Finds a CLIENT based on the ClientName.
-- @param #DATABASE self
@@ -714,7 +750,7 @@ end
--- Iterate the DATABASE and call an iterator function for each **alive** UNIT, providing the UNIT and optional parameters.
-- @param #DATABASE self
--- @param #function IteratorFunction The function that will be called when there is an alive UNIT in the database. The function needs to accept a UNIT parameter.
+-- @param #function IteratorFunction The function that will be called for each object in the database. The function needs to accept a UNIT parameter.
-- @return #DATABASE self
function DATABASE:ForEachUnit( IteratorFunction, FinalizeFunction, ... )
self:F2( arg )
@@ -726,7 +762,7 @@ end
--- Iterate the DATABASE and call an iterator function for each **alive** GROUP, providing the GROUP and optional parameters.
-- @param #DATABASE self
--- @param #function IteratorFunction The function that will be called when there is an alive GROUP in the database. The function needs to accept a GROUP parameter.
+-- @param #function IteratorFunction The function that will be called for each object in the database. The function needs to accept a GROUP parameter.
-- @return #DATABASE self
function DATABASE:ForEachGroup( IteratorFunction, ... )
self:F2( arg )
@@ -739,7 +775,7 @@ end
--- Iterate the DATABASE and call an iterator function for each **ALIVE** player, providing the player name and optional parameters.
-- @param #DATABASE self
--- @param #function IteratorFunction The function that will be called when there is an player in the database. The function needs to accept the player name.
+-- @param #function IteratorFunction The function that will be called for each object in the database. The function needs to accept the player name.
-- @return #DATABASE self
function DATABASE:ForEachPlayer( IteratorFunction, ... )
self:F2( arg )
@@ -752,7 +788,7 @@ end
--- Iterate the DATABASE and call an iterator function for each player who has joined the mission, providing the Unit of the player and optional parameters.
-- @param #DATABASE self
--- @param #function IteratorFunction The function that will be called when there is was a player in the database. The function needs to accept a UNIT parameter.
+-- @param #function IteratorFunction The function that will be called for each object in the database. The function needs to accept a UNIT parameter.
-- @return #DATABASE self
function DATABASE:ForEachPlayerJoined( IteratorFunction, ... )
self:F2( arg )
@@ -764,7 +800,7 @@ end
--- Iterate the DATABASE and call an iterator function for each CLIENT, providing the CLIENT to the function and optional parameters.
-- @param #DATABASE self
--- @param #function IteratorFunction The function that will be called when there is an alive player in the database. The function needs to accept a CLIENT parameter.
+-- @param #function IteratorFunction The function that will be called object in the database. The function needs to accept a CLIENT parameter.
-- @return #DATABASE self
function DATABASE:ForEachClient( IteratorFunction, ... )
self:F2( arg )
@@ -774,6 +810,43 @@ function DATABASE:ForEachClient( IteratorFunction, ... )
return self
end
+--- Iterate the DATABASE and call an iterator function for each CARGO, providing the CARGO object to the function and optional parameters.
+-- @param #DATABASE self
+-- @param #function IteratorFunction The function that will be called for each object in the database. The function needs to accept a CLIENT parameter.
+-- @return #DATABASE self
+function DATABASE:ForEachCargo( IteratorFunction, ... )
+ self:F2( arg )
+
+ self:ForEach( IteratorFunction, arg, self.CARGOS )
+
+ return self
+end
+
+
+--- Handles the OnEventNewCargo event.
+-- @param #DATABASE self
+-- @param Core.Event#EVENTDATA EventData
+function DATABASE:OnEventNewCargo( EventData )
+ self:F2( { EventData } )
+
+ if EventData.Cargo then
+ self:AddCargo( EventData.Cargo )
+ end
+end
+
+
+--- Handles the OnEventDeleteCargo.
+-- @param #DATABASE self
+-- @param Core.Event#EVENTDATA EventData
+function DATABASE:OnEventDeleteCargo( EventData )
+ self:F2( { EventData } )
+
+ if EventData.Cargo then
+ self:DeleteCargo( EventData.Cargo.Name )
+ end
+end
+
+
--- @param #DATABASE self
function DATABASE:_RegisterTemplates()
self:F2()
diff --git a/Moose Development/Moose/Core/Event.lua b/Moose Development/Moose/Core/Event.lua
index c03eac9a9..9891aa5fd 100644
--- a/Moose Development/Moose/Core/Event.lua
+++ b/Moose Development/Moose/Core/Event.lua
@@ -197,6 +197,9 @@ EVENT = {
ClassID = 0,
}
+world.event.S_EVENT_NEW_CARGO = world.event.S_EVENT_MAX + 1000
+world.event.S_EVENT_DELETE_CARGO = world.event.S_EVENT_MAX + 1001
+
--- The different types of events supported by MOOSE.
-- Use this structure to subscribe to events using the @{Base#BASE.HandleEvent}() method.
-- @type EVENTS
@@ -224,13 +227,15 @@ EVENTS = {
PlayerComment = world.event.S_EVENT_PLAYER_COMMENT,
ShootingStart = world.event.S_EVENT_SHOOTING_START,
ShootingEnd = world.event.S_EVENT_SHOOTING_END,
+ NewCargo = world.event.S_EVENT_NEW_CARGO,
+ DeleteCargo = world.event.S_EVENT_DELETE_CARGO,
}
--- The Event structure
-- Note that at the beginning of each field description, there is an indication which field will be populated depending on the object type involved in the Event:
--
-- * A (Object.Category.)UNIT : A UNIT object type is involved in the Event.
--- * A (Object.Category.)STATIC : A STATIC object type is involved in the Event.µ
+-- * A (Object.Category.)STATIC : A STATIC object type is involved in the Event.µ
--
-- @type EVENTDATA
-- @field #number id The identifier of the event.
@@ -271,6 +276,7 @@ EVENTS = {
-- @field WeaponTgtDCSUnit
+
local _EVENTMETA = {
[world.event.S_EVENT_SHOT] = {
Order = 1,
@@ -410,6 +416,16 @@ local _EVENTMETA = {
Event = "OnEventShootingEnd",
Text = "S_EVENT_SHOOTING_END"
},
+ [EVENTS.NewCargo] = {
+ Order = 1,
+ Event = "OnEventNewCargo",
+ Text = "S_EVENT_NEW_CARGO"
+ },
+ [EVENTS.DeleteCargo] = {
+ Order = 1,
+ Event = "OnEventDeleteCargo",
+ Text = "S_EVENT_DELETE_CARGO"
+ },
}
@@ -682,6 +698,39 @@ do -- OnEngineShutDown
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
+
+end
--- @param #EVENT self
-- @param #EVENTDATA Event
@@ -805,6 +854,11 @@ function EVENT:onEvent( Event )
--Event.WeaponTgtDCSUnit = Event.Weapon:getTarget()
end
+ if Event.cargo then
+ Event.Cargo = Event.cargo
+ Event.CargoName = Event.cargo.Name
+ end
+
local PriorityOrder = EventMeta.Order
local PriorityBegin = PriorityOrder == -1 and 5 or 1
local PriorityEnd = PriorityOrder == -1 and 1 or 5
diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua
index 2d206d453..f83a2903a 100644
--- a/Moose Development/Moose/Core/Set.lua
+++ b/Moose Development/Moose/Core/Set.lua
@@ -124,7 +124,7 @@ end
-- @param Core.Base#BASE Object
-- @return Core.Base#BASE The added BASE Object.
function SET_BASE:Add( ObjectName, Object )
- self:F2( ObjectName )
+ self:F( ObjectName )
local t = { _ = Object }
@@ -2391,3 +2391,346 @@ function SET_AIRBASE:IsIncludeObject( MAirbase )
self:T2( MAirbaseInclude )
return MAirbaseInclude
end
+
+--- @type SET_CARGO
+-- @extends Core.Set#SET_BASE
+
+--- # SET_CARGO class, extends @{Set#SET_BASE}
+--
+-- Mission designers can use the @{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 @{Set#SET_CARGO.AddCargosByName} and @{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 prefix string(s).
+-- * @{#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 self
+-- @usage
+-- -- Define a new SET_CARGO Object. The DatabaseSet will contain a reference to all Cargos.
+-- DatabaseSet = SET_CARGO:New()
+function SET_CARGO:New()
+ -- Inherits from BASE
+ local self = BASE:Inherit( self, SET_BASE:New( _DATABASE.CARGOS ) )
+
+ 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 self
+function SET_CARGO:AddCargosByName( AddCargoNames )
+
+ local AddCargoNamesArray = ( type( AddCargoNames ) == "table" ) and AddCargoNames or { AddCargoNames }
+
+ for AddCargoID, AddCargoName in pairs( AddCargoNamesArray ) do
+ self:Add( AddCargoName, CARGO:FindByName( AddCargoName ) )
+ end
+
+ return self
+end
+
+--- Remove CARGOs from SET_CARGO.
+-- @param Core.Set#SET_CARGO self
+-- @param Wrapper.Cargo#CARGO RemoveCargoNames A single name or an array of CARGO names.
+-- @return self
+function SET_CARGO:RemoveCargosByName( RemoveCargoNames )
+
+ local RemoveCargoNamesArray = ( type( RemoveCargoNames ) == "table" ) and RemoveCargoNames or { RemoveCargoNames }
+
+ for RemoveCargoID, RemoveCargoName in pairs( RemoveCargoNamesArray ) do
+ self:Remove( RemoveCargoName.CargoName )
+ end
+
+ return self
+end
+
+
+--- Finds a Cargo based on the Cargo Name.
+-- @param #SET_CARGO self
+-- @param #string CargoName
+-- @return Wrapper.Cargo#CARGO The found Cargo.
+function SET_CARGO:FindCargo( CargoName )
+
+ 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
+function SET_CARGO:FilterCoalitions( Coalitions )
+ if not self.Filter.Coalitions then
+ self.Filter.Coalitions = {}
+ end
+ if type( Coalitions ) ~= "table" then
+ Coalitions = { Coalitions }
+ end
+ for CoalitionID, Coalition in pairs( Coalitions ) do
+ self.Filter.Coalitions[Coalition] = Coalition
+ end
+ return self
+end
+
+--- 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 )
+ 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 )
+ 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 of defined cargo prefixes.
+-- All the cargos starting with the given prefixes will be included within the set.
+-- @param #SET_CARGO self
+-- @param #string Prefixes The prefix of which the cargo name starts with.
+-- @return #SET_CARGO self
+function SET_CARGO:FilterPrefixes( Prefixes )
+ if not self.Filter.CargoPrefixes then
+ self.Filter.CargoPrefixes = {}
+ end
+ if type( Prefixes ) ~= "table" then
+ Prefixes = { Prefixes }
+ end
+ for PrefixID, Prefix in pairs( Prefixes ) do
+ self.Filter.CargoPrefixes[Prefix] = Prefix
+ end
+ return self
+end
+
+
+
+--- Starts the filtering.
+-- @param #SET_CARGO self
+-- @return #SET_CARGO self
+function SET_CARGO:FilterStart()
+
+ if _DATABASE then
+ self:_FilterStart()
+ end
+
+ self:HandleEvent( EVENTS.NewCargo )
+ self:HandleEvent( 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 )
+ 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 )
+ self:F3( { Event } )
+
+ return Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName]
+end
+
+--- Iterate the SET_CARGO and call an interator 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, ... )
+ self:F2( arg )
+
+ self:ForEach( IteratorFunction, arg, self.Set )
+
+ return self
+end
+
+--- Iterate the SET_CARGO while identifying the nearest @{Cargo#CARGO} from a @{Point#POINT_VEC2}.
+-- @param #SET_CARGO self
+-- @param Core.Point#POINT_VEC2 PointVec2 A @{Point#POINT_VEC2} object from where to evaluate the closest @{Cargo#CARGO}.
+-- @return Wrapper.Cargo#CARGO The closest @{Cargo#CARGO}.
+function SET_CARGO:FindNearestCargoFromPointVec2( PointVec2 )
+ self:F2( PointVec2 )
+
+ local NearestCargo = self:FindNearestObjectFromPointVec2( PointVec2 )
+ return NearestCargo
+end
+
+
+
+---
+-- @param #SET_CARGO self
+-- @param AI.AI_Cargo#AI_CARGO MCargo
+-- @return #SET_CARGO self
+function SET_CARGO:IsIncludeObject( MCargo )
+ self:F2( MCargo )
+
+ local MCargoInclude = true
+
+ if MCargo then
+ local MCargoName = MCargo:GetName()
+
+ if self.Filter.Coalitions then
+ local MCargoCoalition = false
+ for CoalitionID, CoalitionName in pairs( self.Filter.Coalitions ) do
+ local CargoCoalitionID = MCargo:GetCoalition()
+ self:T3( { "Coalition:", CargoCoalitionID, self.FilterMeta.Coalitions[CoalitionName], CoalitionName } )
+ if self.FilterMeta.Coalitions[CoalitionName] and self.FilterMeta.Coalitions[CoalitionName] == CargoCoalitionID then
+ MCargoCoalition = true
+ end
+ end
+ self:T( { "Evaluated Coalition", MCargoCoalition } )
+ MCargoInclude = MCargoInclude and MCargoCoalition
+ end
+
+ if self.Filter.Types then
+ local MCargoType = false
+ for TypeID, TypeName in pairs( self.Filter.Types ) do
+ self:T3( { "Type:", MCargo:GetType(), TypeName } )
+ if TypeName == MCargo:GetType() then
+ MCargoType = true
+ end
+ end
+ self:T( { "Evaluated Type", MCargoType } )
+ MCargoInclude = MCargoInclude and MCargoType
+ end
+
+ if self.Filter.CargoPrefixes then
+ local MCargoPrefix = false
+ for CargoPrefixId, CargoPrefix in pairs( self.Filter.CargoPrefixes ) do
+ self:T3( { "Prefix:", string.find( MCargo.Name, CargoPrefix, 1 ), CargoPrefix } )
+ if string.find( MCargo.Name, CargoPrefix, 1 ) then
+ MCargoPrefix = true
+ end
+ end
+ self:T( { "Evaluated Prefix", MCargoPrefix } )
+ MCargoInclude = MCargoInclude and MCargoPrefix
+ end
+ end
+
+ self:T2( MCargoInclude )
+ return MCargoInclude
+end
+
+--- Handles the OnEventNewCargo event for the Set.
+-- @param #SET_CARGO self
+-- @param Core.Event#EVENTDATA EventData
+function SET_CARGO:OnEventNewCargo( EventData )
+
+ if EventData.Cargo then
+ if EventData.Cargo and self:IsIncludeObject( EventData.Cargo ) then
+ self:Add( EventData.Cargo.Name , EventData.Cargo )
+ end
+ end
+end
+
+--- Handles the OnDead or OnCrash event for alive units set.
+-- @param #SET_CARGO self
+-- @param Core.Event#EVENTDATA EventData
+function SET_CARGO:OnEventDeleteCargo( EventData )
+ self:F3( { EventData } )
+
+ if EventData.Cargo then
+ local Cargo = _DATABASE:FindCargo( EventData.Cargo.Name )
+ if Cargo and Cargo.Name then
+ self:Remove( Cargo.Name )
+ end
+ end
+end
+
diff --git a/Moose Development/Moose/Core/Zone.lua b/Moose Development/Moose/Core/Zone.lua
index 8456729a8..d7c00ae39 100644
--- a/Moose Development/Moose/Core/Zone.lua
+++ b/Moose Development/Moose/Core/Zone.lua
@@ -73,41 +73,41 @@
-- @extends Core.Base#BASE
---- # 1) ZONE_BASE class, extends @{Base#BASE}
+--- # ZONE_BASE class, extends @{Base#BASE}
--
-- This class is an abstract BASE class for derived classes, and is not meant to be instantiated.
--
--- ## 1.1) Each zone has a name:
+-- ## Each zone has a name:
--
-- * @{#ZONE_BASE.GetName}(): Returns the name of the zone.
--
--- ## 1.2) Each zone implements two polymorphic functions defined in @{Zone#ZONE_BASE}:
+-- ## Each zone implements two polymorphic functions defined in @{Zone#ZONE_BASE}:
--
-- * @{#ZONE_BASE.IsVec2InZone}(): Returns if a Vec2 is within the zone.
-- * @{#ZONE_BASE.IsVec3InZone}(): Returns if a Vec3 is within the zone.
--
--- ## 1.3) A zone has a probability factor that can be set to randomize a selection between zones:
+-- ## A zone has a probability factor that can be set to randomize a selection between zones:
--
-- * @{#ZONE_BASE.SetRandomizeProbability}(): Set the randomization probability of a zone to be selected, taking a value between 0 and 1 ( 0 = 0%, 1 = 100% )
-- * @{#ZONE_BASE.GetRandomizeProbability}(): Get the randomization probability of a zone to be selected, passing a value between 0 and 1 ( 0 = 0%, 1 = 100% )
-- * @{#ZONE_BASE.GetZoneMaybe}(): Get the zone taking into account the randomization probability. nil is returned if this zone is not a candidate.
--
--- ## 1.4) A zone manages Vectors:
+-- ## A zone manages Vectors:
--
-- * @{#ZONE_BASE.GetVec2}(): Returns the @{DCSTypes#Vec2} coordinate of the zone.
-- * @{#ZONE_BASE.GetRandomVec2}(): Define a random @{DCSTypes#Vec2} within the zone.
--
--- ## 1.5) A zone has a bounding square:
+-- ## A zone has a bounding square:
--
-- * @{#ZONE_BASE.GetBoundingSquare}(): Get the outer most bounding square of the zone.
--
--- ## 1.6) A zone can be marked:
+-- ## A zone can be marked:
--
-- * @{#ZONE_BASE.SmokeZone}(): Smokes the zone boundaries in a color.
-- * @{#ZONE_BASE.FlareZone}(): Flares the zone boundaries in a color.
--
--- ===
-- @field #ZONE_BASE ZONE_BASE
+--
ZONE_BASE = {
ClassName = "ZONE_BASE",
ZoneName = "",
@@ -144,20 +144,21 @@ function ZONE_BASE:GetName()
return self.ZoneName
end
---- Returns if a location is within the zone.
+
+--- Returns if a Vec2 is within the zone.
-- @param #ZONE_BASE self
--- @param Dcs.DCSTypes#Vec2 Vec2 The location to test.
--- @return #boolean true if the location is within the zone.
+-- @param Dcs.DCSTypes#Vec2 Vec2 The Vec2 to test.
+-- @return #boolean true if the Vec2 is within the zone.
function ZONE_BASE:IsVec2InZone( Vec2 )
self:F2( Vec2 )
return false
end
---- Returns if a point is within the zone.
+--- Returns if a Vec3 is within the zone.
-- @param #ZONE_BASE self
-- @param Dcs.DCSTypes#Vec3 Vec3 The point to test.
--- @return #boolean true if the point is within the zone.
+-- @return #boolean true if the Vec3 is within the zone.
function ZONE_BASE:IsVec3InZone( Vec3 )
self:F2( Vec3 )
@@ -166,6 +167,31 @@ function ZONE_BASE:IsVec3InZone( Vec3 )
return InZone
end
+--- Returns if a PointVec2 is within the zone.
+-- @param #ZONE_BASE self
+-- @param Core.Point#POINT_VEC2 PointVec2 The PointVec2 to test.
+-- @return #boolean true if the PointVec2 is within the zone.
+function ZONE_BASE:IsPointVec2InZone( PointVec2 )
+ self:F2( PointVec2 )
+
+ local InZone = self:IsVec2InZone( PointVec2:GetVec2() )
+
+ return InZone
+end
+
+--- Returns if a PointVec3 is within the zone.
+-- @param #ZONE_BASE self
+-- @param Core.Point#POINT_VEC3 PointVec3 The PointVec3 to test.
+-- @return #boolean true if the PointVec3 is within the zone.
+function ZONE_BASE:IsPointVec3InZone( PointVec3 )
+ self:F2( PointVec3 )
+
+ local InZone = self:IsPointVec2InZone( PointVec3 )
+
+ return InZone
+end
+
+
--- Returns the @{DCSTypes#Vec2} coordinate of the zone.
-- @param #ZONE_BASE self
-- @return #nil.
@@ -310,29 +336,29 @@ end
-- @type ZONE_RADIUS
-- @field Dcs.DCSTypes#Vec2 Vec2 The current location of the zone.
-- @field Dcs.DCSTypes#Distance Radius The radius of the zone.
--- @extends Core.Zone#ZONE_BASE
+-- @extends #ZONE_BASE
---- # 2) @{Zone#ZONE_RADIUS} class, extends @{Zone#ZONE_BASE}
+--- # ZONE_RADIUS class, extends @{Zone#ZONE_BASE}
--
-- The ZONE_RADIUS class defined by a zone name, a location and a radius.
-- This class implements the inherited functions from Core.Zone#ZONE_BASE taking into account the own zone format and properties.
--
--- ## 2.1) @{Zone#ZONE_RADIUS} constructor
+-- ## ZONE_RADIUS constructor
--
-- * @{#ZONE_RADIUS.New}(): Constructor.
--
--- ## 2.2) Manage the radius of the zone
+-- ## Manage the radius of the zone
--
-- * @{#ZONE_RADIUS.SetRadius}(): Sets the radius of the zone.
-- * @{#ZONE_RADIUS.GetRadius}(): Returns the radius of the zone.
--
--- ## 2.3) Manage the location of the zone
+-- ## Manage the location of the zone
--
-- * @{#ZONE_RADIUS.SetVec2}(): Sets the @{DCSTypes#Vec2} of the zone.
-- * @{#ZONE_RADIUS.GetVec2}(): Returns the @{DCSTypes#Vec2} of the zone.
-- * @{#ZONE_RADIUS.GetVec3}(): Returns the @{DCSTypes#Vec3} of the zone, taking an additional height parameter.
--
--- ## 2.4) Zone point randomization
+-- ## Zone point randomization
--
-- Various functions exist to find random points within the zone.
--
@@ -340,8 +366,6 @@ end
-- * @{#ZONE_RADIUS.GetRandomPointVec2}(): Gets a @{Point#POINT_VEC2} object representing a random 2D point in the zone.
-- * @{#ZONE_RADIUS.GetRandomPointVec3}(): Gets a @{Point#POINT_VEC3} object representing a random 3D point in the zone. Note that the height of the point is at landheight.
--
--- ===
---
-- @field #ZONE_RADIUS ZONE_RADIUS
--
ZONE_RADIUS = {
@@ -616,16 +640,14 @@ end
--- @type ZONE
--- @extends Core.Zone#ZONE_RADIUS
+-- @extends #ZONE_RADIUS
---- # 3) ZONE class, extends @{Zone#ZONE_RADIUS}
+--- # ZONE class, extends @{Zone#ZONE_RADIUS}
--
-- The ZONE class, defined by the zone name as defined within the Mission Editor.
-- This class implements the inherited functions from @{#ZONE_RADIUS} taking into account the own zone format and properties.
--
--- ===
---
-- @field #ZONE ZONE
--
ZONE = {
@@ -655,18 +677,15 @@ function ZONE:New( ZoneName )
end
---- The ZONE_UNIT class defined by a zone around a @{Unit#UNIT} with a radius.
--- @type ZONE_UNIT
+--- @type ZONE_UNIT
-- @field Wrapper.Unit#UNIT ZoneUNIT
-- @extends Core.Zone#ZONE_RADIUS
---- # 4) #ZONE_UNIT class, extends @{Zone#ZONE_RADIUS}
+--- # ZONE_UNIT class, extends @{Zone#ZONE_RADIUS}
--
-- The ZONE_UNIT class defined by a zone around a @{Unit#UNIT} with a radius.
-- This class implements the inherited functions from @{#ZONE_RADIUS} taking into account the own zone format and properties.
--
--- ===
---
-- @field #ZONE_UNIT ZONE_UNIT
--
ZONE_UNIT = {
@@ -751,16 +770,14 @@ end
--- @type ZONE_GROUP
-- @field Wrapper.Group#GROUP ZoneGROUP
--- @extends Core.Zone#ZONE_RADIUS
+-- @extends #ZONE_RADIUS
---- # 5) #ZONE_GROUP class, extends @{Zone#ZONE_RADIUS}
+--- # ZONE_GROUP class, extends @{Zone#ZONE_RADIUS}
--
-- The ZONE_GROUP class defines by a zone around a @{Group#GROUP} with a radius. The current leader of the group defines the center of the zone.
-- This class implements the inherited functions from @{Zone#ZONE_RADIUS} taking into account the own zone format and properties.
--
--- ===
---
-- @field #ZONE_GROUP ZONE_GROUP
--
ZONE_GROUP = {
@@ -818,16 +835,16 @@ end
--- @type ZONE_POLYGON_BASE
-- @field #ZONE_POLYGON_BASE.ListVec2 Polygon The polygon defined by an array of @{DCSTypes#Vec2}.
--- @extends Core.Zone#ZONE_BASE
+-- @extends #ZONE_BASE
---- # 6) ZONE_POLYGON_BASE class, extends @{Zone#ZONE_BASE}
+--- # ZONE_POLYGON_BASE class, extends @{Zone#ZONE_BASE}
--
-- The ZONE_POLYGON_BASE class defined by a sequence of @{Group#GROUP} waypoints within the Mission Editor, forming a polygon.
-- This class implements the inherited functions from @{Zone#ZONE_RADIUS} taking into account the own zone format and properties.
-- This class is an abstract BASE class for derived classes, and is not meant to be instantiated.
--
--- ## 6.1) Zone point randomization
+-- ## Zone point randomization
--
-- Various functions exist to find random points within the zone.
--
@@ -835,8 +852,6 @@ end
-- * @{#ZONE_POLYGON_BASE.GetRandomPointVec2}(): Return a @{Point#POINT_VEC2} object representing a random 2D point within the zone.
-- * @{#ZONE_POLYGON_BASE.GetRandomPointVec3}(): Return a @{Point#POINT_VEC3} object representing a random 3D point at landheight within the zone.
--
--- ===
---
-- @field #ZONE_POLYGON_BASE ZONE_POLYGON_BASE
--
ZONE_POLYGON_BASE = {
@@ -870,6 +885,17 @@ function ZONE_POLYGON_BASE:New( ZoneName, PointsArray )
return self
end
+--- Returns the center location of the polygon.
+-- @param #ZONE_GROUP self
+-- @return Dcs.DCSTypes#Vec2 The location of the zone based on the @{Group} location.
+function ZONE_POLYGON_BASE:GetVec2()
+ self:F( self.ZoneName )
+
+ local Bounds = self:GetBoundingSquare()
+
+ return { x = ( Bounds.x2 + Bounds.x1 ) / 2, y = ( Bounds.y2 + Bounds.y1 ) / 2 }
+end
+
--- Flush polygon coordinates as a table in DCS.log.
-- @param #ZONE_POLYGON_BASE self
-- @return #ZONE_POLYGON_BASE self
@@ -1073,16 +1099,14 @@ end
--- @type ZONE_POLYGON
--- @extends Core.Zone#ZONE_POLYGON_BASE
+-- @extends #ZONE_POLYGON_BASE
---- # 7) ZONE_POLYGON class, extends @{Zone#ZONE_POLYGON_BASE}
+--- # ZONE_POLYGON class, extends @{Zone#ZONE_POLYGON_BASE}
--
-- The ZONE_POLYGON class defined by a sequence of @{Group#GROUP} waypoints within the Mission Editor, forming a polygon.
-- This class implements the inherited functions from @{Zone#ZONE_RADIUS} taking into account the own zone format and properties.
--
--- ===
---
-- @field #ZONE_POLYGON ZONE_POLYGON
--
ZONE_POLYGON = {
diff --git a/Moose Development/Moose/Tasking/CommandCenter.lua b/Moose Development/Moose/Tasking/CommandCenter.lua
index 09ad2ab23..6589d43bd 100644
--- a/Moose Development/Moose/Tasking/CommandCenter.lua
+++ b/Moose Development/Moose/Tasking/CommandCenter.lua
@@ -117,6 +117,21 @@ function COMMANDCENTER:New( CommandCenterPositionable, CommandCenterName )
end
)
+ -- Handle when a player leaves a slot and goes back to spectators ...
+ -- The PlayerUnit will be UnAssigned from the Task.
+ -- When there is no Unit left running the Task, the Task goes into Abort...
+ self:HandleEvent( EVENTS.MissionEnd,
+ --- @param #TASK self
+ -- @param Core.Event#EVENTDATA EventData
+ function( self, EventData )
+ local PlayerUnit = EventData.IniUnit
+ for MissionID, Mission in pairs( self:GetMissions() ) do
+ local Mission = Mission -- Tasking.Mission#MISSION
+ Mission:Stop()
+ end
+ end
+ )
+
-- Handle when a player leaves a slot and goes back to spectators ...
-- The PlayerUnit will be UnAssigned from the Task.
-- When there is no Unit left running the Task, the Task goes into Abort...
@@ -127,7 +142,9 @@ function COMMANDCENTER:New( CommandCenterPositionable, CommandCenterName )
local PlayerUnit = EventData.IniUnit
for MissionID, Mission in pairs( self:GetMissions() ) do
local Mission = Mission -- Tasking.Mission#MISSION
- Mission:AbortUnit( PlayerUnit )
+ if Mission:IsOngoing() then
+ Mission:AbortUnit( PlayerUnit )
+ end
end
end
)
@@ -257,8 +274,7 @@ end
-- @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.
function COMMANDCENTER:MessageToGroup( Message, TaskGroup, Name )
- local Prefix = "@ Group"
- Prefix = Prefix .. ( Name and " (" .. Name .. "): " or '' )
+ local Prefix = Name and "@ " .. Name .. ": " or "@ " .. TaskGroup:GetCallsign() .. ": "
Message = Prefix .. Message
self:GetPositionable():MessageToGroup( Message , 20, TaskGroup, self:GetName() )
diff --git a/Moose Development/Moose/Tasking/Task.lua b/Moose Development/Moose/Tasking/Task.lua
index 2457077ef..30f93d0a4 100644
--- a/Moose Development/Moose/Tasking/Task.lua
+++ b/Moose Development/Moose/Tasking/Task.lua
@@ -275,8 +275,9 @@ function TASK:AbortUnit( PlayerUnit )
local IsAssignedToGroup = self:IsAssignedToGroup( PlayerGroup )
self:E( { IsAssignedToGroup = IsAssignedToGroup } )
if IsAssignedToGroup then
+ local PlayerName = PlayerUnit:GetPlayerName()
self:UnAssignFromUnit( PlayerUnit )
- self:MessageToGroups( PlayerUnit:GetPlayerName() .. " aborted Task " .. self:GetName() )
+ self:MessageToGroups( PlayerName .. " aborted Task " .. self:GetName() )
self:E( { TaskGroup = PlayerGroup:GetName(), GetUnits = PlayerGroup:GetUnits() } )
if #PlayerGroup:GetUnits() == 1 then
self:UnAssignFromGroup( PlayerGroup )
diff --git a/Moose Development/Moose/Tasking/Task_CARGO.lua b/Moose Development/Moose/Tasking/Task_CARGO.lua
new file mode 100644
index 000000000..39a179600
--- /dev/null
+++ b/Moose Development/Moose/Tasking/Task_CARGO.lua
@@ -0,0 +1,669 @@
+--- **Tasking (Release 2.1)** -- The TASK_CARGO models tasks for players to transport @{Cargo}.
+--
+-- 
+--
+-- ====
+--
+-- The Moose framework provides various CARGO classes that allow DCS phisical or logical objects to be transported or sling loaded by Carriers.
+-- The CARGO_ classes, as part of the moose core, are able to Board, Load, UnBoard and UnLoad cargo between Carrier units.
+--
+-- This collection of classes in this module define tasks for human players to handle these cargo objects.
+-- Cargo can be transported, picked-up, deployed and sling-loaded from and to other places.
+--
+-- The following classes are important to consider:
+--
+-- * @{#TASK_CARGO_TRANSPORT}: Defines a task for a human player to transport a set of cargo between various zones.
+--
+-- ==
+--
+-- # **API CHANGE HISTORY**
+--
+-- The underlying change log documents the API changes. Please read this carefully. The following notation is used:
+--
+-- * **Added** parts are expressed in bold type face.
+-- * _Removed_ parts are expressed in italic type face.
+--
+-- Hereby the change log:
+--
+-- 2017-03-09: Revised version.
+--
+-- ===
+--
+-- # **AUTHORS and CONTRIBUTIONS**
+--
+-- ### Contributions:
+--
+-- ### Authors:
+--
+-- * **FlightControl**: Concept, Design & Programming.
+--
+-- @module Task_Cargo
+
+do -- TASK_CARGO
+
+ --- @type TASK_CARGO
+ -- @extends Tasking.Task#TASK
+
+ ---
+ -- # TASK_CARGO class, extends @{Task#TASK}
+ --
+ -- ## A flexible tasking system
+ --
+ -- The TASK_CARGO classes provide you with a flexible tasking sytem,
+ -- that allows you to transport cargo of various types between various locations
+ -- and various dedicated deployment zones.
+ --
+ -- The cargo in scope of the TASK_CARGO classes must be explicitly given, and is of type SET_CARGO.
+ -- The SET_CARGO contains a collection of CARGO objects that must be handled by the players in the mission.
+ --
+ --
+ -- ## Task execution experience from the player perspective
+ --
+ -- A human player can join the battle field in a client airborne slot or a ground vehicle within the CA module (ALT-J).
+ -- The player needs to accept the task from the task overview list within the mission, using the radio menus.
+ --
+ -- Once the TASK_CARGO is assigned to the player and accepted by the player, the player will obtain
+ -- an extra **Cargo Handling Radio Menu** that contains the CARGO objects that need to be transported.
+ --
+ -- Each CARGO object has a certain state:
+ --
+ -- * **UnLoaded**: The CARGO is located within the battlefield. It may still need to be transported.
+ -- * **Loaded**: The CARGO is loaded within a Carrier. This can be your air unit, or another air unit, or even a vehicle.
+ -- * **Boarding**: The CARGO is running or moving towards your Carrier for loading.
+ -- * **UnBoarding**: The CARGO is driving or jumping out of your Carrier and moves to a location in the Deployment Zone.
+ --
+ -- Cargo must be transported towards different **Deployment @{Zone}s**.
+ --
+ -- The Cargo Handling Radio Menu system allows to execute **various actions** to handle the cargo.
+ -- In the menu, you'll find for each CARGO, that is part of the scope of the task, various actions that can be completed.
+ -- Depending on the location of your Carrier unit, the menu options will vary.
+ --
+ --
+ -- ## Cargo Pickup and Boarding
+ --
+ -- For cargo boarding, a cargo can only execute the boarding actions if it is within the foreseen **Reporting Range**.
+ -- Therefore, it is important that you steer your Carrier within the Reporting Range,
+ -- so that boarding actions can be executed on the cargo.
+ -- To Pickup and Board cargo, the following menu items will be shown in your carrier radio menu:
+ --
+ -- ### Board Cargo
+ --
+ -- If your Carrier is within the Reporting Range of the cargo, it will allow to pickup the cargo by selecting this menu option.
+ -- Depending on the Cargo type, the cargo will either move to your Carrier or you will receive instructions how to handle the cargo
+ -- pickup. If the cargo moves to your carrier, it will indicate the boarding status.
+ -- Note that multiple units need to board your Carrier, so it is required to await the full boarding process.
+ -- Once the cargo is fully boarded within your Carrier, you will be notified of this.
+ --
+ -- Note that for airborne Carriers, it is required to land first before the Boarding process can be initiated.
+ -- If during boarding the Carrier gets airborne, the boarding process will be cancelled.
+ --
+ -- ## Pickup Cargo
+ --
+ -- If your Carrier is not within the Reporting Range of the cargo, the HQ will guide you to its location.
+ -- Routing information is shown in flight that directs you to the cargo within Reporting Range.
+ -- Upon arrival, the Cargo will contact you and further instructions will be given.
+ -- When your Carrier is airborne, you will receive instructions to land your Carrier.
+ -- The action will not be completed until you've landed your Carrier.
+ --
+ --
+ -- ## Cargo Deploy and UnBoarding
+ --
+ -- Various Deployment Zones can be foreseen in the scope of the Cargo transportation. Each deployment zone can be of varying @{Zone} type.
+ -- The Cargo Handling Radio Menu provides with menu options to execute an action to steer your Carrier to a specific Zone.
+ --
+ -- ### UnBoard Cargo
+ --
+ -- If your Carrier is already within a Deployment Zone,
+ -- then the Cargo Handling Radio Menu allows to **UnBoard** a specific cargo that is
+ -- loaded within your Carrier group into the Deployment Zone.
+ -- Note that the Unboarding process takes a while, as the cargo units (infantry or vehicles) must unload from your Carrier.
+ -- Ensure that you stay at the position or stay on the ground while Unboarding.
+ -- If any unforeseen manoeuvre is done by the Carrier, then the Unboarding will be cancelled.
+ --
+ -- ### Deploy Cargo
+ --
+ -- If your Carrier is not within a Deployment Zone, you'll need to fly towards one.
+ -- Fortunately, the Cargo Handling Radio Menu provides you with menu options to select a specific Deployment Zone to fly towards.
+ -- Once a Deployment Zone has been selected, your Carrier will receive routing information from HQ towards the Deployment Zone center.
+ -- Upon arrival, the HQ will provide you with further instructions.
+ -- When your Carrier is airborne, you will receive instructions to land your Carrier.
+ -- The action will not be completed until you've landed your Carrier!
+ --
+ -- ## Handle TASK_CARGO Events ...
+ --
+ -- The TASK_CARGO classes define @{Cargo} transport tasks,
+ -- based on the tasking capabilities defined in @{Task#TASK}.
+ --
+ -- ### Specific TASK_CARGO Events
+ --
+ -- Specific Cargo Handling event can be captured, that allow to trigger specific actions!
+ --
+ -- * **Boarded**: Triggered when the Cargo has been Boarded into your Carrier.
+ -- * **UnBoarded**: Triggered when the cargo has been Unboarded from your Carrier and has arrived at the Deployment Zone.
+ --
+ -- ### Standard TASK_CARGO Events
+ --
+ -- The TASK_CARGO is implemented using a @{Statemachine#FSM_TASK}, and has the following standard statuses:
+ --
+ -- * **None**: Start of the process.
+ -- * **Planned**: The cargo task is planned.
+ -- * **Assigned**: The cargo task is assigned to a @{Group#GROUP}.
+ -- * **Success**: The cargo task is successfully completed.
+ -- * **Failed**: The cargo task has failed. This will happen if the player exists the task early, without communicating a possible cancellation to HQ.
+ --
+ -- ===
+ --
+ -- @field #TASK_CARGO TASK_CARGO
+ --
+ TASK_CARGO = {
+ ClassName = "TASK_CARGO",
+ }
+
+ --- Instantiates a new TASK_CARGO.
+ -- @param #TASK_CARGO self
+ -- @param Tasking.Mission#MISSION Mission
+ -- @param Set#SET_GROUP SetGroup The set of groups for which the Task can be assigned.
+ -- @param #string TaskName The name of the Task.
+ -- @param Core.Set#SET_CARGO SetCargo The scope of the cargo to be transported.
+ -- @param #string TaskType The type of Cargo task.
+ -- @return #TASK_CARGO self
+ function TASK_CARGO:New( Mission, SetGroup, TaskName, SetCargo, TaskType )
+ local self = BASE:Inherit( self, TASK:New( Mission, SetGroup, TaskName, TaskType ) ) -- #TASK_CARGO
+ self:F( {Mission, SetGroup, TaskName, SetCargo, TaskType})
+
+ self.SetCargo = SetCargo
+ self.TaskType = TaskType
+
+ self.DeployZones = {} -- setmetatable( {}, { __mode = "v" } ) -- weak table on value
+
+ Mission:AddTask( self )
+
+ local Fsm = self:GetUnitProcess()
+
+
+ Fsm:AddProcess ( "Planned", "Accept", ACT_ASSIGN_ACCEPT:New( self.TaskBriefing ), { Assigned = "SelectAction", Rejected = "Reject" } )
+
+ Fsm:AddTransition( "*", "SelectAction", "WaitingForCommand" )
+
+ Fsm:AddTransition( "WaitingForCommand", "RouteToPickup", "RoutingToPickup" )
+ Fsm:AddProcess ( "RoutingToPickup", "RouteToPickupPoint", ACT_ROUTE_POINT:New(), { Arrived = "ArriveAtPickup" } )
+ Fsm:AddTransition( "Arrived", "ArriveAtPickup", "ArrivedAtPickup" )
+
+ Fsm:AddTransition( "WaitingForCommand", "RouteToDeploy", "RoutingToDeploy" )
+ Fsm:AddProcess ( "RoutingToDeploy", "RouteToDeployZone", ACT_ROUTE_ZONE:New(), { Arrived = "ArriveAtDeploy" } )
+ Fsm:AddTransition( "Arrived", "ArriveAtDeploy", "ArrivedAtDeploy" )
+
+ Fsm:AddTransition( { "ArrivedAtPickup", "ArrivedAtDeploy", "Landing" }, "Land", "Landing" )
+ Fsm:AddTransition( "Landing", "Landed", "Landed" )
+
+ Fsm:AddTransition( "WaitingForCommand", "PrepareBoarding", "AwaitBoarding" )
+ Fsm:AddTransition( "AwaitBoarding", "Board", "Boarding" )
+ Fsm:AddTransition( "Boarding", "Boarded", "Boarded" )
+
+ Fsm:AddTransition( "WaitingForCommand", "PrepareUnBoarding", "AwaitUnBoarding" )
+ Fsm:AddTransition( "AwaitUnBoarding", "UnBoard", "UnBoarding" )
+ Fsm:AddTransition( "UnBoarding", "UnBoarded", "UnBoarded" )
+
+
+ Fsm:AddTransition( "Deployed", "Success", "Success" )
+ Fsm:AddTransition( "Rejected", "Reject", "Aborted" )
+ Fsm:AddTransition( "Failed", "Fail", "Failed" )
+
+
+ ---
+ -- @param #FSM_PROCESS self
+ -- @param Wrapper.Unit#UNIT TaskUnit
+ -- @param Tasking.Task_Cargo#TASK_CARGO Task
+ function Fsm:OnEnterWaitingForCommand( TaskUnit, Task )
+ self:E( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } )
+
+ TaskUnit.Menu = MENU_GROUP:New( TaskUnit:GetGroup(), Task:GetName() .. " @ " .. TaskUnit:GetName() )
+
+ Task.SetCargo:Flush()
+
+ Task.SetCargo:ForEachCargo(
+
+ --- @param Core.Cargo#CARGO Cargo
+ function( Cargo )
+ if Cargo:IsUnLoaded() then
+ if Cargo:IsInRadius( TaskUnit:GetPointVec2() ) then
+ MENU_GROUP_COMMAND:New(
+ TaskUnit:GetGroup(),
+ "Pickup cargo " .. Cargo.Name,
+ TaskUnit.Menu,
+ self.MenuBoardCargo,
+ self,
+ Cargo
+ )
+ else
+ MENU_GROUP_COMMAND:New(
+ TaskUnit:GetGroup(),
+ "Route to cargo " .. Cargo.Name,
+ TaskUnit.Menu,
+ self.MenuRouteToPickup,
+ self,
+ Cargo
+ )
+ end
+ end
+
+ if Cargo:IsLoaded() then
+ for DeployZoneName, DeployZone in pairs( Task.DeployZones ) do
+ if Cargo:IsInZone( DeployZone ) then
+ MENU_GROUP_COMMAND:New(
+ TaskUnit:GetGroup(),
+ "Deploy cargo " .. Cargo.Name,
+ TaskUnit.Menu,
+ self.MenuUnBoardCargo,
+ self,
+ Cargo,
+ DeployZone
+ )
+ else
+ MENU_GROUP_COMMAND:New(
+ TaskUnit:GetGroup(),
+ "Route to deploy zone " .. DeployZoneName,
+ TaskUnit.Menu,
+ self.MenuRouteToDeploy,
+ self,
+ DeployZone
+ )
+ end
+ end
+ end
+
+ end
+ )
+ end
+
+ ---
+ -- @param #FSM_PROCESS self
+ -- @param Wrapper.Unit#UNIT TaskUnit
+ -- @param Tasking.Task_Cargo#TASK_CARGO Task
+ function Fsm:OnLeaveWaitingForCommand( TaskUnit, Task )
+ self:E( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } )
+
+ TaskUnit.Menu:Remove()
+ end
+
+ function Fsm:MenuBoardCargo( Cargo )
+ self:__PrepareBoarding( 1.0, Cargo )
+ end
+
+ function Fsm:MenuUnBoardCargo( Cargo, DeployZone )
+ self:__PrepareUnBoarding( 1.0, Cargo, DeployZone )
+ end
+
+ function Fsm:MenuRouteToPickup( Cargo )
+ self:__RouteToPickup( 1.0, Cargo )
+ end
+
+ function Fsm:MenuRouteToDeploy( DeployZone )
+ self:__RouteToDeploy( 1.0, DeployZone )
+ end
+
+ --- Route to Cargo
+ -- @param #FSM_PROCESS self
+ -- @param Wrapper.Unit#UNIT TaskUnit
+ -- @param Tasking.Task_Cargo#TASK_CARGO Task
+ function Fsm:onafterRouteToPickup( TaskUnit, Task, From, Event, To, Cargo )
+ self:E( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } )
+
+
+ self.Cargo = Cargo
+ Task:SetCargoPickup( self.Cargo, TaskUnit )
+ self:__RouteToPickupPoint( -0.1 )
+ end
+
+
+ ---
+ -- @param #FSM_PROCESS self
+ -- @param Wrapper.Unit#UNIT TaskUnit
+ -- @param Tasking.Task_Cargo#TASK_CARGO Task
+ function Fsm:onafterArriveAtPickup( TaskUnit, Task )
+ self:E( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } )
+
+ if TaskUnit:IsAir() then
+ self:__Land( -0.1, "Pickup" )
+ else
+ self:__SelectAction( -0.1 )
+ end
+ end
+
+
+ --- Route to DeployZone
+ -- @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() } )
+
+
+ self.DeployZone = DeployZone
+ Task:SetDeployZone( self.DeployZone, TaskUnit )
+ self:__RouteToDeployZone( -0.1 )
+ end
+
+
+ ---
+ -- @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
+ self:__Land( -0.1, "Deploy" )
+ else
+ self:__SelectAction( -0.1 )
+ end
+ end
+
+
+
+ ---
+ -- @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 )
+ self:E( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } )
+
+ 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() )
+ self:__Landed( -0.1, Action )
+ end
+ else
+ if Action == "Pickup" then
+ self:__RouteToPickupZone( -0.1 )
+ else
+ self:__RouteToDeployZone( -0.1 )
+ end
+ end
+ end
+
+ ---
+ -- @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 )
+ self:E( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } )
+
+ if self.Cargo:IsInRadius( TaskUnit:GetPointVec2() ) then
+ if TaskUnit:InAir() then
+ self:__Land( -0.1, Action )
+ else
+ self:__SelectAction( -0.1 )
+ end
+ else
+ if Action == "Pickup" then
+ self:__RouteToPickupZone( -0.1 )
+ else
+ self:__RouteToDeployZone( -0.1 )
+ end
+ end
+ end
+
+ ---
+ -- @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 )
+ self:E( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } )
+
+ self.Cargo = Cargo -- Core.Cargo#CARGO_GROUP
+ self:__Board( -0.1 )
+ end
+
+ ---
+ -- @param #FSM_PROCESS self
+ -- @param Wrapper.Unit#UNIT TaskUnit
+ -- @param Tasking.Task_Cargo#TASK_CARGO Task
+ function Fsm:onafterBoard( TaskUnit, Task )
+ self:E( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } )
+
+ function self.Cargo:OnEnterLoaded( From, Event, To, TaskUnit, TaskProcess )
+
+ self:E({From, Event, To, TaskUnit, TaskProcess })
+
+ TaskProcess:__Boarded( 0.1 )
+
+ end
+
+
+ if self.Cargo:IsInRadius( TaskUnit:GetPointVec2() ) then
+ if TaskUnit:InAir() then
+ --- ABORT the boarding. Split group if any and go back to select action.
+ else
+ self.Cargo:MessageToGroup( "Boarding ...", TaskUnit:GetGroup() )
+ self.Cargo:Board( TaskUnit, 20, self )
+ end
+ else
+ --self:__ArriveAtCargo( -0.1 )
+ end
+ end
+
+
+ ---
+ -- @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() } )
+
+ self.Cargo:MessageToGroup( "Boarded ...", TaskUnit:GetGroup() )
+ self:__SelectAction( 1 )
+ end
+
+
+ ---
+ -- @param #FSM_PROCESS self
+ -- @param Wrapper.Unit#UNIT TaskUnit
+ -- @param Tasking.Task_Cargo#TASK_CARGO Task
+ function Fsm:onafterPrepareUnBoarding( TaskUnit, Task, From, Event, To, Cargo, DeployZone )
+ self:E( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } )
+
+ self.Cargo = Cargo
+ self.DeployZone = DeployZone
+ self:__UnBoard( -0.1 )
+ end
+
+ ---
+ -- @param #FSM_PROCESS self
+ -- @param Wrapper.Unit#UNIT TaskUnit
+ -- @param Tasking.Task_Cargo#TASK_CARGO Task
+ function Fsm:onafterUnBoard( TaskUnit, Task )
+ self:E( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } )
+
+ function self.Cargo:OnEnterUnLoaded( From, Event, To, DeployZone, TaskProcess )
+
+ self:E({From, Event, To, TaskUnit, TaskProcess })
+
+ TaskProcess:__UnBoarded( -0.1 )
+
+ end
+
+ self.Cargo:MessageToGroup( "UnBoarding ...", TaskUnit:GetGroup() )
+ self.Cargo:UnBoard( self.DeployZone:GetPointVec2(), 20, self )
+ end
+
+
+ ---
+ -- @param #FSM_PROCESS self
+ -- @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() } )
+
+ self.Cargo:MessageToGroup( "UnBoarded ...", TaskUnit:GetGroup() )
+ self:__SelectAction( 1 )
+ end
+
+
+ return self
+
+ end
+
+ --- @param #TASK_CARGO self
+ function TASK_CARGO:GetPlannedMenuText()
+ return self:GetStateString() .. " - " .. self:GetTaskName() .. " ( " .. self.TargetSetUnit:GetUnitTypesText() .. " )"
+ end
+
+
+ --- @param #TASK_CARGO self
+ -- @param AI.AI_Cargo#AI_CARGO Cargo The cargo.
+ -- @param Wrapper.Unit#UNIT TaskUnit
+ -- @return #TASK_CARGO
+ function TASK_CARGO:SetCargoPickup( Cargo, TaskUnit )
+
+ self:F({Cargo, TaskUnit})
+ local ProcessUnit = self:GetUnitProcess( TaskUnit )
+
+ local ActRouteCargo = ProcessUnit:GetProcess( "RoutingToPickup", "RouteToPickupPoint" ) -- Actions.Act_Route#ACT_ROUTE_POINT
+ ActRouteCargo:SetPointVec2( Cargo:GetPointVec2() )
+ ActRouteCargo:SetRange( Cargo:GetBoardingRange() )
+ return self
+ end
+
+
+ --- @param #TASK_CARGO self
+ -- @param Core.Zone#ZONE DeployZone
+ -- @param Wrapper.Unit#UNIT TaskUnit
+ -- @return #TASK_CARGO
+ function TASK_CARGO:SetDeployZone( DeployZone, TaskUnit )
+
+ local ProcessUnit = self:GetUnitProcess( TaskUnit )
+
+ local ActRouteDeployZone = ProcessUnit:GetProcess( "RoutingToDeploy", "RouteToDeployZone" ) -- Actions.Act_Route#ACT_ROUTE_ZONE
+ ActRouteDeployZone:SetZone( DeployZone )
+ return self
+ end
+
+
+ --- @param #TASK_CARGO self
+ -- @param Core.Zone#ZONE DeployZone
+ -- @param Wrapper.Unit#UNIT TaskUnit
+ -- @return #TASK_CARGO
+ function TASK_CARGO:AddDeployZone( DeployZone, TaskUnit )
+
+ self.DeployZones[DeployZone:GetName()] = DeployZone
+
+ return self
+ end
+
+ --- @param #TASK_CARGO self
+ -- @param Core.Zone#ZONE DeployZone
+ -- @param Wrapper.Unit#UNIT TaskUnit
+ -- @return #TASK_CARGO
+ function TASK_CARGO:RemoveDeployZone( DeployZone, TaskUnit )
+
+ self.DeployZones[DeployZone:GetName()] = nil
+
+ return self
+ end
+
+ --- @param #TASK_CARGO self
+ -- @param @list DeployZones
+ -- @param Wrapper.Unit#UNIT TaskUnit
+ -- @return #TASK_CARGO
+ function TASK_CARGO:SetDeployZones( DeployZones, TaskUnit )
+
+ for DeployZoneID, DeployZone in pairs( DeployZones ) do
+ self.DeployZones[DeployZone:GetName()] = DeployZone
+ end
+
+ return self
+ end
+
+
+
+ --- @param #TASK_CARGO self
+ -- @param Wrapper.Unit#UNIT TaskUnit
+ -- @return Core.Zone#ZONE_BASE The Zone object where the Target is located on the map.
+ function TASK_CARGO:GetTargetZone( TaskUnit )
+
+ local ProcessUnit = self:GetUnitProcess( TaskUnit )
+
+ local ActRouteTarget = ProcessUnit:GetProcess( "Engaging", "RouteToTargetZone" ) -- Actions.Act_Route#ACT_ROUTE_ZONE
+ return ActRouteTarget:GetZone()
+ end
+
+ --- Set a score when a target in scope of the A2G attack, has been destroyed .
+ -- @param #TASK_CARGO self
+ -- @param #string Text The text to display to the player, when the target has been destroyed.
+ -- @param #number Score The score in points.
+ -- @param Wrapper.Unit#UNIT TaskUnit
+ -- @return #TASK_CARGO
+ function TASK_CARGO:SetScoreOnDestroy( Text, Score, TaskUnit )
+ self:F( { Text, Score, TaskUnit } )
+
+ local ProcessUnit = self:GetUnitProcess( TaskUnit )
+
+ ProcessUnit:AddScoreProcess( "Engaging", "Account", "Account", Text, Score )
+
+ return self
+ end
+
+ --- Set a score when all the targets in scope of the A2G attack, have been destroyed.
+ -- @param #TASK_CARGO self
+ -- @param #string Text The text to display to the player, when all targets hav been destroyed.
+ -- @param #number Score The score in points.
+ -- @param Wrapper.Unit#UNIT TaskUnit
+ -- @return #TASK_CARGO
+ function TASK_CARGO:SetScoreOnSuccess( Text, Score, TaskUnit )
+ self:F( { Text, Score, TaskUnit } )
+
+ local ProcessUnit = self:GetUnitProcess( TaskUnit )
+
+ ProcessUnit:AddScore( "Success", Text, Score )
+
+ return self
+ end
+
+ --- Set a penalty when the A2G attack has failed.
+ -- @param #TASK_CARGO self
+ -- @param #string Text The text to display to the player, when the A2G attack has failed.
+ -- @param #number Penalty The penalty in points.
+ -- @param Wrapper.Unit#UNIT TaskUnit
+ -- @return #TASK_CARGO
+ function TASK_CARGO:SetPenaltyOnFailed( Text, Penalty, TaskUnit )
+ self:F( { Text, Score, TaskUnit } )
+
+ local ProcessUnit = self:GetUnitProcess( TaskUnit )
+
+ ProcessUnit:AddScore( "Failed", Text, Penalty )
+
+ return self
+ end
+
+
+end
+
+
+do -- TASK_CARGO_TRANSPORT
+
+ --- The TASK_CARGO_TRANSPORT class
+ -- @type TASK_CARGO_TRANSPORT
+ -- @extends #TASK_CARGO
+ TASK_CARGO_TRANSPORT = {
+ ClassName = "TASK_CARGO_TRANSPORT",
+ }
+
+ --- Instantiates a new TASK_CARGO_TRANSPORT.
+ -- @param #TASK_CARGO_TRANSPORT self
+ -- @param Tasking.Mission#MISSION Mission
+ -- @param Set#SET_GROUP SetGroup The set of groups for which the Task can be assigned.
+ -- @param #string TaskName The name of the Task.
+ -- @param Core.Set#SET_CARGO SetCargo The scope of the cargo to be transported.
+ -- @return #TASK_CARGO_TRANSPORT self
+ function TASK_CARGO_TRANSPORT:New( Mission, SetGroup, TaskName, SetCargo )
+ local self = BASE:Inherit( self, TASK_CARGO:New( Mission, SetGroup, TaskName, SetCargo, "Transport" ) ) -- #TASK_CARGO_TRANSPORT
+ self:F()
+
+ return self
+ end
+
+end
+
diff --git a/Moose Mission Setup/Moose Mission Update/l10n/DEFAULT/Moose.lua b/Moose Mission Setup/Moose Mission Update/l10n/DEFAULT/Moose.lua
new file mode 100644
index 000000000..3b2b611ed
--- /dev/null
+++ b/Moose Mission Setup/Moose Mission Update/l10n/DEFAULT/Moose.lua
@@ -0,0 +1,31 @@
+env.info( '*** MOOSE DYNAMIC INCLUDE START *** ' )
+env.info( 'Moose Generation Timestamp: 20170328_0728' )
+
+local base = _G
+
+Include = {}
+
+Include.File = function( IncludeFile )
+ if not Include.Files[ IncludeFile ] then
+ Include.Files[IncludeFile] = IncludeFile
+ env.info( "Include:" .. IncludeFile .. " from " .. Include.ProgramPath )
+ local f = assert( base.loadfile( Include.ProgramPath .. IncludeFile .. ".lua" ) )
+ if f == nil then
+ error ("Could not load MOOSE file " .. IncludeFile .. ".lua" )
+ else
+ env.info( "Include:" .. IncludeFile .. " loaded from " .. Include.ProgramPath )
+ return f()
+ end
+ end
+end
+
+Include.ProgramPath = "Scripts/Moose/"
+
+env.info( "Include.ProgramPath = " .. Include.ProgramPath)
+
+Include.Files = {}
+
+Include.File( "Moose" )
+
+BASE:TraceOnOff( true )
+env.info( '*** MOOSE INCLUDE END *** ' )
diff --git a/Moose Mission Setup/Moose.files b/Moose Mission Setup/Moose.files
index b8084a749..57f9bca5a 100644
--- a/Moose Mission Setup/Moose.files
+++ b/Moose Mission Setup/Moose.files
@@ -14,6 +14,7 @@ Core/Message.lua
Core/Fsm.lua
Core/Radio.lua
Core/SpawnStatic.lua
+Core/Cargo.lua
Wrapper/Object.lua
Wrapper/Identifiable.lua
@@ -40,7 +41,6 @@ AI/AI_Balancer.lua
AI/AI_Patrol.lua
AI/AI_Cap.lua
AI/AI_Cas.lua
-AI/AI_Cargo.lua
Actions/Act_Assign.lua
Actions/Act_Route.lua
@@ -53,5 +53,6 @@ Tasking/Task.lua
Tasking/DetectionManager.lua
Tasking/Task_A2G_Dispatcher.lua
Tasking/Task_A2G.lua
+Tasking/Task_Cargo.lua
Moose.lua
diff --git a/Moose Mission Setup/Moose.lua b/Moose Mission Setup/Moose.lua
index 4e7356543..688d42a41 100644
--- a/Moose Mission Setup/Moose.lua
+++ b/Moose Mission Setup/Moose.lua
@@ -1,5 +1,5 @@
env.info( '*** MOOSE DYNAMIC INCLUDE START *** ' )
-env.info( 'Moose Generation Timestamp: 20170412_0926' )
+env.info( 'Moose Generation Timestamp: 20170413_0920' )
local base = _G
@@ -36,6 +36,7 @@ __Moose.Include( 'Core/Message.lua' )
__Moose.Include( 'Core/Fsm.lua' )
__Moose.Include( 'Core/Radio.lua' )
__Moose.Include( 'Core/SpawnStatic.lua' )
+__Moose.Include( 'Core/Cargo.lua' )
__Moose.Include( 'Wrapper/Object.lua' )
__Moose.Include( 'Wrapper/Identifiable.lua' )
__Moose.Include( 'Wrapper/Positionable.lua' )
@@ -59,7 +60,6 @@ __Moose.Include( 'AI/AI_Balancer.lua' )
__Moose.Include( 'AI/AI_Patrol.lua' )
__Moose.Include( 'AI/AI_Cap.lua' )
__Moose.Include( 'AI/AI_Cas.lua' )
-__Moose.Include( 'AI/AI_Cargo.lua' )
__Moose.Include( 'Actions/Act_Assign.lua' )
__Moose.Include( 'Actions/Act_Route.lua' )
__Moose.Include( 'Actions/Act_Account.lua' )
@@ -70,6 +70,7 @@ __Moose.Include( 'Tasking/Task.lua' )
__Moose.Include( 'Tasking/DetectionManager.lua' )
__Moose.Include( 'Tasking/Task_A2G_Dispatcher.lua' )
__Moose.Include( 'Tasking/Task_A2G.lua' )
+__Moose.Include( 'Tasking/Task_Cargo.lua' )
__Moose.Include( 'Moose.lua' )
BASE:TraceOnOff( true )
env.info( '*** MOOSE INCLUDE END *** ' )
diff --git a/docs/Documentation/AI_Balancer.html b/docs/Documentation/AI_Balancer.html
index 15193880f..84f7b559e 100644
--- a/docs/Documentation/AI_Balancer.html
+++ b/docs/Documentation/AI_Balancer.html
@@ -80,6 +80,7 @@
Single-Player:Yes / Multi-Player:Yes / AI:Yes / Human:No / Types:Ground --
-Management of logical cargo objects, that can be transported from and to transportation carriers.
+
Core -- Management of CARGO logistics, that can be transported from and to transportation carriers.
-
+
+
+
Cargo can be of various forms, always are composed out of ONE object ( one unit or one static or one slingload crate ):
-
AICARGOUNIT, represented by a Unit in a Group: Cargo can be represented by a Unit in a Group.
+
CARGO_UNIT, represented by a Unit in a singleton Group: Cargo can be represented by a Unit in a Group. a CARGO_UNIT is representable...
+
CARGO_GROUP, represented by a Group. A CARGO_GROUP is reportable...
-
-
Destruction of the Unit will mean that the cargo is lost.
- * CARGO_STATIC, represented by a Static: Cargo can be represented by a Static. Destruction of the Static will mean that the cargo is lost.
- * AICARGOPACKAGE, contained in a Unit of a Group: Cargo can be contained within a Unit of a Group. The cargo can be delivered by the Unit. If the Unit is destroyed, the cargo will be destroyed also.
- * AICARGOPACKAGE, Contained in a Static: Cargo can be contained within a Static. The cargo can be collected from the @Static. If the Static is destroyed, the cargo will be destroyed.
- * CARGO_SLINGLOAD, represented by a Cargo that is transportable: Cargo can be represented by a Cargo object that is transportable. Destruction of the Cargo will mean that the cargo is lost.
The CARGO class defines the core functions that defines a cargo object within MOOSE.
+
+
+
A cargo is a logical object defined that is available for transport, and has a life status within a simulation.
+
+
The CARGO is a state machine: it manages the different events and states of the cargo.
+All derived classes from CARGO follow the same state machine, expose the same cargo event functions, and provide the same cargo states.
+
+
CARGO Events:
-
AICARGOGROUPED, represented by a Group of CARGO_UNITs.
+
CARGO.Board( ToCarrier ): Boards the cargo to a carrier.
+
CARGO.Load( ToCarrier ): Loads the cargo into a carrier, regardless of its position.
+
CARGO.UnBoard( ToPointVec2 ): UnBoard the cargo from a carrier. This will trigger a movement of the cargo to the option ToPointVec2.
+
CARGO.UnLoad( ToPointVec2 ): UnLoads the cargo from a carrier.
+
CARGO.Dead( Controllable ): The cargo is dead. The cargo process will be ended.
The #AI_CARGO class defines the core functions that defines a cargo object within MOOSE.
-A cargo is a logical object defined that is available for transport, and has a life status within a simulation.
-
-
The AICARGO is a state machine: it manages the different events and states of the cargo.
-All derived classes from AICARGO follow the same state machine, expose the same cargo event functions, and provide the same cargo states.
-
-
1.2.1) AI_CARGO Events:
-
-
-
AI_CARGO.Board( ToCarrier ): Boards the cargo to a carrier.
-
AI_CARGO.Load( ToCarrier ): Loads the cargo into a carrier, regardless of its position.
-
AI_CARGO.UnBoard( ToPointVec2 ): UnBoard the cargo from a carrier. This will trigger a movement of the cargo to the option ToPointVec2.
-
AI_CARGO.UnLoad( ToPointVec2 ): UnLoads the cargo from a carrier.
-
AI_CARGO.Dead( Controllable ): The cargo is dead. The cargo process will be ended.
-
-
-
1.2.2) AI_CARGO States:
+
CARGO States:
UnLoaded: The cargo is unloaded from a carrier.
@@ -145,7 +732,7 @@ All derived classes from AICARGO follow the same state machine, expose the
End: The process has come to an end.
-
1.2.3) AI_CARGO state transition methods:
+
CARGO state transition methods:
State transition functions can be set by the mission designer customizing or improving the behaviour of the state.
There are 2 moments when state transition methods will be called by the state machine:
@@ -161,602 +748,6 @@ There are 2 moments when state transition methods will be called by the state ma
These state transition methods need to provide a return value, which is specified at the function description.
-
2) #AICARGOUNIT class
-
-
The AICARGOUNIT class defines a cargo that is represented by a UNIT object within the simulator, and can be transported by a carrier.
-Use the event functions as described above to Load, UnLoad, Board, UnBoard the AICARGOUNIT objects to and from carriers.
-
-
5) #AICARGOGROUPED class
-
-
The AICARGOGROUPED class defines a cargo that is represented by a group of UNIT objects within the simulator, and can be transported by a carrier.
-Use the event functions as described above to Load, UnLoad, Board, UnBoard the AICARGOUNIT objects to and from carriers.
-
-
This module is still under construction, but is described above works already, and will keep working ...
#function IteratorFunction :
-The function that will be called when there is an alive player in the database. The function needs to accept a CLIENT parameter.
+The function that will be called object in the database. The function needs to accept a CLIENT parameter.
@@ -1026,7 +1194,7 @@ self
#function IteratorFunction :
-The function that will be called when there is an alive GROUP in the database. The function needs to accept a GROUP parameter.
+The function that will be called for each object in the database. The function needs to accept a GROUP parameter.
@@ -1058,7 +1226,7 @@ self
#function IteratorFunction :
-The function that will be called when there is an player in the database. The function needs to accept the player name.
+The function that will be called for each object in the database. The function needs to accept the player name.
@@ -1090,7 +1258,7 @@ self
#function IteratorFunction :
-The function that will be called when there is was a player in the database. The function needs to accept a UNIT parameter.
+The function that will be called for each object in the database. The function needs to accept a UNIT parameter.
@@ -1122,7 +1290,7 @@ self
#function IteratorFunction :
-The function that will be called when there is an alive UNIT in the database. The function needs to accept a UNIT parameter.
+The function that will be called for each object in the database. The function needs to accept a UNIT parameter.
@@ -1415,6 +1583,48 @@ self
-- Define a new DATABASE Object. This DBObject will contain a reference to all Group and Unit Templates defined within the ME and the DCSRTE.
DBObject = DATABASE:New()
@@ -942,6 +1065,72 @@ The default "time interval" is after 0.001 seconds.
You can set the "yield interval", and the "time interval". (See above).
+
+
+
Once the filters have been defined and the SETCARGO has been built, you can iterate the SETCARGO with the available iterator methods.
+The iterator methods will walk the SETCARGO set, and call for each cargo within the set a function that you provide.
+The following iterator methods are currently available within the SETCARGO:
Iterate the SET_CARGO and call an interator function for each CARGO, providing the CARGO and optional parameters.
+
+
Parameters
+
+
+
+
#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.
Tasking (Release 2.1) -- The TASK_CARGO models tasks for players to transport Cargo.
+
+
+
+
+
+
+
+
The Moose framework provides various CARGO classes that allow DCS phisical or logical objects to be transported or sling loaded by Carriers.
+The CARGO_ classes, as part of the moose core, are able to Board, Load, UnBoard and UnLoad cargo between Carrier units.
+
+
This collection of classes in this module define tasks for human players to handle these cargo objects.
+Cargo can be transported, picked-up, deployed and sling-loaded from and to other places.
+
+
The following classes are important to consider:
+
+
+
#TASKCARGOTRANSPORT: Defines a task for a human player to transport a set of cargo between various zones.
+
+
+
==
+
+
API CHANGE HISTORY
+
+
The underlying change log documents the API changes. Please read this carefully. The following notation is used:
The TASK_CARGO classes provide you with a flexible tasking sytem,
+that allows you to transport cargo of various types between various locations
+and various dedicated deployment zones.
The TASK_CARGO classes provide you with a flexible tasking sytem,
+that allows you to transport cargo of various types between various locations
+and various dedicated deployment zones.
+
+
+
+
The cargo in scope of the TASKCARGO classes must be explicitly given, and is of type SETCARGO.
+The SET_CARGO contains a collection of CARGO objects that must be handled by the players in the mission.
+
+
+
Task execution experience from the player perspective
+
+
A human player can join the battle field in a client airborne slot or a ground vehicle within the CA module (ALT-J).
+The player needs to accept the task from the task overview list within the mission, using the radio menus.
+
+
Once the TASK_CARGO is assigned to the player and accepted by the player, the player will obtain
+an extra Cargo Handling Radio Menu that contains the CARGO objects that need to be transported.
+
+
Each CARGO object has a certain state:
+
+
+
UnLoaded: The CARGO is located within the battlefield. It may still need to be transported.
+
Loaded: The CARGO is loaded within a Carrier. This can be your air unit, or another air unit, or even a vehicle.
+
Boarding: The CARGO is running or moving towards your Carrier for loading.
+
UnBoarding: The CARGO is driving or jumping out of your Carrier and moves to a location in the Deployment Zone.
+
+
+
Cargo must be transported towards different **Deployment Zones**.
+
+
The Cargo Handling Radio Menu system allows to execute various actions to handle the cargo.
+In the menu, you'll find for each CARGO, that is part of the scope of the task, various actions that can be completed.
+Depending on the location of your Carrier unit, the menu options will vary.
+
+
+
Cargo Pickup and Boarding
+
+
For cargo boarding, a cargo can only execute the boarding actions if it is within the foreseen Reporting Range.
+Therefore, it is important that you steer your Carrier within the Reporting Range,
+so that boarding actions can be executed on the cargo.
+To Pickup and Board cargo, the following menu items will be shown in your carrier radio menu:
+
+
Board Cargo
+
+
If your Carrier is within the Reporting Range of the cargo, it will allow to pickup the cargo by selecting this menu option.
+Depending on the Cargo type, the cargo will either move to your Carrier or you will receive instructions how to handle the cargo
+pickup. If the cargo moves to your carrier, it will indicate the boarding status.
+Note that multiple units need to board your Carrier, so it is required to await the full boarding process.
+Once the cargo is fully boarded within your Carrier, you will be notified of this.
+
+
Note that for airborne Carriers, it is required to land first before the Boarding process can be initiated.
+If during boarding the Carrier gets airborne, the boarding process will be cancelled.
+
+
Pickup Cargo
+
+
If your Carrier is not within the Reporting Range of the cargo, the HQ will guide you to its location.
+Routing information is shown in flight that directs you to the cargo within Reporting Range.
+Upon arrival, the Cargo will contact you and further instructions will be given.
+When your Carrier is airborne, you will receive instructions to land your Carrier.
+The action will not be completed until you've landed your Carrier.
+
+
+
Cargo Deploy and UnBoarding
+
+
Various Deployment Zones can be foreseen in the scope of the Cargo transportation. Each deployment zone can be of varying Zone type.
+The Cargo Handling Radio Menu provides with menu options to execute an action to steer your Carrier to a specific Zone.
+
+
UnBoard Cargo
+
+
If your Carrier is already within a Deployment Zone,
+then the Cargo Handling Radio Menu allows to UnBoard a specific cargo that is
+loaded within your Carrier group into the Deployment Zone.
+Note that the Unboarding process takes a while, as the cargo units (infantry or vehicles) must unload from your Carrier.
+Ensure that you stay at the position or stay on the ground while Unboarding.
+If any unforeseen manoeuvre is done by the Carrier, then the Unboarding will be cancelled.
+
+
Deploy Cargo
+
+
If your Carrier is not within a Deployment Zone, you'll need to fly towards one.
+Fortunately, the Cargo Handling Radio Menu provides you with menu options to select a specific Deployment Zone to fly towards.
+Once a Deployment Zone has been selected, your Carrier will receive routing information from HQ towards the Deployment Zone center.
+Upon arrival, the HQ will provide you with further instructions.
+When your Carrier is airborne, you will receive instructions to land your Carrier.
+The action will not be completed until you've landed your Carrier!
+
+
Handle TASK_CARGO Events ...
+
+
The TASK_CARGO classes define Cargo transport tasks,
+based on the tasking capabilities defined in Task#TASK.
+
+
Specific TASK_CARGO Events
+
+
Specific Cargo Handling event can be captured, that allow to trigger specific actions!
+
+
+
Boarded: Triggered when the Cargo has been Boarded into your Carrier.
+
UnBoarded: Triggered when the cargo has been Unboarded from your Carrier and has arrived at the Deployment Zone.
+
+
+
Standard TASK_CARGO Events
+
+
The TASK_CARGO is implemented using a Statemachine#FSM_TASK, and has the following standard statuses:
+
+
+
None: Start of the process.
+
Planned: The cargo task is planned.
+
Assigned: The cargo task is assigned to a Group#GROUP.
+
Success: The cargo task is successfully completed.
+
Failed: The cargo task has failed. This will happen if the player exists the task early, without communicating a possible cancellation to HQ.
The ZONE_GROUP class defines by a zone around a Group#GROUP with a radius.
@@ -727,8 +743,6 @@
The current leader of the group defines the center of the zone.
This class implements the inherited functions from Zone#ZONE_RADIUS taking into account the own zone format and properties.
-
-
@@ -742,15 +756,13 @@ This class implements the inherited functions from Zone#ZONEPOLYGONBASE
+
The ZONEPOLYGONBASE class defined by a sequence of Group#GROUP waypoints within the Mission Editor, forming a polygon.
@@ -772,7 +784,7 @@ This class implements the inherited functions from Zone#ZONE_RADIUS taking into account the own zone format and properties.
This class is an abstract BASE class for derived classes, and is not meant to be instantiated.
-
6.1) Zone point randomization
+
Zone point randomization
Various functions exist to find random points within the zone.
@@ -782,8 +794,6 @@ This class is an abstract BASE class for derived classes, and is not meant to be
Single-Player:Yes / Multi-Player:Yes / AI:Yes / Human:No / Types:Ground --
-Management of logical cargo objects, that can be transported from and to transportation carriers.
-
-
-
-
-
-
Cargo can be of various forms, always are composed out of ONE object ( one unit or one static or one slingload crate ):
-
-
-
AICARGOUNIT, represented by a Unit in a Group: Cargo can be represented by a Unit in a Group.
-
+
Core -- Management of CARGO logistics, that can be transported from and to transportation carriers.
@@ -517,6 +507,12 @@ and creates a CSV file logging the scoring events and results for use at team or