From a94e7440284d60c04f372f8ec90d7a9e65212a62 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Sat, 31 Mar 2018 07:35:18 +0200 Subject: [PATCH 1/9] -- New modules for CSAR tasking. --- .../Moose/Tasking/Task_CARGO.lua | 5 +- .../Moose/Tasking/Task_Cargo_CSAR.lua | 187 +++++++++ .../Moose/Tasking/Task_Cargo_Dispatcher.lua | 362 ++++++++++++++++++ .../Moose/Tasking/Task_Cargo_Transport.lua | 187 +++++++++ .../Moose/Tasking/Task_Manager.lua | 150 ++++++++ Moose Setup/Moose.files | 4 + 6 files changed, 892 insertions(+), 3 deletions(-) create mode 100644 Moose Development/Moose/Tasking/Task_Cargo_CSAR.lua create mode 100644 Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua create mode 100644 Moose Development/Moose/Tasking/Task_Cargo_Transport.lua create mode 100644 Moose Development/Moose/Tasking/Task_Manager.lua diff --git a/Moose Development/Moose/Tasking/Task_CARGO.lua b/Moose Development/Moose/Tasking/Task_CARGO.lua index 7d11cae8d..c9127d3fe 100644 --- a/Moose Development/Moose/Tasking/Task_CARGO.lua +++ b/Moose Development/Moose/Tasking/Task_CARGO.lua @@ -726,10 +726,9 @@ do -- TASK_CARGO end --- @param #TASK_CARGO self - -- @param @list DeployZones - -- @param Wrapper.Unit#UNIT TaskUnit + -- @param #list DeployZones -- @return #TASK_CARGO - function TASK_CARGO:SetDeployZones( DeployZones, TaskUnit ) + function TASK_CARGO:SetDeployZones( DeployZones ) for DeployZoneID, DeployZone in pairs( DeployZones ) do self.DeployZones[DeployZone:GetName()] = DeployZone diff --git a/Moose Development/Moose/Tasking/Task_Cargo_CSAR.lua b/Moose Development/Moose/Tasking/Task_Cargo_CSAR.lua new file mode 100644 index 000000000..b45dc7e26 --- /dev/null +++ b/Moose Development/Moose/Tasking/Task_Cargo_CSAR.lua @@ -0,0 +1,187 @@ +--- **Tasking** -- Models tasks for players to execute CSAR @{Cargo} downed pilots. +-- +-- ![Banner Image](..\Presentations\TASK_CARGO\Dia1.JPG) +-- +-- === + + +do -- TASK_CARGO_CSAR + + --- The TASK_CARGO_CSAR class + -- @type TASK_CARGO_CSAR + -- @extends Tasking.Task_Cargo#TASK_CARGO + TASK_CARGO_CSAR = { + ClassName = "TASK_CARGO_CSAR", + } + + --- Instantiates a new TASK_CARGO_CSAR. + -- @param #TASK_CARGO_CSAR 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 TaskBriefing The Cargo Task briefing. + -- @return #TASK_CARGO_CSAR self + function TASK_CARGO_CSAR:New( Mission, SetGroup, TaskName, SetCargo, TaskBriefing ) + local self = BASE:Inherit( self, TASK_CARGO:New( Mission, SetGroup, TaskName, SetCargo, "Transport", TaskBriefing ) ) -- #TASK_CARGO_CSAR + self:F() + + Mission:AddTask( self ) + + + -- Events + + self:AddTransition( "*", "CargoPickedUp", "*" ) + self:AddTransition( "*", "CargoDeployed", "*" ) + + self:F( { CargoDeployed = self.CargoDeployed ~= nil and "true" or "false" } ) + + --- OnBefore Transition Handler for Event CargoPickedUp. + -- @function [parent=#TASK_CARGO_CSAR] OnBeforeCargoPickedUp + -- @param #TASK_CARGO_CSAR self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that PickedUp the cargo. You can use this to retrieve the PlayerName etc. + -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. + -- @return #boolean Return false to cancel Transition. + + --- OnAfter Transition Handler for Event CargoPickedUp. + -- @function [parent=#TASK_CARGO_CSAR] OnAfterCargoPickedUp + -- @param #TASK_CARGO_CSAR self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that PickedUp the cargo. You can use this to retrieve the PlayerName etc. + -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. + + --- Synchronous Event Trigger for Event CargoPickedUp. + -- @function [parent=#TASK_CARGO_CSAR] CargoPickedUp + -- @param #TASK_CARGO_CSAR self + -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that PickedUp the cargo. You can use this to retrieve the PlayerName etc. + -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. + + --- Asynchronous Event Trigger for Event CargoPickedUp. + -- @function [parent=#TASK_CARGO_CSAR] __CargoPickedUp + -- @param #TASK_CARGO_CSAR self + -- @param #number Delay The delay in seconds. + -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that PickedUp the cargo. You can use this to retrieve the PlayerName etc. + -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. + + --- OnBefore Transition Handler for Event CargoDeployed. + -- @function [parent=#TASK_CARGO_CSAR] OnBeforeCargoDeployed + -- @param #TASK_CARGO_CSAR self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that Deployed the cargo. You can use this to retrieve the PlayerName etc. + -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. + -- @param Core.Zone#ZONE DeployZone The zone where the Cargo got Deployed or UnBoarded. + -- @return #boolean Return false to cancel Transition. + + --- OnAfter Transition Handler for Event CargoDeployed. + -- @function [parent=#TASK_CARGO_CSAR] OnAfterCargoDeployed + -- @param #TASK_CARGO_CSAR self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that Deployed the cargo. You can use this to retrieve the PlayerName etc. + -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. + -- @param Core.Zone#ZONE DeployZone The zone where the Cargo got Deployed or UnBoarded. + + --- Synchronous Event Trigger for Event CargoDeployed. + -- @function [parent=#TASK_CARGO_CSAR] CargoDeployed + -- @param #TASK_CARGO_CSAR self + -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that Deployed the cargo. You can use this to retrieve the PlayerName etc. + -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. + -- @param Core.Zone#ZONE DeployZone The zone where the Cargo got Deployed or UnBoarded. + + --- Asynchronous Event Trigger for Event CargoDeployed. + -- @function [parent=#TASK_CARGO_CSAR] __CargoDeployed + -- @param #TASK_CARGO_CSAR self + -- @param #number Delay The delay in seconds. + -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that Deployed the cargo. You can use this to retrieve the PlayerName etc. + -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. + -- @param Core.Zone#ZONE DeployZone The zone where the Cargo got Deployed or UnBoarded. + + local Fsm = self:GetUnitProcess() + + local CargoReport = REPORT:New( "Rescue a downed pilot from the following position:") + + SetCargo:ForEachCargo( + --- @param Core.Cargo#CARGO Cargo + function( Cargo ) + local CargoType = Cargo:GetType() + local CargoName = Cargo:GetName() + local CargoCoordinate = Cargo:GetCoordinate() + CargoReport:Add( string.format( '- "%s" (%s) at %s', CargoName, CargoType, CargoCoordinate:ToStringMGRS() ) ) + end + ) + + self:SetBriefing( + TaskBriefing or + CargoReport:Text() + ) + + + return self + end + + function TASK_CARGO_CSAR:ReportOrder( ReportGroup ) + + return 0 + end + + + --- + -- @param #TASK_CARGO_CSAR self + -- @return #boolean + function TASK_CARGO_CSAR:IsAllCargoTransported() + + local CargoSet = self:GetCargoSet() + local Set = CargoSet:GetSet() + + local DeployZones = self:GetDeployZones() + + local CargoDeployed = true + + -- Loop the CargoSet (so evaluate each Cargo in the SET_CARGO ). + for CargoID, CargoData in pairs( Set ) do + local Cargo = CargoData -- Core.Cargo#CARGO + + self:F( { Cargo = Cargo:GetName(), CargoDeployed = Cargo:IsDeployed() } ) + + if Cargo:IsDeployed() then + +-- -- Loop the DeployZones set for the TASK_CARGO_CSAR. +-- for DeployZoneID, DeployZone in pairs( DeployZones ) do +-- +-- -- If all cargo is in one of the deploy zones, then all is good. +-- self:T( { Cargo.CargoObject } ) +-- if Cargo:IsInZone( DeployZone ) == false then +-- CargoDeployed = false +-- end +-- end + else + CargoDeployed = false + end + end + + self:F( { CargoDeployed = CargoDeployed } ) + + return CargoDeployed + end + + --- @param #TASK_CARGO_CSAR self + function TASK_CARGO_CSAR:onafterGoal( TaskUnit, From, Event, To ) + local CargoSet = self.CargoSet + + if self:IsAllCargoTransported() then + self:Success() + end + + self:__Goal( -10 ) + end + +end + diff --git a/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua new file mode 100644 index 000000000..3b22c9e01 --- /dev/null +++ b/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua @@ -0,0 +1,362 @@ +--- **Tasking** - Creates and manages player TASK_CARGO tasks. +-- +-- === +-- +-- ### Author: **FlightControl** +-- +-- ### Contributions: +-- +-- === +-- +-- @module Task_Cargo_Dispatcher + +do -- TASK_CARGO_DISPATCHER + + --- TASK_CARGO_DISPATCHER class. + -- @type TASK_CARGO_DISPATCHER + -- @extends Tasking.Task_Manager#TASK_MANAGER + -- @field TASK_CARGO_DISPATCHER.CSAR CSAR + + --- @type TASK_CARGO_DISPATCHER.CSAR + -- @field Wrapper.Unit#UNIT PilotUnit + -- @field Tasking.Task#TASK Task + + + --- # TASK_CARGO_DISPATCHER class, extends @{Task_Manager#TASK_MANAGER} + -- + -- ![Banner Image](..\Presentations\TASK_CARGO_DISPATCHER\Dia1.JPG) + -- + -- The @{#TASK_CARGO_DISPATCHER} class implements the dynamic dispatching of cargo tasks. + -- + -- ![Banner Image](..\Presentations\TASK_CARGO_DISPATCHER\Dia3.JPG) + -- + -- The EWR will detect units, will group them, and will dispatch @{Task}s to groups. Depending on the type of target detected, different tasks will be dispatched. + -- Find a summary below describing for which situation a task type is created: + -- + -- ![Banner Image](..\Presentations\TASK_CARGO_DISPATCHER\Dia9.JPG) + -- + -- * **CSAR Task**: Is created when a fiendly pilot has ejected from a plane, and needs to be rescued (sometimes behind enemy lines). + -- + -- ## 1. TASK\_A2A\_DISPATCHER constructor: + -- + -- The @{#TASK_CARGO_DISPATCHER.New}() method creates a new TASK\_A2A\_DISPATCHER instance. + -- + -- ### 1.1. Define or set the **Mission**: + -- + -- Tasking is executed to accomplish missions. Therefore, a MISSION object needs to be given as the first parameter. + -- + -- local HQ = GROUP:FindByName( "HQ", "Bravo" ) + -- local CommandCenter = COMMANDCENTER:New( HQ, "Lima" ) + -- local Mission = MISSION:New( CommandCenter, "A2A Mission", "High", "Watch the air enemy units being detected.", coalition.side.RED ) + -- + -- Missions are governed by COMMANDCENTERS, so, ensure you have a COMMANDCENTER object installed and setup within your mission. + -- Create the MISSION object, and hook it under the command center. + -- + -- ### 1.2. Build a set of the groups seated by human players: + -- + -- ![Banner Image](..\Presentations\TASK_CARGO_DISPATCHER\Dia6.JPG) + -- + -- A set or collection of the groups wherein human players can be seated, these can be clients or units that can be joined as a slot or jumping into. + -- + -- local AttackGroups = SET_GROUP:New():FilterCoalitions( "red" ):FilterPrefixes( "Defender" ):FilterStart() + -- + -- The set is built using the SET_GROUP class. Apply any filter criteria to identify the correct groups for your mission. + -- Only these slots or units will be able to execute the mission and will receive tasks for this mission, once available. + -- + -- ### 1.3. Define the **EWR network**: + -- + -- As part of the TASK\_A2A\_DISPATCHER constructor, an EWR network must be given as the third parameter. + -- An EWR network, or, Early Warning Radar network, is used to early detect potential airborne targets and to understand the position of patrolling targets of the enemy. + -- + -- ![Banner Image](..\Presentations\TASK_CARGO_DISPATCHER\Dia5.JPG) + -- + -- Typically EWR networks are setup using 55G6 EWR, 1L13 EWR, Hawk sr and Patriot str ground based radar units. + -- These radars have different ranges and 55G6 EWR and 1L13 EWR radars are Eastern Bloc units (eg Russia, Ukraine, Georgia) while the Hawk and Patriot radars are Western (eg US). + -- Additionally, ANY other radar capable unit can be part of the EWR network! Also AWACS airborne units, planes, helicopters can help to detect targets, as long as they have radar. + -- The position of these units is very important as they need to provide enough coverage + -- to pick up enemy aircraft as they approach so that CAP and GCI flights can be tasked to intercept them. + -- + -- ![Banner Image](..\Presentations\TASK_CARGO_DISPATCHER\Dia7.JPG) + -- + -- Additionally in a hot war situation where the border is no longer respected the placement of radars has a big effect on how fast the war escalates. + -- For example if they are a long way forward and can detect enemy planes on the ground and taking off + -- they will start to vector CAP and GCI flights to attack them straight away which will immediately draw a response from the other coalition. + -- Having the radars further back will mean a slower escalation because fewer targets will be detected and + -- therefore less CAP and GCI flights will spawn and this will tend to make just the border area active rather than a melee over the whole map. + -- It all depends on what the desired effect is. + -- + -- EWR networks are **dynamically constructed**, that is, they form part of the @{Functional#DETECTION_BASE} object that is given as the input parameter of the TASK\_A2A\_DISPATCHER class. + -- By defining in a **smart way the names or name prefixes of the groups** with EWR capable units, these groups will be **automatically added or deleted** from the EWR network, + -- increasing or decreasing the radar coverage of the Early Warning System. + -- + -- See the following example to setup an EWR network containing EWR stations and AWACS. + -- + -- local EWRSet = SET_GROUP:New():FilterPrefixes( "EWR" ):FilterCoalitions("red"):FilterStart() + -- + -- local EWRDetection = DETECTION_AREAS:New( EWRSet, 6000 ) + -- EWRDetection:SetFriendliesRange( 10000 ) + -- EWRDetection:SetRefreshTimeInterval(30) + -- + -- -- Setup the A2A dispatcher, and initialize it. + -- A2ADispatcher = TASK_CARGO_DISPATCHER:New( Mission, AttackGroups, EWRDetection ) + -- + -- The above example creates a SET_GROUP instance, and stores this in the variable (object) **EWRSet**. + -- **EWRSet** is then being configured to filter all active groups with a group name starting with **EWR** to be included in the Set. + -- **EWRSet** is then being ordered to start the dynamic filtering. Note that any destroy or new spawn of a group with the above names will be removed or added to the Set. + -- Then a new **EWRDetection** object is created from the class DETECTION_AREAS. A grouping radius of 6000 is choosen, which is 6km. + -- The **EWRDetection** object is then passed to the @{#TASK_CARGO_DISPATCHER.New}() method to indicate the EWR network configuration and setup the A2A tasking and detection mechanism. + -- + -- ### 2. Define the detected **target grouping radius**: + -- + -- ![Banner Image](..\Presentations\TASK_CARGO_DISPATCHER\Dia8.JPG) + -- + -- The target grouping radius is a property of the Detection object, that was passed to the AI\_A2A\_DISPATCHER object, but can be changed. + -- The grouping radius should not be too small, but also depends on the types of planes and the era of the simulation. + -- Fast planes like in the 80s, need a larger radius than WWII planes. + -- Typically I suggest to use 30000 for new generation planes and 10000 for older era aircraft. + -- + -- Note that detected targets are constantly re-grouped, that is, when certain detected aircraft are moving further than the group radius, then these aircraft will become a separate + -- group being detected. This may result in additional GCI being started by the dispatcher! So don't make this value too small! + -- + -- ## 3. Set the **Engage radius**: + -- + -- Define the radius to engage any target by airborne friendlies, which are executing cap or returning from an intercept mission. + -- + -- ![Banner Image](..\Presentations\TASK_CARGO_DISPATCHER\Dia11.JPG) + -- + -- So, if there is a target area detected and reported, + -- then any friendlies that are airborne near this target area, + -- will be commanded to (re-)engage that target when available (if no other tasks were commanded). + -- For example, if 100000 is given as a value, then any friendly that is airborne within 100km from the detected target, + -- will be considered to receive the command to engage that target area. + -- You need to evaluate the value of this parameter carefully. + -- If too small, more intercept missions may be triggered upon detected target areas. + -- If too large, any airborne cap may not be able to reach the detected target area in time, because it is too far. + -- + -- ## 4. Set **Scoring** and **Messages**: + -- + -- The TASK\_A2A\_DISPATCHER is a state machine. It triggers the event Assign when a new player joins a @{Task} dispatched by the TASK\_A2A\_DISPATCHER. + -- An _event handler_ can be defined to catch the **Assign** event, and add **additional processing** to set _scoring_ and to _define messages_, + -- when the player reaches certain achievements in the task. + -- + -- The prototype to handle the **Assign** event needs to be developed as follows: + -- + -- TaskDispatcher = TASK_CARGO_DISPATCHER:New( ... ) + -- + -- --- @param #TaskDispatcher self + -- -- @param #string From Contains the name of the state from where the Event was triggered. + -- -- @param #string Event Contains the name of the event that was triggered. In this case Assign. + -- -- @param #string To Contains the name of the state that will be transitioned to. + -- -- @param Tasking.Task_A2A#TASK_A2A Task The Task object, which is any derived object from TASK_A2A. + -- -- @param Wrapper.Unit#UNIT TaskUnit The Unit or Client that contains the Player. + -- -- @param #string PlayerName The name of the Player that joined the TaskUnit. + -- function TaskDispatcher:OnAfterAssign( From, Event, To, Task, TaskUnit, PlayerName ) + -- Task:SetScoreOnProgress( PlayerName, 20, TaskUnit ) + -- Task:SetScoreOnSuccess( PlayerName, 200, TaskUnit ) + -- Task:SetScoreOnFail( PlayerName, -100, TaskUnit ) + -- end + -- + -- The **OnAfterAssign** method (function) is added to the TaskDispatcher object. + -- This method will be called when a new player joins a unit in the set of groups in scope of the dispatcher. + -- So, this method will be called only **ONCE** when a player joins a unit in scope of the task. + -- + -- The TASK class implements various methods to additional **set scoring** for player achievements: + -- + -- * @{Tasking.Task#TASK.SetScoreOnProgress}() will add additional scores when a player achieves **Progress** while executing the task. + -- Examples of **task progress** can be destroying units, arriving at zones etc. + -- + -- * @{Tasking.Task#TASK.SetScoreOnSuccess}() will add additional scores when the task goes into **Success** state. + -- This means the **task has been successfully completed**. + -- + -- * @{Tasking.Task#TASK.SetScoreOnSuccess}() will add additional (negative) scores when the task goes into **Failed** state. + -- This means the **task has not been successfully completed**, and the scores must be given with a negative value! + -- + -- @field #TASK_CARGO_DISPATCHER + TASK_CARGO_DISPATCHER = { + ClassName = "TASK_CARGO_DISPATCHER", + Mission = nil, + Tasks = {}, + CSAR = {}, + } + + + --- TASK_CARGO_DISPATCHER constructor. + -- @param #TASK_CARGO_DISPATCHER self + -- @param Tasking.Mission#MISSION Mission The mission for which the task dispatching is done. + -- @param Set#SET_GROUP SetGroup The set of groups that can join the tasks within the mission. + -- @return #TASK_CARGO_DISPATCHER self + function TASK_CARGO_DISPATCHER:New( Mission, SetGroup ) + + -- Inherits from DETECTION_MANAGER + local self = BASE:Inherit( self, TASK_MANAGER:New( SetGroup ) ) -- #TASK_CARGO_DISPATCHER + + self.Mission = Mission + + self:AddTransition( "Started", "Assign", "Started" ) + + --- OnAfter Transition Handler for Event Assign. + -- @function [parent=#TASK_CARGO_DISPATCHER] OnAfterAssign + -- @param #TASK_CARGO_DISPATCHER self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @param Tasking.Task_A2A#TASK_A2A Task + -- @param Wrapper.Unit#UNIT TaskUnit + -- @param #string PlayerName + + self:SetCSARRadius() + self:__Start( 5 ) + + -- For CSAR missions, we process the event when a pilot ejects. + + self:HandleEvent( EVENTS.Ejection ) + + return self + end + + + --- Handle the event when a pilot ejects. + -- @param #TASK_CARGO_DISPATCHER self + -- @param Core.Event#EVENTDATA EventData + function TASK_CARGO_DISPATCHER:OnEventEjection( EventData ) + + self:E( { EventData = EventData } ) + + local PilotUnit = EventData.IniUnit + local CSARName = EventData.IniUnitName + + self.CSAR[CSARName] = {} + self.CSAR[CSARName].PilotUnit = PilotUnit + self.CSAR[CSARName].Task = nil + + return self + end + + + --- Define the radius to when a CSAR task will be generated for any downed pilot within range of the nearest CSAR airbase. + -- @param #TASK_CARGO_DISPATCHER self + -- @param #number CSARRadius (Optional, Default = 50000) The radius in meters to decide whether a CSAR needs to be created. + -- @return #TASK_CARGO_DISPATCHER + -- @usage + -- + -- -- Set 20km as the radius to CSAR any downed pilot within range of the nearest CSAR airbase. + -- TaskA2ADispatcher:SetEngageRadius( 20000 ) + -- + -- -- Set 50km as the radius to to CSAR any downed pilot within range of the nearest CSAR airbase. + -- TaskA2ADispatcher:SetEngageRadius() -- 50000 is the default value. + -- + function TASK_CARGO_DISPATCHER:SetCSARRadius( CSARRadius ) + + self.Detection:SetFriendliesRange( CSARRadius or 50000 ) + + return self + end + + + --- Define one deploy zone for the CSAR tasks. + -- @param #TASK_CARGO_DISPATCHER self + -- @param DeployZone A deploy zone. + -- @return #TASK_CARGO_DISPATCHER + function TASK_CARGO_DISPATCHER:SetCSARDeployZone( CSARDeployZone ) + + self.CSARDeployZones = { CSARDeployZone } + + return self + end + + + --- Define the deploy zones for the CSAR tasks. + -- @param #TASK_CARGO_DISPATCHER self + -- @param DeployZones A list of the deploy zones. + -- @return #TASK_CARGO_DISPATCHER + function TASK_CARGO_DISPATCHER:SetCSARDeployZones( CSARDeployZones ) + + self.CSARDeployZones = CSARDeployZones + + return self + end + + + --- Evaluates of a CSAR task needs to be started. + -- @param #TASK_CARGO_DISPATCHER self + -- @return Set#SET_CARGO The SetCargo to be rescued. + -- @return #nil If there is no CSAR task required. + function TASK_CARGO_DISPATCHER:EvaluateCSAR( CSARUnit ) + + local CSARCargo = CARGO_UNIT:New( CSARUnit, "Pilot", CSARUnit:GetName(), 80, 1500, 10 ) + + local SetCargo = SET_CARGO:New() + SetCargo:AddCargosByName( CSARUnit:GetName() ) + + SetCargo:Flush(self) + + return SetCargo + + end + + + + --- Assigns tasks to the @{Set#SET_GROUP}. + -- @param #TASK_CARGO_DISPATCHER self + -- @return #boolean Return true if you want the task assigning to continue... false will cancel the loop. + function TASK_CARGO_DISPATCHER:ManageTasks() + self:F() + + local AreaMsg = {} + local TaskMsg = {} + local ChangeMsg = {} + + local Mission = self.Mission + + if Mission:IsIDLE() or Mission:IsENGAGED() then + + local TaskReport = REPORT:New() + + -- Checking the task queue for the dispatcher, and removing any obsolete task! + for TaskIndex, TaskData in pairs( self.Tasks ) do + local Task = TaskData -- Tasking.Task#TASK + if Task:IsStatePlanned() then + -- Here we need to check if the pilot is still existing. +-- local DetectedItem = Detection:GetDetectedItemByIndex( TaskIndex ) +-- if not DetectedItem then +-- local TaskText = Task:GetName() +-- for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do +-- Mission:GetCommandCenter():MessageToGroup( string.format( "Obsolete A2A task %s for %s removed.", TaskText, Mission:GetShortText() ), TaskGroup ) +-- end +-- Task = self:RemoveTask( TaskIndex ) +-- end + end + end + + -- Now that all obsolete tasks are removed, loop through the CSAR pilots. + for CSARID, CSARData in pairs( self.CSAR ) do + + if CSARData.Task then + else + -- New CSAR Task + local SetCargo = self:EvaluateCSAR( CSARData.PilotUnit ) + local CSARTask = TASK_CARGO_CSAR:New( Mission, self.SetGroup, "Rescue Pilot", SetCargo ) + CSARTask:SetDeployZones( { self.CSARDeployZones } ) + Mission:AddTask( CSARTask ) + TaskReport:Add( CSARTask:GetName() ) + end + end + + + -- TODO set menus using the HQ coordinator + Mission:GetCommandCenter():SetMenu() + + local TaskText = TaskReport:Text(", ") + + for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do + if ( not Mission:IsGroupAssigned(TaskGroup) ) and TaskText ~= "" then + Mission:GetCommandCenter():MessageToGroup( string.format( "%s has tasks %s. Subscribe to a task using the radio menu.", Mission:GetShortText(), TaskText ), TaskGroup ) + end + end + + end + + return true + end + +end diff --git a/Moose Development/Moose/Tasking/Task_Cargo_Transport.lua b/Moose Development/Moose/Tasking/Task_Cargo_Transport.lua new file mode 100644 index 000000000..0deff06e4 --- /dev/null +++ b/Moose Development/Moose/Tasking/Task_Cargo_Transport.lua @@ -0,0 +1,187 @@ +--- **Tasking** -- The TASK_CARGO models tasks for players to transport @{Cargo}. +-- +-- ![Banner Image](..\Presentations\TASK_CARGO\Dia1.JPG) +-- +-- === + + +do -- TASK_CARGO_TRANSPORT + + --- The TASK_CARGO_TRANSPORT class + -- @type TASK_CARGO_TRANSPORT + -- @extends Tasking.Task_Cargo#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. + -- @param #string TaskBriefing The Cargo Task briefing. + -- @return #TASK_CARGO_TRANSPORT self + function TASK_CARGO_TRANSPORT:New( Mission, SetGroup, TaskName, SetCargo, TaskBriefing ) + local self = BASE:Inherit( self, TASK_CARGO:New( Mission, SetGroup, TaskName, SetCargo, "Transport", TaskBriefing ) ) -- #TASK_CARGO_TRANSPORT + self:F() + + Mission:AddTask( self ) + + + -- Events + + self:AddTransition( "*", "CargoPickedUp", "*" ) + self:AddTransition( "*", "CargoDeployed", "*" ) + + self:F( { CargoDeployed = self.CargoDeployed ~= nil and "true" or "false" } ) + + --- OnBefore Transition Handler for Event CargoPickedUp. + -- @function [parent=#TASK_CARGO_TRANSPORT] OnBeforeCargoPickedUp + -- @param #TASK_CARGO_TRANSPORT self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that PickedUp the cargo. You can use this to retrieve the PlayerName etc. + -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. + -- @return #boolean Return false to cancel Transition. + + --- OnAfter Transition Handler for Event CargoPickedUp. + -- @function [parent=#TASK_CARGO_TRANSPORT] OnAfterCargoPickedUp + -- @param #TASK_CARGO_TRANSPORT self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that PickedUp the cargo. You can use this to retrieve the PlayerName etc. + -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. + + --- Synchronous Event Trigger for Event CargoPickedUp. + -- @function [parent=#TASK_CARGO_TRANSPORT] CargoPickedUp + -- @param #TASK_CARGO_TRANSPORT self + -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that PickedUp the cargo. You can use this to retrieve the PlayerName etc. + -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. + + --- Asynchronous Event Trigger for Event CargoPickedUp. + -- @function [parent=#TASK_CARGO_TRANSPORT] __CargoPickedUp + -- @param #TASK_CARGO_TRANSPORT self + -- @param #number Delay The delay in seconds. + -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that PickedUp the cargo. You can use this to retrieve the PlayerName etc. + -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. + + --- OnBefore Transition Handler for Event CargoDeployed. + -- @function [parent=#TASK_CARGO_TRANSPORT] OnBeforeCargoDeployed + -- @param #TASK_CARGO_TRANSPORT self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that Deployed the cargo. You can use this to retrieve the PlayerName etc. + -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. + -- @param Core.Zone#ZONE DeployZone The zone where the Cargo got Deployed or UnBoarded. + -- @return #boolean Return false to cancel Transition. + + --- OnAfter Transition Handler for Event CargoDeployed. + -- @function [parent=#TASK_CARGO_TRANSPORT] OnAfterCargoDeployed + -- @param #TASK_CARGO_TRANSPORT self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that Deployed the cargo. You can use this to retrieve the PlayerName etc. + -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. + -- @param Core.Zone#ZONE DeployZone The zone where the Cargo got Deployed or UnBoarded. + + --- Synchronous Event Trigger for Event CargoDeployed. + -- @function [parent=#TASK_CARGO_TRANSPORT] CargoDeployed + -- @param #TASK_CARGO_TRANSPORT self + -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that Deployed the cargo. You can use this to retrieve the PlayerName etc. + -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. + -- @param Core.Zone#ZONE DeployZone The zone where the Cargo got Deployed or UnBoarded. + + --- Asynchronous Event Trigger for Event CargoDeployed. + -- @function [parent=#TASK_CARGO_TRANSPORT] __CargoDeployed + -- @param #TASK_CARGO_TRANSPORT self + -- @param #number Delay The delay in seconds. + -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that Deployed the cargo. You can use this to retrieve the PlayerName etc. + -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. + -- @param Core.Zone#ZONE DeployZone The zone where the Cargo got Deployed or UnBoarded. + + local Fsm = self:GetUnitProcess() + + local CargoReport = REPORT:New( "Transport Cargo. The following cargo needs to be transported including initial positions:") + + SetCargo:ForEachCargo( + --- @param Core.Cargo#CARGO Cargo + function( Cargo ) + local CargoType = Cargo:GetType() + local CargoName = Cargo:GetName() + local CargoCoordinate = Cargo:GetCoordinate() + CargoReport:Add( string.format( '- "%s" (%s) at %s', CargoName, CargoType, CargoCoordinate:ToStringMGRS() ) ) + end + ) + + self:SetBriefing( + TaskBriefing or + CargoReport:Text() + ) + + + return self + end + + function TASK_CARGO_TRANSPORT:ReportOrder( ReportGroup ) + + return 0 + end + + + --- + -- @param #TASK_CARGO_TRANSPORT self + -- @return #boolean + function TASK_CARGO_TRANSPORT:IsAllCargoTransported() + + local CargoSet = self:GetCargoSet() + local Set = CargoSet:GetSet() + + local DeployZones = self:GetDeployZones() + + local CargoDeployed = true + + -- Loop the CargoSet (so evaluate each Cargo in the SET_CARGO ). + for CargoID, CargoData in pairs( Set ) do + local Cargo = CargoData -- Core.Cargo#CARGO + + self:F( { Cargo = Cargo:GetName(), CargoDeployed = Cargo:IsDeployed() } ) + + if Cargo:IsDeployed() then + +-- -- Loop the DeployZones set for the TASK_CARGO_TRANSPORT. +-- for DeployZoneID, DeployZone in pairs( DeployZones ) do +-- +-- -- If all cargo is in one of the deploy zones, then all is good. +-- self:T( { Cargo.CargoObject } ) +-- if Cargo:IsInZone( DeployZone ) == false then +-- CargoDeployed = false +-- end +-- end + else + CargoDeployed = false + end + end + + self:F( { CargoDeployed = CargoDeployed } ) + + return CargoDeployed + end + + --- @param #TASK_CARGO_TRANSPORT self + function TASK_CARGO_TRANSPORT:onafterGoal( TaskUnit, From, Event, To ) + local CargoSet = self.CargoSet + + if self:IsAllCargoTransported() then + self:Success() + end + + self:__Goal( -10 ) + end + +end + diff --git a/Moose Development/Moose/Tasking/Task_Manager.lua b/Moose Development/Moose/Tasking/Task_Manager.lua new file mode 100644 index 000000000..2bf10fea6 --- /dev/null +++ b/Moose Development/Moose/Tasking/Task_Manager.lua @@ -0,0 +1,150 @@ +--- This module contains the TASK_MANAGER class and derived classes. +-- +-- === +-- +-- 1) @{Task_Manager#TASK_MANAGER} class, extends @{Fsm#FSM} +-- === +-- The @{Task_Manager#TASK_MANAGER} class defines the core functions to report tasks to groups. +-- Reportings can be done in several manners, and it is up to the derived classes if TASK_MANAGER to model the reporting behaviour. +-- +-- 1.1) TASK_MANAGER constructor: +-- ----------------------------------- +-- * @{Task_Manager#TASK_MANAGER.New}(): Create a new TASK_MANAGER instance. +-- +-- 1.2) TASK_MANAGER reporting: +-- --------------------------------- +-- Derived TASK_MANAGER classes will manage tasks using the method @{Task_Manager#TASK_MANAGER.ManageTasks}(). This method implements polymorphic behaviour. +-- +-- The time interval in seconds of the task management can be changed using the methods @{Task_Manager#TASK_MANAGER.SetRefreshTimeInterval}(). +-- To control how long a reporting message is displayed, use @{Task_Manager#TASK_MANAGER.SetReportDisplayTime}(). +-- Derived classes need to implement the method @{Task_Manager#TASK_MANAGER.GetReportDisplayTime}() to use the correct display time for displayed messages during a report. +-- +-- Task management can be started and stopped using the methods @{Task_Manager#TASK_MANAGER.StartTasks}() and @{Task_Manager#TASK_MANAGER.StopTasks}() respectively. +-- If an ad-hoc report is requested, use the method @{Task_Manager#TASK_MANAGER#ManageTasks}(). +-- +-- The default task management interval is every 60 seconds. +-- +-- === +-- +-- ### Contributions: Mechanist, Prof_Hilactic, FlightControl - Concept & Testing +-- ### Author: FlightControl - Framework Design & Programming +-- +-- @module Task_Manager + +do -- TASK_MANAGER + + --- TASK_MANAGER class. + -- @type TASK_MANAGER + -- @field Set#SET_GROUP SetGroup The set of group objects containing players for which tasks are managed. + -- @extends Core.Fsm#FSM + TASK_MANAGER = { + ClassName = "TASK_MANAGER", + SetGroup = nil, + } + + --- TASK\_MANAGER constructor. + -- @param #TASK_MANAGER self + -- @param Set#SET_GROUP SetGroup The set of group objects containing players for which tasks are managed. + -- @return #TASK_MANAGER self + function TASK_MANAGER:New( SetGroup ) + + -- Inherits from BASE + local self = BASE:Inherit( self, FSM:New() ) -- #TASK_MANAGER + + self.SetGroup = SetGroup + + self:SetStartState( "Stopped" ) + self:AddTransition( "Stopped", "StartTasks", "Started" ) + + --- StartTasks Handler OnBefore for TASK_MANAGER + -- @function [parent=#TASK_MANAGER] OnBeforeStartTasks + -- @param #TASK_MANAGER self + -- @param #string From + -- @param #string Event + -- @param #string To + -- @return #boolean + + --- StartTasks Handler OnAfter for TASK_MANAGER + -- @function [parent=#TASK_MANAGER] OnAfterStartTasks + -- @param #TASK_MANAGER self + -- @param #string From + -- @param #string Event + -- @param #string To + + --- StartTasks Trigger for TASK_MANAGER + -- @function [parent=#TASK_MANAGER] StartTasks + -- @param #TASK_MANAGER self + + --- StartTasks Asynchronous Trigger for TASK_MANAGER + -- @function [parent=#TASK_MANAGER] __StartTasks + -- @param #TASK_MANAGER self + -- @param #number Delay + + + + self:AddTransition( "Started", "StopTasks", "Stopped" ) + + --- StopTasks Handler OnBefore for TASK_MANAGER + -- @function [parent=#TASK_MANAGER] OnBeforeStopTasks + -- @param #TASK_MANAGER self + -- @param #string From + -- @param #string Event + -- @param #string To + -- @return #boolean + + --- StopTasks Handler OnAfter for TASK_MANAGER + -- @function [parent=#TASK_MANAGER] OnAfterStopTasks + -- @param #TASK_MANAGER self + -- @param #string From + -- @param #string Event + -- @param #string To + + --- StopTasks Trigger for TASK_MANAGER + -- @function [parent=#TASK_MANAGER] StopTasks + -- @param #TASK_MANAGER self + + --- StopTasks Asynchronous Trigger for TASK_MANAGER + -- @function [parent=#TASK_MANAGER] __StopTasks + -- @param #TASK_MANAGER self + -- @param #number Delay + + + self:AddTransition( "Started", "Manage", "Started" ) + + self:SetRefreshTimeInterval( 30 ) + + return self + end + + function TASK_MANAGER:onafterStartTasks( From, Event, To ) + self:Report() + end + + function TASK_MANAGER:onafterManage( From, Event, To ) + + self:__Manage( -self._RefreshTimeInterval ) + + self:ManageTasks() + end + + --- Set the refresh time interval in seconds when a new task management action needs to be done. + -- @param #TASK_MANAGER self + -- @param #number RefreshTimeInterval The refresh time interval in seconds when a new task management action needs to be done. + -- @return #TASK_MANAGER self + function TASK_MANAGER:SetRefreshTimeInterval( RefreshTimeInterval ) + self:F2() + + self._RefreshTimeInterval = RefreshTimeInterval + end + + + --- Manages the tasks for the @{Set#SET_GROUP}. + -- @param #TASK_MANAGER self + -- @return #TASK_MANAGER self + function TASK_MANAGER:ManageTasks() + self:E() + + end + +end + diff --git a/Moose Setup/Moose.files b/Moose Setup/Moose.files index ebc56985c..d1328835d 100644 --- a/Moose Setup/Moose.files +++ b/Moose Setup/Moose.files @@ -76,12 +76,16 @@ Tasking/CommandCenter.lua Tasking/Mission.lua Tasking/Task.lua Tasking/TaskInfo.lua +Tasking/Task_Manager.lua Tasking/DetectionManager.lua Tasking/Task_A2G_Dispatcher.lua Tasking/Task_A2G.lua Tasking/Task_A2A_Dispatcher.lua Tasking/Task_A2A.lua Tasking/Task_Cargo.lua +Tasking/Task_Cargo_Transport.lua +Tasking/Task_Cargo_CSAR.lua +Tasking/Task_Cargo_Dispatcher.lua Tasking/TaskZoneCapture.lua Moose.lua From a4d3089fdb6e204d9fd4a49d91dd852835854c88 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Sat, 31 Mar 2018 09:10:11 +0200 Subject: [PATCH 2/9] Updates Csar --- Moose Development/Moose/Cargo/Cargo.lua | 11 ++++ .../Moose/Tasking/Task_CARGO.lua | 5 +- .../Moose/Tasking/Task_Cargo_Dispatcher.lua | 54 ++++++++++++++++--- .../Moose/Tasking/Task_Manager.lua | 2 +- 4 files changed, 61 insertions(+), 11 deletions(-) diff --git a/Moose Development/Moose/Cargo/Cargo.lua b/Moose Development/Moose/Cargo/Cargo.lua index e6b3bde6e..07ee37a6d 100644 --- a/Moose Development/Moose/Cargo/Cargo.lua +++ b/Moose Development/Moose/Cargo/Cargo.lua @@ -277,6 +277,17 @@ do -- CARGO return self end + + --- Find a CARGO in the _DATABASE. + -- @param #CARGO self + -- @param #string CargoName The Cargo Name. + -- @return #CARGO self + function CARGO:FindByName( CargoName ) + + local CargoFound = _DATABASE:FindCargo( CargoName ) + return CargoFound + end + --- Destroy the cargo. -- @param #CARGO self function CARGO:Destroy() diff --git a/Moose Development/Moose/Tasking/Task_CARGO.lua b/Moose Development/Moose/Tasking/Task_CARGO.lua index c9127d3fe..d59473047 100644 --- a/Moose Development/Moose/Tasking/Task_CARGO.lua +++ b/Moose Development/Moose/Tasking/Task_CARGO.lua @@ -727,10 +727,11 @@ do -- TASK_CARGO --- @param #TASK_CARGO self -- @param #list DeployZones + -- @param Wrapper.Unit#UNIT TaskUnit -- @return #TASK_CARGO - function TASK_CARGO:SetDeployZones( DeployZones ) + function TASK_CARGO:SetDeployZones( DeployZones, TaskUnit ) - for DeployZoneID, DeployZone in pairs( DeployZones ) do + for DeployZoneID, DeployZone in pairs( DeployZones or {} ) do self.DeployZones[DeployZone:GetName()] = DeployZone end diff --git a/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua index 3b22c9e01..7e07deb90 100644 --- a/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua +++ b/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua @@ -205,7 +205,7 @@ do -- TASK_CARGO_DISPATCHER -- @param #string PlayerName self:SetCSARRadius() - self:__Start( 5 ) + self:__StartTasks( 5 ) -- For CSAR missions, we process the event when a pilot ejects. @@ -221,14 +221,52 @@ do -- TASK_CARGO_DISPATCHER function TASK_CARGO_DISPATCHER:OnEventEjection( EventData ) self:E( { EventData = EventData } ) - - local PilotUnit = EventData.IniUnit + + local PlaneUnit = EventData.IniUnit local CSARName = EventData.IniUnitName - self.CSAR[CSARName] = {} - self.CSAR[CSARName].PilotUnit = PilotUnit - self.CSAR[CSARName].Task = nil + local PilotUnit = nil + + self:ScheduleOnce( 1, + function() + + -- Search for the ejected pilot + + local PlaneCoord = PlaneUnit:GetCoordinate() + + local SphereSearch = { + id = world.VolumeType.SPHERE, + params = { + point = PlaneCoord:GetVec3(), + radius = 100, + } + + } + + --- @param Dcs.DCSWrapper.Unit#Unit FoundDCSUnit + -- @param Wrapper.Group#GROUP ReportGroup + -- @param Set#SET_GROUP ReportSetGroup + local FindEjectedPilot = function( FoundDCSUnit ) + + local UnitName = FoundDCSUnit:getName() + + self:E( { "Units near Plane:", UnitName } ) + + PilotUnit = UNIT:Register( UnitName ) + + return true + end + + world.searchObjects( { Object.Category.UNIT, Object.Category.STATIC, Object.Category.SCENERY, Object.Category.WEAPON }, SphereSearch, FindEjectedPilot ) + + self.CSAR[CSARName] = {} + self.CSAR[CSARName].PilotUnit = PlaneUnit + self.CSAR[CSARName].Task = nil + end + ) + + return self end @@ -247,7 +285,7 @@ do -- TASK_CARGO_DISPATCHER -- function TASK_CARGO_DISPATCHER:SetCSARRadius( CSARRadius ) - self.Detection:SetFriendliesRange( CSARRadius or 50000 ) + self.CSARRadius = CSARRadius or 50000 return self end @@ -336,7 +374,7 @@ do -- TASK_CARGO_DISPATCHER -- New CSAR Task local SetCargo = self:EvaluateCSAR( CSARData.PilotUnit ) local CSARTask = TASK_CARGO_CSAR:New( Mission, self.SetGroup, "Rescue Pilot", SetCargo ) - CSARTask:SetDeployZones( { self.CSARDeployZones } ) + CSARTask:SetDeployZones( self.CSARDeployZones or {} ) Mission:AddTask( CSARTask ) TaskReport:Add( CSARTask:GetName() ) end diff --git a/Moose Development/Moose/Tasking/Task_Manager.lua b/Moose Development/Moose/Tasking/Task_Manager.lua index 2bf10fea6..340fd8233 100644 --- a/Moose Development/Moose/Tasking/Task_Manager.lua +++ b/Moose Development/Moose/Tasking/Task_Manager.lua @@ -117,7 +117,7 @@ do -- TASK_MANAGER end function TASK_MANAGER:onafterStartTasks( From, Event, To ) - self:Report() + self:Manage() end function TASK_MANAGER:onafterManage( From, Event, To ) From d0925ddfc189bbab0944df2b359a476de90b5787 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Mon, 2 Apr 2018 09:29:51 +0200 Subject: [PATCH 3/9] Progress --- Moose Development/Moose/Core/Spawn.lua | 249 ++++++++++++++++-- .../Moose/Tasking/Task_Cargo_CSAR.lua | 2 +- .../Moose/Tasking/Task_Cargo_Dispatcher.lua | 71 +++-- 3 files changed, 251 insertions(+), 71 deletions(-) diff --git a/Moose Development/Moose/Core/Spawn.lua b/Moose Development/Moose/Core/Spawn.lua index 5342a6e92..1e4640a62 100644 --- a/Moose Development/Moose/Core/Spawn.lua +++ b/Moose Development/Moose/Core/Spawn.lua @@ -288,20 +288,20 @@ function SPAWN:New( SpawnTemplatePrefix ) self.SpawnIndex = 0 self.SpawnCount = 0 -- The internal counter of the amount of spawning the has happened since SpawnStart. self.AliveUnits = 0 -- Contains the counter how many units are currently alive - self.SpawnIsScheduled = false -- Reflects if the spawning for this SpawnTemplatePrefix is going to be scheduled or not. + self.SpawnIsScheduled = false -- Reflects if the spawning for this SpawnTemplatePrefix is going to be scheduled or not. self.SpawnTemplate = self._GetTemplate( self, SpawnTemplatePrefix ) -- Contains the template structure for a Group Spawn from the Mission Editor. Note that this group must have lateActivation always on!!! - self.Repeat = false -- Don't repeat the group from Take-Off till Landing and back Take-Off by ReSpawning. - self.UnControlled = false -- When working in UnControlled mode, all planes are Spawned in UnControlled mode before the scheduler starts. - self.SpawnInitLimit = false -- By default, no InitLimit - self.SpawnMaxUnitsAlive = 0 -- The maximum amount of groups that can be alive of SpawnTemplatePrefix at the same time. - self.SpawnMaxGroups = 0 -- The maximum amount of groups that can be spawned. - self.SpawnRandomize = false -- Sets the randomization flag of new Spawned units to false. - self.SpawnVisible = false -- Flag that indicates if all the Groups of the SpawnGroup need to be visible when Spawned. - self.AIOnOff = true -- The AI is on by default when spawning a group. + self.Repeat = false -- Don't repeat the group from Take-Off till Landing and back Take-Off by ReSpawning. + self.UnControlled = false -- When working in UnControlled mode, all planes are Spawned in UnControlled mode before the scheduler starts. + self.SpawnInitLimit = false -- By default, no InitLimit + self.SpawnMaxUnitsAlive = 0 -- The maximum amount of groups that can be alive of SpawnTemplatePrefix at the same time. + self.SpawnMaxGroups = 0 -- The maximum amount of groups that can be spawned. + self.SpawnRandomize = false -- Sets the randomization flag of new Spawned units to false. + self.SpawnVisible = false -- Flag that indicates if all the Groups of the SpawnGroup need to be visible when Spawned. + self.AIOnOff = true -- The AI is on by default when spawning a group. self.SpawnUnControlled = false - self.SpawnInitKeepUnitNames = false -- Overwrite unit names by default with group name. - self.DelayOnOff = false -- No intial delay when spawning the first group. - self.Grouping = nil -- No grouping + self.SpawnInitKeepUnitNames = false -- Overwrite unit names by default with group name. + self.DelayOnOff = false -- No intial delay when spawning the first group. + self.Grouping = nil -- No grouping self.SpawnGroups = {} -- Array containing the descriptions of each Group to be Spawned. else @@ -334,19 +334,19 @@ function SPAWN:NewWithAlias( SpawnTemplatePrefix, SpawnAliasPrefix ) self.SpawnIndex = 0 self.SpawnCount = 0 -- The internal counter of the amount of spawning the has happened since SpawnStart. self.AliveUnits = 0 -- Contains the counter how many units are currently alive - self.SpawnIsScheduled = false -- Reflects if the spawning for this SpawnTemplatePrefix is going to be scheduled or not. + self.SpawnIsScheduled = false -- Reflects if the spawning for this SpawnTemplatePrefix is going to be scheduled or not. self.SpawnTemplate = self._GetTemplate( self, SpawnTemplatePrefix ) -- Contains the template structure for a Group Spawn from the Mission Editor. Note that this group must have lateActivation always on!!! - self.Repeat = false -- Don't repeat the group from Take-Off till Landing and back Take-Off by ReSpawning. - self.UnControlled = false -- When working in UnControlled mode, all planes are Spawned in UnControlled mode before the scheduler starts. - self.SpawnInitLimit = false -- By default, no InitLimit - self.SpawnMaxUnitsAlive = 0 -- The maximum amount of groups that can be alive of SpawnTemplatePrefix at the same time. - self.SpawnMaxGroups = 0 -- The maximum amount of groups that can be spawned. - self.SpawnRandomize = false -- Sets the randomization flag of new Spawned units to false. - self.SpawnVisible = false -- Flag that indicates if all the Groups of the SpawnGroup need to be visible when Spawned. - self.AIOnOff = true -- The AI is on by default when spawning a group. + self.Repeat = false -- Don't repeat the group from Take-Off till Landing and back Take-Off by ReSpawning. + self.UnControlled = false -- When working in UnControlled mode, all planes are Spawned in UnControlled mode before the scheduler starts. + self.SpawnInitLimit = false -- By default, no InitLimit + self.SpawnMaxUnitsAlive = 0 -- The maximum amount of groups that can be alive of SpawnTemplatePrefix at the same time. + self.SpawnMaxGroups = 0 -- The maximum amount of groups that can be spawned. + self.SpawnRandomize = false -- Sets the randomization flag of new Spawned units to false. + self.SpawnVisible = false -- Flag that indicates if all the Groups of the SpawnGroup need to be visible when Spawned. + self.AIOnOff = true -- The AI is on by default when spawning a group. self.SpawnUnControlled = false - self.SpawnInitKeepUnitNames = false -- Overwrite unit names by default with group name. - self.DelayOnOff = false -- No intial delay when spawning the first group. + self.SpawnInitKeepUnitNames = false -- Overwrite unit names by default with group name. + self.DelayOnOff = false -- No intial delay when spawning the first group. self.Grouping = nil self.SpawnGroups = {} -- Array containing the descriptions of each Group to be Spawned. @@ -361,6 +361,55 @@ function SPAWN:NewWithAlias( SpawnTemplatePrefix, SpawnAliasPrefix ) end +--- Creates a new SPAWN instance to create new groups based on the provided template. +-- @param #SPAWN self +-- @param #table SpawnTemplate is the Template of the Group. This must be a valid Group Template structure! +-- @param #string SpawnTemplatePrefix is the name of the Group that will be given at each spawn. +-- @param #string SpawnAliasPrefix (optional) is the name that will be given to the Group at runtime. +-- @return #SPAWN +-- @usage +-- -- Create a new SPAWN object based on a Group Template defined from scratch. +-- Spawn_BE_KA50 = SPAWN:NewWithAlias( 'BE KA-50@RAMP-Ground Defense', 'Helicopter Attacking a City' ) +-- @usage +-- -- Create a new CSAR_Spawn object based on a normal Group Template to spawn a soldier. +-- local CSAR_Spawn = SPAWN:NewWithFromTemplate( Template, "CSAR", "Pilot" ) +function SPAWN:NewFromTemplate( SpawnTemplate, SpawnTemplatePrefix, SpawnAliasPrefix ) + local self = BASE:Inherit( self, BASE:New() ) + self:F( { SpawnTemplate, SpawnTemplatePrefix, SpawnAliasPrefix } ) + + if SpawnTemplate then + self.SpawnTemplate = SpawnTemplate -- Contains the template structure for a Group Spawn from the Mission Editor. Note that this group must have lateActivation always on!!! + self.SpawnTemplatePrefix = SpawnTemplatePrefix + self.SpawnAliasPrefix = SpawnAliasPrefix + self.SpawnIndex = 0 + self.SpawnCount = 0 -- The internal counter of the amount of spawning the has happened since SpawnStart. + self.AliveUnits = 0 -- Contains the counter how many units are currently alive + self.SpawnIsScheduled = false -- Reflects if the spawning for this SpawnTemplatePrefix is going to be scheduled or not. + self.Repeat = false -- Don't repeat the group from Take-Off till Landing and back Take-Off by ReSpawning. + self.UnControlled = false -- When working in UnControlled mode, all planes are Spawned in UnControlled mode before the scheduler starts. + self.SpawnInitLimit = false -- By default, no InitLimit. + self.SpawnMaxUnitsAlive = 0 -- The maximum amount of groups that can be alive of SpawnTemplatePrefix at the same time. + self.SpawnMaxGroups = 0 -- The maximum amount of groups that can be spawned. + self.SpawnRandomize = false -- Sets the randomization flag of new Spawned units to false. + self.SpawnVisible = false -- Flag that indicates if all the Groups of the SpawnGroup need to be visible when Spawned. + self.AIOnOff = true -- The AI is on by default when spawning a group. + self.SpawnUnControlled = false + self.SpawnInitKeepUnitNames = false -- Overwrite unit names by default with group name. + self.DelayOnOff = false -- No intial delay when spawning the first group. + self.Grouping = nil + + self.SpawnGroups = {} -- Array containing the descriptions of each Group to be Spawned. + else + error( "There is no template provided for SpawnTemplatePrefix = '" .. SpawnTemplatePrefix .. "'" ) + end + + self:SetEventPriority( 5 ) + self.SpawnHookScheduler = SCHEDULER:New( nil ) + + return self +end + + --- Limits the Maximum amount of Units that can be alive at the same time, and the maximum amount of groups that can be spawned. -- Note that this method is exceptionally important to balance the performance of the mission. Depending on the machine etc, a mission can only process a maximum amount of units. -- If the time interval must be short, but there should not be more Units or Groups alive than a maximum amount of units, then this method should be used... @@ -404,6 +453,57 @@ function SPAWN:InitKeepUnitNames() return self end +--- Defines the Heading for the new spawned units. +-- The heading can be given as one fixed degree, or can be randomized between minimum and maximum degrees. +-- @param #SPAWN self +-- @param #number HeadingMin The minimum or fixed heading in degrees. +-- @param #number HeadingMax (optional) The maximum heading in degrees. This there is no maximum heading, then the heading will be fixed for all units using minimum heading. +-- @return #SPAWN self +-- @usage +-- +-- Spawn = SPAWN:New( ... ) +-- +-- -- Spawn the units pointing to 100 degrees. +-- Spawn:InitHeading( 100 ) +-- +-- -- Spawn the units pointing between 100 and 150 degrees. +-- Spawn:InitHeading( 100, 150 ) +-- +function SPAWN:InitHeading( HeadingMin, HeadingMax ) + self:F( ) + + self.SpawnInitHeadingMin = HeadingMin + self.SpawnInitHeadingMax = HeadingMax + + return self +end + + +function SPAWN:InitCoalition( Coalition ) + self:F( ) + + self.SpawnInitCoalition = Coalition + + return self +end + + +function SPAWN:InitCountry( Country ) + self:F( ) + + self.SpawnInitCountry = Country + + return self +end + + +function SPAWN:InitCategory( Category ) + self:F( ) + + self.SpawnInitCategory = Category + + return self +end --- Randomizes the defined route of the SpawnTemplatePrefix group in the ME. This is very useful to define extra variation of the behaviour of groups. -- @param #SPAWN self @@ -941,6 +1041,18 @@ function SPAWN:SpawnWithIndex( SpawnIndex ) end end + -- If Heading is given, point all the units towards the given Heading. + if self.SpawnInitHeadingMin then + for UnitID = 1, #SpawnTemplate.units do + SpawnTemplate.units[UnitID].heading = self.SpawnInitHeadingMax and math.random( self.SpawnInitHeadingMin, self.SpawnInitHeadingMax ) or self.SpawnInitHeadingMin + end + end + + SpawnTemplate.CategoryID = self.SpawnInitCategory or SpawnTemplate.CategoryID + SpawnTemplate.CountryID = self.SpawnInitCountry or SpawnTemplate.CountryID + SpawnTemplate.CoalitionID = self.SpawnInitCoalition or SpawnTemplate.CoalitionID + + if SpawnTemplate.CategoryID == Group.Category.HELICOPTER or SpawnTemplate.CategoryID == Group.Category.AIRPLANE then if SpawnTemplate.route.points[1].type == "TakeOffParking" then SpawnTemplate.uncontrolled = self.SpawnUnControlled @@ -1247,14 +1359,20 @@ function SPAWN:SpawnFromVec3( Vec3, SpawnIndex ) self:T( { "Current point of ", self.SpawnTemplatePrefix, Vec3 } ) - local TemplateHeight = SpawnTemplate.route.points[1].alt + local TemplateHeight = SpawnTemplate.route and SpawnTemplate.route.points[1].alt or nil + + SpawnTemplate.route = SpawnTemplate.route or {} + SpawnTemplate.route.points = SpawnTemplate.route.points or {} + SpawnTemplate.route.points[1] = SpawnTemplate.route.points[1] or {} + SpawnTemplate.route.points[1].x = SpawnTemplate.route.points[1].x or 0 + SpawnTemplate.route.points[1].y = SpawnTemplate.route.points[1].y or 0 -- Translate the position of the Group Template to the Vec3. for UnitID = 1, #SpawnTemplate.units do - self:T( 'Before Translation SpawnTemplate.units['..UnitID..'].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. SpawnTemplate.units[UnitID].y ) + --self:T( 'Before Translation SpawnTemplate.units['..UnitID..'].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. SpawnTemplate.units[UnitID].y ) local UnitTemplate = SpawnTemplate.units[UnitID] - local SX = UnitTemplate.x - local SY = UnitTemplate.y + local SX = UnitTemplate.x or 0 + local SY = UnitTemplate.y or 0 local BX = SpawnTemplate.route.points[1].x local BY = SpawnTemplate.route.points[1].y local TX = Vec3.x + ( SX - BX ) @@ -1266,7 +1384,6 @@ function SPAWN:SpawnFromVec3( Vec3, SpawnIndex ) end self:T( 'After Translation SpawnTemplate.units['..UnitID..'].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. SpawnTemplate.units[UnitID].y ) end - SpawnTemplate.route.points[1].x = Vec3.x SpawnTemplate.route.points[1].y = Vec3.z if SpawnTemplate.CategoryID ~= Group.Category.SHIP then @@ -1283,6 +1400,47 @@ function SPAWN:SpawnFromVec3( Vec3, SpawnIndex ) return nil end + +--- Will spawn a group from a Coordinate in 3D space. +-- This method is mostly advisable to be used if you want to simulate spawning units in the air, like helicopters or airplanes. +-- Note that each point in the route assigned to the spawning group is reset to the point of the spawn. +-- You can use the returned group to further define the route to be followed. +-- @param #SPAWN self +-- @param Core.Point#Coordinate Coordinate The Coordinate coordinates where to spawn the group. +-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone. +-- @return Wrapper.Group#GROUP that was spawned. +-- @return #nil Nothing was spawned. +function SPAWN:SpawnFromCoordinate( Coordinate, SpawnIndex ) + self:F( { self.SpawnTemplatePrefix, SpawnIndex } ) + + return self:SpawnFromVec3( Coordinate:GetVec3(), SpawnIndex ) +end + + + +--- Will spawn a group from a PointVec3 in 3D space. +-- This method is mostly advisable to be used if you want to simulate spawning units in the air, like helicopters or airplanes. +-- Note that each point in the route assigned to the spawning group is reset to the point of the spawn. +-- You can use the returned group to further define the route to be followed. +-- @param #SPAWN self +-- @param Core.Point#POINT_VEC3 PointVec3 The PointVec3 coordinates where to spawn the group. +-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone. +-- @return Wrapper.Group#GROUP that was spawned. +-- @return #nil Nothing was spawned. +-- @usage +-- +-- local SpawnPointVec3 = ZONE:New( ZoneName ):GetPointVec3( 2000 ) -- Get the center of the ZONE object at 2000 meters from the ground. +-- +-- -- Spawn at the zone center position at 2000 meters from the ground! +-- SpawnAirplanes:SpawnFromPointVec3( SpawnPointVec3 ) +-- +function SPAWN:SpawnFromPointVec3( PointVec3, SpawnIndex ) + self:F( { self.SpawnTemplatePrefix, SpawnIndex } ) + + return self:SpawnFromVec3( PointVec3:GetVec3(), SpawnIndex ) +end + + --- Will spawn a group from a Vec2 in 3D space. -- This method is mostly advisable to be used if you want to simulate spawning groups on the ground from air units, like vehicles. -- Note that each point in the route assigned to the spawning group is reset to the point of the spawn. @@ -1317,6 +1475,35 @@ function SPAWN:SpawnFromVec2( Vec2, MinHeight, MaxHeight, SpawnIndex ) end +--- Will spawn a group from a POINT_VEC2 in 3D space. +-- This method is mostly advisable to be used if you want to simulate spawning groups on the ground from air units, like vehicles. +-- Note that each point in the route assigned to the spawning group is reset to the point of the spawn. +-- You can use the returned group to further define the route to be followed. +-- @param #SPAWN self +-- @param Core.Point#POINT_VEC2 PointVec2 The PointVec2 coordinates where to spawn the group. +-- @param #number MinHeight (optional) The minimum height to spawn an airborne group into the zone. +-- @param #number MaxHeight (optional) The maximum height to spawn an airborne group into the zone. +-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone. +-- @return Wrapper.Group#GROUP that was spawned. +-- @return #nil Nothing was spawned. +-- @usage +-- +-- local SpawnPointVec2 = ZONE:New( ZoneName ):GetPointVec2() +-- +-- -- Spawn at the zone center position at the height specified in the ME of the group template! +-- SpawnAirplanes:SpawnFromPointVec2( SpawnPointVec2 ) +-- +-- -- Spawn from the static position at the height randomized between 2000 and 4000 meters. +-- SpawnAirplanes:SpawnFromPointVec2( SpawnPointVec2, 2000, 4000 ) +-- +function SPAWN:SpawnFromPointVec2( PointVec2, MinHeight, MaxHeight, SpawnIndex ) + self:F( { self.SpawnTemplatePrefix, self.SpawnIndex } ) + + return self:SpawnFromVec2( PointVec2:GetVec2(), MinHeight, MaxHeight, SpawnIndex ) +end + + + --- Will spawn a group from a hosting unit. This method is mostly advisable to be used if you want to simulate spawning from air units, like helicopters, which are dropping infantry into a defined Landing Zone. -- Note that each point in the route assigned to the spawning group is reset to the point of the spawn. -- You can use the returned group to further define the route to be followed. @@ -1715,7 +1902,11 @@ end function SPAWN:_Prepare( SpawnTemplatePrefix, SpawnIndex ) --R2.2 self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix } ) - local SpawnTemplate = self:_GetTemplate( SpawnTemplatePrefix ) + if not self.SpawnTemplate then + self.SpawnTemplate = self:_GetTemplate( SpawnTemplatePrefix ) + end + + local SpawnTemplate = self.SpawnTemplate SpawnTemplate.name = self:SpawnGroupName( SpawnIndex ) SpawnTemplate.groupId = nil diff --git a/Moose Development/Moose/Tasking/Task_Cargo_CSAR.lua b/Moose Development/Moose/Tasking/Task_Cargo_CSAR.lua index b45dc7e26..b2e2aebdb 100644 --- a/Moose Development/Moose/Tasking/Task_Cargo_CSAR.lua +++ b/Moose Development/Moose/Tasking/Task_Cargo_CSAR.lua @@ -23,7 +23,7 @@ do -- TASK_CARGO_CSAR -- @param #string TaskBriefing The Cargo Task briefing. -- @return #TASK_CARGO_CSAR self function TASK_CARGO_CSAR:New( Mission, SetGroup, TaskName, SetCargo, TaskBriefing ) - local self = BASE:Inherit( self, TASK_CARGO:New( Mission, SetGroup, TaskName, SetCargo, "Transport", TaskBriefing ) ) -- #TASK_CARGO_CSAR + local self = BASE:Inherit( self, TASK_CARGO:New( Mission, SetGroup, TaskName, SetCargo, "CSAR", TaskBriefing ) ) -- #TASK_CARGO_CSAR self:F() Mission:AddTask( self ) diff --git a/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua index 7e07deb90..3832d4a7a 100644 --- a/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua +++ b/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua @@ -210,6 +210,26 @@ do -- TASK_CARGO_DISPATCHER -- For CSAR missions, we process the event when a pilot ejects. self:HandleEvent( EVENTS.Ejection ) + + -- Create the CSAR Pilot SPAWN object. + -- Let us create the Template for the replacement Pilot :-) + local Template = { + ["visible"] = false, + ["taskSelected"] = true, + ["hidden"] = false, + ["units"] = + { + [1] = + { + ["type"] = "Soldier M4", + ["skill"] = "Excellent", + ["playerCanDrive"] = false, + }, -- end of [1] + }, -- end of ["units"] + ["task"] = "Ground Nothing", + } + + self.PilotSpawn = SPAWN:NewFromTemplate( Template, "CSAR Pilot" ) return self end @@ -225,47 +245,16 @@ do -- TASK_CARGO_DISPATCHER local PlaneUnit = EventData.IniUnit local CSARName = EventData.IniUnitName - local PilotUnit = nil - - self:ScheduleOnce( 1, - function() - - -- Search for the ejected pilot - - local PlaneCoord = PlaneUnit:GetCoordinate() - - local SphereSearch = { - id = world.VolumeType.SPHERE, - params = { - point = PlaneCoord:GetVec3(), - radius = 100, - } - - } - - --- @param Dcs.DCSWrapper.Unit#Unit FoundDCSUnit - -- @param Wrapper.Group#GROUP ReportGroup - -- @param Set#SET_GROUP ReportSetGroup - local FindEjectedPilot = function( FoundDCSUnit ) - - local UnitName = FoundDCSUnit:getName() - - self:E( { "Units near Plane:", UnitName } ) - - PilotUnit = UNIT:Register( UnitName ) - - return true - end - - world.searchObjects( { Object.Category.UNIT, Object.Category.STATIC, Object.Category.SCENERY, Object.Category.WEAPON }, SphereSearch, FindEjectedPilot ) + local PointVec2Spawn = EventData.IniUnit:GetPointVec2() - self.CSAR[CSARName] = {} - self.CSAR[CSARName].PilotUnit = PlaneUnit - self.CSAR[CSARName].Task = nil - - end - ) - + self.PilotSpawn:InitHeading( EventData.IniUnit:GetHeading() ) -- This will ensure that the new pilot will point towards the same heading as the plane. + self.PilotSpawn:InitCategory( Group.Category.GROUND ) + self.PilotSpawn:InitCountry( EventData.IniUnit:GetCountry() ) + self.PilotSpawn:InitCoalition( EventData.IniUnit:GetCoalition() ) + + self.CSAR[#self.CSAR+1] = {} + self.CSAR[#self.CSAR].PilotUnit = self.PilotSpawn:SpawnFromPointVec2( PointVec2Spawn ) + self.CSAR[#self.CSAR].Task = nil return self end @@ -373,7 +362,7 @@ do -- TASK_CARGO_DISPATCHER else -- New CSAR Task local SetCargo = self:EvaluateCSAR( CSARData.PilotUnit ) - local CSARTask = TASK_CARGO_CSAR:New( Mission, self.SetGroup, "Rescue Pilot", SetCargo ) + local CSARTask = TASK_CARGO_CSAR:New( Mission, self.SetGroup, string.format( "CSAR.%03d", CSARID ), SetCargo ) CSARTask:SetDeployZones( self.CSARDeployZones or {} ) Mission:AddTask( CSARTask ) TaskReport:Add( CSARTask:GetName() ) From 25831db0571e07aefef31f30fed07b12f9bb0962 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Mon, 2 Apr 2018 19:33:44 +0200 Subject: [PATCH 4/9] Progress -- Still need to fix an issue with some strang objects appearing and a crash. --- Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua index 3832d4a7a..5795b947b 100644 --- a/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua +++ b/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua @@ -253,7 +253,7 @@ do -- TASK_CARGO_DISPATCHER self.PilotSpawn:InitCoalition( EventData.IniUnit:GetCoalition() ) self.CSAR[#self.CSAR+1] = {} - self.CSAR[#self.CSAR].PilotUnit = self.PilotSpawn:SpawnFromPointVec2( PointVec2Spawn ) + self.CSAR[#self.CSAR].PilotGroup = self.PilotSpawn:SpawnFromPointVec2( PointVec2Spawn ) self.CSAR[#self.CSAR].Task = nil return self @@ -310,7 +310,7 @@ do -- TASK_CARGO_DISPATCHER -- @return #nil If there is no CSAR task required. function TASK_CARGO_DISPATCHER:EvaluateCSAR( CSARUnit ) - local CSARCargo = CARGO_UNIT:New( CSARUnit, "Pilot", CSARUnit:GetName(), 80, 1500, 10 ) + local CSARCargo = CARGO_GROUP:New( CSARUnit, "Pilot", CSARUnit:GetName(), 80, 1500, 10 ) local SetCargo = SET_CARGO:New() SetCargo:AddCargosByName( CSARUnit:GetName() ) @@ -361,7 +361,8 @@ do -- TASK_CARGO_DISPATCHER if CSARData.Task then else -- New CSAR Task - local SetCargo = self:EvaluateCSAR( CSARData.PilotUnit ) + self:F( { PilotGroup = CSARData.PilotGroup } ) + local SetCargo = self:EvaluateCSAR( CSARData.PilotGroup ) local CSARTask = TASK_CARGO_CSAR:New( Mission, self.SetGroup, string.format( "CSAR.%03d", CSARID ), SetCargo ) CSARTask:SetDeployZones( self.CSARDeployZones or {} ) Mission:AddTask( CSARTask ) From ec973fcc76944a5c012aee5a98349f8edb02b757 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Tue, 3 Apr 2018 07:43:55 +0200 Subject: [PATCH 5/9] Working CSAR ... huray --- .../Moose/Dcs/DCSCoalitionObject.lua | 2 +- Moose Development/Moose/Dcs/DCScoalition.lua | 2 + .../Moose/Tasking/CommandCenter.lua | 8 ++ Moose Development/Moose/Tasking/Mission.lua | 4 +- .../Moose/Tasking/Task_Cargo_Dispatcher.lua | 74 +++++++++++-------- Moose Development/Moose/Wrapper/Group.lua | 2 +- 6 files changed, 58 insertions(+), 34 deletions(-) diff --git a/Moose Development/Moose/Dcs/DCSCoalitionObject.lua b/Moose Development/Moose/Dcs/DCSCoalitionObject.lua index be7dc106b..119c9a807 100644 --- a/Moose Development/Moose/Dcs/DCSCoalitionObject.lua +++ b/Moose Development/Moose/Dcs/DCSCoalitionObject.lua @@ -4,7 +4,7 @@ --- @type CoalitionObject -- @extends Dcs.DCSWrapper.Object#Object -coalition = {} --#coalition + --- Returns coalition of the object. -- @function [parent=#CoalitionObject] getCoalition diff --git a/Moose Development/Moose/Dcs/DCScoalition.lua b/Moose Development/Moose/Dcs/DCScoalition.lua index 4ec5f6f10..e51508a3e 100644 --- a/Moose Development/Moose/Dcs/DCScoalition.lua +++ b/Moose Development/Moose/Dcs/DCScoalition.lua @@ -12,3 +12,5 @@ --- @function [parent=#coalition] getCountryCoalition -- @param #number countryId -- @return #number coalitionId + +coalition = coalition -- #coalition diff --git a/Moose Development/Moose/Tasking/CommandCenter.lua b/Moose Development/Moose/Tasking/CommandCenter.lua index e8e4f1d32..e521f63df 100644 --- a/Moose Development/Moose/Tasking/CommandCenter.lua +++ b/Moose Development/Moose/Tasking/CommandCenter.lua @@ -220,6 +220,14 @@ function COMMANDCENTER:GetShortText() end +--- Gets the coalition of the command center. +-- @param #COMMANDCENTER self +-- @return DCScoalition#coalition +function COMMANDCENTER:GetCoalition() + + return self.CommandCenterCoalition +end + --- Gets the POSITIONABLE of the HQ command center. -- @param #COMMANDCENTER self diff --git a/Moose Development/Moose/Tasking/Mission.lua b/Moose Development/Moose/Tasking/Mission.lua index 06a7e7d9b..441b463aa 100644 --- a/Moose Development/Moose/Tasking/Mission.lua +++ b/Moose Development/Moose/Tasking/Mission.lua @@ -29,7 +29,7 @@ MISSION = { -- @param #string MissionName is the name of the mission. This name will be used to reference the status of each mission by the players. -- @param #string MissionPriority is a string indicating the "priority" of the Mission. f.e. "Primary", "Secondary" or "First", "Second". It is free format and up to the Mission designer to choose. There are no rules behind this field. -- @param #string MissionBriefing is a string indicating the mission briefing to be shown when a player joins a @{CLIENT}. --- @param Dcs.DCSCoalitionWrapper.Object#coalition MissionCoalition is a string indicating the coalition or party to which this mission belongs to. It is free format and can be chosen freely by the mission designer. Note that this field is not to be confused with the coalition concept of the ME. Examples of a Mission Coalition could be "NATO", "CCCP", "Intruders", "Terrorists"... +-- @param #string MissionCoalition is a string indicating the coalition or party to which this mission belongs to. It is free format and can be chosen freely by the mission designer. Note that this field is not to be confused with the coalition concept of the ME. Examples of a Mission Coalition could be "NATO", "CCCP", "Intruders", "Terrorists"... -- @return #MISSION self function MISSION:New( CommandCenter, MissionName, MissionPriority, MissionBriefing, MissionCoalition ) @@ -265,6 +265,8 @@ function MISSION:New( CommandCenter, MissionName, MissionPriority, MissionBriefi end + + --- FSM function for a MISSION -- @param #MISSION self -- @param #string From diff --git a/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua index 5795b947b..df9c36dec 100644 --- a/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua +++ b/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua @@ -177,6 +177,7 @@ do -- TASK_CARGO_DISPATCHER Mission = nil, Tasks = {}, CSAR = {}, + CSARSpawned = 0, } @@ -210,26 +211,6 @@ do -- TASK_CARGO_DISPATCHER -- For CSAR missions, we process the event when a pilot ejects. self:HandleEvent( EVENTS.Ejection ) - - -- Create the CSAR Pilot SPAWN object. - -- Let us create the Template for the replacement Pilot :-) - local Template = { - ["visible"] = false, - ["taskSelected"] = true, - ["hidden"] = false, - ["units"] = - { - [1] = - { - ["type"] = "Soldier M4", - ["skill"] = "Excellent", - ["playerCanDrive"] = false, - }, -- end of [1] - }, -- end of ["units"] - ["task"] = "Ground Nothing", - } - - self.PilotSpawn = SPAWN:NewFromTemplate( Template, "CSAR Pilot" ) return self end @@ -242,19 +223,50 @@ do -- TASK_CARGO_DISPATCHER self:E( { EventData = EventData } ) + self.CSARSpawned = self.CSARSpawned + 1 + local PlaneUnit = EventData.IniUnit local CSARName = EventData.IniUnitName - local PointVec2Spawn = EventData.IniUnit:GetPointVec2() + local CargoPointVec2 = EventData.IniUnit:GetPointVec2() + local CargoCoalition = EventData.IniUnit:GetCoalition() + local CargoCountry = EventData.IniUnit:GetCountry() + + -- Only add a CSAR task if the coalition of the mission is equal to the coalition of the ejected unit. - self.PilotSpawn:InitHeading( EventData.IniUnit:GetHeading() ) -- This will ensure that the new pilot will point towards the same heading as the plane. - self.PilotSpawn:InitCategory( Group.Category.GROUND ) - self.PilotSpawn:InitCountry( EventData.IniUnit:GetCountry() ) - self.PilotSpawn:InitCoalition( EventData.IniUnit:GetCoalition() ) - - self.CSAR[#self.CSAR+1] = {} - self.CSAR[#self.CSAR].PilotGroup = self.PilotSpawn:SpawnFromPointVec2( PointVec2Spawn ) - self.CSAR[#self.CSAR].Task = nil + if CargoCoalition == self.Mission:GetCommandCenter():GetCoalition() then + + -- Create the CSAR Pilot SPAWN object. + -- Let us create the Template for the replacement Pilot :-) + local Template = { + ["visible"] = false, + ["hidden"] = false, + ["task"] = "Ground Nothing", + ["name"] = string.format( "CSAR Pilot#%03d", self.CSARSpawned ), + ["x"] = CargoPointVec2:GetLat(), + ["y"] = CargoPointVec2:GetLon(), + ["units"] = + { + [1] = + { + ["type"] = ( CargoCoalition == coalition.side.BLUE ) and "Soldier M4" or "Infantry AK", + ["name"] = string.format( "CSAR Pilot#%03d-01", self.CSARSpawned ), + ["skill"] = "Excellent", + ["playerCanDrive"] = false, + ["x"] = CargoPointVec2:GetLat(), + ["y"] = CargoPointVec2:GetLon(), + ["heading"] = EventData.IniUnit:GetHeading(), + }, -- end of [1] + }, -- end of ["units"] + } + + local CargoGroup = GROUP:NewTemplate( Template, CargoCoalition, Group.Category.GROUND, CargoCountry ) + + self.CSAR[#self.CSAR+1] = {} + self.CSAR[#self.CSAR].PilotGroup = CargoGroup + self.CSAR[#self.CSAR].Task = nil + + end return self end @@ -294,7 +306,7 @@ do -- TASK_CARGO_DISPATCHER --- Define the deploy zones for the CSAR tasks. -- @param #TASK_CARGO_DISPATCHER self - -- @param DeployZones A list of the deploy zones. + -- @param CSARDeployZones A list of the deploy zones. -- @return #TASK_CARGO_DISPATCHER function TASK_CARGO_DISPATCHER:SetCSARDeployZones( CSARDeployZones ) @@ -361,12 +373,12 @@ do -- TASK_CARGO_DISPATCHER if CSARData.Task then else -- New CSAR Task - self:F( { PilotGroup = CSARData.PilotGroup } ) local SetCargo = self:EvaluateCSAR( CSARData.PilotGroup ) local CSARTask = TASK_CARGO_CSAR:New( Mission, self.SetGroup, string.format( "CSAR.%03d", CSARID ), SetCargo ) CSARTask:SetDeployZones( self.CSARDeployZones or {} ) Mission:AddTask( CSARTask ) TaskReport:Add( CSARTask:GetName() ) + CSARData.Task = CSARTask end end diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index 66d9068a3..26062ea09 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -121,7 +121,7 @@ GROUPTEMPLATE.Takeoff = { -- @return #GROUP self function GROUP:NewTemplate( GroupTemplate, CoalitionSide, CategoryID, CountryID ) local GroupName = GroupTemplate.name - _DATABASE:_RegisterGroupTemplate( GroupTemplate, CategoryID, CountryID, CoalitionSide, GroupName ) + _DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionSide, CategoryID, CountryID, GroupName ) self = BASE:Inherit( self, CONTROLLABLE:New( GroupName ) ) self:F2( GroupName ) self.GroupName = GroupName From 0d995d183284e4944f09c54fb44b3be6b739e584 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Wed, 4 Apr 2018 14:38:49 +0200 Subject: [PATCH 6/9] Progress --- .../Moose/Tasking/Task_Cargo_Dispatcher.lua | 305 ++++++++++++++---- 1 file changed, 244 insertions(+), 61 deletions(-) diff --git a/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua index df9c36dec..ca96b2d87 100644 --- a/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua +++ b/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua @@ -178,6 +178,9 @@ do -- TASK_CARGO_DISPATCHER Tasks = {}, CSAR = {}, CSARSpawned = 0, + + Transport = {}, + TransportCount = 0, } @@ -214,62 +217,163 @@ do -- TASK_CARGO_DISPATCHER return self end - + + + --- Handle the event when a pilot ejects. -- @param #TASK_CARGO_DISPATCHER self -- @param Core.Event#EVENTDATA EventData function TASK_CARGO_DISPATCHER:OnEventEjection( EventData ) + self:F( { EventData = EventData } ) + + if self.CSARTasks == true then - self:E( { EventData = EventData } ) - - self.CSARSpawned = self.CSARSpawned + 1 - - local PlaneUnit = EventData.IniUnit - local CSARName = EventData.IniUnitName - - local CargoPointVec2 = EventData.IniUnit:GetPointVec2() - local CargoCoalition = EventData.IniUnit:GetCoalition() - local CargoCountry = EventData.IniUnit:GetCountry() - - -- Only add a CSAR task if the coalition of the mission is equal to the coalition of the ejected unit. - - if CargoCoalition == self.Mission:GetCommandCenter():GetCoalition() then - - -- Create the CSAR Pilot SPAWN object. - -- Let us create the Template for the replacement Pilot :-) - local Template = { - ["visible"] = false, - ["hidden"] = false, - ["task"] = "Ground Nothing", - ["name"] = string.format( "CSAR Pilot#%03d", self.CSARSpawned ), - ["x"] = CargoPointVec2:GetLat(), - ["y"] = CargoPointVec2:GetLon(), - ["units"] = - { - [1] = - { - ["type"] = ( CargoCoalition == coalition.side.BLUE ) and "Soldier M4" or "Infantry AK", - ["name"] = string.format( "CSAR Pilot#%03d-01", self.CSARSpawned ), - ["skill"] = "Excellent", - ["playerCanDrive"] = false, - ["x"] = CargoPointVec2:GetLat(), - ["y"] = CargoPointVec2:GetLon(), - ["heading"] = EventData.IniUnit:GetHeading(), - }, -- end of [1] - }, -- end of ["units"] - } - - local CargoGroup = GROUP:NewTemplate( Template, CargoCoalition, Group.Category.GROUND, CargoCountry ) - - self.CSAR[#self.CSAR+1] = {} - self.CSAR[#self.CSAR].PilotGroup = CargoGroup - self.CSAR[#self.CSAR].Task = nil - + local CSARCoordinate = EventData.IniUnit:GetCoordinate() + local CSARCoalition = EventData.IniUnit:GetCoalition() + local CSARCountry = EventData.IniUnit:GetCountry() + local CSARHeading = EventData.IniUnit:GetHeading() + + -- Only add a CSAR task if the coalition of the mission is equal to the coalition of the ejected unit. + if CSARCoalition == self.Mission:GetCommandCenter():GetCoalition() then + local CSARTaskName = self:AddCSARTask( self.CSARTaskName, CSARCoordinate, CSARHeading, CSARCountry, self.CSARBriefing ) + self:SetCSARDeployZones( CSARTaskName, self.CSARDeployZones ) + end end return self end + + + --- Define one default deploy zone for all the cargo tasks. + -- @param #TASK_CARGO_DISPATCHER self + -- @param DefaultDeployZone A default deploy zone. + -- @return #TASK_CARGO_DISPATCHER + function TASK_CARGO_DISPATCHER:SetDefaultDeployZone( DefaultDeployZone ) + + self.DefaultDeployZones = { DefaultDeployZone } + + return self + end + + + --- Define the deploy zones for all the cargo tasks. + -- @param #TASK_CARGO_DISPATCHER self + -- @param DefaultDeployZones A list of the deploy zones. + -- @return #TASK_CARGO_DISPATCHER + -- + function TASK_CARGO_DISPATCHER:SetDefaultDeployZones( DefaultDeployZones ) + + self.DefaultDeployZones = DefaultDeployZones + + return self + end + + + --- Start the generation of CSAR tasks to retrieve a downed pilots. + -- You need to specify a task briefing, a task name, default deployment zone(s). + -- This method can only be used once! + -- @param #TASK_CARGO_DISPATCHER self + -- @param #string CSARTaskName The CSAR task name. + -- @param #string CSARDeployZones The zones to where the CSAR deployment should be directed. + -- @param #string CSARBriefing The briefing of the CSAR tasks. + -- @return #TASK_CARGO_DISPATCHER + function TASK_CARGO_DISPATCHER:StartCSARTasks( CSARTaskName, CSARDeployZones, CSARBriefing) + + if not self.CSARTasks then + self.CSARTasks = true + self.CSARTaskName = CSARTaskName + self.CSARDeployZones = CSARDeployZones + self.CSARBriefing = CSARBriefing + else + error( "TASK_CARGO_DISPATCHER: The generation of CSAR tasks has already started." ) + end + + return self + end + + + --- Stop the generation of CSAR tasks to retrieve a downed pilots. + -- @param #TASK_CARGO_DISPATCHER self + -- @return #TASK_CARGO_DISPATCHER + function TASK_CARGO_DISPATCHER:StopCSARTasks() + + if self.CSARTasks then + self.CSARTasks = nil + self.CSARTaskName = nil + self.CSARDeployZones = nil + self.CSARBriefing = nil + else + error( "TASK_CARGO_DISPATCHER: The generation of CSAR tasks was not yet started." ) + end + + return self + end + + + --- Add a CSAR task to retrieve a downed pilot. + -- You need to specify a coordinate from where the pilot will be spawned to be rescued. + -- @param #TASK_CARGO_DISPATCHER self + -- @param #string CSARTaskPrefix (optional) The prefix of the CSAR task. + -- @param Core.Point#COORDINATE CSARCoordinate The coordinate where a downed pilot will be spawned. + -- @param #number CSARHeading The heading of the pilot in degrees. + -- @param DCSCountry#Country CSARCountry The country ID of the pilot that will be spawned. + -- @param #string CSARBriefing The briefing of the CSAR task. + -- @return #string The CSAR Task Name as a string. The Task Name is the main key and is shown in the task list of the Mission Tasking menu. + -- @usage + -- + -- -- Add a CSAR task to rescue a downed pilot from within a coordinate. + -- local Coordinate = PlaneUnit:GetPointVec2() + -- TaskA2ADispatcher:AddCSARTask( Coordinate ) + -- + -- -- Add a CSAR task to rescue a downed pilot from within a coordinate of country RUSSIA, which is pointing to the west (270°). + -- local Coordinate = PlaneUnit:GetPointVec2() + -- TaskA2ADispatcher:AddCSARTask( Coordinate, 270, Country.RUSSIA ) + -- + function TASK_CARGO_DISPATCHER:AddCSARTask( CSARTaskPrefix, CSARCoordinate, CSARHeading, CSARCountry, CSARBriefing ) + + local CSARCoalition = self.Mission:GetCommandCenter():GetCoalition() + + CSARHeading = CSARHeading or 0 + CSARCountry = CSARCountry or self.Mission:GetCommandCenter():GetCountry() + + self.CSARSpawned = self.CSARSpawned + 1 + + local CSARTaskName = string.format( ( CSARTaskPrefix or "CSAR" ) .. ".%03d", self.CSARSpawned ) + + -- Create the CSAR Pilot SPAWN object. + -- Let us create the Template for the replacement Pilot :-) + local Template = { + ["visible"] = false, + ["hidden"] = false, + ["task"] = "Ground Nothing", + ["name"] = string.format( "CSAR Pilot#%03d", self.CSARSpawned ), + ["x"] = CSARCoordinate.x, + ["y"] = CSARCoordinate.z, + ["units"] = + { + [1] = + { + ["type"] = ( CSARCoalition == coalition.side.BLUE ) and "Soldier M4" or "Infantry AK", + ["name"] = string.format( "CSAR Pilot#%03d-01", self.CSARSpawned ), + ["skill"] = "Excellent", + ["playerCanDrive"] = false, + ["x"] = CSARCoordinate.x, + ["y"] = CSARCoordinate.z, + ["heading"] = CSARHeading, + }, -- end of [1] + }, -- end of ["units"] + } + + local CSARGroup = GROUP:NewTemplate( Template, CSARCoalition, Group.Category.GROUND, CSARCountry ) + + self.CSAR[CSARTaskName] = {} + self.CSAR[CSARTaskName].PilotGroup = CSARGroup + self.CSAR[CSARTaskName].Briefing = CSARBriefing + self.CSAR[CSARTaskName].Task = nil + + return CSARTaskName + end --- Define the radius to when a CSAR task will be generated for any downed pilot within range of the nearest CSAR airbase. @@ -294,11 +398,14 @@ do -- TASK_CARGO_DISPATCHER --- Define one deploy zone for the CSAR tasks. -- @param #TASK_CARGO_DISPATCHER self - -- @param DeployZone A deploy zone. + -- @param #string CSARTaskName (optional) The name of the CSAR task. + -- @param CSARDeployZone A CSAR deploy zone. -- @return #TASK_CARGO_DISPATCHER - function TASK_CARGO_DISPATCHER:SetCSARDeployZone( CSARDeployZone ) + function TASK_CARGO_DISPATCHER:SetCSARDeployZone( CSARTaskName, CSARDeployZone ) - self.CSARDeployZones = { CSARDeployZone } + if CSARTaskName then + self.CSAR[CSARTaskName].DeployZones = { CSARDeployZone } + end return self end @@ -306,16 +413,73 @@ do -- TASK_CARGO_DISPATCHER --- Define the deploy zones for the CSAR tasks. -- @param #TASK_CARGO_DISPATCHER self - -- @param CSARDeployZones A list of the deploy zones. + -- @param #string CSARTaskName (optional) The name of the CSAR task. + -- @param CSARDeployZones A list of the CSAR deploy zones. -- @return #TASK_CARGO_DISPATCHER - function TASK_CARGO_DISPATCHER:SetCSARDeployZones( CSARDeployZones ) + -- + function TASK_CARGO_DISPATCHER:SetCSARDeployZones( CSARTaskName, CSARDeployZones ) - self.CSARDeployZones = CSARDeployZones + if CSARTaskName and self.CSAR[CSARTaskName] then + self.CSAR[CSARTaskName].DeployZones = CSARDeployZones + end + + return self + end + + + --- Add a Transport task to transport cargo from fixed locations to a deployment zone. + -- @param #TASK_CARGO_DISPATCHER self + -- @param #string TransportTaskName (optional) The name of the transport task. + -- @param Core.SetCargo#SET_CARGO SetCargo The SetCargo to be transported. + -- @param #string Briefing The briefing of the task transport to be shown to the player. + -- @return #TASK_CARGO_DISPATCHER + -- @usage + -- + -- -- Add a Transport task to transport cargo of different types to a Transport Deployment Zone. + function TASK_CARGO_DISPATCHER:AddTransportTask( TransportTaskName, SetCargo, Briefing ) + + self.TransportCount = self.TransportCount + 1 + local TaskName = string.format( ( TransportTaskName or "Transport" ) .. ".%03d", self.TransportCount ) + + self.Transport[TaskName] = {} + self.Transport[TaskName].SetCargo = SetCargo + self.Transport[TaskName].Briefing = Briefing + self.Transport[TaskName].Task = nil + + return self + end + + + --- Define one deploy zone for the Transport tasks. + -- @param #TASK_CARGO_DISPATCHER self + -- @param #string TransportTaskName (optional) The name of the Transport task. + -- @param TransportDeployZone A Transport deploy zone. + -- @return #TASK_CARGO_DISPATCHER + function TASK_CARGO_DISPATCHER:SetTransportDeployZone( TransportTaskName, TransportDeployZone ) + + if TransportTaskName then + self.Transport[TransportTaskName].DeployZones = { TransportDeployZone } + end return self end + --- Define the deploy zones for the Transport tasks. + -- @param #TASK_CARGO_DISPATCHER self + -- @param #string TransportTaskName (optional) The name of the Transport task. + -- @param TransportDeployZones A list of the Transport deploy zones. + -- @return #TASK_CARGO_DISPATCHER + -- + function TASK_CARGO_DISPATCHER:SetTransportDeployZones( TransportTaskName, TransportDeployZones ) + + if TransportTaskName then + self.Transport[TransportTaskName].DeployZones = TransportDeployZones + end + + return self + end + --- Evaluates of a CSAR task needs to be started. -- @param #TASK_CARGO_DISPATCHER self -- @return Set#SET_CARGO The SetCargo to be rescued. @@ -368,17 +532,36 @@ do -- TASK_CARGO_DISPATCHER end -- Now that all obsolete tasks are removed, loop through the CSAR pilots. - for CSARID, CSARData in pairs( self.CSAR ) do + for CSARName, CSAR in pairs( self.CSAR ) do - if CSARData.Task then - else + if not CSAR.Task then -- New CSAR Task - local SetCargo = self:EvaluateCSAR( CSARData.PilotGroup ) - local CSARTask = TASK_CARGO_CSAR:New( Mission, self.SetGroup, string.format( "CSAR.%03d", CSARID ), SetCargo ) - CSARTask:SetDeployZones( self.CSARDeployZones or {} ) - Mission:AddTask( CSARTask ) - TaskReport:Add( CSARTask:GetName() ) - CSARData.Task = CSARTask + local SetCargo = self:EvaluateCSAR( CSAR.PilotGroup ) + CSAR.Task = TASK_CARGO_CSAR:New( Mission, self.SetGroup, CSARName, SetCargo, CSAR.Briefing ) + Mission:AddTask( CSAR.Task ) + TaskReport:Add( CSARName ) + if CSAR.DeployZones then + CSAR.Task:SetDeployZones( CSAR.DeployZones or {} ) + else + CSAR.Task:SetDeployZones( self.DefaultDeployZones or {} ) + end + end + end + + + -- Now that all obsolete tasks are removed, loop through the Transport tasks. + for TransportName, Transport in pairs( self.Transport ) do + + if not Transport.Task then + -- New Transport Task + Transport.Task = TASK_CARGO_TRANSPORT:New( Mission, self.SetGroup, TransportName, Transport.SetCargo, Transport.Briefing ) + Mission:AddTask( Transport.Task ) + TaskReport:Add( TransportName ) + if Transport.DeployZones then + Transport.Task:SetDeployZones( Transport.DeployZones or {} ) + else + Transport.Task:SetDeployZones( self.DefaultDeployZones or {} ) + end end end From c60dda2545b8b2c174098ecce783b5317d5fb2b2 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Thu, 5 Apr 2018 15:06:36 +0200 Subject: [PATCH 7/9] Cargo Crate transportation working :-) --- Moose Development/Moose/Cargo/Cargo.lua | 42 ++++++- Moose Development/Moose/Cargo/CargoCrate.lua | 111 +++++++++++++++++- Moose Development/Moose/Core/Database.lua | 46 +++----- Moose Development/Moose/Core/SpawnStatic.lua | 2 +- .../Moose/Tasking/Task_CARGO.lua | 97 ++++++++++++--- .../Moose/Wrapper/Controllable.lua | 10 -- .../Moose/Wrapper/Positionable.lua | 14 ++- Moose Development/Moose/Wrapper/Static.lua | 45 ++++++- 8 files changed, 299 insertions(+), 68 deletions(-) diff --git a/Moose Development/Moose/Cargo/Cargo.lua b/Moose Development/Moose/Cargo/Cargo.lua index 07ee37a6d..2528b1b32 100644 --- a/Moose Development/Moose/Cargo/Cargo.lua +++ b/Moose Development/Moose/Cargo/Cargo.lua @@ -259,7 +259,7 @@ do -- CARGO self.Type = Type self.Name = Name - self.Weight = Weight + self.Weight = Weight or 0 self.CargoObject = nil self.CargoCarrier = nil -- Wrapper.Client#CLIENT self.Representable = false @@ -288,6 +288,34 @@ do -- CARGO return CargoFound end + --- Check if the cargo can be Boarded. + -- @param #CARGO self + function CARGO:CanBoard() + return true + end + + --- Check if the cargo can be Unboarded. + -- @param #CARGO self + function CARGO:CanUnboard() + return true + end + + --- Check if the cargo can be Loaded. + -- @param #CARGO self + function CARGO:CanLoad() + return true + end + + --- Check if the cargo can be Unloaded. + -- @param #CARGO self + function CARGO:CanUnload() + return true + end + + + + + --- Destroy the cargo. -- @param #CARGO self function CARGO:Destroy() @@ -315,6 +343,13 @@ do -- CARGO end end + --- Get the amount of Cargo. + -- @param #CARGO self + -- @return #number The amount of Cargo. + function CARGO:GetCount() + return 1 + end + --- Get the type of the Cargo. -- @param #CARGO self -- @return #string The type of the Cargo. @@ -569,8 +604,11 @@ do -- CARGO_REPRESENTABLE -- @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_REPRESENTABLE + local self = BASE:Inherit( self, CARGO:New( Type, Name, Weight ) ) -- #CARGO_REPRESENTABLE self:F( { Type, Name, Weight, ReportRadius, NearRadius } ) + + self.ReportRadius = ReportRadius or 500 + self.NearRadius = NearRadius or 25 return self end diff --git a/Moose Development/Moose/Cargo/CargoCrate.lua b/Moose Development/Moose/Cargo/CargoCrate.lua index 3f943d1ed..28a231d91 100644 --- a/Moose Development/Moose/Cargo/CargoCrate.lua +++ b/Moose Development/Moose/Cargo/CargoCrate.lua @@ -42,19 +42,25 @@ do -- CARGO_CRATE -- @param Wrapper.Static#STATIC CargoStatic -- @param #string Type -- @param #string Name - -- @param #number Weight -- @param #number ReportRadius (optional) -- @param #number NearRadius (optional) -- @return #CARGO_CRATE - function CARGO_CRATE:New( CargoStatic, Type, Name, NearRadius ) - local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoStatic, Type, Name, nil, NearRadius ) ) -- #CARGO_CRATE + function CARGO_CRATE:New( CargoStatic, Type, Name, ReportRadius, NearRadius ) + local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoStatic, Type, Name, nil, ReportRadius, NearRadius ) ) -- #CARGO_CRATE self:F( { Type, Name, NearRadius } ) self.CargoObject = CargoStatic self:T( self.ClassName ) - self:SetEventPriority( 5 ) + -- Cargo objects are added to the _DATABASE and SET_CARGO objects. + _EVENTDISPATCHER:CreateEventNewCargo( self ) + + self:HandleEvent( EVENTS.Dead, self.OnEventCargoDead ) + self:HandleEvent( EVENTS.Crash, self.OnEventCargoDead ) + self:HandleEvent( EVENTS.PlayerLeaveUnit, self.OnEventCargoDead ) + + self:SetEventPriority( 4 ) return self end @@ -116,5 +122,102 @@ do -- CARGO_CRATE end end + --- Check if the cargo can be Boarded. + -- @param #CARGO self + function CARGO:CanBoard() + return false + end + + --- Check if the cargo can be Unboarded. + -- @param #CARGO self + function CARGO_CRATE:CanUnboard() + return false + end + + --- Get the current Coordinate of the CargoGroup. + -- @param #CARGO_CRATE self + -- @return Core.Point#COORDINATE The current Coordinate of the first Cargo of the CargoGroup. + -- @return #nil There is no valid Cargo in the CargoGroup. + function CARGO_CRATE:GetCoordinate() + self:F() + + return self.CargoObject:GetCoordinate() + end + + --- Check if the CargoGroup is alive. + -- @param #CARGO_CRATE self + -- @return #boolean true if the CargoGroup is alive. + -- @return #boolean false if the CargoGroup is dead. + function CARGO_CRATE:IsAlive() + + local Alive = true + + -- When the Cargo is Loaded, the Cargo is in the CargoCarrier, so we check if the CargoCarrier is alive. + -- When the Cargo is not Loaded, the Cargo is the CargoObject, so we check if the CargoObject is alive. + if self:IsLoaded() then + Alive = Alive == true and self.CargoCarrier:IsAlive() + else + Alive = Alive == true and self.CargoObject:IsAlive() + end + + return Alive + + end + + + --- Route Cargo to Coordinate and randomize locations. + -- @param #CARGO_CRATE self + -- @param Core.Point#COORDINATE Coordinate + function CARGO_CRATE:RouteTo( Coordinate ) + self:F( {Coordinate = Coordinate } ) + + end + + --- Check if Cargo is near to the Carrier. + -- The Cargo is near to the Carrier within NearRadius. + -- @param #CARGO_CRATE self + -- @param Wrapper.Group#GROUP CargoCarrier + -- @param #number NearRadius + -- @return #boolean The Cargo is near to the Carrier. + -- @return #nil The Cargo is not near to the Carrier. + function CARGO_CRATE:IsNear( CargoCarrier, NearRadius ) + self:F( {NearRadius = NearRadius } ) + + return self:IsNear( CargoCarrier:GetCoordinate(), NearRadius ) + end + + --- Check if CargoGroup is in the ReportRadius for the Cargo to be Loaded. + -- @param #CARGO_CRATE self + -- @param Core.Point#Coordinate Coordinate + -- @return #boolean true if the CargoGroup is within the reporting radius. + function CARGO_CRATE:IsInRadius( Coordinate ) + self:F( { Coordinate } ) + + local Distance = 0 + if self:IsLoaded() then + Distance = Coordinate:DistanceFromPointVec2( self.CargoCarrier:GetPointVec2() ) + else + Distance = Coordinate:DistanceFromPointVec2( self.CargoObject:GetPointVec2() ) + end + self:T( Distance ) + + if Distance <= self.ReportRadius then + return true + else + return false + end + end + + --- Respawn the CargoGroup. + -- @param #CARGO_CRATE self + function CARGO_CRATE:Respawn() + + self:F( { "Respawning" } ) + + self:SetDeployed( false ) + self:SetStartState( "UnLoaded" ) + + end + end diff --git a/Moose Development/Moose/Core/Database.lua b/Moose Development/Moose/Core/Database.lua index d90e01284..2235407cb 100644 --- a/Moose Development/Moose/Core/Database.lua +++ b/Moose Development/Moose/Core/Database.lua @@ -450,8 +450,6 @@ function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionSide, Category local GroupTemplateName = GroupName or env.getValueDictByKey( GroupTemplate.name ) - local TraceTable = {} - if not self.Templates.Groups[GroupTemplateName] then self.Templates.Groups[GroupTemplateName] = {} self.Templates.Groups[GroupTemplateName].Status = nil @@ -475,18 +473,7 @@ function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionSide, Category self.Templates.Groups[GroupTemplateName].CoalitionID = CoalitionSide self.Templates.Groups[GroupTemplateName].CountryID = CountryID - - TraceTable[#TraceTable+1] = "Group" - TraceTable[#TraceTable+1] = self.Templates.Groups[GroupTemplateName].GroupName - - TraceTable[#TraceTable+1] = "Coalition" - TraceTable[#TraceTable+1] = self.Templates.Groups[GroupTemplateName].CoalitionID - TraceTable[#TraceTable+1] = "Category" - TraceTable[#TraceTable+1] = self.Templates.Groups[GroupTemplateName].CategoryID - TraceTable[#TraceTable+1] = "Country" - TraceTable[#TraceTable+1] = self.Templates.Groups[GroupTemplateName].CountryID - - TraceTable[#TraceTable+1] = "Units" + local UnitNames = {} for unit_num, UnitTemplate in pairs( GroupTemplate.units ) do @@ -510,10 +497,16 @@ function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionSide, Category self.Templates.ClientsByID[UnitTemplate.unitId] = UnitTemplate end - TraceTable[#TraceTable+1] = self.Templates.Units[UnitTemplate.name].UnitName + UnitNames[#UnitNames+1] = self.Templates.Units[UnitTemplate.name].UnitName end - self:E( TraceTable ) + self:I( { Group = self.Templates.Groups[GroupTemplateName].GroupName, + Coalition = self.Templates.Groups[GroupTemplateName].CoalitionID, + Category = self.Templates.Groups[GroupTemplateName].CategoryID, + Country = self.Templates.Groups[GroupTemplateName].CountryID, + Units = UnitNames + } + ) end function DATABASE:GetGroupTemplate( GroupName ) @@ -530,8 +523,6 @@ end -- @return #DATABASE self function DATABASE:_RegisterStaticTemplate( StaticTemplate, CoalitionID, CategoryID, CountryID ) - local TraceTable = {} - local StaticTemplateName = env.getValueDictByKey(StaticTemplate.name) self.Templates.Statics[StaticTemplateName] = self.Templates.Statics[StaticTemplateName] or {} @@ -547,18 +538,15 @@ function DATABASE:_RegisterStaticTemplate( StaticTemplate, CoalitionID, Category self.Templates.Statics[StaticTemplateName].CoalitionID = CoalitionID self.Templates.Statics[StaticTemplateName].CountryID = CountryID + self:I( { Static = self.Templates.Statics[StaticTemplateName].StaticName, + Coalition = self.Templates.Statics[StaticTemplateName].CoalitionID, + Category = self.Templates.Statics[StaticTemplateName].CategoryID, + Country = self.Templates.Statics[StaticTemplateName].CountryID + } + ) + + self:AddStatic( StaticTemplateName ) - TraceTable[#TraceTable+1] = "Static" - TraceTable[#TraceTable+1] = self.Templates.Statics[StaticTemplateName].StaticName - - TraceTable[#TraceTable+1] = "Coalition" - TraceTable[#TraceTable+1] = self.Templates.Statics[StaticTemplateName].CoalitionID - TraceTable[#TraceTable+1] = "Category" - TraceTable[#TraceTable+1] = self.Templates.Statics[StaticTemplateName].CategoryID - TraceTable[#TraceTable+1] = "Country" - TraceTable[#TraceTable+1] = self.Templates.Statics[StaticTemplateName].CountryID - - self:E( TraceTable ) end diff --git a/Moose Development/Moose/Core/SpawnStatic.lua b/Moose Development/Moose/Core/SpawnStatic.lua index 92a816257..6772956e0 100644 --- a/Moose Development/Moose/Core/SpawnStatic.lua +++ b/Moose Development/Moose/Core/SpawnStatic.lua @@ -85,7 +85,7 @@ function SPAWNSTATIC:NewFromStatic( SpawnTemplatePrefix, CountryID ) --R2.1 local self = BASE:Inherit( self, BASE:New() ) -- #SPAWNSTATIC self:F( { SpawnTemplatePrefix } ) - local TemplateStatic = StaticObject.getByName( SpawnTemplatePrefix ) + local TemplateStatic = STATIC:FindByName( SpawnTemplatePrefix ) if TemplateStatic then self.SpawnTemplatePrefix = SpawnTemplatePrefix self.CountryID = CountryID diff --git a/Moose Development/Moose/Tasking/Task_CARGO.lua b/Moose Development/Moose/Tasking/Task_CARGO.lua index d59473047..78cedeb0c 100644 --- a/Moose Development/Moose/Tasking/Task_CARGO.lua +++ b/Moose Development/Moose/Tasking/Task_CARGO.lua @@ -13,6 +13,7 @@ -- 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. +-- * @{#TASK_CARGO_CSAR}: Defines a task for a human player to Search and Rescue wounded pilots. -- -- === -- @@ -173,7 +174,7 @@ do -- TASK_CARGO Fsm:AddProcess ( "Planned", "Accept", ACT_ASSIGN_ACCEPT:New( self.TaskBriefing ), { Assigned = "SelectAction", Rejected = "Reject" } ) - Fsm:AddTransition( { "Planned", "Assigned", "WaitingForCommand", "ArrivedAtPickup", "ArrivedAtDeploy", "Boarded", "UnBoarded", "Landed", "Boarding" }, "SelectAction", "*" ) + Fsm:AddTransition( { "Planned", "Assigned", "WaitingForCommand", "ArrivedAtPickup", "ArrivedAtDeploy", "Boarded", "UnBoarded", "Loaded", "UnLoaded", "Landed", "Boarding" }, "SelectAction", "*" ) Fsm:AddTransition( "*", "RouteToPickup", "RoutingToPickup" ) Fsm:AddProcess ( "RoutingToPickup", "RouteToPickupPoint", ACT_ROUTE_POINT:New(), { Arrived = "ArriveAtPickup", Cancelled = "CancelRouteToPickup" } ) @@ -191,10 +192,14 @@ do -- TASK_CARGO Fsm:AddTransition( "*", "PrepareBoarding", "AwaitBoarding" ) Fsm:AddTransition( "AwaitBoarding", "Board", "Boarding" ) Fsm:AddTransition( "Boarding", "Boarded", "Boarded" ) + + Fsm:AddTransition( "*", "Load", "Loaded" ) Fsm:AddTransition( "*", "PrepareUnBoarding", "AwaitUnBoarding" ) Fsm:AddTransition( "AwaitUnBoarding", "UnBoard", "UnBoarding" ) Fsm:AddTransition( "UnBoarding", "UnBoarded", "UnBoarded" ) + + Fsm:AddTransition( "*", "Unload", "Unloaded" ) Fsm:AddTransition( "*", "Planned", "Planned" ) @@ -254,7 +259,13 @@ do -- TASK_CARGO end if NotInDeployZones then if not TaskUnit:InAir() then - MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), "Board cargo " .. Cargo.Name, TaskUnit.Menu, self.MenuBoardCargo, self, Cargo ):SetTime(MenuTime) + if Cargo:CanBoard() then + MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), "Board cargo " .. Cargo.Name, TaskUnit.Menu, self.MenuBoardCargo, self, Cargo ):SetTime(MenuTime) + else + if Cargo:CanLoad() then + MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), "Load cargo " .. Cargo.Name, TaskUnit.Menu, self.MenuLoadCargo, self, Cargo ):SetTime(MenuTime) + end + end TaskUnit.Menu:SetTime( MenuTime ) end end @@ -267,7 +278,13 @@ do -- TASK_CARGO if Cargo:IsLoaded() then if not TaskUnit:InAir() then - MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), "Unboard cargo " .. Cargo.Name, TaskUnit.Menu, self.MenuUnBoardCargo, self, Cargo ):SetTime(MenuTime) + if Cargo:CanUnboard() then + MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), "Unboard cargo " .. Cargo.Name, TaskUnit.Menu, self.MenuUnboardCargo, self, Cargo ):SetTime(MenuTime) + else + if Cargo:CanUnload() then + MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), "Unload cargo " .. Cargo.Name, TaskUnit.Menu, self.MenuUnloadCargo, self, Cargo ):SetTime(MenuTime) + end + end TaskUnit.Menu:SetTime( MenuTime ) end -- Deployzones are optional zones that can be selected to request routing information. @@ -305,10 +322,18 @@ do -- TASK_CARGO self:__PrepareBoarding( 1.0, Cargo ) end - function Fsm:MenuUnBoardCargo( Cargo, DeployZone ) + function Fsm:MenuLoadCargo( Cargo ) + self:__Load( 1.0, Cargo ) + end + + function Fsm:MenuUnboardCargo( Cargo, DeployZone ) self:__PrepareUnBoarding( 1.0, Cargo, DeployZone ) end + function Fsm:MenuUnloadCargo( Cargo, DeployZone ) + self:__Unload( 1.0, Cargo, DeployZone ) + end + function Fsm:MenuRouteToPickup( Cargo ) self:__RouteToPickup( 1.0, Cargo ) end @@ -506,9 +531,7 @@ do -- TASK_CARGO self.Cargo:MessageToGroup( "Boarded ...", TaskUnit:GetGroup() ) - TaskUnit:AddCargo( self.Cargo ) - - self:__SelectAction( 1 ) + self:Load( self.Cargo ) -- TODO:I need to find a more decent solution for this. Task:E( { CargoPickedUp = Task.CargoPickedUp } ) @@ -521,6 +544,32 @@ do -- TASK_CARGO end + --- @param #FSM_PROCESS self + -- @param Wrapper.Unit#UNIT TaskUnit + -- @param Tasking.Task_Cargo#TASK_CARGO Task + function Fsm:onafterLoad( TaskUnit, Task, From, Event, To, Cargo ) + + local TaskUnitName = TaskUnit:GetName() + self:F( { TaskUnit = TaskUnitName, Task = Task and Task:GetClassNameAndID() } ) + + if not Cargo:IsLoaded() then + Cargo:Load( TaskUnit ) + TaskUnit:AddCargo( Cargo ) + end + + self:__SelectAction( 1 ) + + -- TODO:I need to find a more decent solution for this. + Task:E( { CargoPickedUp = Task.CargoPickedUp } ) + if Cargo:IsAlive() then + if Task.CargoPickedUp then + Task:CargoPickedUp( TaskUnit, Cargo ) + end + end + + end + + --- -- @param #FSM_PROCESS self -- @param Wrapper.Unit#UNIT TaskUnit @@ -530,7 +579,7 @@ do -- TASK_CARGO -- @param To -- @param Cargo -- @param Core.Zone#ZONE_BASE DeployZone - function Fsm:onafterPrepareUnBoarding( TaskUnit, Task, From, Event, To, Cargo ) + function Fsm:onafterPrepareUnBoarding( TaskUnit, Task, From, Event, To, Cargo ) self:F( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID(), From, Event, To, Cargo } ) self.Cargo = Cargo @@ -586,33 +635,51 @@ do -- TASK_CARGO self:F( { TaskUnit = TaskUnitName, Task = Task and Task:GetClassNameAndID() } ) self.Cargo:MessageToGroup( "UnBoarded ...", TaskUnit:GetGroup() ) + + self:Unload( self.Cargo ) + end - TaskUnit:RemoveCargo( self.Cargo ) + --- + -- @param #FSM_PROCESS self + -- @param Wrapper.Unit#UNIT TaskUnit + -- @param Tasking.Task_Cargo#TASK_CARGO Task + function Fsm:onafterUnload( TaskUnit, Task, From, Event, To, Cargo, DeployZone ) + + local TaskUnitName = TaskUnit:GetName() + self:F( { TaskUnit = TaskUnitName, Task = Task and Task:GetClassNameAndID() } ) + + if not Cargo:IsUnLoaded() then + if DeployZone then + Cargo:UnLoad( DeployZone:GetPointVec2(), 400, self ) + else + Cargo:UnLoad( TaskUnit:GetPointVec2():AddX(60), 400, self ) + end + end + TaskUnit:RemoveCargo( Cargo ) local NotInDeployZones = true for DeployZoneName, DeployZone in pairs( Task.DeployZones ) do - if self.Cargo:IsInZone( DeployZone ) then + if Cargo:IsInZone( DeployZone ) then NotInDeployZones = false end end if NotInDeployZones == false then - self.Cargo:SetDeployed( true ) + Cargo:SetDeployed( true ) end -- TODO:I need to find a more decent solution for this. Task:E( { CargoDeployed = Task.CargoDeployed and "true" or "false" } ) - Task:E( { CargoIsAlive = self.Cargo:IsAlive() and "true" or "false" } ) - if self.Cargo:IsAlive() then + Task:E( { CargoIsAlive = Cargo:IsAlive() and "true" or "false" } ) + if Cargo:IsAlive() then if Task.CargoDeployed then - Task:CargoDeployed( TaskUnit, self.Cargo, self.DeployZone ) + Task:CargoDeployed( TaskUnit, Cargo, self.DeployZone ) end end self:Planned() self:__SelectAction( 1 ) end - return self diff --git a/Moose Development/Moose/Wrapper/Controllable.lua b/Moose Development/Moose/Wrapper/Controllable.lua index 7da5fe917..1847a16cd 100644 --- a/Moose Development/Moose/Wrapper/Controllable.lua +++ b/Moose Development/Moose/Wrapper/Controllable.lua @@ -2783,16 +2783,6 @@ function CONTROLLABLE:IsAirPlane() return nil end -function CONTROLLABLE:GetSize() - - local DCSObject = self:GetDCSObject() - - if DCSObject then - return 1 - else - return 0 - end -end -- Message APIs \ No newline at end of file diff --git a/Moose Development/Moose/Wrapper/Positionable.lua b/Moose Development/Moose/Wrapper/Positionable.lua index 5a7f064c4..b36a2d88b 100644 --- a/Moose Development/Moose/Wrapper/Positionable.lua +++ b/Moose Development/Moose/Wrapper/Positionable.lua @@ -129,7 +129,7 @@ function POSITIONABLE:GetPointVec2() local PositionablePointVec2 = POINT_VEC2:NewFromVec3( PositionableVec3 ) - self:T2( PositionablePointVec2 ) + self:T( PositionablePointVec2 ) return PositionablePointVec2 end @@ -309,6 +309,18 @@ function POSITIONABLE:IsAboveRunway() end +function POSITIONABLE:GetSize() + + local DCSObject = self:GetDCSObject() + + if DCSObject then + return 1 + else + return 0 + end +end + + --- Returns the POSITIONABLE heading in degrees. -- @param Wrapper.Positionable#POSITIONABLE self diff --git a/Moose Development/Moose/Wrapper/Static.lua b/Moose Development/Moose/Wrapper/Static.lua index 28e7c364b..2724ef8ed 100644 --- a/Moose Development/Moose/Wrapper/Static.lua +++ b/Moose Development/Moose/Wrapper/Static.lua @@ -48,6 +48,24 @@ STATIC = { } +function STATIC:Register( StaticName ) + local self = BASE:Inherit( self, POSITIONABLE:New( StaticName ) ) + self.StaticName = StaticName + return self +end + + +--- Finds a STATIC from the _DATABASE using a DCSStatic object. +-- @param #STATIC self +-- @param Dcs.DCSWrapper.Static#Static DCSStatic An existing DCS Static object reference. +-- @return #STATIC self +function STATIC:Find( DCSStatic ) + + local StaticName = DCSStatic:getName() + local StaticFound = _DATABASE:FindStatic( StaticName ) + return StaticFound +end + --- Finds a STATIC from the _DATABASE using the relevant Static Name. -- As an optional parameter, a briefing text can be given also. -- @param #STATIC self @@ -71,12 +89,6 @@ function STATIC:FindByName( StaticName, RaiseError ) return nil end -function STATIC:Register( StaticName ) - local self = BASE:Inherit( self, POSITIONABLE:New( StaticName ) ) - self.StaticName = StaticName - return self -end - function STATIC:GetDCSObject() local DCSStatic = StaticObject.getByName( self.StaticName ) @@ -88,6 +100,27 @@ function STATIC:GetDCSObject() return nil end +--- Returns a list of one @{Static}. +-- @param #STATIC self +-- @return #list A list of one @{Static}. +function STATIC:GetUnits() + self:F2( { self.StaticName } ) + local DCSStatic = self:GetDCSObject() + + local Statics = {} + + if DCSStatic then + Statics[1] = STATIC:Find( DCSStatic ) + self:T3( Statics ) + return Statics + end + + return nil +end + + + + function STATIC:GetThreatLevel() return 1, "Static" From 5971f6de090b1ce4ba22b0b404d63840f2adba51 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Thu, 5 Apr 2018 19:43:24 +0200 Subject: [PATCH 8/9] Added CARGO_SLINGLOAD --- Moose Development/Moose/Cargo/CargoCrate.lua | 8 +- .../Moose/Cargo/CargoSlingload.lua | 179 ++++++++++++++++++ Moose Development/Moose/Core/Database.lua | 5 +- Moose Development/Moose/Core/SpawnStatic.lua | 75 +++++--- .../Moose/Tasking/Task_CARGO.lua | 17 +- Moose Development/Moose/Wrapper/Static.lua | 2 +- Moose Setup/Moose.files | 1 + 7 files changed, 236 insertions(+), 51 deletions(-) create mode 100644 Moose Development/Moose/Cargo/CargoSlingload.lua diff --git a/Moose Development/Moose/Cargo/CargoCrate.lua b/Moose Development/Moose/Cargo/CargoCrate.lua index 28a231d91..1f083a010 100644 --- a/Moose Development/Moose/Cargo/CargoCrate.lua +++ b/Moose Development/Moose/Cargo/CargoCrate.lua @@ -123,13 +123,13 @@ do -- CARGO_CRATE end --- Check if the cargo can be Boarded. - -- @param #CARGO self - function CARGO:CanBoard() + -- @param #CARGO_CRATE self + function CARGO_CRATE:CanBoard() return false end --- Check if the cargo can be Unboarded. - -- @param #CARGO self + -- @param #CARGO_CRATE self function CARGO_CRATE:CanUnboard() return false end @@ -172,6 +172,7 @@ do -- CARGO_CRATE self:F( {Coordinate = Coordinate } ) end + --- Check if Cargo is near to the Carrier. -- The Cargo is near to the Carrier within NearRadius. @@ -186,6 +187,7 @@ do -- CARGO_CRATE return self:IsNear( CargoCarrier:GetCoordinate(), NearRadius ) end + --- Check if CargoGroup is in the ReportRadius for the Cargo to be Loaded. -- @param #CARGO_CRATE self -- @param Core.Point#Coordinate Coordinate diff --git a/Moose Development/Moose/Cargo/CargoSlingload.lua b/Moose Development/Moose/Cargo/CargoSlingload.lua new file mode 100644 index 000000000..21ad7c7e9 --- /dev/null +++ b/Moose Development/Moose/Cargo/CargoSlingload.lua @@ -0,0 +1,179 @@ +--- **Cargo** -- Management of single cargo crates, which are based on a @{Static} object. The cargo can only be slingloaded. +-- +-- === +-- +-- ![Banner Image](..\Presentations\CARGO\Dia1.JPG) +-- +-- === +-- +-- ### [Demo Missions]() +-- +-- ### [YouTube Playlist]() +-- +-- === +-- +-- ### Author: **FlightControl** +-- ### Contributions: +-- +-- === +-- +-- @module CargoCrate + +do -- CARGO_SLINGLOAD + + --- Models the behaviour of cargo crates, which can only be slingloaded. + -- @type CARGO_SLINGLOAD + -- @extends #CARGO_REPRESENTABLE + + --- # CARGO\_CRATE class, extends @{#CARGO_REPRESENTABLE} + -- + -- The CARGO\_CRATE class defines a cargo that is represented by a UNIT object within the simulator, and can be transported by a carrier. + -- + -- === + -- + -- @field #CARGO_SLINGLOAD + CARGO_SLINGLOAD = { + ClassName = "CARGO_SLINGLOAD" + } + + --- CARGO_SLINGLOAD Constructor. + -- @param #CARGO_SLINGLOAD self + -- @param Wrapper.Static#STATIC CargoStatic + -- @param #string Type + -- @param #string Name + -- @param #number ReportRadius (optional) + -- @param #number NearRadius (optional) + -- @return #CARGO_SLINGLOAD + function CARGO_SLINGLOAD:New( CargoStatic, Type, Name, ReportRadius, NearRadius ) + local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoStatic, Type, Name, nil, ReportRadius, NearRadius ) ) -- #CARGO_SLINGLOAD + self:F( { Type, Name, NearRadius } ) + + self.CargoObject = CargoStatic + + self:T( self.ClassName ) + + -- Cargo objects are added to the _DATABASE and SET_CARGO objects. + _EVENTDISPATCHER:CreateEventNewCargo( self ) + + self:HandleEvent( EVENTS.Dead, self.OnEventCargoDead ) + self:HandleEvent( EVENTS.Crash, self.OnEventCargoDead ) + self:HandleEvent( EVENTS.PlayerLeaveUnit, self.OnEventCargoDead ) + + self:SetEventPriority( 4 ) + + return self + end + + + --- Check if the cargo can be Boarded. + -- @param #CARGO_SLINGLOAD self + function CARGO_SLINGLOAD:CanBoard() + return false + end + + --- Check if the cargo can be Unboarded. + -- @param #CARGO_SLINGLOAD self + function CARGO_SLINGLOAD:CanUnboard() + return false + end + + --- Check if the cargo can be Loaded. + -- @param #CARGO_SLINGLOAD self + function CARGO_SLINGLOAD:CanLoad() + return false + end + + --- Check if the cargo can be Unloaded. + -- @param #CARGO_SLINGLOAD self + function CARGO_SLINGLOAD:CanUnload() + return false + end + + --- Get the current Coordinate of the CargoGroup. + -- @param #CARGO_SLINGLOAD self + -- @return Core.Point#COORDINATE The current Coordinate of the first Cargo of the CargoGroup. + -- @return #nil There is no valid Cargo in the CargoGroup. + function CARGO_SLINGLOAD:GetCoordinate() + self:F() + + return self.CargoObject:GetCoordinate() + end + + --- Check if the CargoGroup is alive. + -- @param #CARGO_SLINGLOAD self + -- @return #boolean true if the CargoGroup is alive. + -- @return #boolean false if the CargoGroup is dead. + function CARGO_SLINGLOAD:IsAlive() + + local Alive = true + + -- When the Cargo is Loaded, the Cargo is in the CargoCarrier, so we check if the CargoCarrier is alive. + -- When the Cargo is not Loaded, the Cargo is the CargoObject, so we check if the CargoObject is alive. + if self:IsLoaded() then + Alive = Alive == true and self.CargoCarrier:IsAlive() + else + Alive = Alive == true and self.CargoObject:IsAlive() + end + + return Alive + + end + + + --- Route Cargo to Coordinate and randomize locations. + -- @param #CARGO_SLINGLOAD self + -- @param Core.Point#COORDINATE Coordinate + function CARGO_SLINGLOAD:RouteTo( Coordinate ) + self:F( {Coordinate = Coordinate } ) + + end + + + --- Check if Cargo is near to the Carrier. + -- The Cargo is near to the Carrier within NearRadius. + -- @param #CARGO_SLINGLOAD self + -- @param Wrapper.Group#GROUP CargoCarrier + -- @param #number NearRadius + -- @return #boolean The Cargo is near to the Carrier. + -- @return #nil The Cargo is not near to the Carrier. + function CARGO_SLINGLOAD:IsNear( CargoCarrier, NearRadius ) + self:F( {NearRadius = NearRadius } ) + + return self:IsNear( CargoCarrier:GetCoordinate(), NearRadius ) + end + + + --- Check if CargoGroup is in the ReportRadius for the Cargo to be Loaded. + -- @param #CARGO_SLINGLOAD self + -- @param Core.Point#Coordinate Coordinate + -- @return #boolean true if the CargoGroup is within the reporting radius. + function CARGO_SLINGLOAD:IsInRadius( Coordinate ) + self:F( { Coordinate } ) + + local Distance = 0 + if self:IsLoaded() then + Distance = Coordinate:DistanceFromPointVec2( self.CargoCarrier:GetPointVec2() ) + else + Distance = Coordinate:DistanceFromPointVec2( self.CargoObject:GetPointVec2() ) + end + self:T( Distance ) + + if Distance <= self.ReportRadius then + return true + else + return false + end + end + + --- Respawn the CargoGroup. + -- @param #CARGO_SLINGLOAD self + function CARGO_SLINGLOAD:Respawn() + + self:F( { "Respawning" } ) + + self:SetDeployed( false ) + self:SetStartState( "UnLoaded" ) + + end + +end diff --git a/Moose Development/Moose/Core/Database.lua b/Moose Development/Moose/Core/Database.lua index 2235407cb..01b1c64a0 100644 --- a/Moose Development/Moose/Core/Database.lua +++ b/Moose Development/Moose/Core/Database.lua @@ -553,10 +553,7 @@ end --- @param #DATABASE self function DATABASE:GetStaticUnitTemplate( StaticName ) local StaticTemplate = self.Templates.Statics[StaticName].UnitTemplate - StaticTemplate.SpawnCoalitionID = self.Templates.Statics[StaticName].CoalitionID - StaticTemplate.SpawnCategoryID = self.Templates.Statics[StaticName].CategoryID - StaticTemplate.SpawnCountryID = self.Templates.Statics[StaticName].CountryID - return StaticTemplate + return StaticTemplate, self.Templates.Statics[StaticName].CoalitionID, self.Templates.Statics[StaticName].CategoryID, self.Templates.Statics[StaticName].CountryID end diff --git a/Moose Development/Moose/Core/SpawnStatic.lua b/Moose Development/Moose/Core/SpawnStatic.lua index 6772956e0..118b74b8c 100644 --- a/Moose Development/Moose/Core/SpawnStatic.lua +++ b/Moose Development/Moose/Core/SpawnStatic.lua @@ -81,14 +81,16 @@ SPAWNSTATIC = { -- @param #SPAWNSTATIC self -- @param #string SpawnTemplatePrefix is the name of the Group in the ME that defines the Template. Each new group will have the name starting with SpawnTemplatePrefix. -- @return #SPAWNSTATIC -function SPAWNSTATIC:NewFromStatic( SpawnTemplatePrefix, CountryID ) --R2.1 +function SPAWNSTATIC:NewFromStatic( SpawnTemplatePrefix, SpawnCountryID ) --R2.1 local self = BASE:Inherit( self, BASE:New() ) -- #SPAWNSTATIC self:F( { SpawnTemplatePrefix } ) - local TemplateStatic = STATIC:FindByName( SpawnTemplatePrefix ) + local TemplateStatic, CoalitionID, CategoryID, CountryID = _DATABASE:GetStaticUnitTemplate( SpawnTemplatePrefix ) if TemplateStatic then self.SpawnTemplatePrefix = SpawnTemplatePrefix - self.CountryID = CountryID + self.CountryID = SpawnCountryID or CountryID + self.CategoryID = CategoryID + self.CoalitionID = CoalitionID self.SpawnIndex = 0 else error( "SPAWNSTATIC:New: There is no group declared in the mission editor with SpawnTemplatePrefix = '" .. SpawnTemplatePrefix .. "'" ) @@ -124,22 +126,28 @@ end function SPAWNSTATIC:Spawn( Heading, NewName ) --R2.3 self:F( { Heading, NewName } ) - local CountryName = _DATABASE.COUNTRY_NAME[self.CountryID] - local StaticTemplate = _DATABASE:GetStaticUnitTemplate( self.SpawnTemplatePrefix ) - StaticTemplate.name = NewName or string.format("%s#%05d", self.SpawnTemplatePrefix, self.SpawnIndex ) - StaticTemplate.heading = ( Heading / 180 ) * math.pi + if StaticTemplate then - StaticTemplate.CountryID = nil - StaticTemplate.CoalitionID = nil - StaticTemplate.CategoryID = nil + local CountryID = self.CountryID + local CountryName = _DATABASE.COUNTRY_NAME[CountryID] - local Static = coalition.addStaticObject( self.CountryID, StaticTemplate ) + StaticTemplate.name = NewName or string.format("%s#%05d", self.SpawnTemplatePrefix, self.SpawnIndex ) + StaticTemplate.heading = ( Heading / 180 ) * math.pi + + StaticTemplate.CountryID = nil + StaticTemplate.CoalitionID = nil + StaticTemplate.CategoryID = nil + + local Static = coalition.addStaticObject( CountryID, StaticTemplate ) + + self.SpawnIndex = self.SpawnIndex + 1 - self.SpawnIndex = self.SpawnIndex + 1 - - return Static + return Static + end + + return nil end @@ -153,30 +161,35 @@ end function SPAWNSTATIC:SpawnFromPointVec2( PointVec2, Heading, NewName ) --R2.1 self:F( { PointVec2, Heading, NewName } ) - local CountryName = _DATABASE.COUNTRY_NAME[self.CountryID] - local StaticTemplate = _DATABASE:GetStaticUnitTemplate( self.SpawnTemplatePrefix ) - StaticTemplate.x = PointVec2.x - StaticTemplate.y = PointVec2.z + if StaticTemplate then - StaticTemplate.units = nil - StaticTemplate.route = nil - StaticTemplate.groupId = nil + local CountryID = self.CountryID + local CountryName = _DATABASE.COUNTRY_NAME[CountryID] + StaticTemplate.x = PointVec2.x + StaticTemplate.y = PointVec2.z - StaticTemplate.name = NewName or string.format("%s#%05d", self.SpawnTemplatePrefix, self.SpawnIndex ) - StaticTemplate.heading = ( Heading / 180 ) * math.pi + StaticTemplate.units = nil + StaticTemplate.route = nil + StaticTemplate.groupId = nil + + StaticTemplate.name = NewName or string.format("%s#%05d", self.SpawnTemplatePrefix, self.SpawnIndex ) + StaticTemplate.heading = ( Heading / 180 ) * math.pi + + StaticTemplate.CountryID = nil + StaticTemplate.CoalitionID = nil + StaticTemplate.CategoryID = nil + + local Static = coalition.addStaticObject( CountryID, StaticTemplate ) + + self.SpawnIndex = self.SpawnIndex + 1 - StaticTemplate.CountryID = nil - StaticTemplate.CoalitionID = nil - StaticTemplate.CategoryID = nil + return Static + end - local Static = coalition.addStaticObject( self.CountryID, StaticTemplate ) - - self.SpawnIndex = self.SpawnIndex + 1 - - return Static + return nil end --- Creates a new @{Static} from a @{Zone}. diff --git a/Moose Development/Moose/Tasking/Task_CARGO.lua b/Moose Development/Moose/Tasking/Task_CARGO.lua index 78cedeb0c..efb21f018 100644 --- a/Moose Development/Moose/Tasking/Task_CARGO.lua +++ b/Moose Development/Moose/Tasking/Task_CARGO.lua @@ -259,10 +259,10 @@ do -- TASK_CARGO end if NotInDeployZones then if not TaskUnit:InAir() then - if Cargo:CanBoard() then + if Cargo:CanBoard() == true then MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), "Board cargo " .. Cargo.Name, TaskUnit.Menu, self.MenuBoardCargo, self, Cargo ):SetTime(MenuTime) else - if Cargo:CanLoad() then + if Cargo:CanLoad() == true then MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), "Load cargo " .. Cargo.Name, TaskUnit.Menu, self.MenuLoadCargo, self, Cargo ):SetTime(MenuTime) end end @@ -278,10 +278,10 @@ do -- TASK_CARGO if Cargo:IsLoaded() then if not TaskUnit:InAir() then - if Cargo:CanUnboard() then + if Cargo:CanUnboard() == true then MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), "Unboard cargo " .. Cargo.Name, TaskUnit.Menu, self.MenuUnboardCargo, self, Cargo ):SetTime(MenuTime) else - if Cargo:CanUnload() then + if Cargo:CanUnload() == true then MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), "Unload cargo " .. Cargo.Name, TaskUnit.Menu, self.MenuUnloadCargo, self, Cargo ):SetTime(MenuTime) end end @@ -492,6 +492,7 @@ do -- TASK_CARGO self:__Board( -0.1 ) end end + --- @param #FSM_PROCESS self -- @param Wrapper.Unit#UNIT TaskUnit @@ -533,14 +534,6 @@ do -- TASK_CARGO self:Load( self.Cargo ) - -- TODO:I need to find a more decent solution for this. - Task:E( { CargoPickedUp = Task.CargoPickedUp } ) - if self.Cargo:IsAlive() then - if Task.CargoPickedUp then - Task:CargoPickedUp( TaskUnit, self.Cargo ) - end - end - end diff --git a/Moose Development/Moose/Wrapper/Static.lua b/Moose Development/Moose/Wrapper/Static.lua index 2724ef8ed..6479037a9 100644 --- a/Moose Development/Moose/Wrapper/Static.lua +++ b/Moose Development/Moose/Wrapper/Static.lua @@ -134,7 +134,7 @@ function STATIC:ReSpawn( Coordinate, Heading ) -- todo: need to fix country - local SpawnStatic = SPAWNSTATIC:NewFromStatic( self.StaticName, country.id.USA ) + local SpawnStatic = SPAWNSTATIC:NewFromStatic( self.StaticName ) SpawnStatic:SpawnFromPointVec2( Coordinate, Heading, self.StaticName ) end diff --git a/Moose Setup/Moose.files b/Moose Setup/Moose.files index d1328835d..c206b5416 100644 --- a/Moose Setup/Moose.files +++ b/Moose Setup/Moose.files @@ -36,6 +36,7 @@ Wrapper/Scenery.lua Cargo/Cargo.lua Cargo/CargoUnit.lua +Cargo/CargoSlingload.lua Cargo/CargoCrate.lua Cargo/CargoGroup.lua From 2ebd25d6778dfb4be7db441499fa3602d5c2d946 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Thu, 5 Apr 2018 19:54:24 +0200 Subject: [PATCH 9/9] Finish Cargo/FC/Csar --- Moose Development/Moose/Cargo/CargoSlingload.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/Moose Development/Moose/Cargo/CargoSlingload.lua b/Moose Development/Moose/Cargo/CargoSlingload.lua index 21ad7c7e9..a610e4b34 100644 --- a/Moose Development/Moose/Cargo/CargoSlingload.lua +++ b/Moose Development/Moose/Cargo/CargoSlingload.lua @@ -19,6 +19,7 @@ -- -- @module CargoCrate + do -- CARGO_SLINGLOAD --- Models the behaviour of cargo crates, which can only be slingloaded.