mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-10-29 16:58:06 +00:00
Progress
- Added SPAWN:InitRandomizeZones() method. - Renamed SPAWN:CleanUp() method to SPAWN:InitCleanUp() method. - Reviewed documentation of the PatrolZone module and PATROLZONE class. - Reviewed all test missions
This commit is contained in:
@@ -2,21 +2,28 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- 1) @{Patrol#PATROLZONE} class, extends @{Base#BASE}
|
||||
-- 1) @{#PATROLZONE} class, extends @{Base#BASE}
|
||||
-- ===================================================
|
||||
-- The @{Patrol#PATROLZONE} class implements the core functions to patrol a @{Zone}.
|
||||
-- The @{#PATROLZONE} class implements the core functions to patrol a @{Zone} by air units.
|
||||
-- The PATROLZONE class will guide the airplanes towards the patrolzone.
|
||||
-- The patrol algorithm works that for each airplane patrolling, upon arrival at the patrol zone,
|
||||
-- a random point is selected as the route point within the 3D space, within the given boundary limits.
|
||||
-- The airplane will fly towards the random point using a randomly selected speed within given boundary limits.
|
||||
-- Upon arrival at the random point, a new random point will be selected within the patrol zone within boundary limits.
|
||||
-- This cycle will continue until a fuel treshold has been reached by the airplane.
|
||||
-- When the fuel treshold has been reached, the airplane will fly towards the nearest friendly airbase and will land.
|
||||
--
|
||||
-- 1.1) PATROLZONE constructor:
|
||||
-- ----------------------------
|
||||
-- @{PatrolZone#PATROLZONE.New}(): Creates a new PATROLZONE object.
|
||||
-- @{#PATROLZONE.New}(): Creates a new PATROLZONE object.
|
||||
--
|
||||
-- 1.2) Modify the PATROLZONE parameters:
|
||||
-- --------------------------------------
|
||||
-- The following methods are available to modify the parameters of a PATROLZONE object:
|
||||
--
|
||||
-- * @{PatrolZone#PATROLZONE.SetGroup}(): Set the AI Patrol Group.
|
||||
-- * @{PatrolZone#PATROLZONE.SetSpeed}(): Set the patrol speed of the AI, for the next patrol.
|
||||
-- * @{PatrolZone#PATROLZONE.SetAltitude}(): Set altitude of the AI, for the next patrol.
|
||||
-- * @{#PATROLZONE.SetGroup}(): Set the AI Patrol Group.
|
||||
-- * @{#PATROLZONE.SetSpeed}(): Set the patrol speed of the AI, for the next patrol.
|
||||
-- * @{#PATROLZONE.SetAltitude}(): Set altitude of the AI, for the next patrol.
|
||||
--
|
||||
-- 1.3) Manage the out of fuel in the PATROLZONE:
|
||||
-- ----------------------------------------------
|
||||
@@ -24,12 +31,37 @@
|
||||
-- Therefore, with a parameter and a calculation of the distance to the home base, the fuel treshold is calculated.
|
||||
-- When the fuel treshold is reached, the PatrolGroup will continue for a given time its patrol task in orbit, while a new PatrolGroup is targetted to the PATROLZONE.
|
||||
-- Once the time is finished, the old PatrolGroup will return to the base.
|
||||
-- Use the method @{PatrolZone#PATROLZONE.ManageFuel}() to have this proces in place.
|
||||
-- Use the method @{#PATROLZONE.ManageFuel}() to have this proces in place.
|
||||
--
|
||||
-- ====
|
||||
--
|
||||
-- **API CHANGE HISTORY**
|
||||
-- ======================
|
||||
--
|
||||
-- The underlying change log documents the API changes. Please read this carefully. The following notation is used:
|
||||
--
|
||||
-- * **Added** parts are expressed in bold type face.
|
||||
-- * _Removed_ parts are expressed in italic type face.
|
||||
--
|
||||
-- Hereby the change log:
|
||||
--
|
||||
-- 2016-07-01: Initial class and API.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- AUTHORS and CONTRIBUTIONS
|
||||
-- =========================
|
||||
--
|
||||
-- ### Contributions:
|
||||
--
|
||||
-- * DutchBaron: Testing.
|
||||
--
|
||||
-- ### Authors:
|
||||
--
|
||||
-- * FlightControl: Design & Programming
|
||||
--
|
||||
--
|
||||
-- @module PatrolZone
|
||||
-- @author FlightControl
|
||||
|
||||
|
||||
--- PATROLZONE class
|
||||
|
||||
@@ -26,9 +26,10 @@
|
||||
--
|
||||
-- 1.1) SPAWN construction methods
|
||||
-- -------------------------------
|
||||
-- Create a new SPAWN object with the @{#SPAWN.New} or the @{#SPAWN.NewWithAlias} methods:
|
||||
-- Create a new SPAWN object with the @{#SPAWN.New}() or the @{#SPAWN.NewWithAlias}() methods:
|
||||
--
|
||||
-- * @{#SPAWN.New}: Creates a new SPAWN object taking the name of the group that represents the GROUP Template (definition).
|
||||
-- * @{#SPAWN.New}(): Creates a new SPAWN object taking the name of the group that represents the GROUP Template (definition).
|
||||
-- * @{#SPAWN.NewWithAlias}(): Creates a new SPAWN object taking the name of the group that represents the GROUP Template (definition), and gives each spawned @{Group} an different name.
|
||||
--
|
||||
-- It is important to understand how the SPAWN class works internally. The SPAWN object created will contain internally a list of groups that will be spawned and that are already spawned.
|
||||
-- The initialization methods will modify this list of groups so that when a group gets spawned, ALL information is already prepared when spawning. This is done for performance reasons.
|
||||
@@ -38,27 +39,27 @@
|
||||
-- ---------------------------------
|
||||
-- A spawn object will behave differently based on the usage of **initialization** methods, which all start with the **Init** prefix:
|
||||
--
|
||||
-- * @{#SPAWN.InitLimit}: Limits the amount of groups that can be alive at the same time and that can be dynamically spawned.
|
||||
-- * @{#SPAWN.InitRandomizeRoute}: Randomize the routes of spawned groups, and for air groups also optionally the height.
|
||||
-- * @{#SPAWN.InitRandomizeTemplate}: Randomize the group templates so that when a new group is spawned, a random group template is selected from one of the templates defined.
|
||||
-- * @{#SPAWN.InitUncontrolled}: Spawn plane groups uncontrolled.
|
||||
-- * @{#SPAWN.InitArray}: Make groups visible before they are actually activated, and order these groups like a batallion in an array.
|
||||
-- * @{#SPAWN.InitRepeat}: Re-spawn groups when they land at the home base. Similar methods are @{#SPAWN.InitRepeatOnLanding} and @{#SPAWN.InitRepeatOnEngineShutDown}.
|
||||
-- * @{#SPAWN.InitRandomizeUnits}: Randomizes the @{Unit}s in the @{Group} that is spawned within a **radius band**, given an Outer and Inner radius.
|
||||
-- * @{#SPAWN.InitRandomizeZones}: Randomizes the spawning between a predefined list of @{Zone}s that are declared using this function. Each zone can be given a probability factor.
|
||||
-- * @{#SPAWN.InitLimit}(): Limits the amount of groups that can be alive at the same time and that can be dynamically spawned.
|
||||
-- * @{#SPAWN.InitRandomizeRoute}(): Randomize the routes of spawned groups, and for air groups also optionally the height.
|
||||
-- * @{#SPAWN.InitRandomizeTemplate}(): Randomize the group templates so that when a new group is spawned, a random group template is selected from one of the templates defined.
|
||||
-- * @{#SPAWN.InitUncontrolled}(): Spawn plane groups uncontrolled.
|
||||
-- * @{#SPAWN.InitArray}(): Make groups visible before they are actually activated, and order these groups like a batallion in an array.
|
||||
-- * @{#SPAWN.InitRepeat}(): Re-spawn groups when they land at the home base. Similar methods are @{#SPAWN.InitRepeatOnLanding} and @{#SPAWN.InitRepeatOnEngineShutDown}.
|
||||
-- * @{#SPAWN.InitRandomizeUnits}(): Randomizes the @{Unit}s in the @{Group} that is spawned within a **radius band**, given an Outer and Inner radius.
|
||||
-- * @{#SPAWN.InitRandomizeZones}(): Randomizes the spawning between a predefined list of @{Zone}s that are declared using this function. Each zone can be given a probability factor.
|
||||
--
|
||||
-- 1.3) SPAWN spawning methods
|
||||
-- ---------------------------
|
||||
-- Groups can be spawned at different times and methods:
|
||||
--
|
||||
-- * @{#SPAWN.Spawn}: Spawn one new group based on the last spawned index.
|
||||
-- * @{#SPAWN.ReSpawn}: Re-spawn a group based on a given index.
|
||||
-- * @{#SPAWN.SpawnScheduled}: Spawn groups at scheduled but randomized intervals. You can use @{#SPAWN.SpawnScheduleStart} and @{#SPAWN.SpawnScheduleStop} to start and stop the schedule respectively.
|
||||
-- * @{#SPAWN.SpawnFromVec3}: Spawn a new group from a Vec3 coordinate. (The group will can be spawned at a point in the air).
|
||||
-- * @{#SPAWN.SpawnFromVec2}: Spawn a new group from a Vec2 coordinate. (The group will be spawned at land height ).
|
||||
-- * @{#SPAWN.SpawnFromStatic}: Spawn a new group from a structure, taking the position of a @{STATIC}.
|
||||
-- * @{#SPAWN.SpawnFromUnit}: Spawn a new group taking the position of a @{UNIT}.
|
||||
-- * @{#SPAWN.SpawnInZone}: Spawn a new group in a @{ZONE}.
|
||||
-- * @{#SPAWN.Spawn}(): Spawn one new group based on the last spawned index.
|
||||
-- * @{#SPAWN.ReSpawn}(): Re-spawn a group based on a given index.
|
||||
-- * @{#SPAWN.SpawnScheduled}(): Spawn groups at scheduled but randomized intervals. You can use @{#SPAWN.SpawnScheduleStart}() and @{#SPAWN.SpawnScheduleStop}() to start and stop the schedule respectively.
|
||||
-- * @{#SPAWN.SpawnFromVec3}(): Spawn a new group from a Vec3 coordinate. (The group will can be spawned at a point in the air).
|
||||
-- * @{#SPAWN.SpawnFromVec2}(): Spawn a new group from a Vec2 coordinate. (The group will be spawned at land height ).
|
||||
-- * @{#SPAWN.SpawnFromStatic}(): Spawn a new group from a structure, taking the position of a @{Static}.
|
||||
-- * @{#SPAWN.SpawnFromUnit}(): Spawn a new group taking the position of a @{Unit}.
|
||||
-- * @{#SPAWN.SpawnInZone}(): Spawn a new group in a @{Zone}.
|
||||
--
|
||||
-- Note that @{#SPAWN.Spawn} and @{#SPAWN.ReSpawn} return a @{GROUP#GROUP.New} object, that contains a reference to the DCSGroup object.
|
||||
-- You can use the @{GROUP} object to do further actions with the DCSGroup.
|
||||
@@ -69,27 +70,27 @@
|
||||
-- Every time a SPAWN object spawns a new GROUP object, a reference to the GROUP object is added to an internal table of GROUPS.
|
||||
-- SPAWN provides methods to iterate through that internal GROUP object reference table:
|
||||
--
|
||||
-- * @{#SPAWN.GetFirstAliveGroup}: Will find the first alive GROUP it has spawned, and return the alive GROUP object and the first Index where the first alive GROUP object has been found.
|
||||
-- * @{#SPAWN.GetNextAliveGroup}: Will find the next alive GROUP object from a given Index, and return a reference to the alive GROUP object and the next Index where the alive GROUP has been found.
|
||||
-- * @{#SPAWN.GetLastAliveGroup}: Will find the last alive GROUP object, and will return a reference to the last live GROUP object and the last Index where the last alive GROUP object has been found.
|
||||
-- * @{#SPAWN.GetFirstAliveGroup}(): Will find the first alive GROUP it has spawned, and return the alive GROUP object and the first Index where the first alive GROUP object has been found.
|
||||
-- * @{#SPAWN.GetNextAliveGroup}(): Will find the next alive GROUP object from a given Index, and return a reference to the alive GROUP object and the next Index where the alive GROUP has been found.
|
||||
-- * @{#SPAWN.GetLastAliveGroup}(): Will find the last alive GROUP object, and will return a reference to the last live GROUP object and the last Index where the last alive GROUP object has been found.
|
||||
--
|
||||
-- You can use the methods @{#SPAWN.GetFirstAliveGroup} and sequently @{#SPAWN.GetNextAliveGroup} to iterate through the alive GROUPS within the SPAWN object, and to actions... See the respective methods for an example.
|
||||
-- The method @{#SPAWN.GetGroupFromIndex} will return the GROUP object reference from the given Index, dead or alive...
|
||||
-- You can use the methods @{#SPAWN.GetFirstAliveGroup}() and sequently @{#SPAWN.GetNextAliveGroup}() to iterate through the alive GROUPS within the SPAWN object, and to actions... See the respective methods for an example.
|
||||
-- The method @{#SPAWN.GetGroupFromIndex}() will return the GROUP object reference from the given Index, dead or alive...
|
||||
--
|
||||
-- 1.5) SPAWN object cleaning
|
||||
-- --------------------------
|
||||
-- Sometimes, it will occur during a mission run-time, that ground or especially air objects get damaged, and will while being damged stop their activities, while remaining alive.
|
||||
-- In such cases, the SPAWN object will just sit there and wait until that group gets destroyed, but most of the time it won't,
|
||||
-- and it may occur that no new groups are or can be spawned as limits are reached.
|
||||
-- To prevent this, a @{#SPAWN.CleanUp} initialization method has been defined that will silently monitor the status of each spawned group.
|
||||
-- To prevent this, a @{#SPAWN.InitCleanUp}() initialization method has been defined that will silently monitor the status of each spawned group.
|
||||
-- Once a group has a velocity = 0, and has been waiting for a defined interval, that group will be cleaned or removed from run-time.
|
||||
-- There is a catch however :-) If a damaged group has returned to an airbase within the coalition, that group will not be considered as "lost"...
|
||||
-- In such a case, when the inactive group is cleaned, a new group will Re-spawned automatically.
|
||||
-- This models AI that has succesfully returned to their airbase, to restart their combat activities.
|
||||
-- Check the @{#SPAWN.CleanUp} for further info.
|
||||
-- Check the @{#SPAWN.InitCleanUp}() for further info.
|
||||
--
|
||||
-- 1.6) Catch the @{Group} Spawn event!
|
||||
-- ------------------------------------
|
||||
-- 1.6) Catch the @{Group} spawn event in a callback function!
|
||||
-- -----------------------------------------------------------
|
||||
-- When using the SpawnScheduled method, new @{Group}s are created following the schedule timing parameters.
|
||||
-- When a new @{Group} is spawned, you maybe want to execute actions with that group spawned at the spawn event.
|
||||
-- To SPAWN class supports this functionality through the @{#SPAWN.OnSpawnGroup}( **function( SpawnedGroup ) end ** ) method, which takes a function as a parameter that you can define locally.
|
||||
@@ -109,7 +110,12 @@
|
||||
--
|
||||
-- Hereby the change log:
|
||||
--
|
||||
-- 2016-08-15: SPAWN:**InitRandomizeZones( SpawnZones ) added.
|
||||
-- 2016-08-15: SPAWN:**InitCleanUp**( SpawnCleanUpInterval ) replaces SPAWN:_CleanUp_( SpawnCleanUpInterval )
|
||||
--
|
||||
-- * Want to ensure that the methods starting with **Init** are the first called methods before any _Spawn_ method is called!
|
||||
-- * This notation makes it now more clear which methods are initialization methods and which methods are Spawn enablement methods.
|
||||
--
|
||||
-- 2016-08-15: SPAWN:**InitRandomizeZones( SpawnZones )** added.
|
||||
--
|
||||
-- * This method provides the functionality to randomize the spawning of the Groups at a given list of zones of different types.
|
||||
--
|
||||
@@ -184,7 +190,8 @@
|
||||
--
|
||||
--
|
||||
-- @module Spawn
|
||||
-- @author FlightControl
|
||||
|
||||
|
||||
|
||||
--- SPAWN Class
|
||||
-- @type SPAWN
|
||||
@@ -478,7 +485,7 @@ end
|
||||
-- @param #string SpawnCleanUpInterval The interval to check for inactive groups within seconds.
|
||||
-- @return #SPAWN self
|
||||
-- @usage Spawn_Helicopter:CleanUp( 20 ) -- CleanUp the spawning of the helicopters every 20 seconds when they become inactive.
|
||||
function SPAWN:CleanUp( SpawnCleanUpInterval )
|
||||
function SPAWN:InitCleanUp( SpawnCleanUpInterval )
|
||||
self:F( { self.SpawnTemplatePrefix, SpawnCleanUpInterval } )
|
||||
|
||||
self.SpawnCleanUpInterval = SpawnCleanUpInterval
|
||||
@@ -1238,6 +1245,8 @@ function SPAWN:_RandomizeRoute( SpawnIndex )
|
||||
end
|
||||
end
|
||||
|
||||
self:_RandomizeZones( SpawnIndex )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -1288,8 +1297,12 @@ function SPAWN:_RandomizeZones( SpawnIndex )
|
||||
|
||||
local SpawnVec2 = SpawnZone:GetRandomVec2()
|
||||
|
||||
self:T( { SpawnVec2 = SpawnVec2 } )
|
||||
|
||||
local SpawnTemplate = self.SpawnGroups[SpawnIndex].SpawnTemplate
|
||||
|
||||
self:T( { Route = SpawnTemplate.route } )
|
||||
|
||||
for UnitID = 1, #SpawnTemplate.units do
|
||||
local UnitTemplate = SpawnTemplate.units[UnitID]
|
||||
self:T( 'Before Translation SpawnTemplate.units['..UnitID..'].x = ' .. UnitTemplate.x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. UnitTemplate.y )
|
||||
@@ -1310,10 +1323,9 @@ function SPAWN:_RandomizeZones( SpawnIndex )
|
||||
SpawnTemplate.route.points[1].x = SpawnVec2.x
|
||||
SpawnTemplate.route.points[1].y = SpawnVec2.y
|
||||
end
|
||||
|
||||
self:_RandomizeRoute( SpawnIndex )
|
||||
|
||||
|
||||
return self
|
||||
|
||||
end
|
||||
|
||||
function SPAWN:_TranslateRotate( SpawnIndex, SpawnRootX, SpawnRootY, SpawnX, SpawnY, SpawnAngle )
|
||||
|
||||
@@ -1,967 +0,0 @@
|
||||
--- Stages within a @{TASK} within a @{MISSION}. All of the STAGE functionality is considered internally administered and not to be used by any Mission designer.
|
||||
-- @module STAGE
|
||||
-- @author Flightcontrol
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
--- The STAGE class
|
||||
-- @type
|
||||
STAGE = {
|
||||
ClassName = "STAGE",
|
||||
MSG = { ID = "None", TIME = 10 },
|
||||
FREQUENCY = { NONE = 0, ONCE = 1, REPEAT = -1 },
|
||||
|
||||
Name = "NoStage",
|
||||
StageType = '',
|
||||
WaitTime = 1,
|
||||
Frequency = 1,
|
||||
MessageCount = 0,
|
||||
MessageInterval = 15,
|
||||
MessageShown = {},
|
||||
MessageShow = false,
|
||||
MessageFlash = false
|
||||
}
|
||||
|
||||
|
||||
function STAGE:New()
|
||||
local self = BASE:Inherit( self, BASE:New() )
|
||||
self:F()
|
||||
return self
|
||||
end
|
||||
|
||||
function STAGE:Execute( Mission, Client, Task )
|
||||
|
||||
local Valid = true
|
||||
|
||||
return Valid
|
||||
end
|
||||
|
||||
function STAGE:Executing( Mission, Client, Task )
|
||||
|
||||
end
|
||||
|
||||
function STAGE:Validate( Mission, Client, Task )
|
||||
local Valid = true
|
||||
|
||||
return Valid
|
||||
end
|
||||
|
||||
|
||||
STAGEBRIEF = {
|
||||
ClassName = "BRIEF",
|
||||
MSG = { ID = "Brief", TIME = 1 },
|
||||
Name = "Brief",
|
||||
StageBriefingTime = 0,
|
||||
StageBriefingDuration = 1
|
||||
}
|
||||
|
||||
function STAGEBRIEF:New()
|
||||
local self = BASE:Inherit( self, STAGE:New() )
|
||||
self:F()
|
||||
self.StageType = 'CLIENT'
|
||||
return self
|
||||
end
|
||||
|
||||
--- Execute
|
||||
-- @param #STAGEBRIEF self
|
||||
-- @param Mission#MISSION Mission
|
||||
-- @param Client#CLIENT Client
|
||||
-- @param Task#TASK Task
|
||||
-- @return #boolean
|
||||
function STAGEBRIEF:Execute( Mission, Client, Task )
|
||||
local Valid = BASE:Inherited(self):Execute( Mission, Client, Task )
|
||||
self:F()
|
||||
Client:ShowMissionBriefing( Mission.MissionBriefing )
|
||||
self.StageBriefingTime = timer.getTime()
|
||||
return Valid
|
||||
end
|
||||
|
||||
function STAGEBRIEF:Validate( Mission, Client, Task )
|
||||
local Valid = STAGE:Validate( Mission, Client, Task )
|
||||
self:T()
|
||||
|
||||
if timer.getTime() - self.StageBriefingTime <= self.StageBriefingDuration then
|
||||
return 0
|
||||
else
|
||||
self.StageBriefingTime = timer.getTime()
|
||||
return 1
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
STAGESTART = {
|
||||
ClassName = "START",
|
||||
MSG = { ID = "Start", TIME = 1 },
|
||||
Name = "Start",
|
||||
StageStartTime = 0,
|
||||
StageStartDuration = 1
|
||||
}
|
||||
|
||||
function STAGESTART:New()
|
||||
local self = BASE:Inherit( self, STAGE:New() )
|
||||
self:F()
|
||||
self.StageType = 'CLIENT'
|
||||
return self
|
||||
end
|
||||
|
||||
function STAGESTART:Execute( Mission, Client, Task )
|
||||
self:F()
|
||||
local Valid = BASE:Inherited(self):Execute( Mission, Client, Task )
|
||||
if Task.TaskBriefing then
|
||||
Client:Message( Task.TaskBriefing, 30, "Command" )
|
||||
else
|
||||
Client:Message( 'Task ' .. Task.TaskNumber .. '.', 30, "Command" )
|
||||
end
|
||||
self.StageStartTime = timer.getTime()
|
||||
return Valid
|
||||
end
|
||||
|
||||
function STAGESTART:Validate( Mission, Client, Task )
|
||||
self:F()
|
||||
local Valid = STAGE:Validate( Mission, Client, Task )
|
||||
|
||||
if timer.getTime() - self.StageStartTime <= self.StageStartDuration then
|
||||
return 0
|
||||
else
|
||||
self.StageStartTime = timer.getTime()
|
||||
return 1
|
||||
end
|
||||
|
||||
return 1
|
||||
|
||||
end
|
||||
|
||||
STAGE_CARGO_LOAD = {
|
||||
ClassName = "STAGE_CARGO_LOAD"
|
||||
}
|
||||
|
||||
function STAGE_CARGO_LOAD:New()
|
||||
local self = BASE:Inherit( self, STAGE:New() )
|
||||
self:F()
|
||||
self.StageType = 'CLIENT'
|
||||
return self
|
||||
end
|
||||
|
||||
function STAGE_CARGO_LOAD:Execute( Mission, Client, Task )
|
||||
self:F()
|
||||
local Valid = BASE:Inherited(self):Execute( Mission, Client, Task )
|
||||
|
||||
for LoadCargoID, LoadCargo in pairs( Task.Cargos.LoadCargos ) do
|
||||
LoadCargo:Load( Client )
|
||||
end
|
||||
|
||||
if Mission.MissionReportFlash and Client:IsTransport() then
|
||||
Client:ShowCargo()
|
||||
end
|
||||
|
||||
return Valid
|
||||
end
|
||||
|
||||
function STAGE_CARGO_LOAD:Validate( Mission, Client, Task )
|
||||
self:F()
|
||||
local Valid = STAGE:Validate( Mission, Client, Task )
|
||||
|
||||
return 1
|
||||
end
|
||||
|
||||
|
||||
STAGE_CARGO_INIT = {
|
||||
ClassName = "STAGE_CARGO_INIT"
|
||||
}
|
||||
|
||||
function STAGE_CARGO_INIT:New()
|
||||
local self = BASE:Inherit( self, STAGE:New() )
|
||||
self:F()
|
||||
self.StageType = 'CLIENT'
|
||||
return self
|
||||
end
|
||||
|
||||
function STAGE_CARGO_INIT:Execute( Mission, Client, Task )
|
||||
self:F()
|
||||
local Valid = BASE:Inherited(self):Execute( Mission, Client, Task )
|
||||
|
||||
for InitLandingZoneID, InitLandingZone in pairs( Task.LandingZones.LandingZones ) do
|
||||
self:T( InitLandingZone )
|
||||
InitLandingZone:Spawn()
|
||||
end
|
||||
|
||||
|
||||
self:T( Task.Cargos.InitCargos )
|
||||
for InitCargoID, InitCargoData in pairs( Task.Cargos.InitCargos ) do
|
||||
self:T( { InitCargoData } )
|
||||
InitCargoData:Spawn( Client )
|
||||
end
|
||||
|
||||
return Valid
|
||||
end
|
||||
|
||||
|
||||
function STAGE_CARGO_INIT:Validate( Mission, Client, Task )
|
||||
self:F()
|
||||
local Valid = STAGE:Validate( Mission, Client, Task )
|
||||
|
||||
return 1
|
||||
end
|
||||
|
||||
|
||||
|
||||
STAGEROUTE = {
|
||||
ClassName = "STAGEROUTE",
|
||||
MSG = { ID = "Route", TIME = 5 },
|
||||
Frequency = STAGE.FREQUENCY.REPEAT,
|
||||
Name = "Route"
|
||||
}
|
||||
|
||||
function STAGEROUTE:New()
|
||||
local self = BASE:Inherit( self, STAGE:New() )
|
||||
self:F()
|
||||
self.StageType = 'CLIENT'
|
||||
self.MessageSwitch = true
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Execute the routing.
|
||||
-- @param #STAGEROUTE self
|
||||
-- @param Mission#MISSION Mission
|
||||
-- @param Client#CLIENT Client
|
||||
-- @param Task#TASK Task
|
||||
function STAGEROUTE:Execute( Mission, Client, Task )
|
||||
self:F()
|
||||
local Valid = BASE:Inherited(self):Execute( Mission, Client, Task )
|
||||
|
||||
local RouteMessage = "Fly to: "
|
||||
self:T( Task.LandingZones )
|
||||
for LandingZoneID, LandingZoneName in pairs( Task.LandingZones.LandingZoneNames ) do
|
||||
RouteMessage = RouteMessage .. "\n " .. LandingZoneName .. ' at ' .. routines.getBRStringZone( { zone = LandingZoneName, ref = Client:GetClientGroupDCSUnit():getPoint(), true, true } ) .. ' km.'
|
||||
end
|
||||
|
||||
if Client:IsMultiSeated() then
|
||||
Client:Message( RouteMessage, self.MSG.TIME, "Co-Pilot", 20, "Route" )
|
||||
else
|
||||
Client:Message( RouteMessage, self.MSG.TIME, "Command", 20, "Route" )
|
||||
end
|
||||
|
||||
|
||||
if Mission.MissionReportFlash and Client:IsTransport() then
|
||||
Client:ShowCargo()
|
||||
end
|
||||
|
||||
return Valid
|
||||
end
|
||||
|
||||
function STAGEROUTE:Validate( Mission, Client, Task )
|
||||
self:F()
|
||||
local Valid = STAGE:Validate( Mission, Client, Task )
|
||||
|
||||
-- check if the Client is in the landing zone
|
||||
self:T( Task.LandingZones.LandingZoneNames )
|
||||
Task.CurrentLandingZoneName = routines.IsUnitNearZonesRadius( Client:GetClientGroupDCSUnit(), Task.LandingZones.LandingZoneNames, 500 )
|
||||
|
||||
if Task.CurrentLandingZoneName then
|
||||
|
||||
Task.CurrentLandingZone = Task.LandingZones.LandingZones[Task.CurrentLandingZoneName].CargoZone
|
||||
Task.CurrentCargoZone = Task.LandingZones.LandingZones[Task.CurrentLandingZoneName]
|
||||
|
||||
if Task.CurrentCargoZone then
|
||||
if not Task.Signalled then
|
||||
Task.Signalled = Task.CurrentCargoZone:Signal()
|
||||
end
|
||||
end
|
||||
|
||||
self:T( 1 )
|
||||
return 1
|
||||
end
|
||||
|
||||
self:T( 0 )
|
||||
return 0
|
||||
end
|
||||
|
||||
|
||||
|
||||
STAGELANDING = {
|
||||
ClassName = "STAGELANDING",
|
||||
MSG = { ID = "Landing", TIME = 10 },
|
||||
Name = "Landing",
|
||||
Signalled = false
|
||||
}
|
||||
|
||||
function STAGELANDING:New()
|
||||
local self = BASE:Inherit( self, STAGE:New() )
|
||||
self:F()
|
||||
self.StageType = 'CLIENT'
|
||||
return self
|
||||
end
|
||||
|
||||
--- Execute the landing coordination.
|
||||
-- @param #STAGELANDING self
|
||||
-- @param Mission#MISSION Mission
|
||||
-- @param Client#CLIENT Client
|
||||
-- @param Task#TASK Task
|
||||
function STAGELANDING:Execute( Mission, Client, Task )
|
||||
self:F()
|
||||
|
||||
if Client:IsMultiSeated() then
|
||||
Client:Message( "We have arrived at the landing zone.", self.MSG.TIME, "Co-Pilot" )
|
||||
else
|
||||
Client:Message( "You have arrived at the landing zone.", self.MSG.TIME, "Command" )
|
||||
end
|
||||
|
||||
Task.HostUnit = Task.CurrentCargoZone:GetHostUnit()
|
||||
|
||||
self:T( { Task.HostUnit } )
|
||||
|
||||
if Task.HostUnit then
|
||||
|
||||
Task.HostUnitName = Task.HostUnit:GetPrefix()
|
||||
Task.HostUnitTypeName = Task.HostUnit:GetTypeName()
|
||||
|
||||
local HostMessage = ""
|
||||
Task.CargoNames = ""
|
||||
|
||||
local IsFirst = true
|
||||
|
||||
for CargoID, Cargo in pairs( CARGOS ) do
|
||||
if Cargo.CargoType == Task.CargoType then
|
||||
|
||||
if Cargo:IsLandingRequired() then
|
||||
self:T( "Task for cargo " .. Cargo.CargoType .. " requires landing.")
|
||||
Task.IsLandingRequired = true
|
||||
end
|
||||
|
||||
if Cargo:IsSlingLoad() then
|
||||
self:T( "Task for cargo " .. Cargo.CargoType .. " is a slingload.")
|
||||
Task.IsSlingLoad = true
|
||||
end
|
||||
|
||||
if IsFirst then
|
||||
IsFirst = false
|
||||
Task.CargoNames = Task.CargoNames .. Cargo.CargoName .. "( " .. Cargo.CargoWeight .. " )"
|
||||
else
|
||||
Task.CargoNames = Task.CargoNames .. "; " .. Cargo.CargoName .. "( " .. Cargo.CargoWeight .. " )"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if Task.IsLandingRequired then
|
||||
HostMessage = "Land the helicopter to " .. Task.TEXT[1] .. " " .. Task.CargoNames .. "."
|
||||
else
|
||||
HostMessage = "Use the Radio menu and F6 to find the cargo, then fly or land near the cargo and " .. Task.TEXT[1] .. " " .. Task.CargoNames .. "."
|
||||
end
|
||||
|
||||
local Host = "Command"
|
||||
if Task.HostUnitName then
|
||||
Host = Task.HostUnitName .. " (" .. Task.HostUnitTypeName .. ")"
|
||||
else
|
||||
if Client:IsMultiSeated() then
|
||||
Host = "Co-Pilot"
|
||||
end
|
||||
end
|
||||
|
||||
Client:Message( HostMessage, self.MSG.TIME, Host )
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
function STAGELANDING:Validate( Mission, Client, Task )
|
||||
self:F()
|
||||
|
||||
Task.CurrentLandingZoneName = routines.IsUnitNearZonesRadius( Client:GetClientGroupDCSUnit(), Task.LandingZones.LandingZoneNames, 500 )
|
||||
if Task.CurrentLandingZoneName then
|
||||
|
||||
-- Client is in de landing zone.
|
||||
self:T( Task.CurrentLandingZoneName )
|
||||
|
||||
Task.CurrentLandingZone = Task.LandingZones.LandingZones[Task.CurrentLandingZoneName].CargoZone
|
||||
Task.CurrentCargoZone = Task.LandingZones.LandingZones[Task.CurrentLandingZoneName]
|
||||
|
||||
if Task.CurrentCargoZone then
|
||||
if not Task.Signalled then
|
||||
Task.Signalled = Task.CurrentCargoZone:Signal()
|
||||
end
|
||||
end
|
||||
else
|
||||
if Task.CurrentLandingZone then
|
||||
Task.CurrentLandingZone = nil
|
||||
end
|
||||
if Task.CurrentCargoZone then
|
||||
Task.CurrentCargoZone = nil
|
||||
end
|
||||
Task.Signalled = false
|
||||
Task:RemoveCargoMenus( Client )
|
||||
self:T( -1 )
|
||||
return -1
|
||||
end
|
||||
|
||||
|
||||
local DCSUnitVelocityVec3 = Client:GetClientGroupDCSUnit():getVelocity()
|
||||
local DCSUnitVelocity = ( DCSUnitVelocityVec3.x ^2 + DCSUnitVelocityVec3.y ^2 + DCSUnitVelocityVec3.z ^2 ) ^ 0.5
|
||||
|
||||
local DCSUnitPointVec3 = Client:GetClientGroupDCSUnit():getPoint()
|
||||
local LandHeight = land.getHeight( { x = DCSUnitPointVec3.x, y = DCSUnitPointVec3.z } )
|
||||
local DCSUnitHeight = DCSUnitPointVec3.y - LandHeight
|
||||
|
||||
self:T( { Task.IsLandingRequired, Client:GetClientGroupDCSUnit():inAir() } )
|
||||
if Task.IsLandingRequired and not Client:GetClientGroupDCSUnit():inAir() then
|
||||
self:T( 1 )
|
||||
Task.IsInAirTestRequired = true
|
||||
return 1
|
||||
end
|
||||
|
||||
self:T( { DCSUnitVelocity, DCSUnitHeight, LandHeight, Task.CurrentCargoZone.SignalHeight } )
|
||||
if Task.IsLandingRequired and DCSUnitVelocity <= 0.05 and DCSUnitHeight <= Task.CurrentCargoZone.SignalHeight then
|
||||
self:T( 1 )
|
||||
Task.IsInAirTestRequired = false
|
||||
return 1
|
||||
end
|
||||
|
||||
self:T( 0 )
|
||||
return 0
|
||||
end
|
||||
|
||||
STAGELANDED = {
|
||||
ClassName = "STAGELANDED",
|
||||
MSG = { ID = "Land", TIME = 10 },
|
||||
Name = "Landed",
|
||||
MenusAdded = false
|
||||
}
|
||||
|
||||
function STAGELANDED:New()
|
||||
local self = BASE:Inherit( self, STAGE:New() )
|
||||
self:F()
|
||||
self.StageType = 'CLIENT'
|
||||
return self
|
||||
end
|
||||
|
||||
function STAGELANDED:Execute( Mission, Client, Task )
|
||||
self:F()
|
||||
|
||||
if Task.IsLandingRequired then
|
||||
|
||||
local Host = "Command"
|
||||
if Task.HostUnitName then
|
||||
Host = Task.HostUnitName .. " (" .. Task.HostUnitTypeName .. ")"
|
||||
else
|
||||
if Client:IsMultiSeated() then
|
||||
Host = "Co-Pilot"
|
||||
end
|
||||
end
|
||||
|
||||
Client:Message( 'You have landed within the landing zone. Use the radio menu (F10) to ' .. Task.TEXT[1] .. ' the ' .. Task.CargoType .. '.',
|
||||
self.MSG.TIME, Host )
|
||||
|
||||
if not self.MenusAdded then
|
||||
Task.Cargo = nil
|
||||
Task:RemoveCargoMenus( Client )
|
||||
Task:AddCargoMenus( Client, CARGOS, 250 )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
function STAGELANDED:Validate( Mission, Client, Task )
|
||||
self:F()
|
||||
|
||||
if not routines.IsUnitNearZonesRadius( Client:GetClientGroupDCSUnit(), Task.CurrentLandingZoneName, 500 ) then
|
||||
self:T( "Client is not anymore in the landing zone, go back to stage Route, and remove cargo menus." )
|
||||
Task.Signalled = false
|
||||
Task:RemoveCargoMenus( Client )
|
||||
self:T( -2 )
|
||||
return -2
|
||||
end
|
||||
|
||||
local DCSUnitVelocityVec3 = Client:GetClientGroupDCSUnit():getVelocity()
|
||||
local DCSUnitVelocity = ( DCSUnitVelocityVec3.x ^2 + DCSUnitVelocityVec3.y ^2 + DCSUnitVelocityVec3.z ^2 ) ^ 0.5
|
||||
|
||||
local DCSUnitPointVec3 = Client:GetClientGroupDCSUnit():getPoint()
|
||||
local LandHeight = land.getHeight( { x = DCSUnitPointVec3.x, y = DCSUnitPointVec3.z } )
|
||||
local DCSUnitHeight = DCSUnitPointVec3.y - LandHeight
|
||||
|
||||
self:T( { Task.IsLandingRequired, Client:GetClientGroupDCSUnit():inAir() } )
|
||||
if Task.IsLandingRequired and Task.IsInAirTestRequired == true and Client:GetClientGroupDCSUnit():inAir() then
|
||||
self:T( "Client went back in the air. Go back to stage Landing." )
|
||||
self:T( -1 )
|
||||
return -1
|
||||
end
|
||||
|
||||
self:T( { DCSUnitVelocity, DCSUnitHeight, LandHeight, Task.CurrentCargoZone.SignalHeight } )
|
||||
if Task.IsLandingRequired and Task.IsInAirTestRequired == false and DCSUnitVelocity >= 2 and DCSUnitHeight >= Task.CurrentCargoZone.SignalHeight then
|
||||
self:T( "It seems the Client went back in the air and over the boundary limits. Go back to stage Landing." )
|
||||
self:T( -1 )
|
||||
return -1
|
||||
end
|
||||
|
||||
-- Wait until cargo is selected from the menu.
|
||||
if Task.IsLandingRequired then
|
||||
if not Task.Cargo then
|
||||
self:T( 0 )
|
||||
return 0
|
||||
end
|
||||
end
|
||||
|
||||
self:T( 1 )
|
||||
return 1
|
||||
end
|
||||
|
||||
STAGEUNLOAD = {
|
||||
ClassName = "STAGEUNLOAD",
|
||||
MSG = { ID = "Unload", TIME = 10 },
|
||||
Name = "Unload"
|
||||
}
|
||||
|
||||
function STAGEUNLOAD:New()
|
||||
local self = BASE:Inherit( self, STAGE:New() )
|
||||
self:F()
|
||||
self.StageType = 'CLIENT'
|
||||
return self
|
||||
end
|
||||
|
||||
--- Coordinate UnLoading
|
||||
-- @param #STAGEUNLOAD self
|
||||
-- @param Mission#MISSION Mission
|
||||
-- @param Client#CLIENT Client
|
||||
-- @param Task#TASK Task
|
||||
function STAGEUNLOAD:Execute( Mission, Client, Task )
|
||||
self:F()
|
||||
|
||||
if Client:IsMultiSeated() then
|
||||
Client:Message( 'The ' .. Task.CargoType .. ' are being ' .. Task.TEXT[2] .. ' within the landing zone. Wait until the helicopter is ' .. Task.TEXT[3] .. '.',
|
||||
"Co-Pilot" )
|
||||
else
|
||||
Client:Message( 'You are unloading the ' .. Task.CargoType .. ' ' .. Task.TEXT[2] .. ' within the landing zone. Wait until the helicopter is ' .. Task.TEXT[3] .. '.',
|
||||
"Command" )
|
||||
end
|
||||
Task:RemoveCargoMenus( Client )
|
||||
end
|
||||
|
||||
function STAGEUNLOAD:Executing( Mission, Client, Task )
|
||||
self:F()
|
||||
env.info( 'STAGEUNLOAD:Executing() Task.Cargo.CargoName = ' .. Task.Cargo.CargoName )
|
||||
|
||||
local TargetZoneName
|
||||
|
||||
if Task.TargetZoneName then
|
||||
TargetZoneName = Task.TargetZoneName
|
||||
else
|
||||
TargetZoneName = Task.CurrentLandingZoneName
|
||||
end
|
||||
|
||||
if Task.Cargo:UnLoad( Client, TargetZoneName ) then
|
||||
Task.ExecuteStage = _TransportExecuteStage.SUCCESS
|
||||
if Mission.MissionReportFlash then
|
||||
Client:ShowCargo()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Validate UnLoading
|
||||
-- @param #STAGEUNLOAD self
|
||||
-- @param Mission#MISSION Mission
|
||||
-- @param Client#CLIENT Client
|
||||
-- @param Task#TASK Task
|
||||
function STAGEUNLOAD:Validate( Mission, Client, Task )
|
||||
self:F()
|
||||
env.info( 'STAGEUNLOAD:Validate()' )
|
||||
|
||||
if routines.IsUnitNearZonesRadius( Client:GetClientGroupDCSUnit(), Task.CurrentLandingZoneName, 500 ) then
|
||||
else
|
||||
Task.ExecuteStage = _TransportExecuteStage.FAILED
|
||||
Task:RemoveCargoMenus( Client )
|
||||
if Client:IsMultiSeated() then
|
||||
Client:Message( 'The ' .. Task.CargoType .. " haven't been successfully " .. Task.TEXT[3] .. ' within the landing zone. Task and mission has failed.',
|
||||
_TransportStageMsgTime.DONE, "Co-Pilot" )
|
||||
else
|
||||
Client:Message( 'The ' .. Task.CargoType .. " haven't been successfully " .. Task.TEXT[3] .. ' within the landing zone. Task and mission has failed.',
|
||||
_TransportStageMsgTime.DONE, "Command" )
|
||||
end
|
||||
return 1
|
||||
end
|
||||
|
||||
if not Client:GetClientGroupDCSUnit():inAir() then
|
||||
else
|
||||
Task.ExecuteStage = _TransportExecuteStage.FAILED
|
||||
Task:RemoveCargoMenus( Client )
|
||||
if Client:IsMultiSeated() then
|
||||
Client:Message( 'The ' .. Task.CargoType .. " haven't been successfully " .. Task.TEXT[3] .. ' within the landing zone. Task and mission has failed.',
|
||||
_TransportStageMsgTime.DONE, "Co-Pilot" )
|
||||
else
|
||||
Client:Message( 'The ' .. Task.CargoType .. " haven't been successfully " .. Task.TEXT[3] .. ' within the landing zone. Task and mission has failed.',
|
||||
_TransportStageMsgTime.DONE, "Command" )
|
||||
end
|
||||
return 1
|
||||
end
|
||||
|
||||
if Task.ExecuteStage == _TransportExecuteStage.SUCCESS then
|
||||
if Client:IsMultiSeated() then
|
||||
Client:Message( 'The ' .. Task.CargoType .. ' have been sucessfully ' .. Task.TEXT[3] .. ' within the landing zone.', _TransportStageMsgTime.DONE, "Co-Pilot" )
|
||||
else
|
||||
Client:Message( 'The ' .. Task.CargoType .. ' have been sucessfully ' .. Task.TEXT[3] .. ' within the landing zone.', _TransportStageMsgTime.DONE, "Command" )
|
||||
end
|
||||
Task:RemoveCargoMenus( Client )
|
||||
Task.MissionTask:AddGoalCompletion( Task.MissionTask.GoalVerb, Task.CargoName, 1 ) -- We set the cargo as one more goal completed in the mission.
|
||||
return 1
|
||||
end
|
||||
|
||||
return 1
|
||||
end
|
||||
|
||||
STAGELOAD = {
|
||||
ClassName = "STAGELOAD",
|
||||
MSG = { ID = "Load", TIME = 10 },
|
||||
Name = "Load"
|
||||
}
|
||||
|
||||
function STAGELOAD:New()
|
||||
local self = BASE:Inherit( self, STAGE:New() )
|
||||
self:F()
|
||||
self.StageType = 'CLIENT'
|
||||
return self
|
||||
end
|
||||
|
||||
function STAGELOAD:Execute( Mission, Client, Task )
|
||||
self:F()
|
||||
|
||||
if not Task.IsSlingLoad then
|
||||
|
||||
local Host = "Command"
|
||||
if Task.HostUnitName then
|
||||
Host = Task.HostUnitName .. " (" .. Task.HostUnitTypeName .. ")"
|
||||
else
|
||||
if Client:IsMultiSeated() then
|
||||
Host = "Co-Pilot"
|
||||
end
|
||||
end
|
||||
|
||||
Client:Message( 'The ' .. Task.CargoType .. ' are being ' .. Task.TEXT[2] .. ' within the landing zone. Wait until the helicopter is ' .. Task.TEXT[3] .. '.',
|
||||
_TransportStageMsgTime.EXECUTING, Host )
|
||||
|
||||
-- Route the cargo to the Carrier
|
||||
|
||||
Task.Cargo:OnBoard( Client, Task.CurrentCargoZone, Task.OnBoardSide )
|
||||
Task.ExecuteStage = _TransportExecuteStage.EXECUTING
|
||||
else
|
||||
Task.ExecuteStage = _TransportExecuteStage.EXECUTING
|
||||
end
|
||||
end
|
||||
|
||||
function STAGELOAD:Executing( Mission, Client, Task )
|
||||
self:F()
|
||||
|
||||
-- If the Cargo is ready to be loaded, load it into the Client.
|
||||
|
||||
local Host = "Command"
|
||||
if Task.HostUnitName then
|
||||
Host = Task.HostUnitName .. " (" .. Task.HostUnitTypeName .. ")"
|
||||
else
|
||||
if Client:IsMultiSeated() then
|
||||
Host = "Co-Pilot"
|
||||
end
|
||||
end
|
||||
|
||||
if not Task.IsSlingLoad then
|
||||
self:T( Task.Cargo.CargoName)
|
||||
|
||||
if Task.Cargo:OnBoarded( Client, Task.CurrentCargoZone ) then
|
||||
|
||||
-- Load the Cargo onto the Client
|
||||
Task.Cargo:Load( Client )
|
||||
|
||||
-- Message to the pilot that cargo has been loaded.
|
||||
Client:Message( "The cargo " .. Task.Cargo.CargoName .. " has been loaded in our helicopter.",
|
||||
20, Host )
|
||||
Task.ExecuteStage = _TransportExecuteStage.SUCCESS
|
||||
|
||||
Client:ShowCargo()
|
||||
end
|
||||
else
|
||||
Client:Message( "Hook the " .. Task.CargoNames .. " onto the helicopter " .. Task.TEXT[3] .. " within the landing zone.",
|
||||
_TransportStageMsgTime.EXECUTING, Host )
|
||||
for CargoID, Cargo in pairs( CARGOS ) do
|
||||
self:T( "Cargo.CargoName = " .. Cargo.CargoName )
|
||||
|
||||
if Cargo:IsSlingLoad() then
|
||||
local CargoStatic = StaticObject.getByName( Cargo.CargoStaticName )
|
||||
if CargoStatic then
|
||||
self:T( "Cargo is found in the DCS simulator.")
|
||||
local CargoStaticPosition = CargoStatic:getPosition().p
|
||||
self:T( "Cargo Position x = " .. CargoStaticPosition.x .. ", y = " .. CargoStaticPosition.y .. ", z = " .. CargoStaticPosition.z )
|
||||
local CargoStaticHeight = routines.GetUnitHeight( CargoStatic )
|
||||
if CargoStaticHeight > 5 then
|
||||
self:T( "Cargo is airborne.")
|
||||
Cargo:StatusLoaded()
|
||||
Task.Cargo = Cargo
|
||||
Client:Message( 'The Cargo has been successfully hooked onto the helicopter and is now being sling loaded. Fly outside the landing zone.',
|
||||
self.MSG.TIME, Host )
|
||||
Task.ExecuteStage = _TransportExecuteStage.SUCCESS
|
||||
break
|
||||
end
|
||||
else
|
||||
self:T( "Cargo not found in the DCS simulator." )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function STAGELOAD:Validate( Mission, Client, Task )
|
||||
self:F()
|
||||
|
||||
self:T( "Task.CurrentLandingZoneName = " .. Task.CurrentLandingZoneName )
|
||||
|
||||
local Host = "Command"
|
||||
if Task.HostUnitName then
|
||||
Host = Task.HostUnitName .. " (" .. Task.HostUnitTypeName .. ")"
|
||||
else
|
||||
if Client:IsMultiSeated() then
|
||||
Host = "Co-Pilot"
|
||||
end
|
||||
end
|
||||
|
||||
if not Task.IsSlingLoad then
|
||||
if not routines.IsUnitNearZonesRadius( Client:GetClientGroupDCSUnit(), Task.CurrentLandingZoneName, 500 ) then
|
||||
Task:RemoveCargoMenus( Client )
|
||||
Task.ExecuteStage = _TransportExecuteStage.FAILED
|
||||
Task.CargoName = nil
|
||||
Client:Message( "The " .. Task.CargoType .. " loading has been aborted. You flew outside the pick-up zone while loading. ",
|
||||
self.MSG.TIME, Host )
|
||||
self:T( -1 )
|
||||
return -1
|
||||
end
|
||||
|
||||
local DCSUnitVelocityVec3 = Client:GetClientGroupDCSUnit():getVelocity()
|
||||
local DCSUnitVelocity = ( DCSUnitVelocityVec3.x ^2 + DCSUnitVelocityVec3.y ^2 + DCSUnitVelocityVec3.z ^2 ) ^ 0.5
|
||||
|
||||
local DCSUnitPointVec3 = Client:GetClientGroupDCSUnit():getPoint()
|
||||
local LandHeight = land.getHeight( { x = DCSUnitPointVec3.x, y = DCSUnitPointVec3.z } )
|
||||
local DCSUnitHeight = DCSUnitPointVec3.y - LandHeight
|
||||
|
||||
self:T( { Task.IsLandingRequired, Client:GetClientGroupDCSUnit():inAir() } )
|
||||
if Task.IsLandingRequired and Task.IsInAirTestRequired == true and Client:GetClientGroupDCSUnit():inAir() then
|
||||
Task:RemoveCargoMenus( Client )
|
||||
Task.ExecuteStage = _TransportExecuteStage.FAILED
|
||||
Task.CargoName = nil
|
||||
Client:Message( "The " .. Task.CargoType .. " loading has been aborted. Re-start the " .. Task.TEXT[3] .. " process. Don't fly outside the pick-up zone.",
|
||||
self.MSG.TIME, Host )
|
||||
self:T( -1 )
|
||||
return -1
|
||||
end
|
||||
|
||||
self:T( { DCSUnitVelocity, DCSUnitHeight, LandHeight, Task.CurrentCargoZone.SignalHeight } )
|
||||
if Task.IsLandingRequired and Task.IsInAirTestRequired == false and DCSUnitVelocity >= 2 and DCSUnitHeight >= Task.CurrentCargoZone.SignalHeight then
|
||||
Task:RemoveCargoMenus( Client )
|
||||
Task.ExecuteStage = _TransportExecuteStage.FAILED
|
||||
Task.CargoName = nil
|
||||
Client:Message( "The " .. Task.CargoType .. " loading has been aborted. Re-start the " .. Task.TEXT[3] .. " process. Don't fly outside the pick-up zone.",
|
||||
self.MSG.TIME, Host )
|
||||
self:T( -1 )
|
||||
return -1
|
||||
end
|
||||
|
||||
if Task.ExecuteStage == _TransportExecuteStage.SUCCESS then
|
||||
Task:RemoveCargoMenus( Client )
|
||||
Client:Message( "Good Job. The " .. Task.CargoType .. " has been sucessfully " .. Task.TEXT[3] .. " within the landing zone.",
|
||||
self.MSG.TIME, Host )
|
||||
Task.MissionTask:AddGoalCompletion( Task.MissionTask.GoalVerb, Task.CargoName, 1 )
|
||||
self:T( 1 )
|
||||
return 1
|
||||
end
|
||||
|
||||
else
|
||||
if Task.ExecuteStage == _TransportExecuteStage.SUCCESS then
|
||||
CargoStatic = StaticObject.getByName( Task.Cargo.CargoStaticName )
|
||||
if CargoStatic and not routines.IsStaticInZones( CargoStatic, Task.CurrentLandingZoneName ) then
|
||||
Client:Message( "Good Job. The " .. Task.CargoType .. " has been sucessfully " .. Task.TEXT[3] .. " and flown outside of the landing zone.",
|
||||
self.MSG.TIME, Host )
|
||||
Task.MissionTask:AddGoalCompletion( Task.MissionTask.GoalVerb, Task.Cargo.CargoName, 1 )
|
||||
self:T( 1 )
|
||||
return 1
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
self:T( 0 )
|
||||
return 0
|
||||
end
|
||||
|
||||
|
||||
STAGEDONE = {
|
||||
ClassName = "STAGEDONE",
|
||||
MSG = { ID = "Done", TIME = 10 },
|
||||
Name = "Done"
|
||||
}
|
||||
|
||||
function STAGEDONE:New()
|
||||
local self = BASE:Inherit( self, STAGE:New() )
|
||||
self:F()
|
||||
self.StageType = 'AI'
|
||||
return self
|
||||
end
|
||||
|
||||
function STAGEDONE:Execute( Mission, Client, Task )
|
||||
self:F()
|
||||
|
||||
end
|
||||
|
||||
function STAGEDONE:Validate( Mission, Client, Task )
|
||||
self:F()
|
||||
|
||||
Task:Done()
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
STAGEARRIVE = {
|
||||
ClassName = "STAGEARRIVE",
|
||||
MSG = { ID = "Arrive", TIME = 10 },
|
||||
Name = "Arrive"
|
||||
}
|
||||
|
||||
function STAGEARRIVE:New()
|
||||
local self = BASE:Inherit( self, STAGE:New() )
|
||||
self:F()
|
||||
self.StageType = 'CLIENT'
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Execute Arrival
|
||||
-- @param #STAGEARRIVE self
|
||||
-- @param Mission#MISSION Mission
|
||||
-- @param Client#CLIENT Client
|
||||
-- @param Task#TASK Task
|
||||
function STAGEARRIVE:Execute( Mission, Client, Task )
|
||||
self:F()
|
||||
|
||||
if Client:IsMultiSeated() then
|
||||
Client:Message( 'We have arrived at ' .. Task.CurrentLandingZoneName .. ".", self.MSG.TIME, "Co-Pilot" )
|
||||
else
|
||||
Client:Message( 'We have arrived at ' .. Task.CurrentLandingZoneName .. ".", self.MSG.TIME, "Command" )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function STAGEARRIVE:Validate( Mission, Client, Task )
|
||||
self:F()
|
||||
|
||||
Task.CurrentLandingZoneID = routines.IsUnitInZones( Client:GetClientGroupDCSUnit(), Task.LandingZones )
|
||||
if ( Task.CurrentLandingZoneID ) then
|
||||
else
|
||||
return -1
|
||||
end
|
||||
|
||||
return 1
|
||||
end
|
||||
|
||||
STAGEGROUPSDESTROYED = {
|
||||
ClassName = "STAGEGROUPSDESTROYED",
|
||||
DestroyGroupSize = -1,
|
||||
Frequency = STAGE.FREQUENCY.REPEAT,
|
||||
MSG = { ID = "DestroyGroup", TIME = 10 },
|
||||
Name = "GroupsDestroyed"
|
||||
}
|
||||
|
||||
function STAGEGROUPSDESTROYED:New()
|
||||
local self = BASE:Inherit( self, STAGE:New() )
|
||||
self:F()
|
||||
self.StageType = 'AI'
|
||||
return self
|
||||
end
|
||||
|
||||
--function STAGEGROUPSDESTROYED:Execute( Mission, Client, Task )
|
||||
--
|
||||
-- Client:Message( 'Task: Still ' .. DestroyGroupSize .. " of " .. Task.DestroyGroupCount .. " " .. Task.DestroyGroupType .. " to be destroyed!", self.MSG.TIME, Mission.Name .. "/Stage" )
|
||||
--
|
||||
--end
|
||||
|
||||
function STAGEGROUPSDESTROYED:Validate( Mission, Client, Task )
|
||||
self:F()
|
||||
|
||||
if Task.MissionTask:IsGoalReached() then
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
end
|
||||
end
|
||||
|
||||
function STAGEGROUPSDESTROYED:Execute( Mission, Client, Task )
|
||||
self:F()
|
||||
self:T( { Task.ClassName, Task.Destroyed } )
|
||||
--env.info( 'Event Table Task = ' .. tostring(Task) )
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
--[[
|
||||
_TransportStage: Defines the different stages of which of transport missions can be in. This table is internal and is used to control the sequence of messages, actions and flow.
|
||||
|
||||
- _TransportStage.START
|
||||
- _TransportStage.ROUTE
|
||||
- _TransportStage.LAND
|
||||
- _TransportStage.EXECUTE
|
||||
- _TransportStage.DONE
|
||||
- _TransportStage.REMOVE
|
||||
--]]
|
||||
_TransportStage = {
|
||||
HOLD = "HOLD",
|
||||
START = "START",
|
||||
ROUTE = "ROUTE",
|
||||
LANDING = "LANDING",
|
||||
LANDED = "LANDED",
|
||||
EXECUTING = "EXECUTING",
|
||||
LOAD = "LOAD",
|
||||
UNLOAD = "UNLOAD",
|
||||
DONE = "DONE",
|
||||
NEXT = "NEXT"
|
||||
}
|
||||
|
||||
_TransportStageMsgTime = {
|
||||
HOLD = 10,
|
||||
START = 60,
|
||||
ROUTE = 5,
|
||||
LANDING = 10,
|
||||
LANDED = 30,
|
||||
EXECUTING = 30,
|
||||
LOAD = 30,
|
||||
UNLOAD = 30,
|
||||
DONE = 30,
|
||||
NEXT = 0
|
||||
}
|
||||
|
||||
_TransportStageTime = {
|
||||
HOLD = 10,
|
||||
START = 5,
|
||||
ROUTE = 5,
|
||||
LANDING = 1,
|
||||
LANDED = 1,
|
||||
EXECUTING = 5,
|
||||
LOAD = 5,
|
||||
UNLOAD = 5,
|
||||
DONE = 1,
|
||||
NEXT = 0
|
||||
}
|
||||
|
||||
_TransportStageAction = {
|
||||
REPEAT = -1,
|
||||
NONE = 0,
|
||||
ONCE = 1
|
||||
}
|
||||
@@ -547,19 +547,20 @@ end
|
||||
function ZONE_UNIT:GetRandomVec2()
|
||||
self:F( self.ZoneName )
|
||||
|
||||
local Point = {}
|
||||
local PointVec2 = self.ZoneUNIT:GetPointVec2()
|
||||
if not PointVec2 then
|
||||
PointVec2 = self.LastVec2
|
||||
local RandomVec2 = {}
|
||||
local Vec2 = self.ZoneUNIT:GetVec2()
|
||||
|
||||
if not Vec2 then
|
||||
Vec2 = self.LastVec2
|
||||
end
|
||||
|
||||
local angle = math.random() * math.pi*2;
|
||||
Point.x = PointVec2.x + math.cos( angle ) * math.random() * self:GetRadius();
|
||||
Point.y = PointVec2.y + math.sin( angle ) * math.random() * self:GetRadius();
|
||||
RandomVec2.x = Vec2.x + math.cos( angle ) * math.random() * self:GetRadius();
|
||||
RandomVec2.y = Vec2.y + math.sin( angle ) * math.random() * self:GetRadius();
|
||||
|
||||
self:T( { Point } )
|
||||
self:T( { RandomVec2 } )
|
||||
|
||||
return Point
|
||||
return RandomVec2
|
||||
end
|
||||
|
||||
--- Returns the @{DCSTypes#Vec3} of the ZONE_UNIT.
|
||||
|
||||
Reference in New Issue
Block a user