From 23f92e49ddc1c3843b5bbb4e7c1882a123c853b2 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Wed, 6 Mar 2019 22:40:44 +0100 Subject: [PATCH] New TASK CAPTURE DISPATCHER class. This class allows to send capture tasks to players. It needs a ZONE_CAPTURE_COALITION class to function. --- .../Moose/Functional/ZoneCaptureCoalition.lua | 3 + Moose Development/Moose/Modules.lua | 3 +- .../Moose/Tasking/Task_Capture_Dispatcher.lua | 307 ++++++++++++++++++ ...kZoneCapture.lua => Task_Capture_Zone.lua} | 42 +-- 4 files changed, 333 insertions(+), 22 deletions(-) create mode 100644 Moose Development/Moose/Tasking/Task_Capture_Dispatcher.lua rename Moose Development/Moose/Tasking/{TaskZoneCapture.lua => Task_Capture_Zone.lua} (89%) diff --git a/Moose Development/Moose/Functional/ZoneCaptureCoalition.lua b/Moose Development/Moose/Functional/ZoneCaptureCoalition.lua index 61625bc4f..6d36beae0 100644 --- a/Moose Development/Moose/Functional/ZoneCaptureCoalition.lua +++ b/Moose Development/Moose/Functional/ZoneCaptureCoalition.lua @@ -556,6 +556,8 @@ do -- ZONE_CAPTURE_COALITION --- @param #ZONE_CAPTURE_COALITION self function ZONE_CAPTURE_COALITION:onenterCaptured() + self:F({"hello"}) + self:GetParent( self, ZONE_CAPTURE_COALITION ).onenterCaptured( self ) self.Goal:Achieved() @@ -643,6 +645,7 @@ do -- ZONE_CAPTURE_COALITION self:SetCoalition( NewCoalition ) self:Mark() + self.Goal:Achieved() end diff --git a/Moose Development/Moose/Modules.lua b/Moose Development/Moose/Modules.lua index d0614bbfe..5909ab54a 100644 --- a/Moose Development/Moose/Modules.lua +++ b/Moose Development/Moose/Modules.lua @@ -110,6 +110,7 @@ __Moose.Include( 'Scripts/Moose/Tasking/Task_Cargo.lua' ) __Moose.Include( 'Scripts/Moose/Tasking/Task_Cargo_Transport.lua' ) __Moose.Include( 'Scripts/Moose/Tasking/Task_Cargo_CSAR.lua' ) __Moose.Include( 'Scripts/Moose/Tasking/Task_Cargo_Dispatcher.lua' ) -__Moose.Include( 'Scripts/Moose/Tasking/TaskZoneCapture.lua' ) +__Moose.Include( 'Scripts/Moose/Tasking/Task_Capture_Zone.lua' ) +__Moose.Include( 'Scripts/Moose/Tasking/Task_Capture_Dispatcher.lua' ) __Moose.Include( 'Scripts/Moose/Globals.lua' ) diff --git a/Moose Development/Moose/Tasking/Task_Capture_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_Capture_Dispatcher.lua new file mode 100644 index 000000000..f1b078028 --- /dev/null +++ b/Moose Development/Moose/Tasking/Task_Capture_Dispatcher.lua @@ -0,0 +1,307 @@ +--- **Tasking** - Creates and manages player TASK_ZONE_CAPTURE tasks. +-- +-- The **TASK_CAPTURE_DISPATCHER** allows you to setup various tasks for let human +-- players capture zones in a co-operation effort. +-- +-- The dispatcher will implement for you mechanisms to create capture zone tasks: +-- +-- * As setup by the mission designer. +-- * Dynamically capture zone tasks. +-- +-- +-- +-- **Specific features:** +-- +-- * Creates a task to capture zones and achieve mission goals. +-- * Orchestrate the task flow, so go from Planned to Assigned to Success, Failed or Cancelled. +-- * Co-operation tasking, so a player joins a group of players executing the same task. +-- +-- +-- **A complete task menu system to allow players to:** +-- +-- * Join the task, abort the task. +-- * Mark the location of the zones to capture on the map. +-- * Provide details of the zones. +-- * Route to the zones. +-- * Display the task briefing. +-- +-- +-- **A complete mission menu system to allow players to:** +-- +-- * Join a task, abort the task. +-- * Display task reports. +-- * Display mission statistics. +-- * Mark the task locations on the map. +-- * Provide details of the zones. +-- * Display the mission briefing. +-- * Provide status updates as retrieved from the command center. +-- * Automatically assign a random task as part of a mission. +-- * Manually assign a specific task as part of a mission. +-- +-- +-- **A settings system, using the settings menu:** +-- +-- * Tweak the duration of the display of messages. +-- * Switch between metric and imperial measurement system. +-- * Switch between coordinate formats used in messages: BR, BRA, LL DMS, LL DDM, MGRS. +-- * Various other options. +-- +-- === +-- +-- ### Author: **FlightControl** +-- +-- ### Contributions: +-- +-- === +-- +-- @module Tasking.Task_Zone_Capture_Dispatcher +-- @image Task_Zone_Capture_Dispatcher.JPG + +do -- TASK_CAPTURE_DISPATCHER + + --- TASK_CAPTURE_DISPATCHER class. + -- @type TASK_CAPTURE_DISPATCHER + -- @extends Tasking.Task_Manager#TASK_MANAGER + -- @field TASK_CAPTURE_DISPATCHER.ZONE ZONE + + --- @type TASK_CAPTURE_DISPATCHER.CSAR + -- @field Wrapper.Unit#UNIT PilotUnit + -- @field Tasking.Task#TASK Task + + + --- Implements the dynamic dispatching of capture zone tasks. + -- + -- The **TASK_CAPTURE_DISPATCHER** allows you to setup various tasks for let human + -- players capture zones in a co-operation effort. + -- + -- Let's explore **step by step** how to setup the task capture zone dispatcher. + -- + -- # 1. Setup a mission environment. + -- + -- It is easy, as it works just like any other task setup, so setup a command center and a mission. + -- + -- ## 1.1. Create a command center. + -- + -- First you need to create a command center using the @{Tasking.CommandCenter#COMMANDCENTER.New}() constructor. + -- The command assumes that you´ve setup a group in the mission editor with the name HQ. + -- This group will act as the command center object. + -- It is a good practice to mark this group as invisible and invulnerable. + -- + -- local CommandCenter = COMMANDCENTER + -- :New( GROUP:FindByName( "HQ" ), "HQ" ) -- Create the CommandCenter. + -- + -- ## 1.2. Create a mission. + -- + -- Tasks work in a **mission**, which groups these tasks to achieve a joint **mission goal**. A command center can **govern multiple missions**. + -- + -- Create a new mission, using the @{Tasking.Mission#MISSION.New}() constructor. + -- + -- -- Declare the Mission for the Command Center. + -- local Mission = MISSION + -- :New( CommandCenter, + -- "Overlord", + -- "High", + -- "Capture the blue zones.", + -- coalition.side.RED + -- ) + -- + -- + -- # 2. Dispatch a **capture zone** task. + -- + -- So, now that we have a command center and a mission, we now create the capture zone task. + -- We create the capture zone task using the @{#TASK_CAPTURE_DISPATCHER.AddCaptureZoneTask}() constructor. + -- + -- ## 2.1. Create the capture zones. + -- + -- Because a capture zone task will not generate the capture zones, you'll need to create them first. + -- + -- + -- -- We define here a capture zone; of the type ZONE_CAPTURE_COALITION. + -- -- The zone to be captured has the name Alpha, and was defined in the mission editor as a trigger zone. + -- CaptureZone = ZONE:New( "Alpha" ) + -- CaptureZoneCoalitionApha = ZONE_CAPTURE_COALITION:New( CaptureZone, coalition.side.RED ) + -- + -- ## 2.2. Create a set of player groups. + -- + -- What is also needed, is to have a set of @{Core.Group}s defined that contains the clients of the players. + -- + -- -- Allocate the player slots, which must be aircraft (airplanes or helicopters), that can be manned by players. + -- -- We use the method FilterPrefixes to filter those player groups that have client slots, as defined in the mission editor. + -- -- In this example, we filter the groups where the name starts with "Blue Player", which captures the blue player slots. + -- local PlayerGroupSet = SET_GROUP:New():FilterPrefixes( "Blue Player" ):FilterStart() + -- + -- ## 2.3. Setup the capture zone task. + -- + -- First, we need to create a TASK_CAPTURE_DISPATCHER object. + -- + -- TaskCaptureZoneDispatcher = TASK_CAPTURE_DISPATCHER:New( Mission, PilotGroupSet ) + -- + -- So, the variable `TaskCaptureZoneDispatcher` will contain the object of class TASK_CAPTURE_DISPATCHER, + -- which will allow you to dispatch capture zone tasks: + -- + -- * for mission `Mission`, as was defined in section 1.2. + -- * for the group set `PilotGroupSet`, as was defined in section 2.2. + -- + -- Now that we have `TaskDispatcher` object, we can now **create the TaskCaptureZone**, using the @{#TASK_CAPTURE_DISPATCHER.AddCaptureZoneTask}() method! + -- + -- local TaskCaptureZone = TaskCaptureZoneDispatcher:AddCaptureZoneTask( + -- "Capture zone Alpha", + -- CaptureZoneCoalitionAlpha, + -- "Fly to zone Alpha and eliminate all enemy forces to capture it." ) + -- + -- As a result of this code, the `TaskCaptureZone` (returned) variable will contain an object of @{#TASK_CAPTURE_ZONE}! + -- We pass to the method the title of the task, and the `CaptureZoneCoalitionAlpha`, which is the zone to be captured, as defined in section 2.1! + -- This returned `TaskCaptureZone` object can now be used to setup additional task configurations, or to control this specific task with special events. + -- + -- And you're done! As you can see, it is a small bit of work, but the reward is great. + -- And, because all this is done using program interfaces, you can easily build a mission to capture zones yourself! + -- Based on various events happening within your mission, you can use the above methods to create new capture zones, + -- and setup a new capture zone task and assign it to a group of players, while your mission is running! + -- + -- + -- + -- @field #TASK_CAPTURE_DISPATCHER + TASK_CAPTURE_DISPATCHER = { + ClassName = "TASK_CAPTURE_DISPATCHER", + Mission = nil, + Tasks = {}, + Zones = {}, + ZoneCount = 0, + } + + + --- TASK_CAPTURE_DISPATCHER constructor. + -- @param #TASK_CAPTURE_DISPATCHER self + -- @param Tasking.Mission#MISSION Mission The mission for which the task dispatching is done. + -- @param Core.Set#SET_GROUP SetGroup The set of groups that can join the tasks within the mission. + -- @return #TASK_CAPTURE_DISPATCHER self + function TASK_CAPTURE_DISPATCHER:New( Mission, SetGroup ) + + -- Inherits from DETECTION_MANAGER + local self = BASE:Inherit( self, TASK_MANAGER:New( SetGroup ) ) -- #TASK_CAPTURE_DISPATCHER + + self.Mission = Mission + + self:AddTransition( "Started", "Assign", "Started" ) + self:AddTransition( "Started", "ZoneCaptured", "Started" ) + + self:__StartTasks( 5 ) + + return self + end + + + + --- Add a capture zone task. + -- @param #TASK_CAPTURE_DISPATCHER self + -- @param #string TaskPrefix (optional) The prefix of the capture zone task. + -- This prefix will be appended with a . + a number of 3 digits. + -- If no TaskPrefix is given, then "Capture" will be used as the prefix. + -- @param Functional.CaptureZoneCoalition#ZONE_CAPTURE_COALITION CaptureZone The zone of the coalition to be captured as the task goal. + -- @param #string Briefing The briefing of the task to be shown to the player. + -- @return Tasking.Task_Capture_Zone#TASK_CAPTURE_ZONE + -- @usage + -- + -- + function TASK_CAPTURE_DISPATCHER:AddCaptureZoneTask( TaskPrefix, CaptureZone, Briefing ) + + self.ZoneCount = self.ZoneCount + 1 + + local TaskName = string.format( ( TaskPrefix or "Capture" ) .. ".%03d", self.ZoneCount ) + + self.Zones[TaskName] = {} + self.Zones[TaskName].CaptureZone = CaptureZone + self.Zones[TaskName].Briefing = Briefing + self.Zones[TaskName].Task = nil + self.Zones[TaskName].TaskPrefix = TaskPrefix + + self:ManageTasks() + + return self.Zones[TaskName] and self.Zones[TaskName].Task + end + + + --- Assigns tasks to the @{Core.Set#SET_GROUP}. + -- @param #TASK_CAPTURE_DISPATCHER self + -- @return #boolean Return true if you want the task assigning to continue... false will cancel the loop. + function TASK_CAPTURE_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 Zone tasks. + for TaskName, CaptureZone in pairs( self.Zones ) do + + if not CaptureZone.Task then + -- New Transport Task + CaptureZone.Task = TASK_CAPTURE_ZONE:New( Mission, self.SetGroup, TaskName, CaptureZone.CaptureZone, CaptureZone.Briefing ) + CaptureZone.Task.TaskPrefix = CaptureZone.TaskPrefix -- We keep the TaskPrefix for further reference! + Mission:AddTask( CaptureZone.Task ) + TaskReport:Add( TaskName ) + function CaptureZone.Task.OnEnterSuccess( Task, From, Event, To ) + self:Success( Task ) + end + + function CaptureZone.Task.OnEnterCancelled( Task, From, Event, To ) + self:Cancelled( Task ) + end + + function CaptureZone.Task.OnEnterFailed( Task, From, Event, To ) + self:Failed( Task ) + end + + function CaptureZone.Task.OnEnterAborted( Task, From, Event, To ) + self:Aborted( Task ) + end + + -- Now broadcast the onafterCargoPickedUp event to the Task Cargo Dispatcher. + function CaptureZone.Task.OnAfterCaptured( Task, From, Event, To, TaskUnit ) + self:Captured( Task, Task.TaskPrefix, TaskUnit ) + end + + 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/TaskZoneCapture.lua b/Moose Development/Moose/Tasking/Task_Capture_Zone.lua similarity index 89% rename from Moose Development/Moose/Tasking/TaskZoneCapture.lua rename to Moose Development/Moose/Tasking/Task_Capture_Zone.lua index fb1ab81c5..c9c0f1193 100644 --- a/Moose Development/Moose/Tasking/TaskZoneCapture.lua +++ b/Moose Development/Moose/Tasking/Task_Capture_Zone.lua @@ -160,37 +160,37 @@ do -- TASK_ZONE_GOAL end -do -- TASK_ZONE_CAPTURE +do -- TASK_CAPTURE_ZONE - --- The TASK_ZONE_CAPTURE class - -- @type TASK_ZONE_CAPTURE + --- The TASK_CAPTURE_ZONE class + -- @type TASK_CAPTURE_ZONE -- @field Core.ZoneGoalCoalition#ZONE_GOAL_COALITION ZoneGoal -- @extends #TASK_ZONE_GOAL - --- # TASK_ZONE_CAPTURE class, extends @{Tasking.TaskZoneGoal#TASK_ZONE_GOAL} + --- # TASK_CAPTURE_ZONE class, extends @{Tasking.TaskZoneGoal#TASK_ZONE_GOAL} -- - -- The TASK_ZONE_CAPTURE class defines an Suppression or Extermination of Air Defenses task for a human player to be executed. + -- The TASK_CAPTURE_ZONE class defines an Suppression or Extermination of Air Defenses task for a human player to be executed. -- These tasks are important to be executed as they will help to achieve air superiority at the vicinity. -- - -- The TASK_ZONE_CAPTURE is used by the @{Tasking.Task_A2G_Dispatcher#TASK_A2G_DISPATCHER} to automatically create SEAD tasks + -- The TASK_CAPTURE_ZONE is used by the @{Tasking.Task_A2G_Dispatcher#TASK_A2G_DISPATCHER} to automatically create SEAD tasks -- based on detected enemy ground targets. -- - -- @field #TASK_ZONE_CAPTURE - TASK_ZONE_CAPTURE = { - ClassName = "TASK_ZONE_CAPTURE", + -- @field #TASK_CAPTURE_ZONE + TASK_CAPTURE_ZONE = { + ClassName = "TASK_CAPTURE_ZONE", } - --- Instantiates a new TASK_ZONE_CAPTURE. - -- @param #TASK_ZONE_CAPTURE self + --- Instantiates a new TASK_CAPTURE_ZONE. + -- @param #TASK_CAPTURE_ZONE self -- @param Tasking.Mission#MISSION Mission -- @param Core.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.ZoneGoalCoalition#ZONE_GOAL_COALITION ZoneGoalCoalition -- @param #string TaskBriefing The briefing of the task. - -- @return #TASK_ZONE_CAPTURE self - function TASK_ZONE_CAPTURE:New( Mission, SetGroup, TaskName, ZoneGoalCoalition, TaskBriefing) - local self = BASE:Inherit( self, TASK_ZONE_GOAL:New( Mission, SetGroup, TaskName, ZoneGoalCoalition, "CAPTURE", TaskBriefing ) ) -- #TASK_ZONE_CAPTURE + -- @return #TASK_CAPTURE_ZONE self + function TASK_CAPTURE_ZONE:New( Mission, SetGroup, TaskName, ZoneGoalCoalition, TaskBriefing) + local self = BASE:Inherit( self, TASK_ZONE_GOAL:New( Mission, SetGroup, TaskName, ZoneGoalCoalition, "CAPTURE", TaskBriefing ) ) -- #TASK_CAPTURE_ZONE self:F() Mission:AddTask( self ) @@ -212,9 +212,9 @@ do -- TASK_ZONE_CAPTURE end - --- Instantiates a new TASK_ZONE_CAPTURE. - -- @param #TASK_ZONE_CAPTURE self - function TASK_ZONE_CAPTURE:UpdateTaskInfo() + --- Instantiates a new TASK_CAPTURE_ZONE. + -- @param #TASK_CAPTURE_ZONE self + function TASK_CAPTURE_ZONE:UpdateTaskInfo() local ZoneCoordinate = self.ZoneGoal:GetZone():GetCoordinate() @@ -224,7 +224,7 @@ do -- TASK_ZONE_CAPTURE end - function TASK_ZONE_CAPTURE:ReportOrder( ReportGroup ) + function TASK_CAPTURE_ZONE:ReportOrder( ReportGroup ) local Coordinate = self:GetData( "Coordinate" ) --local Coordinate = self.TaskInfo.Coordinates.TaskInfoText local Distance = ReportGroup:GetCoordinate():Get2DDistance( Coordinate ) @@ -233,11 +233,11 @@ do -- TASK_ZONE_CAPTURE end - --- @param #TASK_ZONE_CAPTURE self + --- @param #TASK_CAPTURE_ZONE self -- @param Wrapper.Unit#UNIT TaskUnit - function TASK_ZONE_CAPTURE:OnAfterGoal( From, Event, To, PlayerUnit, PlayerName ) + function TASK_CAPTURE_ZONE:OnAfterGoal( From, Event, To, PlayerUnit, PlayerName ) - self:F( { PlayerUnit = PlayerUnit } ) + self:F( { PlayerUnit = PlayerUnit, Achieved = self.ZoneGoal.Goal:IsAchieved() } ) if self.ZoneGoal then if self.ZoneGoal.Goal:IsAchieved() then