mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-10-29 16:58:06 +00:00
Merge branch 'feature/Feature-AI_Cargo_Dispatching_Airplane' into FF/Develop
This commit is contained in:
commit
d3273b631f
@ -114,6 +114,18 @@ function AI_CARGO_AIRPLANE:New( Airplane, CargoSet )
|
||||
end
|
||||
|
||||
|
||||
function AI_CARGO_AIRPLANE:IsTransporting()
|
||||
|
||||
return self.Transporting == true
|
||||
end
|
||||
|
||||
function AI_CARGO_AIRPLANE:IsRelocating()
|
||||
|
||||
return self.Relocating == true
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Set the Carrier.
|
||||
-- @param #AI_CARGO_AIRPLANE self
|
||||
-- @param Wrapper.Group#GROUP Airplane
|
||||
@ -158,7 +170,8 @@ function AI_CARGO_AIRPLANE:SetCarrier( Airplane )
|
||||
|
||||
|
||||
function Airplane:OnEventEngineShutdown( EventData )
|
||||
AICargo:Landed()
|
||||
self:F("Calling")
|
||||
AICargo:Landed( self.Airplane )
|
||||
end
|
||||
|
||||
self.Coalition = self.Airplane:GetCoalition()
|
||||
@ -201,6 +214,10 @@ end
|
||||
-- @param To
|
||||
function AI_CARGO_AIRPLANE:onafterLanded( Airplane, From, Event, To )
|
||||
|
||||
self:F({Airplane, From, Event, To})
|
||||
self:F({IsAlive=Airplane:IsAlive()})
|
||||
self:F({RoutePickup=self.RoutePickup})
|
||||
|
||||
if Airplane and Airplane:IsAlive() then
|
||||
|
||||
if self.RoutePickup == true then
|
||||
@ -240,6 +257,8 @@ function AI_CARGO_AIRPLANE:onafterPickup( Airplane, From, Event, To, Airbase, Sp
|
||||
|
||||
-- Set airbase as starting point in the next Route() call.
|
||||
self.Airbase = Airbase
|
||||
self.Transporting = true
|
||||
self.Relocating = false
|
||||
end
|
||||
|
||||
end
|
||||
@ -260,6 +279,8 @@ function AI_CARGO_AIRPLANE:onafterDeploy( Airplane, From, Event, To, Airbase, Sp
|
||||
self:Route( Airplane, Airbase, Speed )
|
||||
self.RouteDeploy = true
|
||||
self.Airbase = Airbase
|
||||
self.Transporting = false
|
||||
self.Relocating = false
|
||||
end
|
||||
|
||||
end
|
||||
@ -278,8 +299,9 @@ function AI_CARGO_AIRPLANE:onafterLoad( Airplane, From, Event, To, Coordinate )
|
||||
--if Airplane then
|
||||
|
||||
for _, Cargo in pairs( self.CargoSet:GetSet() ) do
|
||||
local Cargo=Cargo --Cargo.Cargo#CARGO
|
||||
if Cargo:IsInLoadRadius( Coordinate ) then
|
||||
self:F({Cargo:GetName()})
|
||||
local InRadius = Cargo:IsInLoadRadius( Coordinate )
|
||||
if InRadius then
|
||||
self:__Board( 5 )
|
||||
Cargo:Board( Airplane, 25 )
|
||||
self.Cargo = Cargo
|
||||
@ -399,6 +421,7 @@ function AI_CARGO_AIRPLANE:Route( Airplane, Airbase, Speed )
|
||||
FromWaypoint.helipadId = nil
|
||||
FromWaypoint.airdromeId = nil
|
||||
|
||||
local ParkingSpots = self.Airbase:FindFreeParkingSpotForAircraft( Airplane, AIRBASE.TerminalType.OpenBig )
|
||||
local AirbaseID = self.Airbase:GetID()
|
||||
local AirbaseCategory = self.Airbase:GetDesc().category
|
||||
|
||||
@ -417,8 +440,8 @@ function AI_CARGO_AIRPLANE:Route( Airplane, Airbase, Speed )
|
||||
-- These cause a lot of confusion.
|
||||
local UnitTemplate = Template.units[UnitID]
|
||||
|
||||
UnitTemplate.parking = 15
|
||||
UnitTemplate.parking_id = "1"
|
||||
UnitTemplate.parking = nil
|
||||
UnitTemplate.parking_id = nil
|
||||
UnitTemplate.alt = 0
|
||||
|
||||
local SX = UnitTemplate.x
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
-- ===
|
||||
--
|
||||
-- @module AI.AI_Cargo_Dispatcher
|
||||
-- @image AI_Cargo_Dispatching_For_Helicopters.JPG
|
||||
-- @image AI_Cargo_Dispatcher.JPG
|
||||
|
||||
--- @type AI_CARGO_DISPATCHER
|
||||
-- @extends Core.Fsm#FSM
|
||||
@ -74,7 +74,7 @@
|
||||
AI_CARGO_DISPATCHER = {
|
||||
ClassName = "AI_CARGO_DISPATCHER",
|
||||
SetCarrier = nil,
|
||||
SetDeployZones = nil,
|
||||
DeployZonesSet = nil,
|
||||
AI_Cargo = {},
|
||||
PickupCargo = {}
|
||||
}
|
||||
@ -90,23 +90,21 @@ AI_CARGO_DISPATCHER.PickupCargo = {}
|
||||
-- @param #AI_CARGO_DISPATCHER self
|
||||
-- @param Core.Set#SET_GROUP SetCarrier
|
||||
-- @param Core.Set#SET_CARGO SetCargo
|
||||
-- @param Core.Set#SET_ZONE SetDeployZones
|
||||
-- @return #AI_CARGO_DISPATCHER
|
||||
-- @usage
|
||||
--
|
||||
-- -- Create a new cargo dispatcher
|
||||
-- SetCarrier = SET_GROUP:New():FilterPrefixes( "APC" ):FilterStart()
|
||||
-- SetCargo = SET_CARGO:New():FilterTypes( "Infantry" ):FilterStart()
|
||||
-- SetCarriers = SET_GROUP:New():FilterPrefixes( "APC" ):FilterStart()
|
||||
-- SetCargos = SET_CARGO:New():FilterTypes( "Infantry" ):FilterStart()
|
||||
-- SetDeployZone = SET_ZONE:New():FilterPrefixes( "Deploy" ):FilterStart()
|
||||
-- AICargoDispatcher = AI_CARGO_DISPATCHER:New( SetCarrier, SetCargo, SetDeployZone )
|
||||
-- AICargoDispatcher = AI_CARGO_DISPATCHER:New( SetCarrier, SetCargo )
|
||||
--
|
||||
function AI_CARGO_DISPATCHER:New( SetCarrier, SetCargo, SetDeployZones )
|
||||
function AI_CARGO_DISPATCHER:New( SetCarrier, SetCargo )
|
||||
|
||||
local self = BASE:Inherit( self, FSM:New() ) -- #AI_CARGO_DISPATCHER
|
||||
|
||||
self.SetCarrier = SetCarrier -- Core.Set#SET_GROUP
|
||||
self.SetCargo = SetCargo -- Core.Set#SET_CARGO
|
||||
self.SetDeployZones = SetDeployZones -- Core.Set#SET_ZONE
|
||||
|
||||
self:SetStartState( "Idle" )
|
||||
|
||||
@ -144,6 +142,58 @@ function AI_CARGO_DISPATCHER:New( SetCarrier, SetCargo, SetDeployZones )
|
||||
end
|
||||
|
||||
|
||||
--- Creates a new AI_CARGO_DISPATCHER object.
|
||||
-- @param #AI_CARGO_DISPATCHER self
|
||||
-- @param Core.Set#SET_GROUP SetCarrier
|
||||
-- @param Core.Set#SET_CARGO SetCargo
|
||||
-- @param Core.Set#SET_ZONE DeployZonesSet
|
||||
-- @return #AI_CARGO_DISPATCHER
|
||||
-- @usage
|
||||
--
|
||||
-- -- Create a new cargo dispatcher
|
||||
-- SetCarriers = SET_GROUP:New():FilterPrefixes( "APC" ):FilterStart()
|
||||
-- SetCargos = SET_CARGO:New():FilterTypes( "Infantry" ):FilterStart()
|
||||
-- DeployZonesSet = SET_ZONE:New():FilterPrefixes( "Deploy" ):FilterStart()
|
||||
-- AICargoDispatcher = AI_CARGO_DISPATCHER:New( SetCarrier, SetCargo, SetDeployZone )
|
||||
--
|
||||
function AI_CARGO_DISPATCHER:NewWithZones( SetCarriers, SetCargos, DeployZonesSet )
|
||||
|
||||
local self = AI_CARGO_DISPATCHER:New( SetCarriers, SetCargos ) -- #AI_CARGO_DISPATCHER
|
||||
|
||||
self.DeployZonesSet = DeployZonesSet
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Creates a new AI_CARGO_DISPATCHER object.
|
||||
-- @param #AI_CARGO_DISPATCHER self
|
||||
-- @param Core.Set#SET_GROUP SetCarrier
|
||||
-- @param Core.Set#SET_CARGO SetCargo
|
||||
-- @param Core.Set#SET_AIRBASE PickupAirbasesSet
|
||||
-- @param Core.Set#SET_AIRBASE DeployAirbasesSet
|
||||
-- @return #AI_CARGO_DISPATCHER
|
||||
-- @usage
|
||||
--
|
||||
-- -- Create a new cargo dispatcher
|
||||
-- SetCarriers = SET_GROUP:New():FilterPrefixes( "APC" ):FilterStart()
|
||||
-- SetCargos = SET_CARGO:New():FilterTypes( "Infantry" ):FilterStart()
|
||||
-- PickupAirbasesSet = SET_AIRBASES:New()
|
||||
-- DeployAirbasesSet = SET_AIRBASES:New()
|
||||
-- AICargoDispatcher = AI_CARGO_DISPATCHER:New( SetCarrier, SetCargo, PickupAirbasesSet, DeployAirbasesSet )
|
||||
--
|
||||
function AI_CARGO_DISPATCHER:NewWithAirbases( SetCarriers, SetCargos, PickupAirbasesSet, DeployAirbasesSet )
|
||||
|
||||
local self = AI_CARGO_DISPATCHER:New( SetCarriers, SetCargos ) -- #AI_CARGO_DISPATCHER
|
||||
|
||||
self.DeployAirbasesSet = DeployAirbasesSet
|
||||
self.PickupAirbasesSet = PickupAirbasesSet
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Set the home zone.
|
||||
-- When there is nothing anymore to pickup, the carriers will go to a random coordinate in this zone.
|
||||
-- They will await here new orders.
|
||||
@ -361,7 +411,16 @@ function AI_CARGO_DISPATCHER:onafterMonitor()
|
||||
if PickupCargo then
|
||||
self.CarrierHome[Carrier] = nil
|
||||
local PickupCoordinate = PickupCargo:GetCoordinate():GetRandomCoordinateInRadius( self.PickupOuterRadius, self.PickupInnerRadius )
|
||||
AI_Cargo:Pickup( PickupCoordinate, math.random( self.PickupMinSpeed, self.PickupMaxSpeed ) )
|
||||
|
||||
if self.PickupAirbasesSet then
|
||||
-- Find airbase within 2km from the cargo with the set.
|
||||
local PickupAirbase = self.PickupAirbasesSet:FindAirbaseInRange( PickupCoordinate, 4000 )
|
||||
if PickupAirbase then
|
||||
AI_Cargo:Pickup( PickupAirbase, math.random( self.PickupMinSpeed, self.PickupMaxSpeed ) )
|
||||
end
|
||||
else
|
||||
AI_Cargo:Pickup( PickupCoordinate, math.random( self.PickupMinSpeed, self.PickupMaxSpeed ) )
|
||||
end
|
||||
break
|
||||
else
|
||||
if self.HomeZone then
|
||||
@ -464,12 +523,22 @@ end
|
||||
-- @return #AI_CARGO_DISPATCHER
|
||||
function AI_CARGO_DISPATCHER:OnAfterLoaded( From, Event, To, Carrier, Cargo )
|
||||
|
||||
local DeployZone = self.SetDeployZones:GetRandomZone()
|
||||
if self.DeployZonesSet then
|
||||
|
||||
local DeployCoordinate = DeployZone:GetCoordinate():GetRandomCoordinateInRadius( self.DeployOuterRadius, self.DeployInnerRadius )
|
||||
self.AI_Cargo[Carrier]:Deploy( DeployCoordinate, math.random( self.DeployMinSpeed, self.DeployMaxSpeed ) )
|
||||
local DeployZone = self.DeployZonesSet:GetRandomZone()
|
||||
|
||||
local DeployCoordinate = DeployZone:GetCoordinate():GetRandomCoordinateInRadius( self.DeployOuterRadius, self.DeployInnerRadius )
|
||||
self.AI_Cargo[Carrier]:Deploy( DeployCoordinate, math.random( self.DeployMinSpeed, self.DeployMaxSpeed ) )
|
||||
|
||||
self.PickupCargo[Carrier] = nil
|
||||
end
|
||||
|
||||
if self.DeployAirbasesSet then
|
||||
|
||||
local DeployAirbase = self.DeployAirbasesSet:GetRandomAirbase()
|
||||
self.AI_Cargo[Carrier]:Deploy( DeployAirbase, math.random( self.DeployMinSpeed, self.DeployMaxSpeed ) )
|
||||
end
|
||||
|
||||
self.PickupCargo[Carrier] = nil
|
||||
end
|
||||
|
||||
|
||||
|
||||
@ -101,7 +101,7 @@ AI_CARGO_DISPATCHER_APC = {
|
||||
-- SetDeployZone = SET_ZONE:New():FilterPrefixes( "Deploy" ):FilterStart()
|
||||
-- AICargoDispatcher = AI_CARGO_DISPATCHER_APC:New( SetAPC, SetCargo, SetDeployZone, 500 )
|
||||
--
|
||||
function AI_CARGO_DISPATCHER_APC:New( SetAPC, SetCargo, SetDeployZone, CombatRadius )
|
||||
function AI_CARGO_DISPATCHER_APC:NewWithZones( SetAPC, SetCargo, SetDeployZone, CombatRadius )
|
||||
|
||||
local self = BASE:Inherit( self, AI_CARGO_DISPATCHER:New( SetAPC, SetCargo, SetDeployZone ) ) -- #AI_CARGO_DISPATCHER_APC
|
||||
|
||||
|
||||
@ -16,8 +16,8 @@
|
||||
--- Brings a dynamic cargo handling capability for AI groups.
|
||||
--
|
||||
-- Airplanes can be mobilized to intelligently transport infantry and other cargo within the simulation.
|
||||
-- The AI\_CARGO\_DISPATCHER\_AIRPLANE module uses the @{Cargo} capabilities within the MOOSE framework.
|
||||
-- CARGO derived objects must be declared within the mission to make the AI\_CARGO\_DISPATCHER\_AIRPLANE object recognize the cargo.
|
||||
-- The AI_CARGO_DISPATCHER_AIRPLANE module uses the @{Cargo} capabilities within the MOOSE framework.
|
||||
-- CARGO derived objects must be declared within the mission to make the AI_CARGO_DISPATCHER_AIRPLANE object recognize the cargo.
|
||||
-- Please consult the @{Cargo} module for more information.
|
||||
--
|
||||
--
|
||||
@ -29,23 +29,33 @@ AI_CARGO_DISPATCHER_AIRPLANE = {
|
||||
|
||||
--- Creates a new AI_CARGO_DISPATCHER_AIRPLANE object.
|
||||
-- @param #AI_CARGO_DISPATCHER_AIRPLANE self
|
||||
-- @param Core.Set#SET_GROUP SetAirplane
|
||||
-- @param Core.Set#SET_CARGO SetCargo
|
||||
-- @param Core.Set#SET_ZONE SetDeployZone
|
||||
-- @param Core.Set#SET_GROUP SetAirplanes
|
||||
-- @param Core.Set#SET_CARGO SetCargos
|
||||
-- @param Core.Set#SET_AIRBASE PickupAirbasesSet
|
||||
-- @param Core.Set#SET_AIRBASE DeployAirbasesSet
|
||||
-- @return #AI_CARGO_DISPATCHER_AIRPLANE
|
||||
-- @usage
|
||||
--
|
||||
-- -- Create a new cargo dispatcher
|
||||
-- SetAirplane = SET_GROUP:New():FilterPrefixes( "Airplane" ):FilterStart()
|
||||
-- SetCargo = SET_CARGO:New():FilterTypes( "Infantry" ):FilterStart()
|
||||
-- SetDeployZone = SET_ZONE:New():FilterPrefixes( "Deploy" ):FilterStart()
|
||||
-- AICargoDispatcher = AI_CARGO_DISPATCHER_AIRPLANE:New( SetAirplane, SetCargo )
|
||||
-- SetAirplanes = SET_GROUP:New():FilterPrefixes( "Airplane" ):FilterStart()
|
||||
-- SetCargos = SET_CARGO:New():FilterTypes( "Infantry" ):FilterStart()
|
||||
-- PickupAirbasesSet = SET_AIRBASE:New()
|
||||
-- DeployAirbasesSet = SET_AIRBASE:New()
|
||||
-- AICargoDispatcher = AI_CARGO_DISPATCHER_AIRPLANE:New( SetAirplanes, SetCargos, PickupAirbasesSet, DeployAirbasesSet )
|
||||
--
|
||||
function AI_CARGO_DISPATCHER_AIRPLANE:New( SetAirplane, SetCargo, SetDeployZones )
|
||||
function AI_CARGO_DISPATCHER_AIRPLANE:New( SetAirplanes, SetCargos, PickupAirbasesSet, DeployAirbasesSet )
|
||||
|
||||
local self = BASE:Inherit( self, AI_CARGO_DISPATCHER:New( SetAirplane, SetCargo, SetDeployZones ) ) -- #AI_CARGO_DISPATCHER_AIRPLANE
|
||||
local self = BASE:Inherit( self, AI_CARGO_DISPATCHER:NewWithAirbases( SetAirplanes, SetCargos, PickupAirbasesSet, DeployAirbasesSet ) ) -- #AI_CARGO_DISPATCHER_AIRPLANE
|
||||
|
||||
self:SetDeploySpeed( 200, 150 )
|
||||
self:SetPickupSpeed( 200, 150 )
|
||||
self:SetPickupRadius( 0, 0 )
|
||||
self:SetDeployRadius( 0, 0 )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
function AI_CARGO_DISPATCHER_AIRPLANE:AICargo( Airplane, SetCargo )
|
||||
|
||||
return AI_CARGO_AIRPLANE:New( Airplane, SetCargo )
|
||||
end
|
||||
|
||||
@ -102,7 +102,7 @@ AI_CARGO_DISPATCHER_HELICOPTER = {
|
||||
--
|
||||
function AI_CARGO_DISPATCHER_HELICOPTER:New( SetHelicopter, SetCargo, SetDeployZones )
|
||||
|
||||
local self = BASE:Inherit( self, AI_CARGO_DISPATCHER:New( SetHelicopter, SetCargo, SetDeployZones ) ) -- #AI_CARGO_DISPATCHER_HELICOPTER
|
||||
local self = BASE:Inherit( self, AI_CARGO_DISPATCHER:NewWithZones( SetHelicopter, SetCargo, SetDeployZones ) ) -- #AI_CARGO_DISPATCHER_HELICOPTER
|
||||
|
||||
self:SetDeploySpeed( 200, 150 )
|
||||
self:SetPickupSpeed( 200, 150 )
|
||||
|
||||
@ -4010,6 +4010,45 @@ function SET_AIRBASE:FindAirbase( AirbaseName )
|
||||
end
|
||||
|
||||
|
||||
--- Finds an Airbase in range of a coordinate.
|
||||
-- @param #SET_AIRBASE self
|
||||
-- @param Core.Point#COORDINATE Coordinate
|
||||
-- @param #number Range
|
||||
-- @return Wrapper.Airbase#AIRBASE The found Airbase.
|
||||
function SET_AIRBASE:FindAirbaseInRange( Coordinate, Range )
|
||||
|
||||
local AirbaseFound = nil
|
||||
|
||||
for AirbaseName, AirbaseObject in pairs( self.Set ) do
|
||||
|
||||
local AirbaseCoordinate = AirbaseObject:GetCoordinate()
|
||||
local Distance = Coordinate:Get2DDistance( AirbaseCoordinate )
|
||||
|
||||
self:F({Distance=Distance})
|
||||
|
||||
if Distance <= Range then
|
||||
AirbaseFound = AirbaseObject
|
||||
break
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return AirbaseFound
|
||||
end
|
||||
|
||||
|
||||
--- Finds a random Airbase in the set.
|
||||
-- @param #SET_AIRBASE self
|
||||
-- @return Wrapper.Airbase#AIRBASE The found Airbase.
|
||||
function SET_AIRBASE:GetRandomAirbase()
|
||||
|
||||
local RandomAirbase = self:GetRandom()
|
||||
self:F( { RandomAirbase = RandomAirbase:GetName() } )
|
||||
|
||||
return RandomAirbase
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Builds a set of airbases of coalitions.
|
||||
-- Possible current coalitions are red, blue and neutral.
|
||||
|
||||
@ -1,5 +1,58 @@
|
||||
--- **Tasking** - Creates and manages player TASK_CARGO tasks.
|
||||
--
|
||||
-- The **TASK_CARGO_DISPATCHER** allows you to setup various tasks for let human
|
||||
-- players transport cargo as part of a task.
|
||||
--
|
||||
-- The cargo dispatcher will implement for you mechanisms to create cargo transportation tasks:
|
||||
--
|
||||
-- * As setup by the mission designer.
|
||||
-- * Dynamically create CSAR missions (when a pilot is downed as part of a downed plane).
|
||||
-- * Dynamically spawn new cargo and create cargo taskings!
|
||||
--
|
||||
--
|
||||
--
|
||||
-- **Specific features:**
|
||||
--
|
||||
-- * Creates a task to transport @{Cargo.Cargo} to and between deployment zones.
|
||||
-- * Derived from the TASK_CARGO class, which is derived from the TASK class.
|
||||
-- * 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 task location on the map.
|
||||
-- * Provide details of the target.
|
||||
-- * Route to the cargo.
|
||||
-- * Route to the deploy zones.
|
||||
-- * Load/Unload cargo.
|
||||
-- * Board/Unboard cargo.
|
||||
-- * Slingload cargo.
|
||||
-- * 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 targets.
|
||||
-- * 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.
|
||||
-- * Different settings modes for A2G and A2A operations.
|
||||
-- * Various other options.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **FlightControl**
|
||||
@ -9,7 +62,7 @@
|
||||
-- ===
|
||||
--
|
||||
-- @module Tasking.Task_Cargo_Dispatcher
|
||||
-- @image MOOSE.JPG
|
||||
-- @image Task_Cargo_Dispatcher.JPG
|
||||
|
||||
do -- TASK_CARGO_DISPATCHER
|
||||
|
||||
@ -25,148 +78,189 @@ do -- TASK_CARGO_DISPATCHER
|
||||
|
||||
--- Implements the dynamic dispatching of cargo tasks.
|
||||
--
|
||||
-- 
|
||||
-- The **TASK_CARGO_DISPATCHER** allows you to setup various tasks for let human
|
||||
-- players transport cargo as part of a task.
|
||||
--
|
||||
-- The EWR will detect units, will group them, and will dispatch @{Task}s to groups. Depending on the type of target detected, different tasks will be dispatched.
|
||||
-- Find a summary below describing for which situation a task type is created:
|
||||
-- There are currently **two types of tasks** that can be constructed:
|
||||
--
|
||||
-- 
|
||||
-- * A **normal cargo transport** task, which tasks humans to transport cargo from a location towards a deploy zone.
|
||||
-- * A **CSAR** cargo transport task. CSAR tasks are **automatically generated** when a friendly (AI) plane is downed and the friendly pilot ejects...
|
||||
-- You as a player (the helo pilot) can go out in the battlefield, fly behind enemy lines, and rescue the pilot (back to a deploy zone).
|
||||
--
|
||||
-- * **CSAR Task**: Is created when a fiendly pilot has ejected from a plane, and needs to be rescued (sometimes behind enemy lines).
|
||||
-- Let's explore **step by step** how to setup the task cargo dispatcher.
|
||||
--
|
||||
-- ## 1. TASK\_A2A\_DISPATCHER constructor:
|
||||
-- # 1. Setup a mission environment.
|
||||
--
|
||||
-- The @{#TASK_CARGO_DISPATCHER.New}() method creates a new TASK\_A2A\_DISPATCHER instance.
|
||||
-- It is easy, as it works just like any other task setup, so setup a command center and a mission.
|
||||
--
|
||||
-- ### 1.1. Define or set the **Mission**:
|
||||
-- ## 1.1. Create a command center.
|
||||
--
|
||||
-- Tasking is executed to accomplish missions. Therefore, a MISSION object needs to be given as the first parameter.
|
||||
-- First you need to create a command center using the @{Tasking.CommandCenter#COMMANDCENTER.New}() constructor.
|
||||
--
|
||||
-- local HQ = GROUP:FindByName( "HQ", "Bravo" )
|
||||
-- local CommandCenter = COMMANDCENTER:New( HQ, "Lima" )
|
||||
-- local Mission = MISSION:New( CommandCenter, "A2A Mission", "High", "Watch the air enemy units being detected.", coalition.side.RED )
|
||||
--
|
||||
-- Missions are governed by COMMANDCENTERS, so, ensure you have a COMMANDCENTER object installed and setup within your mission.
|
||||
-- Create the MISSION object, and hook it under the command center.
|
||||
--
|
||||
-- ### 1.2. Build a set of the groups seated by human players:
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- A set or collection of the groups wherein human players can be seated, these can be clients or units that can be joined as a slot or jumping into.
|
||||
-- local CommandCenter = COMMANDCENTER
|
||||
-- :New( HQ, "Lima" ) -- Create the CommandCenter.
|
||||
--
|
||||
-- local AttackGroups = SET_GROUP:New():FilterCoalitions( "red" ):FilterPrefixes( "Defender" ):FilterStart()
|
||||
--
|
||||
-- The set is built using the SET_GROUP class. Apply any filter criteria to identify the correct groups for your mission.
|
||||
-- Only these slots or units will be able to execute the mission and will receive tasks for this mission, once available.
|
||||
-- ## 1.2. Create a mission.
|
||||
--
|
||||
-- ### 1.3. Define the **EWR network**:
|
||||
-- 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.
|
||||
--
|
||||
-- As part of the TASK\_A2A\_DISPATCHER constructor, an EWR network must be given as the third parameter.
|
||||
-- An EWR network, or, Early Warning Radar network, is used to early detect potential airborne targets and to understand the position of patrolling targets of the enemy.
|
||||
-- -- Declare the Mission for the Command Center.
|
||||
-- local Mission = MISSION
|
||||
-- :New( CommandCenter,
|
||||
-- "Overlord",
|
||||
-- "High",
|
||||
-- "Transport the cargo.",
|
||||
-- coalition.side.RED
|
||||
-- )
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- Typically EWR networks are setup using 55G6 EWR, 1L13 EWR, Hawk sr and Patriot str ground based radar units.
|
||||
-- These radars have different ranges and 55G6 EWR and 1L13 EWR radars are Eastern Bloc units (eg Russia, Ukraine, Georgia) while the Hawk and Patriot radars are Western (eg US).
|
||||
-- Additionally, ANY other radar capable unit can be part of the EWR network! Also AWACS airborne units, planes, helicopters can help to detect targets, as long as they have radar.
|
||||
-- The position of these units is very important as they need to provide enough coverage
|
||||
-- to pick up enemy aircraft as they approach so that CAP and GCI flights can be tasked to intercept them.
|
||||
-- # 2. Dispatch a **transport cargo** task.
|
||||
--
|
||||
-- 
|
||||
-- So, now that we have a command center and a mission, we now create the transport task.
|
||||
-- We create the transport task using the @{#TASK_CARGO_DISPATCHER.AddTransportTask}() constructor.
|
||||
--
|
||||
-- ## 2.1. Create the cargo in the mission.
|
||||
--
|
||||
-- Because a transport task will not generate the cargo itself, you'll need to create it first.
|
||||
--
|
||||
-- -- Here we define the "cargo set", which is a collection of cargo objects.
|
||||
-- -- The cargo set will be the input for the cargo transportation task.
|
||||
-- -- So a transportation object is handling a cargo set, which is automatically updated when new cargo is added/deleted.
|
||||
-- local WorkmaterialsCargoSet = SET_CARGO:New():FilterTypes( "Workmaterials" ):FilterStart()
|
||||
--
|
||||
-- -- Now we add cargo into the battle scene.
|
||||
-- local PilotGroup = GROUP:FindByName( "Engineers" )
|
||||
--
|
||||
-- -- CARGO_GROUP can be used to setup cargo with a GROUP object underneath.
|
||||
-- -- We name the type of this group "Workmaterials", so that this cargo group will be included within the WorkmaterialsCargoSet.
|
||||
-- -- Note that the name of the cargo is "Engineer Team 1".
|
||||
-- local CargoGroup = CARGO_GROUP:New( PilotGroup, "Workmaterials", "Engineer Team 1", 500 )
|
||||
--
|
||||
-- What is also needed, is to have a set of @{Core.Group}s defined that contains the clients of the players.
|
||||
--
|
||||
-- -- Allocate the Transport, which are the helicopters to retrieve the pilot, that can be manned by players.
|
||||
-- -- The name of these helicopter groups containing one client begins with "Transport", as modelled within the mission editor.
|
||||
-- local PilotGroupSet = SET_GROUP:New():FilterPrefixes( "Transport" ):FilterStart()
|
||||
--
|
||||
-- ## 2.2. Setup the cargo transport task.
|
||||
--
|
||||
-- First, we need to create a TASK_CARGO_DISPATCHER object.
|
||||
--
|
||||
-- TaskDispatcher = TASK_CARGO_DISPATCHER:New( Mission, PilotGroupSet )
|
||||
--
|
||||
-- So, the variable `TaskDispatcher` will contain the object of class TASK_CARGO_DISPATCHER, which will allow you to dispatch cargo transport tasks:
|
||||
--
|
||||
-- Additionally in a hot war situation where the border is no longer respected the placement of radars has a big effect on how fast the war escalates.
|
||||
-- For example if they are a long way forward and can detect enemy planes on the ground and taking off
|
||||
-- they will start to vector CAP and GCI flights to attack them straight away which will immediately draw a response from the other coalition.
|
||||
-- Having the radars further back will mean a slower escalation because fewer targets will be detected and
|
||||
-- therefore less CAP and GCI flights will spawn and this will tend to make just the border area active rather than a melee over the whole map.
|
||||
-- It all depends on what the desired effect is.
|
||||
-- * for mission `Mission`.
|
||||
-- * for the group set `PilotGroupSet`.
|
||||
--
|
||||
-- EWR networks are **dynamically constructed**, that is, they form part of the @{Functional.Detection#DETECTION_BASE} object that is given as the input parameter of the TASK\_A2A\_DISPATCHER class.
|
||||
-- By defining in a **smart way the names or name prefixes of the groups** with EWR capable units, these groups will be **automatically added or deleted** from the EWR network,
|
||||
-- increasing or decreasing the radar coverage of the Early Warning System.
|
||||
-- Now that we have `TaskDispatcher` object, we can now **create the TransportTask**, using the @{#TASK_CARGO_DISPATCHER.AddTransportTask}() method!
|
||||
--
|
||||
-- See the following example to setup an EWR network containing EWR stations and AWACS.
|
||||
-- local TransportTask = TaskDispatcher:AddTransportTask(
|
||||
-- "Transport workmaterials",
|
||||
-- WorkmaterialsCargoSet,
|
||||
-- "Transport the workers, engineers and the equipment near the Workplace." )
|
||||
--
|
||||
-- local EWRSet = SET_GROUP:New():FilterPrefixes( "EWR" ):FilterCoalitions("red"):FilterStart()
|
||||
--
|
||||
-- local EWRDetection = DETECTION_AREAS:New( EWRSet, 6000 )
|
||||
-- EWRDetection:SetFriendliesRange( 10000 )
|
||||
-- EWRDetection:SetRefreshTimeInterval(30)
|
||||
--
|
||||
-- -- Setup the A2A dispatcher, and initialize it.
|
||||
-- A2ADispatcher = TASK_CARGO_DISPATCHER:New( Mission, AttackGroups, EWRDetection )
|
||||
-- As a result of this code, the `TransportTask` (returned) variable will contain an object of @{#TASK_CARGO_TRANSPORT}!
|
||||
-- We pass to the method the title of the task, and the `WorkmaterialsCargoSet`, which is the set of cargo groups to be transported!
|
||||
-- This object can also be used to setup additional things, or to control this specific task with special actions.
|
||||
--
|
||||
-- The above example creates a SET_GROUP instance, and stores this in the variable (object) **EWRSet**.
|
||||
-- **EWRSet** is then being configured to filter all active groups with a group name starting with **EWR** to be included in the Set.
|
||||
-- **EWRSet** is then being ordered to start the dynamic filtering. Note that any destroy or new spawn of a group with the above names will be removed or added to the Set.
|
||||
-- Then a new **EWRDetection** object is created from the class DETECTION_AREAS. A grouping radius of 6000 is choosen, which is 6km.
|
||||
-- The **EWRDetection** object is then passed to the @{#TASK_CARGO_DISPATCHER.New}() method to indicate the EWR network configuration and setup the A2A tasking and detection mechanism.
|
||||
-- And you're done! As you can see, it is a bit of work, but the reward is great.
|
||||
-- And, because all this is done using program interfaces, you can build a mission with a **dynamic cargo transport task mechanism** yourself!
|
||||
-- Based on events happening within your mission, you can use the above methods to create new cargo, and setup a new task for cargo transportation to a group of players!
|
||||
--
|
||||
-- ### 2. Define the detected **target grouping radius**:
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- The target grouping radius is a property of the Detection object, that was passed to the AI\_A2A\_DISPATCHER object, but can be changed.
|
||||
-- The grouping radius should not be too small, but also depends on the types of planes and the era of the simulation.
|
||||
-- Fast planes like in the 80s, need a larger radius than WWII planes.
|
||||
-- Typically I suggest to use 30000 for new generation planes and 10000 for older era aircraft.
|
||||
--
|
||||
-- Note that detected targets are constantly re-grouped, that is, when certain detected aircraft are moving further than the group radius, then these aircraft will become a separate
|
||||
-- group being detected. This may result in additional GCI being started by the dispatcher! So don't make this value too small!
|
||||
--
|
||||
-- ## 3. Set the **Engage radius**:
|
||||
--
|
||||
-- Define the radius to engage any target by airborne friendlies, which are executing cap or returning from an intercept mission.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- So, if there is a target area detected and reported,
|
||||
-- then any friendlies that are airborne near this target area,
|
||||
-- will be commanded to (re-)engage that target when available (if no other tasks were commanded).
|
||||
-- For example, if 100000 is given as a value, then any friendly that is airborne within 100km from the detected target,
|
||||
-- will be considered to receive the command to engage that target area.
|
||||
-- You need to evaluate the value of this parameter carefully.
|
||||
-- If too small, more intercept missions may be triggered upon detected target areas.
|
||||
-- If too large, any airborne cap may not be able to reach the detected target area in time, because it is too far.
|
||||
--
|
||||
-- ## 4. Set **Scoring** and **Messages**:
|
||||
--
|
||||
-- The TASK\_A2A\_DISPATCHER is a state machine. It triggers the event Assign when a new player joins a @{Task} dispatched by the TASK\_A2A\_DISPATCHER.
|
||||
-- An _event handler_ can be defined to catch the **Assign** event, and add **additional processing** to set _scoring_ and to _define messages_,
|
||||
-- when the player reaches certain achievements in the task.
|
||||
--
|
||||
-- The prototype to handle the **Assign** event needs to be developed as follows:
|
||||
--
|
||||
-- TaskDispatcher = TASK_CARGO_DISPATCHER:New( ... )
|
||||
--
|
||||
-- --- @param #TaskDispatcher self
|
||||
-- -- @param #string From Contains the name of the state from where the Event was triggered.
|
||||
-- -- @param #string Event Contains the name of the event that was triggered. In this case Assign.
|
||||
-- -- @param #string To Contains the name of the state that will be transitioned to.
|
||||
-- -- @param Tasking.Task_A2A#TASK_A2A Task The Task object, which is any derived object from TASK_A2A.
|
||||
-- -- @param Wrapper.Unit#UNIT TaskUnit The Unit or Client that contains the Player.
|
||||
-- -- @param #string PlayerName The name of the Player that joined the TaskUnit.
|
||||
-- function TaskDispatcher:OnAfterAssign( From, Event, To, Task, TaskUnit, PlayerName )
|
||||
-- Task:SetScoreOnProgress( PlayerName, 20, TaskUnit )
|
||||
-- Task:SetScoreOnSuccess( PlayerName, 200, TaskUnit )
|
||||
-- Task:SetScoreOnFail( PlayerName, -100, TaskUnit )
|
||||
-- end
|
||||
--
|
||||
-- The **OnAfterAssign** method (function) is added to the TaskDispatcher object.
|
||||
-- This method will be called when a new player joins a unit in the set of groups in scope of the dispatcher.
|
||||
-- So, this method will be called only **ONCE** when a player joins a unit in scope of the task.
|
||||
--
|
||||
-- The TASK class implements various methods to additional **set scoring** for player achievements:
|
||||
--
|
||||
-- * @{Tasking.Task#TASK.SetScoreOnProgress}() will add additional scores when a player achieves **Progress** while executing the task.
|
||||
-- Examples of **task progress** can be destroying units, arriving at zones etc.
|
||||
--
|
||||
-- * @{Tasking.Task#TASK.SetScoreOnSuccess}() will add additional scores when the task goes into **Success** state.
|
||||
-- This means the **task has been successfully completed**.
|
||||
--
|
||||
-- * @{Tasking.Task#TASK.SetScoreOnSuccess}() will add additional (negative) scores when the task goes into **Failed** state.
|
||||
-- This means the **task has not been successfully completed**, and the scores must be given with a negative value!
|
||||
-- # 3. Dispatch CSAR tasks.
|
||||
--
|
||||
-- CSAR tasks can be dynamically created when a friendly pilot ejects, or can be created manually.
|
||||
-- We'll explore both options.
|
||||
--
|
||||
-- ## 3.1. CSAR task dynamic creation.
|
||||
--
|
||||
-- Because there is an "event" in a running simulation that creates CSAR tasks, the method @{#TASK_CARGO_DISPATCHER.StartCSARTasks}() will create automatically:
|
||||
--
|
||||
-- 1. a new downed pilot at the location where the plane was shot
|
||||
-- 2. declare that pilot as cargo
|
||||
-- 3. creates a CSAR task automatically to retrieve that pilot
|
||||
-- 4. requires deploy zones to be specified where to transport the downed pilot to, in order to complete that task.
|
||||
--
|
||||
-- You create a CSAR task dynamically in a very easy way:
|
||||
--
|
||||
-- TaskDispatcher:StartCSARTasks(
|
||||
-- "CSAR",
|
||||
-- { ZONE_UNIT:New( "Hospital", STATIC:FindByName( "Hospital" ), 100 ) },
|
||||
-- "One of our pilots has ejected. Go out to Search and Rescue our pilot!\n" ..
|
||||
-- "Use the radio menu to let the command center assist you with the CSAR tasking."
|
||||
-- )
|
||||
--
|
||||
-- The method @{#TASK_CARGO_DISPATCHER.StopCSARTasks}() will automatically stop with the creation of CSAR tasks when friendly pilots eject.
|
||||
--
|
||||
-- **Remarks:**
|
||||
--
|
||||
-- * the ZONE_UNIT can also be a ZONE, or a ZONE_POLYGON object, or any other ZONE_ object!
|
||||
-- * you can declare the array of zones in another variable, or course!
|
||||
--
|
||||
--
|
||||
-- ## 3.2. CSAR task manual creation.
|
||||
--
|
||||
-- We create the CSAR task using the @{#TASK_CARGO_DISPATCHER.AddCSARTask}() constructor.
|
||||
--
|
||||
-- The method will create a new CSAR task, and will generate the pilots cargo itself, at the specified coordinate.
|
||||
--
|
||||
-- What is first needed, is to have a set of @{Core.Group}s defined that contains the clients of the players.
|
||||
--
|
||||
-- -- Allocate the Transport, which are the helicopter to retrieve the pilot, that can be manned by players.
|
||||
-- local GroupSet = SET_GROUP:New():FilterPrefixes( "Transport" ):FilterStart()
|
||||
--
|
||||
-- We need to create a TASK_CARGO_DISPATCHER object.
|
||||
--
|
||||
-- TaskDispatcher = TASK_CARGO_DISPATCHER:New( Mission, GroupSet )
|
||||
--
|
||||
-- So, the variable `TaskDispatcher` will contain the object of class TASK_CARGO_DISPATCHER, which will allow you to dispatch cargo CSAR tasks:
|
||||
--
|
||||
-- * for mission `Mission`.
|
||||
-- * for the group of players (pilots) captured within the `GroupSet` (those groups with a name starting with `"Transport"`).
|
||||
--
|
||||
-- Now that we have a PilotsCargoSet and a GroupSet, we can now create the CSAR task manually.
|
||||
--
|
||||
-- -- Declare the CSAR task.
|
||||
-- local CSARTask = TaskDispatcher:AddCSARTask(
|
||||
-- "CSAR Task",
|
||||
-- Coordinate,
|
||||
-- 270,
|
||||
-- "Bring the pilot back!"
|
||||
-- )
|
||||
--
|
||||
-- As a result of this code, the `CSARTask` (returned) variable will contain an object of @{#TASK_CARGO_CSAR}!
|
||||
-- We pass to the method the title of the task, and the `WorkmaterialsCargoSet`, which is the set of cargo groups to be transported!
|
||||
-- This object can also be used to setup additional things, or to control this specific task with special actions.
|
||||
-- Note that when you declare a CSAR task manually, you'll still need to specify a deployment zone!
|
||||
--
|
||||
-- # 4. Setup the deploy zone(s).
|
||||
--
|
||||
-- The task cargo dispatcher also foresees methods to setup the deployment zones to where the cargo needs to be transported!
|
||||
--
|
||||
-- There are two levels on which deployment zones can be configured:
|
||||
--
|
||||
-- * Default deploy zones: The TASK_CARGO_DISPATCHER object can have default deployment zones, which will apply over all tasks active in the task dispatcher.
|
||||
-- * Task specific deploy zones: The TASK_CARGO_DISPATCHER object can have specific deployment zones which apply to a specific task only!
|
||||
--
|
||||
-- Note that for Task specific deployment zones, there are separate deployment zone creation methods per task type!
|
||||
--
|
||||
-- ## 4.1. Setup default deploy zones.
|
||||
--
|
||||
-- Use the @{#TASK_CARGO_DISPATCHER.SetDefaultDeployZone}() to setup one deployment zone, and @{#TASK_CARGO_DISPATCHER.SetDefaultDeployZones}() to setup multiple default deployment zones in one call.
|
||||
--
|
||||
-- ## 4.2. Setup task specific deploy zones for a **transport task**.
|
||||
--
|
||||
-- Use the @{#TASK_CARGO_DISPATCHER.SetTransportDeployZone}() to setup one deployment zone, and @{#TASK_CARGO_DISPATCHER.SetTransportDeployZones}() to setup multiple default deployment zones in one call.
|
||||
--
|
||||
-- ## 4.3. Setup task specific deploy zones for a **CSAR task**.
|
||||
--
|
||||
-- Use the @{#TASK_CARGO_DISPATCHER.SetCSARDeployZone}() to setup one deployment zone, and @{#TASK_CARGO_DISPATCHER.SetCSARDeployZones}() to setup multiple default deployment zones in one call.
|
||||
--
|
||||
--
|
||||
--
|
||||
-- @field #TASK_CARGO_DISPATCHER
|
||||
TASK_CARGO_DISPATCHER = {
|
||||
@ -321,11 +415,11 @@ do -- TASK_CARGO_DISPATCHER
|
||||
--
|
||||
-- -- Add a CSAR task to rescue a downed pilot from within a coordinate.
|
||||
-- local Coordinate = PlaneUnit:GetPointVec2()
|
||||
-- TaskA2ADispatcher:AddCSARTask( Coordinate )
|
||||
-- TaskA2ADispatcher:AddCSARTask( "CSAR Task", Coordinate )
|
||||
--
|
||||
-- -- Add a CSAR task to rescue a downed pilot from within a coordinate of country RUSSIA, which is pointing to the west (270°).
|
||||
-- local Coordinate = PlaneUnit:GetPointVec2()
|
||||
-- TaskA2ADispatcher:AddCSARTask( Coordinate, 270, Country.RUSSIA )
|
||||
-- TaskA2ADispatcher:AddCSARTask( "CSAR Task", Coordinate, 270, Country.RUSSIA )
|
||||
--
|
||||
function TASK_CARGO_DISPATCHER:AddCSARTask( CSARTaskPrefix, CSARCoordinate, CSARHeading, CSARCountry, CSARBriefing )
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user