mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-08-15 10:47:21 +00:00
# Conflicts: # Moose Development/Moose/AI/AI_A2A_Dispatcher.lua # Moose Development/Moose/AI/AI_A2G_Dispatcher.lua # Moose Development/Moose/AI/AI_CAP.lua # Moose Development/Moose/AI/AI_CAS.lua # Moose Development/Moose/AI/AI_Patrol.lua # Moose Development/Moose/Core/Base.lua # Moose Development/Moose/Core/Beacon.lua # Moose Development/Moose/Core/Database.lua # Moose Development/Moose/Core/Fsm.lua # Moose Development/Moose/Core/MarkerOps_Base.lua # Moose Development/Moose/Core/Menu.lua # Moose Development/Moose/Core/Message.lua # Moose Development/Moose/Core/Point.lua # Moose Development/Moose/Core/ScheduleDispatcher.lua # Moose Development/Moose/Core/Scheduler.lua # Moose Development/Moose/Core/Set.lua # Moose Development/Moose/Core/Spawn.lua # Moose Development/Moose/Core/Zone.lua # Moose Development/Moose/DCS.lua # Moose Development/Moose/Functional/Detection.lua # Moose Development/Moose/Functional/Mantis.lua # Moose Development/Moose/Functional/Range.lua # Moose Development/Moose/Functional/Scoring.lua # Moose Development/Moose/Functional/Sead.lua # Moose Development/Moose/Modules.lua # Moose Development/Moose/Ops/ATIS.lua # Moose Development/Moose/Ops/Airboss.lua # Moose Development/Moose/Sound/UserSound.lua # Moose Development/Moose/Utilities/Enums.lua # Moose Development/Moose/Utilities/FiFo.lua # Moose Development/Moose/Utilities/Profiler.lua # Moose Development/Moose/Utilities/Routines.lua # Moose Development/Moose/Utilities/STTS.lua # Moose Development/Moose/Utilities/Utils.lua # Moose Development/Moose/Wrapper/Airbase.lua # Moose Development/Moose/Wrapper/Controllable.lua # Moose Development/Moose/Wrapper/Group.lua # Moose Development/Moose/Wrapper/Marker.lua # Moose Development/Moose/Wrapper/Positionable.lua # Moose Development/Moose/Wrapper/Unit.lua # Moose Setup/Moose.files
2053 lines
67 KiB
Lua
2053 lines
67 KiB
Lua
--- **Tasking** -- A task object governs the main engine to administer human taskings.
|
|
--
|
|
-- **Features:**
|
|
--
|
|
-- * A base class for other task classes filling in the details and making a concrete task process.
|
|
-- * Manage the overall task execution, following-up the progression made by the pilots and actors.
|
|
-- * Provide a mechanism to set a task status, depending on the progress made within the task.
|
|
-- * Manage a task briefing.
|
|
-- * Manage the players executing the task.
|
|
-- * Manage the task menu system.
|
|
-- * Manage the task goal and scoring.
|
|
--
|
|
-- ===
|
|
--
|
|
-- # 1) Tasking from a player perspective.
|
|
--
|
|
-- Tasking can be controlled by using the "other" menu in the radio menu of the player group.
|
|
--
|
|
-- 
|
|
--
|
|
-- ## 1.1) Command Centers govern multiple Missions.
|
|
--
|
|
-- Depending on the tactical situation, your coalition may have one (or multiple) command center(s).
|
|
-- These command centers govern one (or multiple) mission(s).
|
|
--
|
|
-- For each command center, there will be a separate **Command Center Menu** that focuses on the missions governed by that command center.
|
|
--
|
|
-- 
|
|
--
|
|
-- In the above example menu structure, there is one command center with the name **`[Lima]`**.
|
|
-- The command center has one @{Tasking.Mission}, named **`"Overlord"`** with **`High`** priority.
|
|
--
|
|
-- ## 1.2) Missions govern multiple Tasks.
|
|
--
|
|
-- A mission has a mission goal to be achieved by the players within the coalition.
|
|
-- The mission goal is actually dependent on the tactical situation of the overall battlefield and the conditions set to achieve the goal.
|
|
-- So a mission can be much more than just shoot stuff ... It can be a combination of different conditions or events to complete a mission goal.
|
|
--
|
|
-- A mission can be in a specific state during the simulation run. For more information about these states, please check the @{Tasking.Mission} section.
|
|
--
|
|
-- To achieve the mission goal, a mission administers @{Tasking.Task}s that are set to achieve the mission goal by the human players.
|
|
-- Each of these tasks can be **dynamically created** using a task dispatcher, or **coded** by the mission designer.
|
|
-- Each mission has a separate **Mission Menu**, that focuses on the administration of these tasks.
|
|
--
|
|
-- On top, a mission has a mission briefing, can help to allocate specific points of interest on the map, and provides various reports.
|
|
--
|
|
-- 
|
|
--
|
|
-- The above shows a mission menu in detail of **`"Overlord"`**.
|
|
--
|
|
-- The two other menus are related to task assignment. Which will be detailed later.
|
|
--
|
|
-- ### 1.2.1) Mission briefing.
|
|
--
|
|
-- The task briefing will show a message containing a description of the mission goal, and other tactical information.
|
|
--
|
|
-- 
|
|
--
|
|
-- ### 1.2.2) Mission Map Locations.
|
|
--
|
|
-- Various points of interest as part of the mission can be indicated on the map using the *Mark Task Locations on Map* menu.
|
|
-- As a result, the map will contain various points of interest for the player (group).
|
|
--
|
|
-- 
|
|
--
|
|
-- ### 1.2.3) Mission Task Reports.
|
|
--
|
|
-- Various reports can be generated on the status of each task governed within the mission.
|
|
--
|
|
-- 
|
|
--
|
|
-- The Task Overview Report will show each task, with its task status and a short coordinate information.
|
|
--
|
|
-- 
|
|
--
|
|
-- The other Task Menus will show for each task more details, for example here the planned tasks report.
|
|
-- Note that the order of the tasks are shortest distance first to the unit position seated by the player.
|
|
--
|
|
-- ### 1.2.4) Mission Statistics.
|
|
--
|
|
-- Various statistics can be displayed regarding the mission.
|
|
--
|
|
-- 
|
|
--
|
|
-- A statistic report on the progress of the mission. Each task achievement will increase the % to 100% as a goal to complete the task.
|
|
--
|
|
-- ## 1.3) Join a Task.
|
|
--
|
|
-- The mission menu contains a very important option, that is to join a task governed within the mission.
|
|
-- In order to join a task, select the **Join Planned Task** menu, and a new menu will be given.
|
|
--
|
|
-- 
|
|
--
|
|
-- A mission governs multiple tasks, as explained earlier. Each task is of a certain task type.
|
|
-- This task type was introduced to have some sort of task classification system in place for the player.
|
|
-- A short acronym is shown that indicates the task type. The meaning of each acronym can be found in the task types explanation.
|
|
--
|
|
-- 
|
|
--
|
|
-- When the player selects a task type, a list of the available tasks of that type are listed...
|
|
-- In this case the **`SEAD`** task type was selected and a list of available **`SEAD`** tasks can be selected.
|
|
--
|
|
-- 
|
|
--
|
|
-- A new list of menu options are now displayed that allow to join the task selected, but also to obtain first some more information on the task.
|
|
--
|
|
-- ### 1.3.1) Report Task Details.
|
|
--
|
|
-- 
|
|
--
|
|
-- When selected, a message is displayed that shows detailed information on the task, like the coordinate, enemy target information, threat level etc.
|
|
--
|
|
-- ### 1.3.2) Mark Task Location on Map.
|
|
--
|
|
-- 
|
|
--
|
|
-- When selected, the target location on the map is indicated with specific information on the task.
|
|
--
|
|
-- ### 1.3.3) Join Task.
|
|
--
|
|
-- 
|
|
--
|
|
-- By joining a task, the player will indicate that the task is assigned to him, and the task is started.
|
|
-- The Command Center will communicate several task details to the player and the coalition of the player.
|
|
--
|
|
-- ## 1.4) Task Control and Actions.
|
|
--
|
|
-- 
|
|
--
|
|
-- When a player has joined a task, a **Task Action Menu** is available to be used by the player.
|
|
--
|
|
-- 
|
|
--
|
|
-- The task action menu contains now menu items specific to the task, but also one generic menu item, which is to control the task.
|
|
-- This **Task Control Menu** allows to display again the task details and the task map location information.
|
|
-- But it also allows to abort a task!
|
|
--
|
|
-- Depending on the task type, the task action menu can contain more menu items which are specific to the task.
|
|
-- For example, cargo transportation tasks will contain various additional menu items to select relevant cargo coordinates,
|
|
-- or to load/unload cargo.
|
|
--
|
|
-- ## 1.5) Automatic task assignment.
|
|
--
|
|
-- 
|
|
--
|
|
-- When we take back the command center menu, you see two addtional **Assign Task** menu items.
|
|
-- The menu **Assign Task On** will automatically allocate a task to the player.
|
|
-- After the selection of this menu, the menu will change into **Assign Task Off**,
|
|
-- and will need to be selected again by the player to switch of the automatic task assignment.
|
|
--
|
|
-- The other option is to select **Assign Task**, which will assign a new random task to the player.
|
|
--
|
|
-- When a task is automatically assigned to a player, the task needs to be confirmed as accepted within 30 seconds.
|
|
-- If this is not the case, the task will be cancelled automatically, and a new random task will be assigned to the player.
|
|
-- This will continue to happen until the player accepts the task or switches off the automatic task assignment process.
|
|
--
|
|
-- The player can accept the task using the menu **Confirm Task Acceptance** ...
|
|
--
|
|
-- ## 1.6) Task states.
|
|
--
|
|
-- A task has a state, reflecting the progress or completion status of the task:
|
|
--
|
|
-- - **Planned**: Expresses that the task is created, but not yet in execution and is not assigned yet to a pilot.
|
|
-- - **Assigned**: Expresses that the task is assigned to a group of pilots, and that the task is in execution mode.
|
|
-- - **Success**: Expresses the successful execution and finalization of the task.
|
|
-- - **Failed**: Expresses the failure of a task.
|
|
-- - **Abort**: Expresses that the task is aborted by by the player using the abort menu.
|
|
-- - **Cancelled**: Expresses that the task is cancelled by HQ or through a logical situation where a cancellation of the task is required.
|
|
--
|
|
-- ### 1.6.1) Task progress.
|
|
--
|
|
-- The task governor takes care of the **progress** and **completion** of the task **goal(s)**.
|
|
-- Tasks are executed by **human pilots** and actors within a DCS simulation.
|
|
-- Pilots can use a **menu system** to engage or abort a task, and provides means to
|
|
-- understand the **task briefing** and goals, and the relevant **task locations** on the map and
|
|
-- obtain **various reports** related to the task.
|
|
--
|
|
-- ### 1.6.2) Task completion.
|
|
--
|
|
-- As the task progresses, the **task status** will change over time, from Planned state to Completed state.
|
|
-- **Multiple pilots** can execute the same task, as such, the tasking system provides a **co-operative model** for joint task execution.
|
|
-- Depending on the task progress, a **scoring** can be allocated to award pilots of the achievements made.
|
|
-- The scoring is fully flexible, and different levels of awarding can be provided depending on the task type and complexity.
|
|
--
|
|
-- A normal flow of task status would evolve from the **Planned** state, to the **Assigned** state ending either in a **Success** or a **Failed** state.
|
|
--
|
|
-- Planned -> Assigned -> Success
|
|
-- -> Failed
|
|
-- -> Cancelled
|
|
--
|
|
-- The state completion is by default set to **Success**, if the goals of the task have been reached, but can be overruled by a goal method.
|
|
--
|
|
-- Depending on the tactical situation, a task can be **Cancelled** by the mission governer.
|
|
-- It is actually the mission designer who has the flexibility to decide at which conditions a task would be set to **Success**, **Failed** or **Cancelled**.
|
|
-- This decision all depends on the task goals, and the phase/evolution of the task conditions that would accomplish the goals.
|
|
--
|
|
-- For example, if the task goal is to merely destroy a target, and the target is mid-mission destroyed by another event than the pilot destroying the target,
|
|
-- the task goal could be set to **Failed**, or .. **Cancelled** ...
|
|
-- However, it could very well be also acceptable that the task would be flagged as **Success**.
|
|
--
|
|
-- The tasking mechanism governs beside the progress also a scoring mechanism, and in case of goal completion without any active pilot involved
|
|
-- in the execution of the task, could result in a **Success** task completion status, but no score would be awared, as there were no players involved.
|
|
--
|
|
-- These different completion states are important for the mission designer to reflect scoring to a player.
|
|
-- A success could mean a positive score to be given, while a failure could mean a negative score or penalties to be awarded.
|
|
--
|
|
-- ===
|
|
--
|
|
-- ### Author: **FlightControl**
|
|
--
|
|
-- ### Contributions:
|
|
--
|
|
-- ===
|
|
--
|
|
-- @module Tasking.Task
|
|
-- @image MOOSE.JPG
|
|
|
|
--- @type TASK
|
|
-- @field Core.Scheduler#SCHEDULER TaskScheduler
|
|
-- @field Tasking.Mission#MISSION Mission
|
|
-- @field Core.Set#SET_GROUP SetGroup The Set of Groups assigned to the Task
|
|
-- @field Core.Fsm#FSM_PROCESS FsmTemplate
|
|
-- @field Tasking.Mission#MISSION Mission
|
|
-- @field Tasking.CommandCenter#COMMANDCENTER CommandCenter
|
|
-- @field Tasking.TaskInfo#TASKINFO TaskInfo
|
|
-- @extends Core.Fsm#FSM_TASK
|
|
|
|
--- Governs the main engine to administer human taskings.
|
|
--
|
|
-- A task is governed by a @{Tasking.Mission} object. Tasks are of different types.
|
|
-- The @{#TASK} object is used or derived by more detailed tasking classes that will implement the task execution mechanisms
|
|
-- and goals.
|
|
--
|
|
-- # 1) Derived task classes.
|
|
--
|
|
-- The following TASK_ classes are derived from @{#TASK}.
|
|
--
|
|
-- TASK
|
|
-- TASK_A2A
|
|
-- TASK_A2A_ENGAGE
|
|
-- TASK_A2A_INTERCEPT
|
|
-- TASK_A2A_SWEEP
|
|
-- TASK_A2G
|
|
-- TASK_A2G_SEAD
|
|
-- TASK_A2G_CAS
|
|
-- TASK_A2G_BAI
|
|
-- TASK_CARGO
|
|
-- TASK_CARGO_TRANSPORT
|
|
-- TASK_CARGO_CSAR
|
|
--
|
|
-- ## 1.1) A2A Tasks
|
|
--
|
|
-- - @{Tasking.Task_A2A#TASK_A2A_ENGAGE} - Models an A2A engage task of a target group of airborne intruders mid-air.
|
|
-- - @{Tasking.Task_A2A#TASK_A2A_INTERCEPT} - Models an A2A ground intercept task of a target group of airborne intruders mid-air.
|
|
-- - @{Tasking.Task_A2A#TASK_A2A_SWEEP} - Models an A2A sweep task to clean an area of previously detected intruders mid-air.
|
|
--
|
|
-- ## 1.2) A2G Tasks
|
|
--
|
|
-- - @{Tasking.Task_A2G#TASK_A2G_SEAD} - Models an A2G Suppression or Extermination of Air Defenses task to clean an area of air to ground defense threats.
|
|
-- - @{Tasking.Task_A2G#TASK_A2G_CAS} - Models an A2G Close Air Support task to provide air support to nearby friendlies near the front-line.
|
|
-- - @{Tasking.Task_A2G#TASK_A2G_BAI} - Models an A2G Battlefield Air Interdiction task to provide air support to nearby friendlies near the front-line.
|
|
--
|
|
-- ## 1.3) Cargo Tasks
|
|
--
|
|
-- - @{Tasking.Task_Cargo#TASK_CARGO_TRANSPORT} - Models the transportation of cargo to deployment zones.
|
|
-- - @{Tasking.Task_Cargo#TASK_CARGO_CSAR} - Models the rescue of downed friendly pilots from behind enemy lines.
|
|
--
|
|
--
|
|
-- # 2) Task status events.
|
|
--
|
|
-- The task statuses can be set by using the following methods:
|
|
--
|
|
-- - @{#TASK.Success}() - Set the task to **Success** state.
|
|
-- - @{#TASK.Fail}() - Set the task to **Failed** state.
|
|
-- - @{#TASK.Hold}() - Set the task to **Hold** state.
|
|
-- - @{#TASK.Abort}() - Set the task to **Aborted** state, aborting the task. The task may be replanned.
|
|
-- - @{#TASK.Cancel}() - Set the task to **Cancelled** state, cancelling the task.
|
|
--
|
|
-- The mentioned derived TASK_ classes are implementing the task status transitions out of the box.
|
|
-- So no extra logic needs to be written.
|
|
--
|
|
-- # 3) Goal conditions for a task.
|
|
--
|
|
-- Every 30 seconds, a @{#Task.Goal} trigger method is fired.
|
|
-- You as a mission designer, can capture the **Goal** event trigger to check your own task goal conditions and take action!
|
|
--
|
|
-- ## 3.1) Goal event handler `OnAfterGoal()`.
|
|
--
|
|
-- And this is a really great feature! Imagine a task which has **several conditions to check** before the task can move into **Success** state.
|
|
-- You can do this with the OnAfterGoal method.
|
|
--
|
|
-- The following code provides an example of such a goal condition check implementation.
|
|
--
|
|
-- function Task:OnAfterGoal()
|
|
-- if condition == true then
|
|
-- self:Success() -- This will flag the task to Succcess when the condition is true.
|
|
-- else
|
|
-- if condition2 == true and condition3 == true then
|
|
-- self:Fail() -- This will flag the task to Failed, when condition2 and condition3 would be true.
|
|
-- end
|
|
-- end
|
|
-- end
|
|
--
|
|
-- So the @{#TASK.OnAfterGoal}() event handler would be called every 30 seconds automatically,
|
|
-- and within this method, you can now check the conditions and take respective action.
|
|
--
|
|
-- ## 3.2) Goal event trigger `Goal()`.
|
|
--
|
|
-- If you would need to check a goal at your own defined event timing, then just call the @{#TASK.Goal}() method within your logic.
|
|
-- The @{#TASK.OnAfterGoal}() event handler would then directly be called and would execute the logic.
|
|
-- Note that you can also delay the goal check by using the delayed event trigger syntax `:__Goal( Delay )`.
|
|
--
|
|
--
|
|
-- # 4) Score task completion.
|
|
--
|
|
-- Upon reaching a certain task status in a task, additional scoring can be given. If the Mission has a scoring system attached, the scores will be added to the mission scoring.
|
|
-- Use the method @{#TASK.AddScore}() to add scores when a status is reached.
|
|
--
|
|
-- # 5) Task briefing.
|
|
--
|
|
-- A task briefing is a text that is shown to the player when he is assigned to the task.
|
|
-- The briefing is broadcasted by the command center owning the mission.
|
|
--
|
|
-- The briefing is part of the parameters in the @{#TASK.New}() constructor,
|
|
-- but can separately be modified later in your mission using the
|
|
-- @{#TASK.SetBriefing}() method.
|
|
--
|
|
--
|
|
-- @field #TASK TASK
|
|
--
|
|
TASK = {
|
|
ClassName = "TASK",
|
|
TaskScheduler = nil,
|
|
ProcessClasses = {}, -- The container of the Process classes that will be used to create and assign new processes for the task to ProcessUnits.
|
|
Processes = {}, -- The container of actual process objects instantiated and assigned to ProcessUnits.
|
|
Players = nil,
|
|
Scores = {},
|
|
Menu = {},
|
|
SetGroup = nil,
|
|
FsmTemplate = nil,
|
|
Mission = nil,
|
|
CommandCenter = nil,
|
|
TimeOut = 0,
|
|
AssignedGroups = {},
|
|
}
|
|
|
|
--- FSM PlayerAborted event handler prototype for TASK.
|
|
-- @function [parent=#TASK] OnAfterPlayerAborted
|
|
-- @param #TASK self
|
|
-- @param Wrapper.Unit#UNIT PlayerUnit The Unit of the Player when he went back to spectators or left the mission.
|
|
-- @param #string PlayerName The name of the Player.
|
|
|
|
--- FSM PlayerCrashed event handler prototype for TASK.
|
|
-- @function [parent=#TASK] OnAfterPlayerCrashed
|
|
-- @param #TASK self
|
|
-- @param Wrapper.Unit#UNIT PlayerUnit The Unit of the Player when he crashed in the mission.
|
|
-- @param #string PlayerName The name of the Player.
|
|
|
|
--- FSM PlayerDead event handler prototype for TASK.
|
|
-- @function [parent=#TASK] OnAfterPlayerDead
|
|
-- @param #TASK self
|
|
-- @param Wrapper.Unit#UNIT PlayerUnit The Unit of the Player when he died in the mission.
|
|
-- @param #string PlayerName The name of the Player.
|
|
|
|
--- FSM Fail synchronous event function for TASK.
|
|
-- Use this event to Fail the Task.
|
|
-- @function [parent=#TASK] Fail
|
|
-- @param #TASK self
|
|
|
|
--- FSM Fail asynchronous event function for TASK.
|
|
-- Use this event to Fail the Task.
|
|
-- @function [parent=#TASK] __Fail
|
|
-- @param #TASK self
|
|
|
|
--- FSM Abort synchronous event function for TASK.
|
|
-- Use this event to Abort the Task.
|
|
-- @function [parent=#TASK] Abort
|
|
-- @param #TASK self
|
|
|
|
--- FSM Abort asynchronous event function for TASK.
|
|
-- Use this event to Abort the Task.
|
|
-- @function [parent=#TASK] __Abort
|
|
-- @param #TASK self
|
|
|
|
--- FSM Success synchronous event function for TASK.
|
|
-- Use this event to make the Task a Success.
|
|
-- @function [parent=#TASK] Success
|
|
-- @param #TASK self
|
|
|
|
--- FSM Success asynchronous event function for TASK.
|
|
-- Use this event to make the Task a Success.
|
|
-- @function [parent=#TASK] __Success
|
|
-- @param #TASK self
|
|
|
|
--- FSM Cancel synchronous event function for TASK.
|
|
-- Use this event to Cancel the Task.
|
|
-- @function [parent=#TASK] Cancel
|
|
-- @param #TASK self
|
|
|
|
--- FSM Cancel asynchronous event function for TASK.
|
|
-- Use this event to Cancel the Task.
|
|
-- @function [parent=#TASK] __Cancel
|
|
-- @param #TASK self
|
|
|
|
--- FSM Replan synchronous event function for TASK.
|
|
-- Use this event to Replan the Task.
|
|
-- @function [parent=#TASK] Replan
|
|
-- @param #TASK self
|
|
|
|
--- FSM Replan asynchronous event function for TASK.
|
|
-- Use this event to Replan the Task.
|
|
-- @function [parent=#TASK] __Replan
|
|
-- @param #TASK self
|
|
|
|
|
|
--- Instantiates a new TASK. Should never be used. Interface Class.
|
|
-- @param #TASK self
|
|
-- @param Tasking.Mission#MISSION Mission The mission wherein the Task is registered.
|
|
-- @param Core.Set#SET_GROUP SetGroupAssign The set of groups for which the Task can be assigned.
|
|
-- @param #string TaskName The name of the Task
|
|
-- @param #string TaskType The type of the Task
|
|
-- @return #TASK self
|
|
function TASK:New( Mission, SetGroupAssign, TaskName, TaskType, TaskBriefing )
|
|
|
|
local self = BASE:Inherit( self, FSM_TASK:New( TaskName ) ) -- Tasking.Task#TASK
|
|
|
|
self:SetStartState( "Planned" )
|
|
self:AddTransition( "Planned", "Assign", "Assigned" )
|
|
self:AddTransition( "Assigned", "AssignUnit", "Assigned" )
|
|
self:AddTransition( "Assigned", "Success", "Success" )
|
|
self:AddTransition( "Assigned", "Hold", "Hold" )
|
|
self:AddTransition( "Assigned", "Fail", "Failed" )
|
|
self:AddTransition( { "Planned", "Assigned" }, "Abort", "Aborted" )
|
|
self:AddTransition( "Assigned", "Cancel", "Cancelled" )
|
|
self:AddTransition( "Assigned", "Goal", "*" )
|
|
|
|
self.Fsm = {}
|
|
|
|
local Fsm = self:GetUnitProcess()
|
|
Fsm:SetStartState( "Planned" )
|
|
Fsm:AddProcess ( "Planned", "Accept", ACT_ASSIGN_ACCEPT:New( self.TaskBriefing ), { Assigned = "Assigned", Rejected = "Reject" } )
|
|
Fsm:AddTransition( "Assigned", "Assigned", "*" )
|
|
|
|
--- Goal Handler OnBefore for TASK
|
|
-- @function [parent=#TASK] OnBeforeGoal
|
|
-- @param #TASK self
|
|
-- @param #string From
|
|
-- @param #string Event
|
|
-- @param #string To
|
|
-- @param Wrapper.Unit#UNIT PlayerUnit The @{Wrapper.Unit} of the player.
|
|
-- @param #string PlayerName The name of the player.
|
|
-- @return #boolean
|
|
|
|
--- Goal Handler OnAfter for TASK
|
|
-- @function [parent=#TASK] OnAfterGoal
|
|
-- @param #TASK self
|
|
-- @param #string From
|
|
-- @param #string Event
|
|
-- @param #string To
|
|
-- @param Wrapper.Unit#UNIT PlayerUnit The @{Wrapper.Unit} of the player.
|
|
-- @param #string PlayerName The name of the player.
|
|
|
|
--- Goal Trigger for TASK
|
|
-- @function [parent=#TASK] Goal
|
|
-- @param #TASK self
|
|
-- @param Wrapper.Unit#UNIT PlayerUnit The @{Wrapper.Unit} of the player.
|
|
-- @param #string PlayerName The name of the player.
|
|
|
|
--- Goal Asynchronous Trigger for TASK
|
|
-- @function [parent=#TASK] __Goal
|
|
-- @param #TASK self
|
|
-- @param #number Delay
|
|
-- @param Wrapper.Unit#UNIT PlayerUnit The @{Wrapper.Unit} of the player.
|
|
-- @param #string PlayerName The name of the player.
|
|
|
|
|
|
|
|
self:AddTransition( "*", "PlayerCrashed", "*" )
|
|
self:AddTransition( "*", "PlayerAborted", "*" )
|
|
self:AddTransition( "*", "PlayerRejected", "*" )
|
|
self:AddTransition( "*", "PlayerDead", "*" )
|
|
self:AddTransition( { "Failed", "Aborted", "Cancelled" }, "Replan", "Planned" )
|
|
self:AddTransition( "*", "TimeOut", "Cancelled" )
|
|
|
|
self:F( "New TASK " .. TaskName )
|
|
|
|
self.Processes = {}
|
|
|
|
self.Mission = Mission
|
|
self.CommandCenter = Mission:GetCommandCenter()
|
|
|
|
self.SetGroup = SetGroupAssign
|
|
|
|
self:SetType( TaskType )
|
|
self:SetName( TaskName )
|
|
self:SetID( Mission:GetNextTaskID( self ) ) -- The Mission orchestrates the task sequences ..
|
|
|
|
self:SetBriefing( TaskBriefing )
|
|
|
|
|
|
self.TaskInfo = TASKINFO:New( self )
|
|
|
|
self.TaskProgress = {}
|
|
|
|
return self
|
|
end
|
|
|
|
--- Get the Task FSM Process Template
|
|
-- @param #TASK self
|
|
-- @return Core.Fsm#FSM_PROCESS
|
|
function TASK:GetUnitProcess( TaskUnit )
|
|
|
|
if TaskUnit then
|
|
return self:GetStateMachine( TaskUnit )
|
|
else
|
|
self.FsmTemplate = self.FsmTemplate or FSM_PROCESS:New()
|
|
return self.FsmTemplate
|
|
end
|
|
end
|
|
|
|
--- Sets the Task FSM Process Template
|
|
-- @param #TASK self
|
|
-- @param Core.Fsm#FSM_PROCESS
|
|
function TASK:SetUnitProcess( FsmTemplate )
|
|
|
|
self.FsmTemplate = FsmTemplate
|
|
end
|
|
|
|
--- Add a PlayerUnit to join the Task.
|
|
-- For each Group within the Task, the Unit is checked if it can join the Task.
|
|
-- If the Unit was not part of the Task, false is returned.
|
|
-- If the Unit is part of the Task, true is returned.
|
|
-- @param #TASK self
|
|
-- @param Wrapper.Unit#UNIT PlayerUnit The CLIENT or UNIT of the Player joining the Mission.
|
|
-- @param Wrapper.Group#GROUP PlayerGroup The GROUP of the player joining the Mission.
|
|
-- @return #boolean true if Unit is part of the Task.
|
|
function TASK:JoinUnit( PlayerUnit, PlayerGroup )
|
|
self:F( { PlayerUnit = PlayerUnit, PlayerGroup = PlayerGroup } )
|
|
|
|
local PlayerUnitAdded = false
|
|
|
|
local PlayerGroups = self:GetGroups()
|
|
|
|
-- Is the PlayerGroup part of the PlayerGroups?
|
|
if PlayerGroups:IsIncludeObject( PlayerGroup ) then
|
|
|
|
-- Check if the PlayerGroup is already assigned to the Task. If yes, the PlayerGroup is added to the Task.
|
|
-- If the PlayerGroup is not assigned to the Task, the menu needs to be set. In that case, the PlayerUnit will become the GroupPlayer leader.
|
|
if self:IsStatePlanned() or self:IsStateReplanned() then
|
|
--self:SetMenuForGroup( PlayerGroup )
|
|
--self:MessageToGroups( PlayerUnit:GetPlayerName() .. " is planning to join Task " .. self:GetName() )
|
|
end
|
|
if self:IsStateAssigned() then
|
|
local IsGroupAssigned = self:IsGroupAssigned( PlayerGroup )
|
|
self:F( { IsGroupAssigned = IsGroupAssigned } )
|
|
if IsGroupAssigned then
|
|
self:AssignToUnit( PlayerUnit )
|
|
self:MessageToGroups( PlayerUnit:GetPlayerName() .. " joined Task " .. self:GetName() )
|
|
end
|
|
end
|
|
end
|
|
|
|
return PlayerUnitAdded
|
|
end
|
|
|
|
--- A group rejecting a planned task.
|
|
-- @param #TASK self
|
|
-- @param Wrapper.Group#GROUP PlayerGroup The group rejecting the task.
|
|
-- @return #TASK
|
|
function TASK:RejectGroup( PlayerGroup )
|
|
|
|
local PlayerGroups = self:GetGroups()
|
|
|
|
-- Is the PlayerGroup part of the PlayerGroups?
|
|
if PlayerGroups:IsIncludeObject( PlayerGroup ) then
|
|
|
|
-- Check if the PlayerGroup is already assigned or is planned to be assigned to the Task.
|
|
-- If yes, the PlayerGroup is aborted from the Task.
|
|
-- If the PlayerUnit was the last unit of the PlayerGroup, the menu needs to be removed from the Group.
|
|
if self:IsStatePlanned() then
|
|
|
|
local IsGroupAssigned = self:IsGroupAssigned( PlayerGroup )
|
|
if IsGroupAssigned then
|
|
local PlayerName = PlayerGroup:GetUnit(1):GetPlayerName()
|
|
self:GetMission():GetCommandCenter():MessageToGroup( "Task " .. self:GetName() .. " has been rejected! We will select another task.", PlayerGroup )
|
|
self:UnAssignFromGroup( PlayerGroup )
|
|
|
|
self:PlayerRejected( PlayerGroup:GetUnit(1) )
|
|
end
|
|
|
|
end
|
|
end
|
|
|
|
return self
|
|
end
|
|
|
|
|
|
--- A group aborting the task.
|
|
-- @param #TASK self
|
|
-- @param Wrapper.Group#GROUP PlayerGroup The group aborting the task.
|
|
-- @return #TASK
|
|
function TASK:AbortGroup( PlayerGroup )
|
|
|
|
local PlayerGroups = self:GetGroups()
|
|
|
|
-- Is the PlayerGroup part of the PlayerGroups?
|
|
if PlayerGroups:IsIncludeObject( PlayerGroup ) then
|
|
|
|
-- Check if the PlayerGroup is already assigned or is planned to be assigned to the Task.
|
|
-- If yes, the PlayerGroup is aborted from the Task.
|
|
-- If the PlayerUnit was the last unit of the PlayerGroup, the menu needs to be removed from the Group.
|
|
if self:IsStateAssigned() then
|
|
|
|
local IsGroupAssigned = self:IsGroupAssigned( PlayerGroup )
|
|
if IsGroupAssigned then
|
|
local PlayerName = PlayerGroup:GetUnit(1):GetPlayerName()
|
|
self:UnAssignFromGroup( PlayerGroup )
|
|
|
|
-- Now check if the task needs to go to hold...
|
|
-- It will go to hold, if there are no players in the mission...
|
|
PlayerGroups:Flush( self )
|
|
local IsRemaining = false
|
|
for GroupName, AssignedGroup in pairs( PlayerGroups:GetSet() or {} ) do
|
|
if self:IsGroupAssigned( AssignedGroup ) == true then
|
|
IsRemaining = true
|
|
self:F( { Task = self:GetName(), IsRemaining = IsRemaining } )
|
|
break
|
|
end
|
|
end
|
|
|
|
self:F( { Task = self:GetName(), IsRemaining = IsRemaining } )
|
|
if IsRemaining == false then
|
|
self:Abort()
|
|
end
|
|
|
|
self:PlayerAborted( PlayerGroup:GetUnit(1) )
|
|
end
|
|
|
|
end
|
|
end
|
|
|
|
return self
|
|
end
|
|
|
|
|
|
--- A group crashing and thus aborting from the task.
|
|
-- @param #TASK self
|
|
-- @param Wrapper.Group#GROUP PlayerGroup The group aborting the task.
|
|
-- @return #TASK
|
|
function TASK:CrashGroup( PlayerGroup )
|
|
self:F( { PlayerGroup = PlayerGroup } )
|
|
|
|
local PlayerGroups = self:GetGroups()
|
|
|
|
-- Is the PlayerGroup part of the PlayerGroups?
|
|
if PlayerGroups:IsIncludeObject( PlayerGroup ) then
|
|
|
|
-- Check if the PlayerGroup is already assigned to the Task. If yes, the PlayerGroup is aborted from the Task.
|
|
-- If the PlayerUnit was the last unit of the PlayerGroup, the menu needs to be removed from the Group.
|
|
if self:IsStateAssigned() then
|
|
local IsGroupAssigned = self:IsGroupAssigned( PlayerGroup )
|
|
self:F( { IsGroupAssigned = IsGroupAssigned } )
|
|
if IsGroupAssigned then
|
|
local PlayerName = PlayerGroup:GetUnit(1):GetPlayerName()
|
|
self:MessageToGroups( PlayerName .. " crashed! " )
|
|
self:UnAssignFromGroup( PlayerGroup )
|
|
|
|
-- Now check if the task needs to go to hold...
|
|
-- It will go to hold, if there are no players in the mission...
|
|
|
|
PlayerGroups:Flush( self )
|
|
local IsRemaining = false
|
|
for GroupName, AssignedGroup in pairs( PlayerGroups:GetSet() or {} ) do
|
|
if self:IsGroupAssigned( AssignedGroup ) == true then
|
|
IsRemaining = true
|
|
self:F( { Task = self:GetName(), IsRemaining = IsRemaining } )
|
|
break
|
|
end
|
|
end
|
|
|
|
self:F( { Task = self:GetName(), IsRemaining = IsRemaining } )
|
|
if IsRemaining == false then
|
|
self:Abort()
|
|
end
|
|
|
|
self:PlayerCrashed( PlayerGroup:GetUnit(1) )
|
|
end
|
|
|
|
end
|
|
end
|
|
|
|
return self
|
|
end
|
|
|
|
|
|
|
|
--- Gets the Mission to where the TASK belongs.
|
|
-- @param #TASK self
|
|
-- @return Tasking.Mission#MISSION
|
|
function TASK:GetMission()
|
|
|
|
return self.Mission
|
|
end
|
|
|
|
|
|
--- Gets the SET_GROUP assigned to the TASK.
|
|
-- @param #TASK self
|
|
-- @return Core.Set#SET_GROUP
|
|
function TASK:GetGroups()
|
|
|
|
return self.SetGroup
|
|
end
|
|
|
|
|
|
--- Gets the SET_GROUP assigned to the TASK.
|
|
-- @param #TASK self
|
|
-- @param Core.Set#SET_GROUP GroupSet
|
|
-- @return Core.Set#SET_GROUP
|
|
function TASK:AddGroups( GroupSet )
|
|
|
|
GroupSet = GroupSet or SET_GROUP:New()
|
|
|
|
self.SetGroup:ForEachGroup(
|
|
--- @param Wrapper.Group#GROUP GroupSet
|
|
function( GroupItem )
|
|
GroupSet:Add( GroupItem:GetName(), GroupItem)
|
|
end
|
|
)
|
|
|
|
return GroupSet
|
|
end
|
|
|
|
do -- Group Assignment
|
|
|
|
--- Returns if the @{Task} is assigned to the Group.
|
|
-- @param #TASK self
|
|
-- @param Wrapper.Group#GROUP TaskGroup
|
|
-- @return #boolean
|
|
function TASK:IsGroupAssigned( TaskGroup )
|
|
|
|
local TaskGroupName = TaskGroup:GetName()
|
|
|
|
if self.AssignedGroups[TaskGroupName] then
|
|
--self:T( { "Task is assigned to:", TaskGroup:GetName() } )
|
|
return true
|
|
end
|
|
|
|
--self:T( { "Task is not assigned to:", TaskGroup:GetName() } )
|
|
return false
|
|
end
|
|
|
|
|
|
--- Set @{Wrapper.Group} assigned to the @{Task}.
|
|
-- @param #TASK self
|
|
-- @param Wrapper.Group#GROUP TaskGroup
|
|
-- @return #TASK
|
|
function TASK:SetGroupAssigned( TaskGroup )
|
|
|
|
local TaskName = self:GetName()
|
|
local TaskGroupName = TaskGroup:GetName()
|
|
|
|
self.AssignedGroups[TaskGroupName] = TaskGroup
|
|
self:F( string.format( "Task %s is assigned to %s", TaskName, TaskGroupName ) )
|
|
|
|
-- Set the group to be assigned at mission level. This allows to decide the menu options on mission level for this group.
|
|
self:GetMission():SetGroupAssigned( TaskGroup )
|
|
|
|
local SetAssignedGroups = self:GetGroups()
|
|
|
|
-- SetAssignedGroups:ForEachGroup(
|
|
-- function( AssignedGroup )
|
|
-- if self:IsGroupAssigned(AssignedGroup) then
|
|
-- self:GetMission():GetCommandCenter():MessageToGroup( string.format( "Task %s is assigned to group %s.", TaskName, TaskGroupName ), AssignedGroup )
|
|
-- else
|
|
-- self:GetMission():GetCommandCenter():MessageToGroup( string.format( "Task %s is assigned to your group.", TaskName ), AssignedGroup )
|
|
-- end
|
|
-- end
|
|
-- )
|
|
|
|
return self
|
|
end
|
|
|
|
--- Clear the @{Wrapper.Group} assignment from the @{Task}.
|
|
-- @param #TASK self
|
|
-- @param Wrapper.Group#GROUP TaskGroup
|
|
-- @return #TASK
|
|
function TASK:ClearGroupAssignment( TaskGroup )
|
|
|
|
local TaskName = self:GetName()
|
|
local TaskGroupName = TaskGroup:GetName()
|
|
|
|
self.AssignedGroups[TaskGroupName] = nil
|
|
--self:F( string.format( "Task %s is unassigned to %s", TaskName, TaskGroupName ) )
|
|
|
|
-- Set the group to be assigned at mission level. This allows to decide the menu options on mission level for this group.
|
|
self:GetMission():ClearGroupAssignment( TaskGroup )
|
|
|
|
local SetAssignedGroups = self:GetGroups()
|
|
|
|
SetAssignedGroups:ForEachGroup(
|
|
function( AssignedGroup )
|
|
if self:IsGroupAssigned(AssignedGroup) then
|
|
--self:GetMission():GetCommandCenter():MessageToGroup( string.format( "Task %s is unassigned from group %s.", TaskName, TaskGroupName ), AssignedGroup )
|
|
else
|
|
--self:GetMission():GetCommandCenter():MessageToGroup( string.format( "Task %s is unassigned from your group.", TaskName ), AssignedGroup )
|
|
end
|
|
end
|
|
)
|
|
|
|
return self
|
|
end
|
|
|
|
end
|
|
|
|
do -- Group Assignment
|
|
|
|
--- @param #TASK self
|
|
-- @param Actions.Act_Assign#ACT_ASSIGN AcceptClass
|
|
function TASK:SetAssignMethod( AcceptClass )
|
|
|
|
local ProcessTemplate = self:GetUnitProcess()
|
|
|
|
ProcessTemplate:SetProcess( "Planned", "Accept", AcceptClass ) -- Actions.Act_Assign#ACT_ASSIGN
|
|
end
|
|
|
|
|
|
--- Assign the @{Task} to a @{Wrapper.Group}.
|
|
-- @param #TASK self
|
|
-- @param Wrapper.Group#GROUP TaskGroup
|
|
-- @return #TASK
|
|
function TASK:AssignToGroup( TaskGroup )
|
|
self:F( TaskGroup:GetName() )
|
|
|
|
local TaskGroupName = TaskGroup:GetName()
|
|
local Mission = self:GetMission()
|
|
local CommandCenter = Mission:GetCommandCenter()
|
|
|
|
self:SetGroupAssigned( TaskGroup )
|
|
|
|
local TaskUnits = TaskGroup:GetUnits()
|
|
for UnitID, UnitData in pairs( TaskUnits ) do
|
|
local TaskUnit = UnitData -- Wrapper.Unit#UNIT
|
|
local PlayerName = TaskUnit:GetPlayerName()
|
|
self:F(PlayerName)
|
|
if PlayerName ~= nil and PlayerName ~= "" then
|
|
self:AssignToUnit( TaskUnit )
|
|
CommandCenter:MessageToGroup(
|
|
string.format( 'Task "%s": Briefing for player (%s):\n%s',
|
|
self:GetName(),
|
|
PlayerName,
|
|
self:GetBriefing()
|
|
), TaskGroup
|
|
)
|
|
end
|
|
end
|
|
|
|
CommandCenter:SetMenu()
|
|
|
|
self:MenuFlashTaskStatus( TaskGroup, self:GetMission():GetCommandCenter().FlashStatus )
|
|
|
|
return self
|
|
end
|
|
|
|
--- UnAssign the @{Task} from a @{Wrapper.Group}.
|
|
-- @param #TASK self
|
|
-- @param Wrapper.Group#GROUP TaskGroup
|
|
function TASK:UnAssignFromGroup( TaskGroup )
|
|
self:F2( { TaskGroup = TaskGroup:GetName() } )
|
|
|
|
self:ClearGroupAssignment( TaskGroup )
|
|
|
|
local TaskUnits = TaskGroup:GetUnits()
|
|
for UnitID, UnitData in pairs( TaskUnits ) do
|
|
local TaskUnit = UnitData -- Wrapper.Unit#UNIT
|
|
local PlayerName = TaskUnit:GetPlayerName()
|
|
if PlayerName ~= nil and PlayerName ~= "" then -- Only remove units that have players!
|
|
self:UnAssignFromUnit( TaskUnit )
|
|
end
|
|
end
|
|
|
|
local Mission = self:GetMission()
|
|
local CommandCenter = Mission:GetCommandCenter()
|
|
CommandCenter:SetMenu()
|
|
|
|
self:MenuFlashTaskStatus( TaskGroup, false ) -- stop message flashing, if any #1383 & #1312
|
|
|
|
end
|
|
end
|
|
|
|
|
|
---
|
|
-- @param #TASK self
|
|
-- @param Wrapper.Group#GROUP FindGroup
|
|
-- @return #boolean
|
|
function TASK:HasGroup( FindGroup )
|
|
|
|
local SetAttackGroup = self:GetGroups()
|
|
return SetAttackGroup:FindGroup( FindGroup:GetName() )
|
|
|
|
end
|
|
|
|
--- Assign the @{Task} to an alive @{Wrapper.Unit}.
|
|
-- @param #TASK self
|
|
-- @param Wrapper.Unit#UNIT TaskUnit
|
|
-- @return #TASK self
|
|
function TASK:AssignToUnit( TaskUnit )
|
|
self:F( TaskUnit:GetName() )
|
|
|
|
local FsmTemplate = self:GetUnitProcess()
|
|
|
|
-- Assign a new FsmUnit to TaskUnit.
|
|
local FsmUnit = self:SetStateMachine( TaskUnit, FsmTemplate:Copy( TaskUnit, self ) ) -- Core.Fsm#FSM_PROCESS
|
|
|
|
FsmUnit:SetStartState( "Planned" )
|
|
|
|
FsmUnit:Accept() -- Each Task needs to start with an Accept event to start the flow.
|
|
|
|
return self
|
|
end
|
|
|
|
--- UnAssign the @{Task} from an alive @{Wrapper.Unit}.
|
|
-- @param #TASK self
|
|
-- @param Wrapper.Unit#UNIT TaskUnit
|
|
-- @return #TASK self
|
|
function TASK:UnAssignFromUnit( TaskUnit )
|
|
self:F( TaskUnit:GetName() )
|
|
|
|
self:RemoveStateMachine( TaskUnit )
|
|
|
|
-- If a Task Control Menu had been set, then this will be removed.
|
|
self:RemoveTaskControlMenu( TaskUnit )
|
|
return self
|
|
end
|
|
|
|
--- Sets the TimeOut for the @{Task}. If @{Task} stayed planned for longer than TimeOut, it gets into Cancelled status.
|
|
-- @param #TASK self
|
|
-- @param #integer Timer in seconds
|
|
-- @return #TASK self
|
|
function TASK:SetTimeOut ( Timer )
|
|
self:F( Timer )
|
|
self.TimeOut = Timer
|
|
self:__TimeOut( self.TimeOut )
|
|
return self
|
|
end
|
|
|
|
--- Send a message of the @{Task} to the assigned @{Wrapper.Group}s.
|
|
-- @param #TASK self
|
|
function TASK:MessageToGroups( Message )
|
|
self:F( { Message = Message } )
|
|
|
|
local Mission = self:GetMission()
|
|
local CC = Mission:GetCommandCenter()
|
|
|
|
for TaskGroupName, TaskGroup in pairs( self.SetGroup:GetSet() ) do
|
|
TaskGroup = TaskGroup -- Wrapper.Group#GROUP
|
|
if TaskGroup:IsAlive() == true then
|
|
CC:MessageToGroup( Message, TaskGroup, TaskGroup:GetName() )
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
--- Send the briefng message of the @{Task} to the assigned @{Wrapper.Group}s.
|
|
-- @param #TASK self
|
|
function TASK:SendBriefingToAssignedGroups()
|
|
self:F2()
|
|
|
|
for TaskGroupName, TaskGroup in pairs( self.SetGroup:GetSet() ) do
|
|
if TaskGroup:IsAlive() then
|
|
if self:IsGroupAssigned( TaskGroup ) then
|
|
TaskGroup:Message( self.TaskBriefing, 60 )
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
--- UnAssign the @{Task} from the @{Wrapper.Group}s.
|
|
-- @param #TASK self
|
|
function TASK:UnAssignFromGroups()
|
|
self:F2()
|
|
|
|
for TaskGroupName, TaskGroup in pairs( self.SetGroup:GetSet() ) do
|
|
if TaskGroup:IsAlive() == true then
|
|
if self:IsGroupAssigned(TaskGroup) then
|
|
self:UnAssignFromGroup( TaskGroup )
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
|
|
--- Returns if the @{Task} has still alive and assigned Units.
|
|
-- @param #TASK self
|
|
-- @return #boolean
|
|
function TASK:HasAliveUnits()
|
|
self:F()
|
|
|
|
for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do
|
|
if TaskGroup:IsAlive() == true then
|
|
if self:IsStateAssigned() then
|
|
if self:IsGroupAssigned( TaskGroup ) then
|
|
for TaskUnitID, TaskUnit in pairs( TaskGroup:GetUnits() ) do
|
|
if TaskUnit:IsAlive() then
|
|
self:T( { HasAliveUnits = true } )
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
self:T( { HasAliveUnits = false } )
|
|
return false
|
|
end
|
|
|
|
--- Set the menu options of the @{Task} to all the groups in the SetGroup.
|
|
-- @param #TASK self
|
|
-- @param #number MenuTime
|
|
-- @return #TASK
|
|
function TASK:SetMenu( MenuTime ) --R2.1 Mission Reports and Task Reports added. Fixes issue #424.
|
|
self:F( { self:GetName(), MenuTime } )
|
|
|
|
--self.SetGroup:Flush()
|
|
--for TaskGroupID, TaskGroupData in pairs( self.SetGroup:GetAliveSet() ) do
|
|
for TaskGroupID, TaskGroupData in pairs( self.SetGroup:GetSet() ) do
|
|
local TaskGroup = TaskGroupData -- Wrapper.Group#GROUP
|
|
if TaskGroup:IsAlive() == true and TaskGroup:GetPlayerNames() then
|
|
|
|
-- Set Mission Menus
|
|
|
|
local Mission = self:GetMission()
|
|
local MissionMenu = Mission:GetMenu( TaskGroup )
|
|
if MissionMenu then
|
|
self:SetMenuForGroup( TaskGroup, MenuTime )
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
|
|
--- Set the Menu for a Group
|
|
-- @param #TASK self
|
|
-- @param #number MenuTime
|
|
-- @return #TASK
|
|
function TASK:SetMenuForGroup( TaskGroup, MenuTime )
|
|
|
|
if self:IsStatePlanned() or self:IsStateAssigned() then
|
|
self:SetPlannedMenuForGroup( TaskGroup, MenuTime )
|
|
if self:IsGroupAssigned( TaskGroup ) then
|
|
self:SetAssignedMenuForGroup( TaskGroup, MenuTime )
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
--- Set the planned menu option of the @{Task}.
|
|
-- @param #TASK self
|
|
-- @param Wrapper.Group#GROUP TaskGroup
|
|
-- @param #string MenuText The menu text.
|
|
-- @param #number MenuTime
|
|
-- @return #TASK self
|
|
function TASK:SetPlannedMenuForGroup( TaskGroup, MenuTime )
|
|
self:F( TaskGroup:GetName() )
|
|
|
|
local Mission = self:GetMission()
|
|
local MissionName = Mission:GetName()
|
|
local MissionMenu = Mission:GetMenu( TaskGroup )
|
|
|
|
local TaskType = self:GetType()
|
|
local TaskPlayerCount = self:GetPlayerCount()
|
|
local TaskPlayerString = string.format( " (%dp)", TaskPlayerCount )
|
|
local TaskText = string.format( "%s", self:GetName() )
|
|
local TaskName = string.format( "%s", self:GetName() )
|
|
|
|
self.MenuPlanned = self.MenuPlanned or {}
|
|
self.MenuPlanned[TaskGroup] = MENU_GROUP_DELAYED:New( TaskGroup, "Join Planned Task", MissionMenu, Mission.MenuReportTasksPerStatus, Mission, TaskGroup, "Planned" ):SetTime( MenuTime ):SetTag( "Tasking" )
|
|
local TaskTypeMenu = MENU_GROUP_DELAYED:New( TaskGroup, TaskType, self.MenuPlanned[TaskGroup] ):SetTime( MenuTime ):SetTag( "Tasking" )
|
|
local TaskTypeMenu = MENU_GROUP_DELAYED:New( TaskGroup, TaskText, TaskTypeMenu ):SetTime( MenuTime ):SetTag( "Tasking" )
|
|
|
|
if not Mission:IsGroupAssigned( TaskGroup ) then
|
|
--self:F( { "Replacing Join Task menu" } )
|
|
local JoinTaskMenu = MENU_GROUP_COMMAND_DELAYED:New( TaskGroup, string.format( "Join Task" ), TaskTypeMenu, self.MenuAssignToGroup, self, TaskGroup ):SetTime( MenuTime ):SetTag( "Tasking" )
|
|
local MarkTaskMenu = MENU_GROUP_COMMAND_DELAYED:New( TaskGroup, string.format( "Mark Task Location on Map" ), TaskTypeMenu, self.MenuMarkToGroup, self, TaskGroup ):SetTime( MenuTime ):SetTag( "Tasking" )
|
|
end
|
|
|
|
local ReportTaskMenu = MENU_GROUP_COMMAND_DELAYED:New( TaskGroup, string.format( "Report Task Details" ), TaskTypeMenu, self.MenuTaskStatus, self, TaskGroup ):SetTime( MenuTime ):SetTag( "Tasking" )
|
|
|
|
return self
|
|
end
|
|
|
|
--- Set the assigned menu options of the @{Task}.
|
|
-- @param #TASK self
|
|
-- @param Wrapper.Group#GROUP TaskGroup
|
|
-- @param #number MenuTime
|
|
-- @return #TASK self
|
|
function TASK:SetAssignedMenuForGroup( TaskGroup, MenuTime )
|
|
self:F( { TaskGroup:GetName(), MenuTime } )
|
|
|
|
local TaskType = self:GetType()
|
|
local TaskPlayerCount = self:GetPlayerCount()
|
|
local TaskPlayerString = string.format( " (%dp)", TaskPlayerCount )
|
|
local TaskText = string.format( "%s%s", self:GetName(), TaskPlayerString ) --, TaskThreatLevelString )
|
|
local TaskName = string.format( "%s", self:GetName() )
|
|
|
|
for UnitName, TaskUnit in pairs( TaskGroup:GetPlayerUnits() ) do
|
|
local TaskUnit = TaskUnit -- Wrapper.Unit#UNIT
|
|
if TaskUnit then
|
|
local MenuControl = self:GetTaskControlMenu( TaskUnit )
|
|
local TaskControl = MENU_GROUP:New( TaskGroup, "Control Task", MenuControl ):SetTime( MenuTime ):SetTag( "Tasking" )
|
|
if self:IsStateAssigned() then
|
|
local TaskMenu = MENU_GROUP_COMMAND:New( TaskGroup, string.format( "Abort Task" ), TaskControl, self.MenuTaskAbort, self, TaskGroup ):SetTime( MenuTime ):SetTag( "Tasking" )
|
|
end
|
|
local MarkMenu = MENU_GROUP_COMMAND:New( TaskGroup, string.format( "Mark Task Location on Map" ), TaskControl, self.MenuMarkToGroup, self, TaskGroup ):SetTime( MenuTime ):SetTag( "Tasking" )
|
|
local TaskTypeMenu = MENU_GROUP_COMMAND:New( TaskGroup, string.format( "Report Task Details" ), TaskControl, self.MenuTaskStatus, self, TaskGroup ):SetTime( MenuTime ):SetTag( "Tasking" )
|
|
if not self.FlashTaskStatus then
|
|
local TaskFlashStatusMenu = MENU_GROUP_COMMAND:New( TaskGroup, string.format( "Flash Task Details" ), TaskControl, self.MenuFlashTaskStatus, self, TaskGroup, true ):SetTime( MenuTime ):SetTag( "Tasking" )
|
|
else
|
|
local TaskFlashStatusMenu = MENU_GROUP_COMMAND:New( TaskGroup, string.format( "Stop Flash Task Details" ), TaskControl, self.MenuFlashTaskStatus, self, TaskGroup, nil ):SetTime( MenuTime ):SetTag( "Tasking" )
|
|
end
|
|
end
|
|
end
|
|
|
|
return self
|
|
end
|
|
|
|
--- Remove the menu options of the @{Task} to all the groups in the SetGroup.
|
|
-- @param #TASK self
|
|
-- @param #number MenuTime
|
|
-- @return #TASK
|
|
function TASK:RemoveMenu( MenuTime )
|
|
self:F( { self:GetName(), MenuTime } )
|
|
|
|
for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do
|
|
if TaskGroup:IsAlive() == true then
|
|
local TaskGroup = TaskGroup -- Wrapper.Group#GROUP
|
|
if TaskGroup:IsAlive() == true and TaskGroup:GetPlayerNames() then
|
|
self:RefreshMenus( TaskGroup, MenuTime )
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
--- Remove the menu option of the @{Task} for a @{Wrapper.Group}.
|
|
-- @param #TASK self
|
|
-- @param Wrapper.Group#GROUP TaskGroup
|
|
-- @param #number MenuTime
|
|
-- @return #TASK self
|
|
function TASK:RefreshMenus( TaskGroup, MenuTime )
|
|
self:F( { TaskGroup:GetName(), MenuTime } )
|
|
|
|
local Mission = self:GetMission()
|
|
local MissionName = Mission:GetName()
|
|
local MissionMenu = Mission:GetMenu( TaskGroup )
|
|
|
|
local TaskName = self:GetName()
|
|
self.MenuPlanned = self.MenuPlanned or {}
|
|
local PlannedMenu = self.MenuPlanned[TaskGroup]
|
|
|
|
self.MenuAssigned = self.MenuAssigned or {}
|
|
local AssignedMenu = self.MenuAssigned[TaskGroup]
|
|
|
|
if PlannedMenu then
|
|
self.MenuPlanned[TaskGroup] = PlannedMenu:Remove( MenuTime , "Tasking" )
|
|
PlannedMenu:Set()
|
|
end
|
|
|
|
if AssignedMenu then
|
|
self.MenuAssigned[TaskGroup] = AssignedMenu:Remove( MenuTime, "Tasking" )
|
|
AssignedMenu:Set()
|
|
end
|
|
|
|
end
|
|
|
|
--- Remove the assigned menu option of the @{Task} for a @{Wrapper.Group}.
|
|
-- @param #TASK self
|
|
-- @param Wrapper.Group#GROUP TaskGroup
|
|
-- @param #number MenuTime
|
|
-- @return #TASK self
|
|
function TASK:RemoveAssignedMenuForGroup( TaskGroup )
|
|
self:F()
|
|
|
|
local Mission = self:GetMission()
|
|
local MissionName = Mission:GetName()
|
|
local MissionMenu = Mission:GetMenu( TaskGroup )
|
|
|
|
if MissionMenu then
|
|
MissionMenu:RemoveSubMenus()
|
|
end
|
|
|
|
end
|
|
|
|
--- @param #TASK self
|
|
-- @param Wrapper.Group#GROUP TaskGroup
|
|
function TASK:MenuAssignToGroup( TaskGroup )
|
|
|
|
self:F( "Join Task menu selected")
|
|
|
|
self:AssignToGroup( TaskGroup )
|
|
end
|
|
|
|
--- @param #TASK self
|
|
-- @param Wrapper.Group#GROUP TaskGroup
|
|
function TASK:MenuMarkToGroup( TaskGroup )
|
|
self:F()
|
|
|
|
self:UpdateTaskInfo( self.DetectedItem )
|
|
|
|
local TargetCoordinates = self.TaskInfo:GetData( "Coordinates" ) -- Core.Point#COORDINATE
|
|
if TargetCoordinates then
|
|
for TargetCoordinateID, TargetCoordinate in pairs( TargetCoordinates ) do
|
|
local Report = REPORT:New():SetIndent( 0 )
|
|
self.TaskInfo:Report( Report, "M", TaskGroup, self )
|
|
local MarkText = Report:Text( ", " )
|
|
self:F( { Coordinate = TargetCoordinate, MarkText = MarkText } )
|
|
TargetCoordinate:MarkToGroup( MarkText, TaskGroup )
|
|
--Coordinate:MarkToAll( Briefing )
|
|
end
|
|
else
|
|
local TargetCoordinate = self.TaskInfo:GetData( "Coordinate" ) -- Core.Point#COORDINATE
|
|
if TargetCoordinate then
|
|
local Report = REPORT:New():SetIndent( 0 )
|
|
self.TaskInfo:Report( Report, "M", TaskGroup, self )
|
|
local MarkText = Report:Text( ", " )
|
|
self:F( { Coordinate = TargetCoordinate, MarkText = MarkText } )
|
|
TargetCoordinate:MarkToGroup( MarkText, TaskGroup )
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
--- Report the task status.
|
|
-- @param #TASK self
|
|
-- @param Wrapper.Group#GROUP TaskGroup
|
|
function TASK:MenuTaskStatus( TaskGroup )
|
|
|
|
if TaskGroup:IsAlive() then
|
|
|
|
local ReportText = self:ReportDetails( TaskGroup )
|
|
|
|
self:T( ReportText )
|
|
self:GetMission():GetCommandCenter():MessageTypeToGroup( ReportText, TaskGroup, MESSAGE.Type.Detailed )
|
|
end
|
|
|
|
end
|
|
|
|
--- Report the task status.
|
|
-- @param #TASK self
|
|
function TASK:MenuFlashTaskStatus( TaskGroup, Flash )
|
|
|
|
self.FlashTaskStatus = Flash
|
|
|
|
if self.FlashTaskStatus then
|
|
self.FlashTaskScheduler, self.FlashTaskScheduleID = SCHEDULER:New( self, self.MenuTaskStatus, { TaskGroup }, 0, 60) --Issue #1383 never ending flash messages
|
|
else
|
|
if self.FlashTaskScheduler then
|
|
self.FlashTaskScheduler:Stop( self.FlashTaskScheduleID )
|
|
self.FlashTaskScheduler = nil
|
|
self.FlashTaskScheduleID = nil
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
--- Report the task status.
|
|
-- @param #TASK self
|
|
function TASK:MenuTaskAbort( TaskGroup )
|
|
|
|
self:AbortGroup( TaskGroup )
|
|
end
|
|
|
|
|
|
|
|
--- Returns the @{Task} name.
|
|
-- @param #TASK self
|
|
-- @return #string TaskName
|
|
function TASK:GetTaskName()
|
|
return self.TaskName
|
|
end
|
|
|
|
--- Returns the @{Task} briefing.
|
|
-- @param #TASK self
|
|
-- @return #string Task briefing.
|
|
function TASK:GetTaskBriefing()
|
|
return self.TaskBriefing
|
|
end
|
|
|
|
|
|
|
|
|
|
--- Get the default or currently assigned @{Process} template with key ProcessName.
|
|
-- @param #TASK self
|
|
-- @param #string ProcessName
|
|
-- @return Core.Fsm#FSM_PROCESS
|
|
function TASK:GetProcessTemplate( ProcessName )
|
|
|
|
local ProcessTemplate = self.ProcessClasses[ProcessName]
|
|
|
|
return ProcessTemplate
|
|
end
|
|
|
|
|
|
|
|
-- TODO: Obscolete?
|
|
--- Fail processes from @{Task} with key @{Wrapper.Unit}
|
|
-- @param #TASK self
|
|
-- @param #string TaskUnitName
|
|
-- @return #TASK self
|
|
function TASK:FailProcesses( TaskUnitName )
|
|
|
|
for ProcessID, ProcessData in pairs( self.Processes[TaskUnitName] ) do
|
|
local Process = ProcessData
|
|
Process.Fsm:Fail()
|
|
end
|
|
end
|
|
|
|
--- Add a FiniteStateMachine to @{Task} with key Task@{Wrapper.Unit}
|
|
-- @param #TASK self
|
|
-- @param Wrapper.Unit#UNIT TaskUnit
|
|
-- @param Core.Fsm#FSM_PROCESS Fsm
|
|
-- @return #TASK self
|
|
function TASK:SetStateMachine( TaskUnit, Fsm )
|
|
self:F2( { TaskUnit, self.Fsm[TaskUnit] ~= nil, Fsm:GetClassNameAndID() } )
|
|
|
|
self.Fsm[TaskUnit] = Fsm
|
|
|
|
return Fsm
|
|
end
|
|
|
|
--- Gets the FiniteStateMachine of @{Task} with key Task@{Wrapper.Unit}
|
|
-- @param #TASK self
|
|
-- @param Wrapper.Unit#UNIT TaskUnit
|
|
-- @return Core.Fsm#FSM_PROCESS
|
|
function TASK:GetStateMachine( TaskUnit )
|
|
self:F2( { TaskUnit, self.Fsm[TaskUnit] ~= nil } )
|
|
|
|
return self.Fsm[TaskUnit]
|
|
end
|
|
|
|
--- Remove FiniteStateMachines from @{Task} with key Task@{Wrapper.Unit}
|
|
-- @param #TASK self
|
|
-- @param Wrapper.Unit#UNIT TaskUnit
|
|
-- @return #TASK self
|
|
function TASK:RemoveStateMachine( TaskUnit )
|
|
self:F( { TaskUnit = TaskUnit:GetName(), HasFsm = ( self.Fsm[TaskUnit] ~= nil ) } )
|
|
|
|
--self:F( self.Fsm )
|
|
--for TaskUnitT, Fsm in pairs( self.Fsm ) do
|
|
--local Fsm = Fsm -- Core.Fsm#FSM_PROCESS
|
|
--self:F( TaskUnitT )
|
|
--self.Fsm[TaskUnit] = nil
|
|
--end
|
|
|
|
if self.Fsm[TaskUnit] then
|
|
self.Fsm[TaskUnit]:Remove()
|
|
self.Fsm[TaskUnit] = nil
|
|
end
|
|
|
|
collectgarbage()
|
|
self:F( "Garbage Collected, Processes should be finalized now ...")
|
|
end
|
|
|
|
|
|
--- Checks if there is a FiniteStateMachine assigned to Task@{Wrapper.Unit} for @{Task}
|
|
-- @param #TASK self
|
|
-- @param Wrapper.Unit#UNIT TaskUnit
|
|
-- @return #TASK self
|
|
function TASK:HasStateMachine( TaskUnit )
|
|
self:F( { TaskUnit, self.Fsm[TaskUnit] ~= nil } )
|
|
|
|
return ( self.Fsm[TaskUnit] ~= nil )
|
|
end
|
|
|
|
|
|
--- Gets the Scoring of the task
|
|
-- @param #TASK self
|
|
-- @return Functional.Scoring#SCORING Scoring
|
|
function TASK:GetScoring()
|
|
return self.Mission:GetScoring()
|
|
end
|
|
|
|
|
|
--- Gets the Task Index, which is a combination of the Task type, the Task name.
|
|
-- @param #TASK self
|
|
-- @return #string The Task ID
|
|
function TASK:GetTaskIndex()
|
|
|
|
local TaskType = self:GetType()
|
|
local TaskName = self:GetName()
|
|
|
|
return TaskType .. "." .. TaskName
|
|
end
|
|
|
|
--- Sets the Name of the Task
|
|
-- @param #TASK self
|
|
-- @param #string TaskName
|
|
function TASK:SetName( TaskName )
|
|
self.TaskName = TaskName
|
|
end
|
|
|
|
--- Gets the Name of the Task
|
|
-- @param #TASK self
|
|
-- @return #string The Task Name
|
|
function TASK:GetName()
|
|
return self.TaskName
|
|
end
|
|
|
|
--- Sets the Type of the Task
|
|
-- @param #TASK self
|
|
-- @param #string TaskType
|
|
function TASK:SetType( TaskType )
|
|
self.TaskType = TaskType
|
|
end
|
|
|
|
--- Gets the Type of the Task
|
|
-- @param #TASK self
|
|
-- @return #string TaskType
|
|
function TASK:GetType()
|
|
return self.TaskType
|
|
end
|
|
|
|
--- Sets the ID of the Task
|
|
-- @param #TASK self
|
|
-- @param #string TaskID
|
|
function TASK:SetID( TaskID )
|
|
self.TaskID = TaskID
|
|
end
|
|
|
|
--- Gets the ID of the Task
|
|
-- @param #TASK self
|
|
-- @return #string TaskID
|
|
function TASK:GetID()
|
|
return self.TaskID
|
|
end
|
|
|
|
|
|
--- Sets a @{Task} to status **Success**.
|
|
-- @param #TASK self
|
|
function TASK:StateSuccess()
|
|
self:SetState( self, "State", "Success" )
|
|
return self
|
|
end
|
|
|
|
--- Is the @{Task} status **Success**.
|
|
-- @param #TASK self
|
|
function TASK:IsStateSuccess()
|
|
return self:Is( "Success" )
|
|
end
|
|
|
|
--- Sets a @{Task} to status **Failed**.
|
|
-- @param #TASK self
|
|
function TASK:StateFailed()
|
|
self:SetState( self, "State", "Failed" )
|
|
return self
|
|
end
|
|
|
|
--- Is the @{Task} status **Failed**.
|
|
-- @param #TASK self
|
|
function TASK:IsStateFailed()
|
|
return self:Is( "Failed" )
|
|
end
|
|
|
|
--- Sets a @{Task} to status **Planned**.
|
|
-- @param #TASK self
|
|
function TASK:StatePlanned()
|
|
self:SetState( self, "State", "Planned" )
|
|
return self
|
|
end
|
|
|
|
--- Is the @{Task} status **Planned**.
|
|
-- @param #TASK self
|
|
function TASK:IsStatePlanned()
|
|
return self:Is( "Planned" )
|
|
end
|
|
|
|
--- Sets a @{Task} to status **Aborted**.
|
|
-- @param #TASK self
|
|
function TASK:StateAborted()
|
|
self:SetState( self, "State", "Aborted" )
|
|
return self
|
|
end
|
|
|
|
--- Is the @{Task} status **Aborted**.
|
|
-- @param #TASK self
|
|
function TASK:IsStateAborted()
|
|
return self:Is( "Aborted" )
|
|
end
|
|
|
|
--- Sets a @{Task} to status **Cancelled**.
|
|
-- @param #TASK self
|
|
function TASK:StateCancelled()
|
|
self:SetState( self, "State", "Cancelled" )
|
|
return self
|
|
end
|
|
|
|
--- Is the @{Task} status **Cancelled**.
|
|
-- @param #TASK self
|
|
function TASK:IsStateCancelled()
|
|
return self:Is( "Cancelled" )
|
|
end
|
|
|
|
--- Sets a @{Task} to status **Assigned**.
|
|
-- @param #TASK self
|
|
function TASK:StateAssigned()
|
|
self:SetState( self, "State", "Assigned" )
|
|
return self
|
|
end
|
|
|
|
--- Is the @{Task} status **Assigned**.
|
|
-- @param #TASK self
|
|
function TASK:IsStateAssigned()
|
|
return self:Is( "Assigned" )
|
|
end
|
|
|
|
--- Sets a @{Task} to status **Hold**.
|
|
-- @param #TASK self
|
|
function TASK:StateHold()
|
|
self:SetState( self, "State", "Hold" )
|
|
return self
|
|
end
|
|
|
|
--- Is the @{Task} status **Hold**.
|
|
-- @param #TASK self
|
|
function TASK:IsStateHold()
|
|
return self:Is( "Hold" )
|
|
end
|
|
|
|
--- Sets a @{Task} to status **Replanned**.
|
|
-- @param #TASK self
|
|
function TASK:StateReplanned()
|
|
self:SetState( self, "State", "Replanned" )
|
|
return self
|
|
end
|
|
|
|
--- Is the @{Task} status **Replanned**.
|
|
-- @param #TASK self
|
|
function TASK:IsStateReplanned()
|
|
return self:Is( "Replanned" )
|
|
end
|
|
|
|
--- Gets the @{Task} status.
|
|
-- @param #TASK self
|
|
function TASK:GetStateString()
|
|
return self:GetState( self, "State" )
|
|
end
|
|
|
|
--- Sets a @{Task} briefing.
|
|
-- @param #TASK self
|
|
-- @param #string TaskBriefing
|
|
-- @return #TASK self
|
|
function TASK:SetBriefing( TaskBriefing )
|
|
self:F(TaskBriefing)
|
|
self.TaskBriefing = TaskBriefing
|
|
return self
|
|
end
|
|
|
|
--- Gets the @{Task} briefing.
|
|
-- @param #TASK self
|
|
-- @return #string The briefing text.
|
|
function TASK:GetBriefing()
|
|
return self.TaskBriefing
|
|
end
|
|
|
|
|
|
|
|
|
|
--- FSM function for a TASK
|
|
-- @param #TASK self
|
|
-- @param #string Event
|
|
-- @param #string From
|
|
-- @param #string To
|
|
function TASK:onenterAssigned( From, Event, To, PlayerUnit, PlayerName )
|
|
|
|
--- This test is required, because the state transition will be fired also when the state does not change in case of an event.
|
|
if From ~= "Assigned" then
|
|
|
|
local PlayerNames = self:GetPlayerNames()
|
|
local PlayerText = REPORT:New()
|
|
for PlayerName, TaskName in pairs( PlayerNames ) do
|
|
PlayerText:Add( PlayerName )
|
|
end
|
|
|
|
self:GetMission():GetCommandCenter():MessageToCoalition( "Task " .. self:GetName() .. " is assigned to players " .. PlayerText:Text(",") .. ". Good Luck!" )
|
|
|
|
-- Set the total Progress to be achieved.
|
|
self:SetGoalTotal() -- Polymorphic to set the initial goal total!
|
|
|
|
if self.Dispatcher then
|
|
self:F( "Firing Assign event " )
|
|
self.Dispatcher:Assign( self, PlayerUnit, PlayerName )
|
|
end
|
|
|
|
self:GetMission():__Start( 1 )
|
|
|
|
-- When the task is assigned, the task goal needs to be checked of the derived classes.
|
|
self:__Goal( -10, PlayerUnit, PlayerName ) -- Polymorphic
|
|
|
|
self:SetMenu()
|
|
|
|
self:F( { "--> Task Assigned", TaskName = self:GetName(), Mission = self:GetMission():GetName() } )
|
|
self:F( { "--> Task Player Names", PlayerNames = PlayerNames } )
|
|
|
|
end
|
|
end
|
|
|
|
|
|
--- FSM function for a TASK
|
|
-- @param #TASK self
|
|
-- @param #string Event
|
|
-- @param #string From
|
|
-- @param #string To
|
|
function TASK:onenterSuccess( From, Event, To )
|
|
|
|
self:F( { "<-> Task Replanned", TaskName = self:GetName(), Mission = self:GetMission():GetName() } )
|
|
self:F( { "<-> Task Player Names", PlayerNames = self:GetPlayerNames() } )
|
|
|
|
self:GetMission():GetCommandCenter():MessageToCoalition( "Task " .. self:GetName() .. " is successful! Good job!" )
|
|
self:UnAssignFromGroups()
|
|
|
|
self:GetMission():__MissionGoals( 1 )
|
|
|
|
end
|
|
|
|
|
|
--- FSM function for a TASK
|
|
-- @param #TASK self
|
|
-- @param #string From
|
|
-- @param #string Event
|
|
-- @param #string To
|
|
function TASK:onenterAborted( From, Event, To )
|
|
|
|
self:F( { "<-- Task Aborted", TaskName = self:GetName(), Mission = self:GetMission():GetName() } )
|
|
self:F( { "<-- Task Player Names", PlayerNames = self:GetPlayerNames() } )
|
|
|
|
if From ~= "Aborted" then
|
|
self:GetMission():GetCommandCenter():MessageToCoalition( "Task " .. self:GetName() .. " has been aborted! Task may be replanned." )
|
|
self:__Replan( 5 )
|
|
self:SetMenu()
|
|
end
|
|
|
|
end
|
|
|
|
|
|
--- FSM function for a TASK
|
|
-- @param #TASK self
|
|
-- @param #string From
|
|
-- @param #string Event
|
|
-- @param #string To
|
|
function TASK:onenterCancelled( From, Event, To )
|
|
|
|
self:F( { "<-- Task Cancelled", TaskName = self:GetName(), Mission = self:GetMission():GetName() } )
|
|
self:F( { "<-- Player Names", PlayerNames = self:GetPlayerNames() } )
|
|
|
|
if From ~= "Cancelled" then
|
|
self:GetMission():GetCommandCenter():MessageToCoalition( "Task " .. self:GetName() .. " has been cancelled! The tactical situation has changed." )
|
|
self:UnAssignFromGroups()
|
|
self:SetMenu()
|
|
end
|
|
|
|
end
|
|
|
|
--- FSM function for a TASK
|
|
-- @param #TASK self
|
|
-- @param #string From
|
|
-- @param #string Event
|
|
-- @param #string To
|
|
function TASK:onafterReplan( From, Event, To )
|
|
|
|
self:F( { "Task Replanned", TaskName = self:GetName(), Mission = self:GetMission():GetName() } )
|
|
self:F( { "Task Player Names", PlayerNames = self:GetPlayerNames() } )
|
|
|
|
self:GetMission():GetCommandCenter():MessageToCoalition( "Replanning Task " .. self:GetName() .. "." )
|
|
|
|
self:SetMenu()
|
|
|
|
end
|
|
|
|
--- FSM function for a TASK
|
|
-- @param #TASK self
|
|
-- @param #string From
|
|
-- @param #string Event
|
|
-- @param #string To
|
|
function TASK:onenterFailed( From, Event, To )
|
|
|
|
self:F( { "Task Failed", TaskName = self:GetName(), Mission = self:GetMission():GetName() } )
|
|
self:F( { "Task Player Names", PlayerNames = self:GetPlayerNames() } )
|
|
|
|
self:GetMission():GetCommandCenter():MessageToCoalition( "Task " .. self:GetName() .. " has failed!" )
|
|
|
|
self:UnAssignFromGroups()
|
|
end
|
|
|
|
--- FSM function for a TASK
|
|
-- @param #TASK self
|
|
-- @param #string Event
|
|
-- @param #string From
|
|
-- @param #string To
|
|
function TASK:onstatechange( From, Event, To )
|
|
|
|
if self:IsTrace() then
|
|
--MESSAGE:New( "@ Task " .. self.TaskName .. " : " .. From .. " changed to " .. To .. " by " .. Event, 2 ):ToAll()
|
|
end
|
|
|
|
if self.Scores[To] then
|
|
local Scoring = self:GetScoring()
|
|
if Scoring then
|
|
self:F( { self.Scores[To].ScoreText, self.Scores[To].Score } )
|
|
Scoring:_AddMissionScore( self.Mission, self.Scores[To].ScoreText, self.Scores[To].Score )
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
--- FSM function for a TASK
|
|
-- @param #TASK self
|
|
-- @param #string Event
|
|
-- @param #string From
|
|
-- @param #string To
|
|
function TASK:onenterPlanned( From, Event, To)
|
|
if not self.TimeOut == 0 then
|
|
self.__TimeOut( self.TimeOut )
|
|
end
|
|
end
|
|
|
|
--- FSM function for a TASK
|
|
-- @param #TASK self
|
|
-- @param #string Event
|
|
-- @param #string From
|
|
-- @param #string To
|
|
function TASK:onbeforeTimeOut( From, Event, To )
|
|
if From == "Planned" then
|
|
self:RemoveMenu()
|
|
return true
|
|
end
|
|
return false
|
|
end
|
|
|
|
do -- Links
|
|
|
|
--- Set goal of a task
|
|
-- @param #TASK self
|
|
-- @param Core.Goal#GOAL Goal
|
|
-- @return #TASK
|
|
function TASK:SetGoal( Goal )
|
|
self.Goal = Goal
|
|
end
|
|
|
|
|
|
--- Get goal of a task
|
|
-- @param #TASK self
|
|
-- @return Core.Goal#GOAL The Goal
|
|
function TASK:GetGoal()
|
|
return self.Goal
|
|
end
|
|
|
|
|
|
--- Set dispatcher of a task
|
|
-- @param #TASK self
|
|
-- @param Tasking.DetectionManager#DETECTION_MANAGER Dispatcher
|
|
-- @return #TASK
|
|
function TASK:SetDispatcher( Dispatcher )
|
|
self.Dispatcher = Dispatcher
|
|
end
|
|
|
|
--- Set detection of a task
|
|
-- @param #TASK self
|
|
-- @param Function.Detection#DETECTION_BASE Detection
|
|
-- @param DetectedItem
|
|
-- @return #TASK
|
|
function TASK:SetDetection( Detection, DetectedItem )
|
|
|
|
self:F( { DetectedItem, Detection } )
|
|
|
|
self.Detection = Detection
|
|
self.DetectedItem = DetectedItem
|
|
end
|
|
|
|
end
|
|
|
|
do -- Reporting
|
|
|
|
--- Create a summary report of the Task.
|
|
-- List the Task Name and Status
|
|
-- @param #TASK self
|
|
-- @param Wrapper.Group#GROUP ReportGroup
|
|
-- @return #string
|
|
function TASK:ReportSummary( ReportGroup )
|
|
|
|
self:UpdateTaskInfo( self.DetectedItem )
|
|
|
|
local Report = REPORT:New()
|
|
|
|
-- List the name of the Task.
|
|
Report:Add( "Task " .. self:GetName() )
|
|
|
|
-- Determine the status of the Task.
|
|
Report:Add( "State: <" .. self:GetState() .. ">" )
|
|
|
|
self.TaskInfo:Report( Report, "S", ReportGroup, self )
|
|
|
|
return Report:Text( ', ' )
|
|
end
|
|
|
|
--- Create an overiew report of the Task.
|
|
-- List the Task Name and Status
|
|
-- @param #TASK self
|
|
-- @return #string
|
|
function TASK:ReportOverview( ReportGroup )
|
|
|
|
self:UpdateTaskInfo( self.DetectedItem )
|
|
|
|
-- List the name of the Task.
|
|
local TaskName = self:GetName()
|
|
local Report = REPORT:New()
|
|
|
|
self.TaskInfo:Report( Report, "O", ReportGroup, self )
|
|
|
|
return Report:Text()
|
|
end
|
|
|
|
--- Create a count of the players in the Task.
|
|
-- @param #TASK self
|
|
-- @return #number The total number of players in the task.
|
|
function TASK:GetPlayerCount() --R2.1 Get a count of the players.
|
|
|
|
local PlayerCount = 0
|
|
|
|
-- Loop each Unit active in the Task, and find Player Names.
|
|
for TaskGroupID, PlayerGroup in pairs( self:GetGroups():GetSet() ) do
|
|
local PlayerGroup = PlayerGroup -- Wrapper.Group#GROUP
|
|
if PlayerGroup:IsAlive() == true then
|
|
if self:IsGroupAssigned( PlayerGroup ) then
|
|
local PlayerNames = PlayerGroup:GetPlayerNames()
|
|
PlayerCount = PlayerCount + ((PlayerNames) and #PlayerNames or 0) -- PlayerNames can be nil when there are no players.
|
|
end
|
|
end
|
|
end
|
|
|
|
return PlayerCount
|
|
end
|
|
|
|
|
|
--- Create a list of the players in the Task.
|
|
-- @param #TASK self
|
|
-- @return #map<#string,Wrapper.Group#GROUP> A map of the players
|
|
function TASK:GetPlayerNames() --R2.1 Get a map of the players.
|
|
|
|
local PlayerNameMap = {}
|
|
|
|
-- Loop each Unit active in the Task, and find Player Names.
|
|
for TaskGroupID, PlayerGroup in pairs( self:GetGroups():GetSet() ) do
|
|
local PlayerGroup = PlayerGroup -- Wrapper.Group#GROUP
|
|
if PlayerGroup:IsAlive() == true then
|
|
if self:IsGroupAssigned( PlayerGroup ) then
|
|
local PlayerNames = PlayerGroup:GetPlayerNames()
|
|
for PlayerNameID, PlayerName in pairs( PlayerNames or {} ) do
|
|
PlayerNameMap[PlayerName] = PlayerGroup
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
return PlayerNameMap
|
|
end
|
|
|
|
|
|
--- Create a detailed report of the Task.
|
|
-- List the Task Status, and the Players assigned to the Task.
|
|
-- @param #TASK self
|
|
-- @param Wrapper.Group#GROUP TaskGroup
|
|
-- @return #string
|
|
function TASK:ReportDetails( ReportGroup )
|
|
|
|
self:UpdateTaskInfo( self.DetectedItem )
|
|
|
|
local Report = REPORT:New():SetIndent( 3 )
|
|
|
|
-- List the name of the Task.
|
|
local Name = self:GetName()
|
|
|
|
-- Determine the status of the Task.
|
|
local Status = "<" .. self:GetState() .. ">"
|
|
|
|
Report:Add( "Task " .. Name .. " - " .. Status .. " - Detailed Report" )
|
|
|
|
-- Loop each Unit active in the Task, and find Player Names.
|
|
local PlayerNames = self:GetPlayerNames()
|
|
|
|
local PlayerReport = REPORT:New()
|
|
for PlayerName, PlayerGroup in pairs( PlayerNames ) do
|
|
PlayerReport:Add( "Players group " .. PlayerGroup:GetCallsign() .. ": " .. PlayerName )
|
|
end
|
|
local Players = PlayerReport:Text()
|
|
|
|
if Players ~= "" then
|
|
Report:AddIndent( "Players assigned:", "-" )
|
|
Report:AddIndent( Players )
|
|
end
|
|
|
|
self.TaskInfo:Report( Report, "D", ReportGroup, self )
|
|
|
|
return Report:Text()
|
|
end
|
|
|
|
|
|
end -- Reporting
|
|
|
|
|
|
do -- Additional Task Scoring and Task Progress
|
|
|
|
--- Add Task Progress for a Player Name
|
|
-- @param #TASK self
|
|
-- @param #string PlayerName The name of the player.
|
|
-- @param #string ProgressText The text that explains the Progress achieved.
|
|
-- @param #number ProgressTime The time the progress was achieved.
|
|
-- @oaram #number ProgressPoints The amount of points of magnitude granted. This will determine the shared Mission Success scoring.
|
|
-- @return #TASK
|
|
function TASK:AddProgress( PlayerName, ProgressText, ProgressTime, ProgressPoints )
|
|
self.TaskProgress = self.TaskProgress or {}
|
|
self.TaskProgress[ProgressTime] = self.TaskProgress[ProgressTime] or {}
|
|
self.TaskProgress[ProgressTime].PlayerName = PlayerName
|
|
self.TaskProgress[ProgressTime].ProgressText = ProgressText
|
|
self.TaskProgress[ProgressTime].ProgressPoints = ProgressPoints
|
|
self:GetMission():AddPlayerName( PlayerName )
|
|
return self
|
|
end
|
|
|
|
function TASK:GetPlayerProgress( PlayerName )
|
|
local ProgressPlayer = 0
|
|
for ProgressTime, ProgressData in pairs( self.TaskProgress ) do
|
|
if PlayerName == ProgressData.PlayerName then
|
|
ProgressPlayer = ProgressPlayer + ProgressData.ProgressPoints
|
|
end
|
|
end
|
|
return ProgressPlayer
|
|
end
|
|
|
|
--- Set a score when progress has been made by the player.
|
|
-- @param #TASK self
|
|
-- @param #string PlayerName The name of the player.
|
|
-- @param #number Score The score in points to be granted when task process has been achieved.
|
|
-- @param Wrapper.Unit#UNIT TaskUnit
|
|
-- @return #TASK
|
|
function TASK:SetScoreOnProgress( PlayerName, Score, TaskUnit )
|
|
self:F( { PlayerName, Score, TaskUnit } )
|
|
|
|
local ProcessUnit = self:GetUnitProcess( TaskUnit )
|
|
|
|
ProcessUnit:AddScoreProcess( "Engaging", "Account", "AccountPlayer", "Player " .. PlayerName .. " has achieved progress.", Score )
|
|
|
|
return self
|
|
end
|
|
|
|
--- Set a score when all the targets in scope of the A2A attack, have been destroyed.
|
|
-- @param #TASK self
|
|
-- @param #string PlayerName The name of the player.
|
|
-- @param #number Score The score in points.
|
|
-- @param Wrapper.Unit#UNIT TaskUnit
|
|
-- @return #TASK
|
|
function TASK:SetScoreOnSuccess( PlayerName, Score, TaskUnit )
|
|
self:F( { PlayerName, Score, TaskUnit } )
|
|
|
|
local ProcessUnit = self:GetUnitProcess( TaskUnit )
|
|
|
|
ProcessUnit:AddScore( "Success", "The task is a success!", Score )
|
|
|
|
return self
|
|
end
|
|
|
|
--- Set a penalty when the A2A attack has failed.
|
|
-- @param #TASK self
|
|
-- @param #string PlayerName The name of the player.
|
|
-- @param #number Penalty The penalty in points, must be a negative value!
|
|
-- @param Wrapper.Unit#UNIT TaskUnit
|
|
-- @return #TASK
|
|
function TASK:SetScoreOnFail( PlayerName, Penalty, TaskUnit )
|
|
self:F( { PlayerName, Penalty, TaskUnit } )
|
|
|
|
local ProcessUnit = self:GetUnitProcess( TaskUnit )
|
|
|
|
ProcessUnit:AddScore( "Failed", "The task is a failure!", Penalty )
|
|
|
|
return self
|
|
end
|
|
|
|
end
|
|
|
|
do -- Task Control Menu
|
|
|
|
-- The Task Control Menu is a menu attached to the task at the main menu to quickly be able to do actions in the task.
|
|
-- The Task Control Menu can only be shown when the task is assigned to the player.
|
|
-- The Task Control Menu is linked to the process executing the task, so no task menu can be set to the main static task definition.
|
|
|
|
--- Init Task Control Menu
|
|
-- @param #TASK self
|
|
-- @param Wrapper.Unit#UNIT TaskUnit The @{Wrapper.Unit} that contains a player.
|
|
-- @return Task Control Menu Refresh ID
|
|
function TASK:InitTaskControlMenu( TaskUnit )
|
|
|
|
self.TaskControlMenuTime = timer.getTime()
|
|
|
|
return self.TaskControlMenuTime
|
|
end
|
|
|
|
--- Get Task Control Menu
|
|
-- @param #TASK self
|
|
-- @param Wrapper.Unit#UNIT TaskUnit The @{Wrapper.Unit} that contains a player.
|
|
-- @return Core.Menu#MENU_GROUP TaskControlMenu The Task Control Menu
|
|
function TASK:GetTaskControlMenu( TaskUnit, TaskName )
|
|
|
|
TaskName = TaskName or ""
|
|
|
|
local TaskGroup = TaskUnit:GetGroup()
|
|
local TaskPlayerCount = TaskGroup:GetPlayerCount()
|
|
|
|
if TaskPlayerCount <= 1 then
|
|
self.TaskControlMenu = MENU_GROUP:New( TaskUnit:GetGroup(), "Task " .. self:GetName() .. " control" ):SetTime( self.TaskControlMenuTime )
|
|
else
|
|
self.TaskControlMenu = MENU_GROUP:New( TaskUnit:GetGroup(), "Task " .. self:GetName() .. " control for " .. TaskUnit:GetPlayerName() ):SetTime( self.TaskControlMenuTime )
|
|
end
|
|
|
|
return self.TaskControlMenu
|
|
end
|
|
|
|
--- Remove Task Control Menu
|
|
-- @param #TASK self
|
|
-- @param Wrapper.Unit#UNIT TaskUnit The @{Wrapper.Unit} that contains a player.
|
|
function TASK:RemoveTaskControlMenu( TaskUnit )
|
|
|
|
if self.TaskControlMenu then
|
|
self.TaskControlMenu:Remove()
|
|
self.TaskControlMenu = nil
|
|
end
|
|
end
|
|
|
|
--- Refresh Task Control Menu
|
|
-- @param #TASK self
|
|
-- @param Wrapper.Unit#UNIT TaskUnit The @{Wrapper.Unit} that contains a player.
|
|
-- @param MenuTime The refresh time that was used to refresh the Task Control Menu items.
|
|
-- @param MenuTag The tag.
|
|
function TASK:RefreshTaskControlMenu( TaskUnit, MenuTime, MenuTag )
|
|
|
|
if self.TaskControlMenu then
|
|
self.TaskControlMenu:Remove( MenuTime, MenuTag )
|
|
end
|
|
end
|
|
|
|
end
|