mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-08-15 10:47:21 +00:00
- AI_A2A_Gci Removed reference to SetEngageZone - Fixed link to #AI_A2G_SEAD.SetEngageRange #2025 - AI_Air_Engage removed reference to SetEngageZone. Does not seem to exist any more. - AI_Air_Patrol removed reference to SetEngageZone. Does not seem to exist any more or is passed as argument now. - AI_FORMATION Fixed DCSTypes#AI.Option.Air.val.ROE OptionROE #2029 - SETTINGS Fixed link to Message #2021 - Fixed wrong indent of "Developer Note" in various classes
403 lines
16 KiB
Lua
403 lines
16 KiB
Lua
--- **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.
|
||
--
|
||
-- # Developer Note
|
||
--
|
||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||
-- Therefore, this class is considered to be deprecated
|
||
--
|
||
-- ===
|
||
--
|
||
-- ### Author: **FlightControl**
|
||
--
|
||
-- ### Contributions:
|
||
--
|
||
-- ===
|
||
--
|
||
-- @module Tasking.Task_Capture_Dispatcher
|
||
-- @image MOOSE.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.AI_A2G_Dispatcher = nil -- AI.AI_A2G_Dispatcher#AI_A2G_DISPATCHER
|
||
|
||
--- 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.FlashNewTask = false
|
||
|
||
self:AddTransition( "Started", "Assign", "Started" )
|
||
self:AddTransition( "Started", "ZoneCaptured", "Started" )
|
||
|
||
self:__StartTasks( 5 )
|
||
|
||
return self
|
||
end
|
||
|
||
|
||
--- Link a task capture dispatcher from the other coalition to understand its plan for defenses.
|
||
-- This is used for the tactical overview, so the players also know the zones attacked by the other coalition!
|
||
-- @param #TASK_CAPTURE_DISPATCHER self
|
||
-- @param #TASK_CAPTURE_DISPATCHER DefenseTaskCaptureDispatcher
|
||
function TASK_CAPTURE_DISPATCHER:SetDefenseTaskCaptureDispatcher( DefenseTaskCaptureDispatcher )
|
||
|
||
self.DefenseTaskCaptureDispatcher = DefenseTaskCaptureDispatcher
|
||
end
|
||
|
||
|
||
--- Get the linked task capture dispatcher from the other coalition to understand its plan for defenses.
|
||
-- This is used for the tactical overview, so the players also know the zones attacked by the other coalition!
|
||
-- @param #TASK_CAPTURE_DISPATCHER self
|
||
-- @return #TASK_CAPTURE_DISPATCHER
|
||
function TASK_CAPTURE_DISPATCHER:GetDefenseTaskCaptureDispatcher()
|
||
|
||
return self.DefenseTaskCaptureDispatcher
|
||
end
|
||
|
||
|
||
--- Link an AI A2G dispatcher from the other coalition to understand its plan for defenses.
|
||
-- This is used for the tactical overview, so the players also know the zones attacked by the other AI A2G dispatcher!
|
||
-- @param #TASK_CAPTURE_DISPATCHER self
|
||
-- @param AI.AI_A2G_Dispatcher#AI_A2G_DISPATCHER DefenseAIA2GDispatcher
|
||
function TASK_CAPTURE_DISPATCHER:SetDefenseAIA2GDispatcher( DefenseAIA2GDispatcher )
|
||
|
||
self.DefenseAIA2GDispatcher = DefenseAIA2GDispatcher
|
||
end
|
||
|
||
|
||
--- Get the linked AI A2G dispatcher from the other coalition to understand its plan for defenses.
|
||
-- This is used for the tactical overview, so the players also know the zones attacked by the AI A2G dispatcher!
|
||
-- @param #TASK_CAPTURE_DISPATCHER self
|
||
-- @return AI.AI_A2G_Dispatcher#AI_A2G_DISPATCHER
|
||
function TASK_CAPTURE_DISPATCHER:GetDefenseAIA2GDispatcher()
|
||
|
||
return self.DefenseAIA2GDispatcher
|
||
end
|
||
|
||
|
||
--- Add a capture zone task.
|
||
-- @param #TASK_CAPTURE_DISPATCHER self
|
||
-- @param #string TaskPrefix (optional) The prefix of the capture zone task.
|
||
-- If no TaskPrefix is given, then "Capture" will be used as the TaskPrefix.
|
||
-- The TaskPrefix will be appended with a . + a number of 3 digits, if the TaskPrefix already exists in the task collection.
|
||
-- @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 )
|
||
|
||
local TaskName = TaskPrefix or "Capture"
|
||
if self.Zones[TaskName] then
|
||
self.ZoneCount = self.ZoneCount + 1
|
||
TaskName = string.format( "%s.%03d", TaskName, self.ZoneCount )
|
||
end
|
||
|
||
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
|
||
|
||
|
||
--- Link an AI_A2G_DISPATCHER to the TASK_CAPTURE_DISPATCHER.
|
||
-- @param #TASK_CAPTURE_DISPATCHER self
|
||
-- @param AI.AI_A2G_Dispatcher#AI_A2G_DISPATCHER AI_A2G_Dispatcher The AI Dispatcher to be linked to the tasking.
|
||
-- @return Tasking.Task_Capture_Zone#TASK_CAPTURE_ZONE
|
||
function TASK_CAPTURE_DISPATCHER:Link_AI_A2G_Dispatcher( AI_A2G_Dispatcher )
|
||
|
||
self.AI_A2G_Dispatcher = AI_A2G_Dispatcher -- AI.AI_A2G_Dispatcher#AI_A2G_DISPATCHER
|
||
AI_A2G_Dispatcher.Detection:LockDetectedItems()
|
||
|
||
return self
|
||
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.
|
||
-- Task = self:RemoveTask( TaskIndex )
|
||
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 )
|
||
|
||
-- Link the Task Dispatcher to the capture zone task, because it is used on the UpdateTaskInfo.
|
||
CaptureZone.Task:SetDispatcher( self )
|
||
CaptureZone.Task:UpdateTaskInfo()
|
||
|
||
function CaptureZone.Task.OnEnterAssigned( Task, From, Event, To )
|
||
if self.AI_A2G_Dispatcher then
|
||
self.AI_A2G_Dispatcher:Unlock( Task.TaskZoneName ) -- This will unlock the zone to be defended by AI.
|
||
end
|
||
CaptureZone.Task:UpdateTaskInfo()
|
||
CaptureZone.Task.ZoneGoal.Attacked = true
|
||
end
|
||
|
||
function CaptureZone.Task.OnEnterSuccess( Task, From, Event, To )
|
||
--self:Success( Task )
|
||
if self.AI_A2G_Dispatcher then
|
||
self.AI_A2G_Dispatcher:Lock( Task.TaskZoneName ) -- This will lock the zone from being defended by AI.
|
||
end
|
||
CaptureZone.Task:UpdateTaskInfo()
|
||
CaptureZone.Task.ZoneGoal.Attacked = false
|
||
end
|
||
|
||
function CaptureZone.Task.OnEnterCancelled( Task, From, Event, To )
|
||
self:Cancelled( Task )
|
||
if self.AI_A2G_Dispatcher then
|
||
self.AI_A2G_Dispatcher:Lock( Task.TaskZoneName ) -- This will lock the zone from being defended by AI.
|
||
end
|
||
CaptureZone.Task:UpdateTaskInfo()
|
||
CaptureZone.Task.ZoneGoal.Attacked = false
|
||
end
|
||
|
||
function CaptureZone.Task.OnEnterFailed( Task, From, Event, To )
|
||
self:Failed( Task )
|
||
if self.AI_A2G_Dispatcher then
|
||
self.AI_A2G_Dispatcher:Lock( Task.TaskZoneName ) -- This will lock the zone from being defended by AI.
|
||
end
|
||
CaptureZone.Task:UpdateTaskInfo()
|
||
CaptureZone.Task.ZoneGoal.Attacked = false
|
||
end
|
||
|
||
function CaptureZone.Task.OnEnterAborted( Task, From, Event, To )
|
||
self:Aborted( Task )
|
||
if self.AI_A2G_Dispatcher then
|
||
self.AI_A2G_Dispatcher:Lock( Task.TaskZoneName ) -- This will lock the zone from being defended by AI.
|
||
end
|
||
CaptureZone.Task:UpdateTaskInfo()
|
||
CaptureZone.Task.ZoneGoal.Attacked = false
|
||
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 )
|
||
if self.AI_A2G_Dispatcher then
|
||
self.AI_A2G_Dispatcher:Lock( Task.TaskZoneName ) -- This will lock the zone from being defended by AI.
|
||
end
|
||
CaptureZone.Task:UpdateTaskInfo()
|
||
CaptureZone.Task.ZoneGoal.Attacked = false
|
||
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 ~= "" and ( not self.FlashNewTask ) 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
|