diff --git a/Moose Development/Moose/Base.lua b/Moose Development/Moose/Base.lua
index 4c089958d..1b1a7f9e7 100644
--- a/Moose Development/Moose/Base.lua
+++ b/Moose Development/Moose/Base.lua
@@ -331,8 +331,8 @@ function BASE:SetState( Object, StateName, State )
if not self.States[ClassNameAndID] then
self.States[ClassNameAndID] = {}
end
-
self.States[ClassNameAndID][StateName] = State
+ self:E( { ClassNameAndID, StateName, State } )
return self.States[ClassNameAndID][StateName]
end
@@ -340,8 +340,11 @@ end
function BASE:GetState( Object, StateName )
local ClassNameAndID = Object:GetClassNameAndID()
+ self:E( { ClassNameAndID } )
if self.States[ClassNameAndID] then
- return self.States[ClassNameAndID][StateName]
+ local State = self.States[ClassNameAndID][StateName]
+ self:E( { ClassNameAndID, StateName, State } )
+ return State
end
return nil
diff --git a/Moose Development/Moose/Database.lua b/Moose Development/Moose/Database.lua
index ca8dfa7f2..c74cbdd64 100644
--- a/Moose Development/Moose/Database.lua
+++ b/Moose Development/Moose/Database.lua
@@ -54,9 +54,6 @@ DATABASE = {
ClientsByName = {},
ClientsByID = {},
},
- DCSUnits = {},
- DCSGroups = {},
- DCSStatics = {},
UNITS = {},
STATICS = {},
GROUPS = {},
@@ -125,10 +122,13 @@ end
--- Adds a Unit based on the Unit Name in the DATABASE.
-- @param #DATABASE self
-function DATABASE:AddUnit( DCSUnit, DCSUnitName )
+function DATABASE:AddUnit( DCSUnitName )
- self.DCSUnits[DCSUnitName] = DCSUnit
- self.UNITS[DCSUnitName] = UNIT:Register( DCSUnitName )
+ if not self.UNITS[DCSUnitName] then
+ self.UNITS[DCSUnitName] = UNIT:Register( DCSUnitName )
+ end
+
+ return self.UNITS[DCSUnitName]
end
@@ -136,15 +136,16 @@ end
-- @param #DATABASE self
function DATABASE:DeleteUnit( DCSUnitName )
- self.DCSUnits[DCSUnitName] = nil
+ --self.UNITS[DCSUnitName] = nil
end
--- Adds a Static based on the Static Name in the DATABASE.
-- @param #DATABASE self
-function DATABASE:AddStatic( DCSStatic, DCSStaticName )
+function DATABASE:AddStatic( DCSStaticName )
- self.DCSStatics[DCSStaticName] = DCSStatic
- self.STATICS[DCSStaticName] = STATIC:Register( DCSStaticName )
+ if not self.STATICS[DCSStaticName] then
+ self.STATICS[DCSStaticName] = STATIC:Register( DCSStaticName )
+ end
end
@@ -152,7 +153,7 @@ end
-- @param #DATABASE self
function DATABASE:DeleteStatic( DCSStaticName )
- self.DCSStatics[DCSStaticName] = nil
+ --self.STATICS[DCSStaticName] = nil
end
--- Finds a STATIC based on the StaticName.
@@ -181,8 +182,11 @@ end
-- @param #DATABASE self
function DATABASE:AddClient( ClientName )
- self.CLIENTS[ClientName] = CLIENT:Register( ClientName )
- self:E( self.CLIENTS[ClientName]:GetClassNameAndID() )
+ if not self.CLIENTS[ClientName] then
+ self.CLIENTS[ClientName] = CLIENT:Register( ClientName )
+ end
+
+ return self.CLIENTS[ClientName]
end
@@ -199,10 +203,13 @@ end
--- Adds a GROUP based on the GroupName in the DATABASE.
-- @param #DATABASE self
-function DATABASE:AddGroup( DCSGroup, GroupName )
+function DATABASE:AddGroup( GroupName )
- self.DCSGroups[GroupName] = DCSGroup
- self.GROUPS[GroupName] = GROUP:Register( GroupName )
+ if not self.GROUPS[GroupName] then
+ self.GROUPS[GroupName] = GROUP:Register( GroupName )
+ end
+
+ return self.GROUPS[GroupName]
end
--- Adds a player based on the Player Name in the DATABASE.
@@ -261,7 +268,7 @@ function DATABASE:Spawn( SpawnTemplate )
SpawnTemplate.SpawnCountryID = SpawnCountryID
SpawnTemplate.SpawnCategoryID = SpawnCategoryID
- local SpawnGroup = GROUP:Register( SpawnTemplate.name )
+ local SpawnGroup = self:AddGroup( SpawnTemplate.name )
return SpawnGroup
end
@@ -400,14 +407,14 @@ function DATABASE:_RegisterGroupsAndUnits()
if DCSGroup:isExist() then
local DCSGroupName = DCSGroup:getName()
- self:E( { "Register Group:", DCSGroup, DCSGroupName } )
- self:AddGroup( DCSGroup, DCSGroupName )
+ self:E( { "Register Group:", DCSGroupName } )
+ self:AddGroup( DCSGroupName )
for DCSUnitId, DCSUnit in pairs( DCSGroup:getUnits() ) do
local DCSUnitName = DCSUnit:getName()
- self:E( { "Register Unit:", DCSUnit, DCSUnitName } )
- self:AddUnit( DCSUnit, DCSUnitName )
+ self:E( { "Register Unit:", DCSUnitName } )
+ self:AddUnit( DCSUnitName )
end
else
self:E( { "Group does not exist: ", DCSGroup } )
@@ -441,8 +448,8 @@ function DATABASE:_RegisterStatics()
if DCSStatic:isExist() then
local DCSStaticName = DCSStatic:getName()
- self:E( { "Register Static:", DCSStatic, DCSStaticName } )
- self:AddStatic( DCSStatic, DCSStaticName )
+ self:E( { "Register Static:", DCSStaticName } )
+ self:AddStatic( DCSStaticName )
else
self:E( { "Static does not exist: ", DCSStatic } )
end
@@ -462,8 +469,8 @@ function DATABASE:_EventOnBirth( Event )
self:F2( { Event } )
if Event.IniDCSUnit then
- self:AddUnit( Event.IniDCSUnit, Event.IniDCSUnitName )
- self:AddGroup( Event.IniDCSGroup, Event.IniDCSGroupName )
+ self:AddUnit( Event.IniDCSUnitName )
+ self:AddGroup( Event.IniDCSGroupName )
self:_EventOnPlayerEnterUnit( Event )
end
end
@@ -476,7 +483,7 @@ function DATABASE:_EventOnDeadOrCrash( Event )
self:F2( { Event } )
if Event.IniDCSUnit then
- if self.DCSUnits[Event.IniDCSUnitName] then
+ if self.UNITS[Event.IniDCSUnitName] then
self:DeleteUnit( Event.IniDCSUnitName )
-- add logic to correctly remove a group once all units are destroyed...
end
@@ -558,19 +565,6 @@ function DATABASE:ForEach( IteratorFunction, arg, Set )
end
---- Iterate the DATABASE and call an iterator function for each **alive** unit, providing the DCSUnit and optional parameters.
--- @param #DATABASE self
--- @param #function IteratorFunction The function that will be called when there is an alive unit in the database. The function needs to accept a DCSUnit parameter.
--- @return #DATABASE self
-function DATABASE:ForEachDCSUnit( IteratorFunction, ... )
- self:F2( arg )
-
- self:ForEach( IteratorFunction, arg, self.DCSUnits )
-
- return self
-end
-
-
--- Iterate the DATABASE and call an iterator function for each **alive** UNIT, providing the UNIT and optional parameters.
-- @param #DATABASE self
-- @param #function IteratorFunction The function that will be called when there is an alive UNIT in the database. The function needs to accept a UNIT parameter.
diff --git a/Moose Development/Moose/Escort.lua b/Moose Development/Moose/Escort.lua
index 355a576fb..2a543e7c5 100644
--- a/Moose Development/Moose/Escort.lua
+++ b/Moose Development/Moose/Escort.lua
@@ -99,23 +99,31 @@
-- * @{#ESCORT.MenuEvasion: Creates a menu structure to set the evasion techniques when the escort is under threat.
-- * @{#ESCORT.MenuResumeMission}: Creates a menu structure so that the escort can resume from a waypoint.
--
+--
+-- @usage
+-- -- Declare a new EscortPlanes object as follows:
+--
+-- -- First find the GROUP object and the CLIENT object.
+-- local EscortClient = CLIENT:FindByName( "Unit Name" ) -- The Unit Name is the name of the unit flagged with the skill Client in the mission editor.
+-- local EscortGroup = GROUP:FindByName( "Group Name" ) -- The Group Name is the name of the group that will escort the Escort Client.
+--
+-- -- Now use these 2 objects to construct the new EscortPlanes object.
+-- EscortPlanes = ESCORT:New( EscortClient, EscortGroup, "Desert", "Welcome to the mission. You are escorted by a plane with code name 'Desert', which can be instructed through the F10 radio menu." )
+--
+--
+--
-- @module Escort
-- @author FlightControl
-
-
-
-
-
-
----
+--- ESCORT class
-- @type ESCORT
-- @extends Base#BASE
-- @field Client#CLIENT EscortClient
-- @field Group#GROUP EscortGroup
-- @field #string EscortName
-- @field #ESCORT.MODE EscortMode The mode the escort is in.
--- @field #number FollowScheduler The id of the _FollowScheduler function.
+-- @field Scheduler#SCHEDULER FollowScheduler The instance of the SCHEDULER class.
+-- @field #number FollowDistance The current follow distance.
-- @field #boolean ReportTargets If true, nearby targets are reported.
-- @Field DCSTypes#AI.Option.Air.val.ROE OptionROE Which ROE is set to the EscortGroup.
-- @field DCSTypes#AI.Option.Air.val.REACTION_ON_THREAT OptionReactionOnThreat Which REACTION_ON_THREAT is set to the EscortGroup.
@@ -125,7 +133,7 @@ ESCORT = {
EscortName = nil, -- The Escort Name
EscortClient = nil,
EscortGroup = nil,
- EscortMode = nil,
+ EscortMode = 1,
MODE = {
FOLLOW = 1,
MISSION = 2,
@@ -135,6 +143,7 @@ ESCORT = {
ReportTargets = true,
OptionROE = AI.Option.Air.val.ROE.OPEN_FIRE,
OptionReactionOnThreat = AI.Option.Air.val.REACTION_ON_THREAT.ALLOW_ABORT_MISSION,
+ SmokeDirectionVector = false,
TaskPoints = {}
}
@@ -156,6 +165,15 @@ ESCORT = {
-- @param Group#GROUP EscortGroup The group AI escorting the EscortClient.
-- @param #string EscortName Name of the escort.
-- @return #ESCORT self
+-- @usage
+-- -- Declare a new EscortPlanes object as follows:
+--
+-- -- First find the GROUP object and the CLIENT object.
+-- local EscortClient = CLIENT:FindByName( "Unit Name" ) -- The Unit Name is the name of the unit flagged with the skill Client in the mission editor.
+-- local EscortGroup = GROUP:FindByName( "Group Name" ) -- The Group Name is the name of the group that will escort the Escort Client.
+--
+-- -- Now use these 2 objects to construct the new EscortPlanes object.
+-- EscortPlanes = ESCORT:New( EscortClient, EscortGroup, "Desert", "Welcome to the mission. You are escorted by a plane with code name 'Desert', which can be instructed through the F10 radio menu." )
function ESCORT:New( EscortClient, EscortGroup, EscortName, EscortBriefing )
local self = BASE:Inherit( self, BASE:New() )
self:F( { EscortClient, EscortGroup, EscortName } )
@@ -165,8 +183,6 @@ function ESCORT:New( EscortClient, EscortGroup, EscortName, EscortBriefing )
self.EscortName = EscortName
self.EscortBriefing = EscortBriefing
- self:T( EscortGroup:GetClassNameAndID() )
-
-- Set EscortGroup known at EscortClient.
if not self.EscortClient._EscortGroups then
self.EscortClient._EscortGroups = {}
@@ -177,10 +193,8 @@ function ESCORT:New( EscortClient, EscortGroup, EscortName, EscortBriefing )
self.EscortClient._EscortGroups[EscortGroup:GetName()].EscortGroup = self.EscortGroup
self.EscortClient._EscortGroups[EscortGroup:GetName()].EscortName = self.EscortName
self.EscortClient._EscortGroups[EscortGroup:GetName()].Targets = {}
- self.EscortMode = ESCORT.MODE.FOLLOW
end
-
self.EscortMenu = MENU_CLIENT:New( self.EscortClient, self.EscortName )
self.EscortGroup:WayPointInitialize(1)
@@ -194,9 +208,24 @@ function ESCORT:New( EscortClient, EscortGroup, EscortName, EscortBriefing )
60, EscortClient
)
+ self.FollowDistance = 100
+ self.CT1 = 0
+ self.GT1 = 0
+ self.FollowScheduler = SCHEDULER:New( self, self._FollowScheduler, {}, 1, .5, .01 )
+ self.EscortMode = ESCORT.MODE.MISSION
+ self.FollowScheduler:Stop()
+
return self
end
+--- This function is for test, it will put on the frequency of the FollowScheduler a red smoke at the direction vector calculated for the escort to fly to.
+-- This allows to visualize where the escort is flying to.
+-- @param #ESCORT self
+-- @param #boolean SmokeDirection If true, then the direction vector will be smoked.
+function ESCORT:TestSmokeDirectionVector( SmokeDirection )
+ self.SmokeDirectionVector = ( SmokeDirection == true ) and true or false
+end
+
--- Defines the default menus
-- @param #ESCORT self
@@ -223,6 +252,7 @@ function ESCORT:Menus()
self:MenuEvasion()
self:MenuResumeMission()
+
return self
end
@@ -633,7 +663,7 @@ function ESCORT._HoldPosition( MenuParam )
local OrbitHeight = MenuParam.ParamHeight
local OrbitSeconds = MenuParam.ParamSeconds -- Not implemented yet
- routines.removeFunction( self.FollowScheduler )
+ self.FollowScheduler:Stop()
local PointFrom = {}
local GroupPoint = EscortGroup:GetUnit(1):GetPointVec3()
@@ -662,6 +692,7 @@ function ESCORT._HoldPosition( MenuParam )
EscortGroup:SetTask( EscortGroup:TaskRoute( Points ) )
EscortGroup:MessageToClient( "Orbiting at location.", 10, EscortClient )
+
end
--- @param #MENUPARAM MenuParam
@@ -684,9 +715,7 @@ end
function ESCORT:JoinUpAndFollow( EscortGroup, EscortClient, Distance )
self:F( { EscortGroup, EscortClient, Distance } )
- if self.FollowScheduler then
- routines.removeFunction( self.FollowScheduler )
- end
+ self.FollowScheduler:Stop()
EscortGroup:OptionROEHoldFire()
EscortGroup:OptionROTPassiveDefense()
@@ -695,8 +724,8 @@ function ESCORT:JoinUpAndFollow( EscortGroup, EscortClient, Distance )
self.CT1 = 0
self.GT1 = 0
- --self.FollowScheduler = routines.scheduleFunction( self._FollowScheduler, { self, Distance }, timer.getTime() + 1, .5 )
- self.FollowScheduler = SCHEDULER:New( self, self._FollowScheduler, { Distance }, 1, .5, .1 )
+ self.FollowScheduler:Start()
+
EscortGroup:MessageToClient( "Rejoining and Following at " .. Distance .. "!", 30, EscortClient )
end
@@ -768,11 +797,7 @@ function ESCORT._ScanTargets( MenuParam )
local ScanDuration = MenuParam.ParamScanDuration
- if self.FollowScheduler then
- routines.removeFunction( self.FollowScheduler )
- end
-
- self:T( { "FollowScheduler after removefunction: ", self.FollowScheduler } )
+ self.FollowScheduler:Stop()
if EscortGroup:IsHelicopter() then
SCHEDULER:New( EscortGroup, EscortGroup.PushTask,
@@ -797,16 +822,16 @@ function ESCORT._ScanTargets( MenuParam )
EscortGroup:MessageToClient( "Scanning targets for " .. ScanDuration .. " seconds.", ScanDuration, EscortClient )
if self.EscortMode == ESCORT.MODE.FOLLOW then
- --self.FollowScheduler = routines.scheduleFunction( self._FollowScheduler, { self, Distance }, timer.getTime() + ScanDuration, 1 )
self.FollowScheduler:Start()
end
end
+--- @param Group#GROUP EscortGroup
function _Resume( EscortGroup )
env.info( '_Resume' )
- local Escort = EscortGroup.Escort -- #ESCORT
+ local Escort = EscortGroup:GetState( EscortGroup, "Escort" )
env.info( "EscortMode = " .. Escort.EscortMode )
if Escort.EscortMode == ESCORT.MODE.FOLLOW then
Escort:JoinUpAndFollow( EscortGroup, Escort.EscortClient, Escort.Distance )
@@ -819,19 +844,18 @@ function ESCORT._AttackTarget( MenuParam )
local self = MenuParam.ParamSelf
local EscortGroup = self.EscortGroup
+
local EscortClient = self.EscortClient
local AttackUnit = MenuParam.ParamUnit -- Unit#UNIT
- if self.FollowScheduler then
- routines.removeFunction( self.FollowScheduler )
- end
+ self.FollowScheduler:Stop()
self:T( AttackUnit )
if EscortGroup:IsAir() then
EscortGroup:OptionROEOpenFire()
EscortGroup:OptionROTPassiveDefense()
- EscortGroup.Escort = self -- Need to do this trick to get the reference for the escort in the _Resume function.
+ EscortGroup:SetState( EscortGroup, "Escort", self )
-- routines.scheduleFunction(
-- EscortGroup.PushTask,
-- { EscortGroup,
@@ -846,7 +870,7 @@ function ESCORT._AttackTarget( MenuParam )
EscortGroup.PushTask,
{ EscortGroup:TaskCombo(
{ EscortGroup:TaskAttackUnit( AttackUnit ),
- EscortGroup:TaskFunction( 1, 2, "_Resume", {"''"} )
+ EscortGroup:TaskFunction( 1, 2, "_Resume", { "''" } )
}
)
}, 10
@@ -870,9 +894,9 @@ function ESCORT._AttackTarget( MenuParam )
}, 10
)
end
+
EscortGroup:MessageToClient( "Engaging Designated Unit!", 10, EscortClient )
-
end
--- @param #MENUPARAM MenuParam
@@ -884,10 +908,7 @@ function ESCORT._AssistTarget( MenuParam )
local EscortGroupAttack = MenuParam.ParamEscortGroup
local AttackUnit = MenuParam.ParamUnit -- Unit#UNIT
- if self.FollowScheduler then
- routines.removeFunction( self.FollowScheduler )
- end
-
+ self.FollowScheduler:Stop()
self:T( AttackUnit )
@@ -973,8 +994,7 @@ function ESCORT._ResumeMission( MenuParam )
local WayPoint = MenuParam.ParamWayPoint
- routines.removeFunction( self.FollowScheduler )
- self.FollowScheduler = nil
+ self.FollowScheduler:Stop()
local WayPoints = EscortGroup:GetTaskRoute()
self:T( WayPoint, WayPoints )
@@ -1005,16 +1025,21 @@ function ESCORT:RegisterRoute()
end
--- @param Escort#ESCORT self
-function ESCORT:_FollowScheduler( FollowDistance )
- self:F( { FollowDistance })
+function ESCORT:_FollowScheduler()
+ self:F( { self.FollowDistance } )
+ self:T( {self.EscortClient.UnitName, self.EscortGroup.GroupName } )
if self.EscortGroup:IsAlive() and self.EscortClient:IsAlive() then
local ClientUnit = self.EscortClient:GetClientGroupUnit()
local GroupUnit = self.EscortGroup:GetUnit( 1 )
+ local FollowDistance = self.FollowDistance
+
+ self:T( {ClientUnit.UnitName, GroupUnit.UnitName } )
if self.CT1 == 0 and self.GT1 == 0 then
self.CV1 = ClientUnit:GetPointVec3()
+ self:T( { "self.CV1", self.CV1 } )
self.CT1 = timer.getTime()
self.GV1 = GroupUnit:GetPointVec3()
self.GT1 = timer.getTime()
@@ -1074,7 +1099,10 @@ function ESCORT:_FollowScheduler( FollowDistance )
-- Now we can calculate the group destination vector GDV.
local GDV = { x = DVu.x * CS * 8 + CVI.x, y = CVI.y, z = DVu.z * CS * 8 + CVI.z }
- --trigger.action.smoke( GDV, trigger.smokeColor.Red )
+ if self.SmokeDirectionVector == true then
+ trigger.action.smoke( GDV, trigger.smokeColor.Red )
+ end
+
self:T2( { "CV2:", CV2 } )
self:T2( { "CVI:", CVI } )
self:T2( { "GDV:", GDV } )
@@ -1092,11 +1120,12 @@ function ESCORT:_FollowScheduler( FollowDistance )
Speed = 0
end
- self:T( { "Client Speed, Escort Speed, Speed, FlyDistance, Time:", CS, GS, Speed, Distance, Time } )
+ self:T( { "Client Speed, Escort Speed, Speed, FollowDistance, Time:", CS, GS, Speed, FollowDistance, Time } )
-- Now route the escort to the desired point with the desired speed.
self.EscortGroup:TaskRouteToVec3( GDV, Speed / 3.6 ) -- DCS models speed in Mps (Miles per second)
end
+
return true
end
@@ -1278,6 +1307,7 @@ function ESCORT:_ReportTargetsScheduler()
MENU_CLIENT_COMMAND:New( self.EscortClient, "Waypoint " .. WayPointID .. " at " .. string.format( "%.2f", Distance ).. "km", self.EscortMenuResumeMission, ESCORT._ResumeMission, { ParamSelf = self, ParamWayPoint = WayPointID } )
end
end
+
return true
end
diff --git a/Moose Development/Moose/Event.lua b/Moose Development/Moose/Event.lua
index e58e8a2ec..959d9839a 100644
--- a/Moose Development/Moose/Event.lua
+++ b/Moose Development/Moose/Event.lua
@@ -494,11 +494,11 @@ function EVENT:onEvent( Event )
self:E( { _EVENTCODES[Event.id], Event } )
for ClassName, EventData in pairs( self.Events[Event.id] ) do
if Event.IniDCSUnitName and EventData.IniUnit and EventData.IniUnit[Event.IniDCSUnitName] then
- self:T2( { "Calling event function for class ", ClassName, " unit ", Event.IniDCSUnitName } )
+ self:E( { "Calling event function for class ", ClassName, " unit ", Event.IniDCSUnitName } )
EventData.IniUnit[Event.IniDCSUnitName].EventFunction( EventData.IniUnit[Event.IniDCSUnitName].EventSelf, Event )
else
if Event.IniDCSUnit and not EventData.IniUnit then
- self:T2( { "Calling event function for class ", ClassName } )
+ self:E( { "Calling event function for class ", ClassName } )
EventData.EventFunction( EventData.EventSelf, Event )
end
end
diff --git a/Moose Development/Moose/Group.lua b/Moose Development/Moose/Group.lua
index 4778c31c5..87cddd07e 100644
--- a/Moose Development/Moose/Group.lua
+++ b/Moose Development/Moose/Group.lua
@@ -185,6 +185,7 @@ function GROUP:Find( DCSGroup )
local GroupName = DCSGroup:getName() -- Group#GROUP
local GroupFound = _DATABASE:FindGroup( GroupName )
+ GroupFound:E( { GroupName, GroupFound:GetClassNameAndID() } )
return GroupFound
end
@@ -517,13 +518,14 @@ end
function GROUP:TaskFunction( WayPoint, WayPointIndex, FunctionString, FunctionArguments )
+ self:F2( { WayPoint, WayPointIndex, FunctionString, FunctionArguments } )
local DCSTask
local DCSScript = {}
DCSScript[#DCSScript+1] = "local MissionGroup = GROUP:Find( ... ) "
- if FunctionArguments.n > 0 then
+ if FunctionArguments and #FunctionArguments > 0 then
DCSScript[#DCSScript+1] = FunctionString .. "( MissionGroup, " .. table.concat( FunctionArguments, "," ) .. ")"
else
DCSScript[#DCSScript+1] = FunctionString .. "( MissionGroup )"
diff --git a/Moose Development/Moose/Scheduler.lua b/Moose Development/Moose/Scheduler.lua
index 652c74da9..82e78c5d3 100644
--- a/Moose Development/Moose/Scheduler.lua
+++ b/Moose Development/Moose/Scheduler.lua
@@ -46,13 +46,12 @@ function SCHEDULER:New( TimeEventObject, TimeEventFunction, TimeEventFunctionArg
self.TimeEventFunction = TimeEventFunction
self.TimeEventFunctionArguments = TimeEventFunctionArguments
self.StartSeconds = StartSeconds
+ self.Repeat = false
if RepeatSecondsInterval then
self.RepeatSecondsInterval = RepeatSecondsInterval
- self.Repeat = true
else
self.RepeatSecondsInterval = 0
- self.Repeat = false
end
if RandomizationFactor then
@@ -79,7 +78,10 @@ end
function SCHEDULER:Start()
self:F2( self.TimeEventObject )
- timer.scheduleFunction( self._Scheduler, self, timer.getTime() + self.StartSeconds + .01 )
+ if self.RepeatSecondsInterval ~= 0 then
+ self.Repeat = true
+ end
+ timer.scheduleFunction( self._Scheduler, self, timer.getTime() + self.StartSeconds + .01 )
return self
end
diff --git a/Moose Development/Moose/Test.lua b/Moose Development/Moose/Test.lua
deleted file mode 100644
index e69de29bb..000000000
diff --git a/Moose Mission Setup/Moose Mission Update/l10n/DEFAULT/Moose.lua b/Moose Mission Setup/Moose Mission Update/l10n/DEFAULT/Moose.lua
index 682e1f28d..f96a2fdf1 100644
--- a/Moose Mission Setup/Moose Mission Update/l10n/DEFAULT/Moose.lua
+++ b/Moose Mission Setup/Moose Mission Update/l10n/DEFAULT/Moose.lua
@@ -1,5 +1,5 @@
env.info( '*** MOOSE STATIC INCLUDE START *** ' )
-env.info( 'Moose Generation Timestamp: 20160611_1029' )
+env.info( 'Moose Generation Timestamp: 20160614_1503' )
local base = _G
Include = {}
@@ -2866,8 +2866,8 @@ function BASE:SetState( Object, StateName, State )
if not self.States[ClassNameAndID] then
self.States[ClassNameAndID] = {}
end
-
self.States[ClassNameAndID][StateName] = State
+ self:E( { ClassNameAndID, StateName, State } )
return self.States[ClassNameAndID][StateName]
end
@@ -2875,8 +2875,11 @@ end
function BASE:GetState( Object, StateName )
local ClassNameAndID = Object:GetClassNameAndID()
+ self:E( { ClassNameAndID } )
if self.States[ClassNameAndID] then
- return self.States[ClassNameAndID][StateName]
+ local State = self.States[ClassNameAndID][StateName]
+ self:E( { ClassNameAndID, StateName, State } )
+ return State
end
return nil
@@ -3134,13 +3137,12 @@ function SCHEDULER:New( TimeEventObject, TimeEventFunction, TimeEventFunctionArg
self.TimeEventFunction = TimeEventFunction
self.TimeEventFunctionArguments = TimeEventFunctionArguments
self.StartSeconds = StartSeconds
+ self.Repeat = false
if RepeatSecondsInterval then
self.RepeatSecondsInterval = RepeatSecondsInterval
- self.Repeat = true
else
self.RepeatSecondsInterval = 0
- self.Repeat = false
end
if RandomizationFactor then
@@ -3167,7 +3169,10 @@ end
function SCHEDULER:Start()
self:F2( self.TimeEventObject )
- timer.scheduleFunction( self._Scheduler, self, timer.getTime() + self.StartSeconds + .01 )
+ if self.RepeatSecondsInterval ~= 0 then
+ self.Repeat = true
+ end
+ timer.scheduleFunction( self._Scheduler, self, timer.getTime() + self.StartSeconds + .01 )
return self
end
@@ -3722,11 +3727,11 @@ function EVENT:onEvent( Event )
self:E( { _EVENTCODES[Event.id], Event } )
for ClassName, EventData in pairs( self.Events[Event.id] ) do
if Event.IniDCSUnitName and EventData.IniUnit and EventData.IniUnit[Event.IniDCSUnitName] then
- self:T2( { "Calling event function for class ", ClassName, " unit ", Event.IniDCSUnitName } )
+ self:E( { "Calling event function for class ", ClassName, " unit ", Event.IniDCSUnitName } )
EventData.IniUnit[Event.IniDCSUnitName].EventFunction( EventData.IniUnit[Event.IniDCSUnitName].EventSelf, Event )
else
if Event.IniDCSUnit and not EventData.IniUnit then
- self:T2( { "Calling event function for class ", ClassName } )
+ self:E( { "Calling event function for class ", ClassName } )
EventData.EventFunction( EventData.EventSelf, Event )
end
end
@@ -4289,6 +4294,7 @@ function GROUP:Find( DCSGroup )
local GroupName = DCSGroup:getName() -- Group#GROUP
local GroupFound = _DATABASE:FindGroup( GroupName )
+ GroupFound:E( { GroupName, GroupFound:GetClassNameAndID() } )
return GroupFound
end
@@ -4621,13 +4627,14 @@ end
function GROUP:TaskFunction( WayPoint, WayPointIndex, FunctionString, FunctionArguments )
+ self:F2( { WayPoint, WayPointIndex, FunctionString, FunctionArguments } )
local DCSTask
local DCSScript = {}
DCSScript[#DCSScript+1] = "local MissionGroup = GROUP:Find( ... ) "
- if FunctionArguments.n > 0 then
+ if FunctionArguments and #FunctionArguments > 0 then
DCSScript[#DCSScript+1] = FunctionString .. "( MissionGroup, " .. table.concat( FunctionArguments, "," ) .. ")"
else
DCSScript[#DCSScript+1] = FunctionString .. "( MissionGroup )"
@@ -8739,9 +8746,6 @@ DATABASE = {
ClientsByName = {},
ClientsByID = {},
},
- DCSUnits = {},
- DCSGroups = {},
- DCSStatics = {},
UNITS = {},
STATICS = {},
GROUPS = {},
@@ -8810,10 +8814,13 @@ end
--- Adds a Unit based on the Unit Name in the DATABASE.
-- @param #DATABASE self
-function DATABASE:AddUnit( DCSUnit, DCSUnitName )
+function DATABASE:AddUnit( DCSUnitName )
- self.DCSUnits[DCSUnitName] = DCSUnit
- self.UNITS[DCSUnitName] = UNIT:Register( DCSUnitName )
+ if not self.UNITS[DCSUnitName] then
+ self.UNITS[DCSUnitName] = UNIT:Register( DCSUnitName )
+ end
+
+ return self.UNITS[DCSUnitName]
end
@@ -8821,15 +8828,16 @@ end
-- @param #DATABASE self
function DATABASE:DeleteUnit( DCSUnitName )
- self.DCSUnits[DCSUnitName] = nil
+ --self.UNITS[DCSUnitName] = nil
end
--- Adds a Static based on the Static Name in the DATABASE.
-- @param #DATABASE self
-function DATABASE:AddStatic( DCSStatic, DCSStaticName )
+function DATABASE:AddStatic( DCSStaticName )
- self.DCSStatics[DCSStaticName] = DCSStatic
- self.STATICS[DCSStaticName] = STATIC:Register( DCSStaticName )
+ if not self.STATICS[DCSStaticName] then
+ self.STATICS[DCSStaticName] = STATIC:Register( DCSStaticName )
+ end
end
@@ -8837,7 +8845,7 @@ end
-- @param #DATABASE self
function DATABASE:DeleteStatic( DCSStaticName )
- self.DCSStatics[DCSStaticName] = nil
+ --self.STATICS[DCSStaticName] = nil
end
--- Finds a STATIC based on the StaticName.
@@ -8866,8 +8874,11 @@ end
-- @param #DATABASE self
function DATABASE:AddClient( ClientName )
- self.CLIENTS[ClientName] = CLIENT:Register( ClientName )
- self:E( self.CLIENTS[ClientName]:GetClassNameAndID() )
+ if not self.CLIENTS[ClientName] then
+ self.CLIENTS[ClientName] = CLIENT:Register( ClientName )
+ end
+
+ return self.CLIENTS[ClientName]
end
@@ -8884,10 +8895,13 @@ end
--- Adds a GROUP based on the GroupName in the DATABASE.
-- @param #DATABASE self
-function DATABASE:AddGroup( DCSGroup, GroupName )
+function DATABASE:AddGroup( GroupName )
- self.DCSGroups[GroupName] = DCSGroup
- self.GROUPS[GroupName] = GROUP:Register( GroupName )
+ if not self.GROUPS[GroupName] then
+ self.GROUPS[GroupName] = GROUP:Register( GroupName )
+ end
+
+ return self.GROUPS[GroupName]
end
--- Adds a player based on the Player Name in the DATABASE.
@@ -8946,7 +8960,7 @@ function DATABASE:Spawn( SpawnTemplate )
SpawnTemplate.SpawnCountryID = SpawnCountryID
SpawnTemplate.SpawnCategoryID = SpawnCategoryID
- local SpawnGroup = GROUP:Register( SpawnTemplate.name )
+ local SpawnGroup = self:AddGroup( SpawnTemplate.name )
return SpawnGroup
end
@@ -9085,14 +9099,14 @@ function DATABASE:_RegisterGroupsAndUnits()
if DCSGroup:isExist() then
local DCSGroupName = DCSGroup:getName()
- self:E( { "Register Group:", DCSGroup, DCSGroupName } )
- self:AddGroup( DCSGroup, DCSGroupName )
+ self:E( { "Register Group:", DCSGroupName } )
+ self:AddGroup( DCSGroupName )
for DCSUnitId, DCSUnit in pairs( DCSGroup:getUnits() ) do
local DCSUnitName = DCSUnit:getName()
- self:E( { "Register Unit:", DCSUnit, DCSUnitName } )
- self:AddUnit( DCSUnit, DCSUnitName )
+ self:E( { "Register Unit:", DCSUnitName } )
+ self:AddUnit( DCSUnitName )
end
else
self:E( { "Group does not exist: ", DCSGroup } )
@@ -9126,8 +9140,8 @@ function DATABASE:_RegisterStatics()
if DCSStatic:isExist() then
local DCSStaticName = DCSStatic:getName()
- self:E( { "Register Static:", DCSStatic, DCSStaticName } )
- self:AddStatic( DCSStatic, DCSStaticName )
+ self:E( { "Register Static:", DCSStaticName } )
+ self:AddStatic( DCSStaticName )
else
self:E( { "Static does not exist: ", DCSStatic } )
end
@@ -9147,8 +9161,8 @@ function DATABASE:_EventOnBirth( Event )
self:F2( { Event } )
if Event.IniDCSUnit then
- self:AddUnit( Event.IniDCSUnit, Event.IniDCSUnitName )
- self:AddGroup( Event.IniDCSGroup, Event.IniDCSGroupName )
+ self:AddUnit( Event.IniDCSUnitName )
+ self:AddGroup( Event.IniDCSGroupName )
self:_EventOnPlayerEnterUnit( Event )
end
end
@@ -9161,7 +9175,7 @@ function DATABASE:_EventOnDeadOrCrash( Event )
self:F2( { Event } )
if Event.IniDCSUnit then
- if self.DCSUnits[Event.IniDCSUnitName] then
+ if self.UNITS[Event.IniDCSUnitName] then
self:DeleteUnit( Event.IniDCSUnitName )
-- add logic to correctly remove a group once all units are destroyed...
end
@@ -9243,19 +9257,6 @@ function DATABASE:ForEach( IteratorFunction, arg, Set )
end
---- Iterate the DATABASE and call an iterator function for each **alive** unit, providing the DCSUnit and optional parameters.
--- @param #DATABASE self
--- @param #function IteratorFunction The function that will be called when there is an alive unit in the database. The function needs to accept a DCSUnit parameter.
--- @return #DATABASE self
-function DATABASE:ForEachDCSUnit( IteratorFunction, ... )
- self:F2( arg )
-
- self:ForEach( IteratorFunction, arg, self.DCSUnits )
-
- return self
-end
-
-
--- Iterate the DATABASE and call an iterator function for each **alive** UNIT, providing the UNIT and optional parameters.
-- @param #DATABASE self
-- @param #function IteratorFunction The function that will be called when there is an alive UNIT in the database. The function needs to accept a UNIT parameter.
@@ -18082,23 +18083,31 @@ end
-- * @{#ESCORT.MenuEvasion: Creates a menu structure to set the evasion techniques when the escort is under threat.
-- * @{#ESCORT.MenuResumeMission}: Creates a menu structure so that the escort can resume from a waypoint.
--
+--
+-- @usage
+-- -- Declare a new EscortPlanes object as follows:
+--
+-- -- First find the GROUP object and the CLIENT object.
+-- local EscortClient = CLIENT:FindByName( "Unit Name" ) -- The Unit Name is the name of the unit flagged with the skill Client in the mission editor.
+-- local EscortGroup = GROUP:FindByName( "Group Name" ) -- The Group Name is the name of the group that will escort the Escort Client.
+--
+-- -- Now use these 2 objects to construct the new EscortPlanes object.
+-- EscortPlanes = ESCORT:New( EscortClient, EscortGroup, "Desert", "Welcome to the mission. You are escorted by a plane with code name 'Desert', which can be instructed through the F10 radio menu." )
+--
+--
+--
-- @module Escort
-- @author FlightControl
-
-
-
-
-
-
----
+--- ESCORT class
-- @type ESCORT
-- @extends Base#BASE
-- @field Client#CLIENT EscortClient
-- @field Group#GROUP EscortGroup
-- @field #string EscortName
-- @field #ESCORT.MODE EscortMode The mode the escort is in.
--- @field #number FollowScheduler The id of the _FollowScheduler function.
+-- @field Scheduler#SCHEDULER FollowScheduler The instance of the SCHEDULER class.
+-- @field #number FollowDistance The current follow distance.
-- @field #boolean ReportTargets If true, nearby targets are reported.
-- @Field DCSTypes#AI.Option.Air.val.ROE OptionROE Which ROE is set to the EscortGroup.
-- @field DCSTypes#AI.Option.Air.val.REACTION_ON_THREAT OptionReactionOnThreat Which REACTION_ON_THREAT is set to the EscortGroup.
@@ -18108,7 +18117,7 @@ ESCORT = {
EscortName = nil, -- The Escort Name
EscortClient = nil,
EscortGroup = nil,
- EscortMode = nil,
+ EscortMode = 1,
MODE = {
FOLLOW = 1,
MISSION = 2,
@@ -18118,6 +18127,7 @@ ESCORT = {
ReportTargets = true,
OptionROE = AI.Option.Air.val.ROE.OPEN_FIRE,
OptionReactionOnThreat = AI.Option.Air.val.REACTION_ON_THREAT.ALLOW_ABORT_MISSION,
+ SmokeDirectionVector = false,
TaskPoints = {}
}
@@ -18139,6 +18149,15 @@ ESCORT = {
-- @param Group#GROUP EscortGroup The group AI escorting the EscortClient.
-- @param #string EscortName Name of the escort.
-- @return #ESCORT self
+-- @usage
+-- -- Declare a new EscortPlanes object as follows:
+--
+-- -- First find the GROUP object and the CLIENT object.
+-- local EscortClient = CLIENT:FindByName( "Unit Name" ) -- The Unit Name is the name of the unit flagged with the skill Client in the mission editor.
+-- local EscortGroup = GROUP:FindByName( "Group Name" ) -- The Group Name is the name of the group that will escort the Escort Client.
+--
+-- -- Now use these 2 objects to construct the new EscortPlanes object.
+-- EscortPlanes = ESCORT:New( EscortClient, EscortGroup, "Desert", "Welcome to the mission. You are escorted by a plane with code name 'Desert', which can be instructed through the F10 radio menu." )
function ESCORT:New( EscortClient, EscortGroup, EscortName, EscortBriefing )
local self = BASE:Inherit( self, BASE:New() )
self:F( { EscortClient, EscortGroup, EscortName } )
@@ -18148,8 +18167,6 @@ function ESCORT:New( EscortClient, EscortGroup, EscortName, EscortBriefing )
self.EscortName = EscortName
self.EscortBriefing = EscortBriefing
- self:T( EscortGroup:GetClassNameAndID() )
-
-- Set EscortGroup known at EscortClient.
if not self.EscortClient._EscortGroups then
self.EscortClient._EscortGroups = {}
@@ -18160,10 +18177,8 @@ function ESCORT:New( EscortClient, EscortGroup, EscortName, EscortBriefing )
self.EscortClient._EscortGroups[EscortGroup:GetName()].EscortGroup = self.EscortGroup
self.EscortClient._EscortGroups[EscortGroup:GetName()].EscortName = self.EscortName
self.EscortClient._EscortGroups[EscortGroup:GetName()].Targets = {}
- self.EscortMode = ESCORT.MODE.FOLLOW
end
-
self.EscortMenu = MENU_CLIENT:New( self.EscortClient, self.EscortName )
self.EscortGroup:WayPointInitialize(1)
@@ -18177,9 +18192,24 @@ function ESCORT:New( EscortClient, EscortGroup, EscortName, EscortBriefing )
60, EscortClient
)
+ self.FollowDistance = 100
+ self.CT1 = 0
+ self.GT1 = 0
+ self.FollowScheduler = SCHEDULER:New( self, self._FollowScheduler, {}, 1, .5, .01 )
+ self.EscortMode = ESCORT.MODE.MISSION
+ self.FollowScheduler:Stop()
+
return self
end
+--- This function is for test, it will put on the frequency of the FollowScheduler a red smoke at the direction vector calculated for the escort to fly to.
+-- This allows to visualize where the escort is flying to.
+-- @param #ESCORT self
+-- @param #boolean SmokeDirection If true, then the direction vector will be smoked.
+function ESCORT:TestSmokeDirectionVector( SmokeDirection )
+ self.SmokeDirectionVector = ( SmokeDirection == true ) and true or false
+end
+
--- Defines the default menus
-- @param #ESCORT self
@@ -18206,6 +18236,7 @@ function ESCORT:Menus()
self:MenuEvasion()
self:MenuResumeMission()
+
return self
end
@@ -18616,7 +18647,7 @@ function ESCORT._HoldPosition( MenuParam )
local OrbitHeight = MenuParam.ParamHeight
local OrbitSeconds = MenuParam.ParamSeconds -- Not implemented yet
- routines.removeFunction( self.FollowScheduler )
+ self.FollowScheduler:Stop()
local PointFrom = {}
local GroupPoint = EscortGroup:GetUnit(1):GetPointVec3()
@@ -18645,6 +18676,7 @@ function ESCORT._HoldPosition( MenuParam )
EscortGroup:SetTask( EscortGroup:TaskRoute( Points ) )
EscortGroup:MessageToClient( "Orbiting at location.", 10, EscortClient )
+
end
--- @param #MENUPARAM MenuParam
@@ -18667,9 +18699,7 @@ end
function ESCORT:JoinUpAndFollow( EscortGroup, EscortClient, Distance )
self:F( { EscortGroup, EscortClient, Distance } )
- if self.FollowScheduler then
- routines.removeFunction( self.FollowScheduler )
- end
+ self.FollowScheduler:Stop()
EscortGroup:OptionROEHoldFire()
EscortGroup:OptionROTPassiveDefense()
@@ -18678,8 +18708,8 @@ function ESCORT:JoinUpAndFollow( EscortGroup, EscortClient, Distance )
self.CT1 = 0
self.GT1 = 0
- --self.FollowScheduler = routines.scheduleFunction( self._FollowScheduler, { self, Distance }, timer.getTime() + 1, .5 )
- self.FollowScheduler = SCHEDULER:New( self, self._FollowScheduler, { Distance }, 1, .5, .1 )
+ self.FollowScheduler:Start()
+
EscortGroup:MessageToClient( "Rejoining and Following at " .. Distance .. "!", 30, EscortClient )
end
@@ -18751,11 +18781,7 @@ function ESCORT._ScanTargets( MenuParam )
local ScanDuration = MenuParam.ParamScanDuration
- if self.FollowScheduler then
- routines.removeFunction( self.FollowScheduler )
- end
-
- self:T( { "FollowScheduler after removefunction: ", self.FollowScheduler } )
+ self.FollowScheduler:Stop()
if EscortGroup:IsHelicopter() then
SCHEDULER:New( EscortGroup, EscortGroup.PushTask,
@@ -18780,16 +18806,16 @@ function ESCORT._ScanTargets( MenuParam )
EscortGroup:MessageToClient( "Scanning targets for " .. ScanDuration .. " seconds.", ScanDuration, EscortClient )
if self.EscortMode == ESCORT.MODE.FOLLOW then
- --self.FollowScheduler = routines.scheduleFunction( self._FollowScheduler, { self, Distance }, timer.getTime() + ScanDuration, 1 )
self.FollowScheduler:Start()
end
end
+--- @param Group#GROUP EscortGroup
function _Resume( EscortGroup )
env.info( '_Resume' )
- local Escort = EscortGroup.Escort -- #ESCORT
+ local Escort = EscortGroup:GetState( EscortGroup, "Escort" )
env.info( "EscortMode = " .. Escort.EscortMode )
if Escort.EscortMode == ESCORT.MODE.FOLLOW then
Escort:JoinUpAndFollow( EscortGroup, Escort.EscortClient, Escort.Distance )
@@ -18802,19 +18828,18 @@ function ESCORT._AttackTarget( MenuParam )
local self = MenuParam.ParamSelf
local EscortGroup = self.EscortGroup
+
local EscortClient = self.EscortClient
local AttackUnit = MenuParam.ParamUnit -- Unit#UNIT
- if self.FollowScheduler then
- routines.removeFunction( self.FollowScheduler )
- end
+ self.FollowScheduler:Stop()
self:T( AttackUnit )
if EscortGroup:IsAir() then
EscortGroup:OptionROEOpenFire()
EscortGroup:OptionROTPassiveDefense()
- EscortGroup.Escort = self -- Need to do this trick to get the reference for the escort in the _Resume function.
+ EscortGroup:SetState( EscortGroup, "Escort", self )
-- routines.scheduleFunction(
-- EscortGroup.PushTask,
-- { EscortGroup,
@@ -18829,7 +18854,7 @@ function ESCORT._AttackTarget( MenuParam )
EscortGroup.PushTask,
{ EscortGroup:TaskCombo(
{ EscortGroup:TaskAttackUnit( AttackUnit ),
- EscortGroup:TaskFunction( 1, 2, "_Resume", {"''"} )
+ EscortGroup:TaskFunction( 1, 2, "_Resume", { "''" } )
}
)
}, 10
@@ -18853,9 +18878,9 @@ function ESCORT._AttackTarget( MenuParam )
}, 10
)
end
+
EscortGroup:MessageToClient( "Engaging Designated Unit!", 10, EscortClient )
-
end
--- @param #MENUPARAM MenuParam
@@ -18867,10 +18892,7 @@ function ESCORT._AssistTarget( MenuParam )
local EscortGroupAttack = MenuParam.ParamEscortGroup
local AttackUnit = MenuParam.ParamUnit -- Unit#UNIT
- if self.FollowScheduler then
- routines.removeFunction( self.FollowScheduler )
- end
-
+ self.FollowScheduler:Stop()
self:T( AttackUnit )
@@ -18956,8 +18978,7 @@ function ESCORT._ResumeMission( MenuParam )
local WayPoint = MenuParam.ParamWayPoint
- routines.removeFunction( self.FollowScheduler )
- self.FollowScheduler = nil
+ self.FollowScheduler:Stop()
local WayPoints = EscortGroup:GetTaskRoute()
self:T( WayPoint, WayPoints )
@@ -18988,16 +19009,21 @@ function ESCORT:RegisterRoute()
end
--- @param Escort#ESCORT self
-function ESCORT:_FollowScheduler( FollowDistance )
- self:F( { FollowDistance })
+function ESCORT:_FollowScheduler()
+ self:F( { self.FollowDistance } )
+ self:T( {self.EscortClient.UnitName, self.EscortGroup.GroupName } )
if self.EscortGroup:IsAlive() and self.EscortClient:IsAlive() then
local ClientUnit = self.EscortClient:GetClientGroupUnit()
local GroupUnit = self.EscortGroup:GetUnit( 1 )
+ local FollowDistance = self.FollowDistance
+
+ self:T( {ClientUnit.UnitName, GroupUnit.UnitName } )
if self.CT1 == 0 and self.GT1 == 0 then
self.CV1 = ClientUnit:GetPointVec3()
+ self:T( { "self.CV1", self.CV1 } )
self.CT1 = timer.getTime()
self.GV1 = GroupUnit:GetPointVec3()
self.GT1 = timer.getTime()
@@ -19057,7 +19083,10 @@ function ESCORT:_FollowScheduler( FollowDistance )
-- Now we can calculate the group destination vector GDV.
local GDV = { x = DVu.x * CS * 8 + CVI.x, y = CVI.y, z = DVu.z * CS * 8 + CVI.z }
- --trigger.action.smoke( GDV, trigger.smokeColor.Red )
+ if self.SmokeDirectionVector == true then
+ trigger.action.smoke( GDV, trigger.smokeColor.Red )
+ end
+
self:T2( { "CV2:", CV2 } )
self:T2( { "CVI:", CVI } )
self:T2( { "GDV:", GDV } )
@@ -19075,11 +19104,12 @@ function ESCORT:_FollowScheduler( FollowDistance )
Speed = 0
end
- self:T( { "Client Speed, Escort Speed, Speed, FlyDistance, Time:", CS, GS, Speed, Distance, Time } )
+ self:T( { "Client Speed, Escort Speed, Speed, FollowDistance, Time:", CS, GS, Speed, FollowDistance, Time } )
-- Now route the escort to the desired point with the desired speed.
self.EscortGroup:TaskRouteToVec3( GDV, Speed / 3.6 ) -- DCS models speed in Mps (Miles per second)
end
+
return true
end
@@ -19261,6 +19291,7 @@ function ESCORT:_ReportTargetsScheduler()
MENU_CLIENT_COMMAND:New( self.EscortClient, "Waypoint " .. WayPointID .. " at " .. string.format( "%.2f", Distance ).. "km", self.EscortMenuResumeMission, ESCORT._ResumeMission, { ParamSelf = self, ParamWayPoint = WayPointID } )
end
end
+
return true
end
diff --git a/Moose Mission Setup/Moose.lua b/Moose Mission Setup/Moose.lua
index 682e1f28d..f96a2fdf1 100644
--- a/Moose Mission Setup/Moose.lua
+++ b/Moose Mission Setup/Moose.lua
@@ -1,5 +1,5 @@
env.info( '*** MOOSE STATIC INCLUDE START *** ' )
-env.info( 'Moose Generation Timestamp: 20160611_1029' )
+env.info( 'Moose Generation Timestamp: 20160614_1503' )
local base = _G
Include = {}
@@ -2866,8 +2866,8 @@ function BASE:SetState( Object, StateName, State )
if not self.States[ClassNameAndID] then
self.States[ClassNameAndID] = {}
end
-
self.States[ClassNameAndID][StateName] = State
+ self:E( { ClassNameAndID, StateName, State } )
return self.States[ClassNameAndID][StateName]
end
@@ -2875,8 +2875,11 @@ end
function BASE:GetState( Object, StateName )
local ClassNameAndID = Object:GetClassNameAndID()
+ self:E( { ClassNameAndID } )
if self.States[ClassNameAndID] then
- return self.States[ClassNameAndID][StateName]
+ local State = self.States[ClassNameAndID][StateName]
+ self:E( { ClassNameAndID, StateName, State } )
+ return State
end
return nil
@@ -3134,13 +3137,12 @@ function SCHEDULER:New( TimeEventObject, TimeEventFunction, TimeEventFunctionArg
self.TimeEventFunction = TimeEventFunction
self.TimeEventFunctionArguments = TimeEventFunctionArguments
self.StartSeconds = StartSeconds
+ self.Repeat = false
if RepeatSecondsInterval then
self.RepeatSecondsInterval = RepeatSecondsInterval
- self.Repeat = true
else
self.RepeatSecondsInterval = 0
- self.Repeat = false
end
if RandomizationFactor then
@@ -3167,7 +3169,10 @@ end
function SCHEDULER:Start()
self:F2( self.TimeEventObject )
- timer.scheduleFunction( self._Scheduler, self, timer.getTime() + self.StartSeconds + .01 )
+ if self.RepeatSecondsInterval ~= 0 then
+ self.Repeat = true
+ end
+ timer.scheduleFunction( self._Scheduler, self, timer.getTime() + self.StartSeconds + .01 )
return self
end
@@ -3722,11 +3727,11 @@ function EVENT:onEvent( Event )
self:E( { _EVENTCODES[Event.id], Event } )
for ClassName, EventData in pairs( self.Events[Event.id] ) do
if Event.IniDCSUnitName and EventData.IniUnit and EventData.IniUnit[Event.IniDCSUnitName] then
- self:T2( { "Calling event function for class ", ClassName, " unit ", Event.IniDCSUnitName } )
+ self:E( { "Calling event function for class ", ClassName, " unit ", Event.IniDCSUnitName } )
EventData.IniUnit[Event.IniDCSUnitName].EventFunction( EventData.IniUnit[Event.IniDCSUnitName].EventSelf, Event )
else
if Event.IniDCSUnit and not EventData.IniUnit then
- self:T2( { "Calling event function for class ", ClassName } )
+ self:E( { "Calling event function for class ", ClassName } )
EventData.EventFunction( EventData.EventSelf, Event )
end
end
@@ -4289,6 +4294,7 @@ function GROUP:Find( DCSGroup )
local GroupName = DCSGroup:getName() -- Group#GROUP
local GroupFound = _DATABASE:FindGroup( GroupName )
+ GroupFound:E( { GroupName, GroupFound:GetClassNameAndID() } )
return GroupFound
end
@@ -4621,13 +4627,14 @@ end
function GROUP:TaskFunction( WayPoint, WayPointIndex, FunctionString, FunctionArguments )
+ self:F2( { WayPoint, WayPointIndex, FunctionString, FunctionArguments } )
local DCSTask
local DCSScript = {}
DCSScript[#DCSScript+1] = "local MissionGroup = GROUP:Find( ... ) "
- if FunctionArguments.n > 0 then
+ if FunctionArguments and #FunctionArguments > 0 then
DCSScript[#DCSScript+1] = FunctionString .. "( MissionGroup, " .. table.concat( FunctionArguments, "," ) .. ")"
else
DCSScript[#DCSScript+1] = FunctionString .. "( MissionGroup )"
@@ -8739,9 +8746,6 @@ DATABASE = {
ClientsByName = {},
ClientsByID = {},
},
- DCSUnits = {},
- DCSGroups = {},
- DCSStatics = {},
UNITS = {},
STATICS = {},
GROUPS = {},
@@ -8810,10 +8814,13 @@ end
--- Adds a Unit based on the Unit Name in the DATABASE.
-- @param #DATABASE self
-function DATABASE:AddUnit( DCSUnit, DCSUnitName )
+function DATABASE:AddUnit( DCSUnitName )
- self.DCSUnits[DCSUnitName] = DCSUnit
- self.UNITS[DCSUnitName] = UNIT:Register( DCSUnitName )
+ if not self.UNITS[DCSUnitName] then
+ self.UNITS[DCSUnitName] = UNIT:Register( DCSUnitName )
+ end
+
+ return self.UNITS[DCSUnitName]
end
@@ -8821,15 +8828,16 @@ end
-- @param #DATABASE self
function DATABASE:DeleteUnit( DCSUnitName )
- self.DCSUnits[DCSUnitName] = nil
+ --self.UNITS[DCSUnitName] = nil
end
--- Adds a Static based on the Static Name in the DATABASE.
-- @param #DATABASE self
-function DATABASE:AddStatic( DCSStatic, DCSStaticName )
+function DATABASE:AddStatic( DCSStaticName )
- self.DCSStatics[DCSStaticName] = DCSStatic
- self.STATICS[DCSStaticName] = STATIC:Register( DCSStaticName )
+ if not self.STATICS[DCSStaticName] then
+ self.STATICS[DCSStaticName] = STATIC:Register( DCSStaticName )
+ end
end
@@ -8837,7 +8845,7 @@ end
-- @param #DATABASE self
function DATABASE:DeleteStatic( DCSStaticName )
- self.DCSStatics[DCSStaticName] = nil
+ --self.STATICS[DCSStaticName] = nil
end
--- Finds a STATIC based on the StaticName.
@@ -8866,8 +8874,11 @@ end
-- @param #DATABASE self
function DATABASE:AddClient( ClientName )
- self.CLIENTS[ClientName] = CLIENT:Register( ClientName )
- self:E( self.CLIENTS[ClientName]:GetClassNameAndID() )
+ if not self.CLIENTS[ClientName] then
+ self.CLIENTS[ClientName] = CLIENT:Register( ClientName )
+ end
+
+ return self.CLIENTS[ClientName]
end
@@ -8884,10 +8895,13 @@ end
--- Adds a GROUP based on the GroupName in the DATABASE.
-- @param #DATABASE self
-function DATABASE:AddGroup( DCSGroup, GroupName )
+function DATABASE:AddGroup( GroupName )
- self.DCSGroups[GroupName] = DCSGroup
- self.GROUPS[GroupName] = GROUP:Register( GroupName )
+ if not self.GROUPS[GroupName] then
+ self.GROUPS[GroupName] = GROUP:Register( GroupName )
+ end
+
+ return self.GROUPS[GroupName]
end
--- Adds a player based on the Player Name in the DATABASE.
@@ -8946,7 +8960,7 @@ function DATABASE:Spawn( SpawnTemplate )
SpawnTemplate.SpawnCountryID = SpawnCountryID
SpawnTemplate.SpawnCategoryID = SpawnCategoryID
- local SpawnGroup = GROUP:Register( SpawnTemplate.name )
+ local SpawnGroup = self:AddGroup( SpawnTemplate.name )
return SpawnGroup
end
@@ -9085,14 +9099,14 @@ function DATABASE:_RegisterGroupsAndUnits()
if DCSGroup:isExist() then
local DCSGroupName = DCSGroup:getName()
- self:E( { "Register Group:", DCSGroup, DCSGroupName } )
- self:AddGroup( DCSGroup, DCSGroupName )
+ self:E( { "Register Group:", DCSGroupName } )
+ self:AddGroup( DCSGroupName )
for DCSUnitId, DCSUnit in pairs( DCSGroup:getUnits() ) do
local DCSUnitName = DCSUnit:getName()
- self:E( { "Register Unit:", DCSUnit, DCSUnitName } )
- self:AddUnit( DCSUnit, DCSUnitName )
+ self:E( { "Register Unit:", DCSUnitName } )
+ self:AddUnit( DCSUnitName )
end
else
self:E( { "Group does not exist: ", DCSGroup } )
@@ -9126,8 +9140,8 @@ function DATABASE:_RegisterStatics()
if DCSStatic:isExist() then
local DCSStaticName = DCSStatic:getName()
- self:E( { "Register Static:", DCSStatic, DCSStaticName } )
- self:AddStatic( DCSStatic, DCSStaticName )
+ self:E( { "Register Static:", DCSStaticName } )
+ self:AddStatic( DCSStaticName )
else
self:E( { "Static does not exist: ", DCSStatic } )
end
@@ -9147,8 +9161,8 @@ function DATABASE:_EventOnBirth( Event )
self:F2( { Event } )
if Event.IniDCSUnit then
- self:AddUnit( Event.IniDCSUnit, Event.IniDCSUnitName )
- self:AddGroup( Event.IniDCSGroup, Event.IniDCSGroupName )
+ self:AddUnit( Event.IniDCSUnitName )
+ self:AddGroup( Event.IniDCSGroupName )
self:_EventOnPlayerEnterUnit( Event )
end
end
@@ -9161,7 +9175,7 @@ function DATABASE:_EventOnDeadOrCrash( Event )
self:F2( { Event } )
if Event.IniDCSUnit then
- if self.DCSUnits[Event.IniDCSUnitName] then
+ if self.UNITS[Event.IniDCSUnitName] then
self:DeleteUnit( Event.IniDCSUnitName )
-- add logic to correctly remove a group once all units are destroyed...
end
@@ -9243,19 +9257,6 @@ function DATABASE:ForEach( IteratorFunction, arg, Set )
end
---- Iterate the DATABASE and call an iterator function for each **alive** unit, providing the DCSUnit and optional parameters.
--- @param #DATABASE self
--- @param #function IteratorFunction The function that will be called when there is an alive unit in the database. The function needs to accept a DCSUnit parameter.
--- @return #DATABASE self
-function DATABASE:ForEachDCSUnit( IteratorFunction, ... )
- self:F2( arg )
-
- self:ForEach( IteratorFunction, arg, self.DCSUnits )
-
- return self
-end
-
-
--- Iterate the DATABASE and call an iterator function for each **alive** UNIT, providing the UNIT and optional parameters.
-- @param #DATABASE self
-- @param #function IteratorFunction The function that will be called when there is an alive UNIT in the database. The function needs to accept a UNIT parameter.
@@ -18082,23 +18083,31 @@ end
-- * @{#ESCORT.MenuEvasion: Creates a menu structure to set the evasion techniques when the escort is under threat.
-- * @{#ESCORT.MenuResumeMission}: Creates a menu structure so that the escort can resume from a waypoint.
--
+--
+-- @usage
+-- -- Declare a new EscortPlanes object as follows:
+--
+-- -- First find the GROUP object and the CLIENT object.
+-- local EscortClient = CLIENT:FindByName( "Unit Name" ) -- The Unit Name is the name of the unit flagged with the skill Client in the mission editor.
+-- local EscortGroup = GROUP:FindByName( "Group Name" ) -- The Group Name is the name of the group that will escort the Escort Client.
+--
+-- -- Now use these 2 objects to construct the new EscortPlanes object.
+-- EscortPlanes = ESCORT:New( EscortClient, EscortGroup, "Desert", "Welcome to the mission. You are escorted by a plane with code name 'Desert', which can be instructed through the F10 radio menu." )
+--
+--
+--
-- @module Escort
-- @author FlightControl
-
-
-
-
-
-
----
+--- ESCORT class
-- @type ESCORT
-- @extends Base#BASE
-- @field Client#CLIENT EscortClient
-- @field Group#GROUP EscortGroup
-- @field #string EscortName
-- @field #ESCORT.MODE EscortMode The mode the escort is in.
--- @field #number FollowScheduler The id of the _FollowScheduler function.
+-- @field Scheduler#SCHEDULER FollowScheduler The instance of the SCHEDULER class.
+-- @field #number FollowDistance The current follow distance.
-- @field #boolean ReportTargets If true, nearby targets are reported.
-- @Field DCSTypes#AI.Option.Air.val.ROE OptionROE Which ROE is set to the EscortGroup.
-- @field DCSTypes#AI.Option.Air.val.REACTION_ON_THREAT OptionReactionOnThreat Which REACTION_ON_THREAT is set to the EscortGroup.
@@ -18108,7 +18117,7 @@ ESCORT = {
EscortName = nil, -- The Escort Name
EscortClient = nil,
EscortGroup = nil,
- EscortMode = nil,
+ EscortMode = 1,
MODE = {
FOLLOW = 1,
MISSION = 2,
@@ -18118,6 +18127,7 @@ ESCORT = {
ReportTargets = true,
OptionROE = AI.Option.Air.val.ROE.OPEN_FIRE,
OptionReactionOnThreat = AI.Option.Air.val.REACTION_ON_THREAT.ALLOW_ABORT_MISSION,
+ SmokeDirectionVector = false,
TaskPoints = {}
}
@@ -18139,6 +18149,15 @@ ESCORT = {
-- @param Group#GROUP EscortGroup The group AI escorting the EscortClient.
-- @param #string EscortName Name of the escort.
-- @return #ESCORT self
+-- @usage
+-- -- Declare a new EscortPlanes object as follows:
+--
+-- -- First find the GROUP object and the CLIENT object.
+-- local EscortClient = CLIENT:FindByName( "Unit Name" ) -- The Unit Name is the name of the unit flagged with the skill Client in the mission editor.
+-- local EscortGroup = GROUP:FindByName( "Group Name" ) -- The Group Name is the name of the group that will escort the Escort Client.
+--
+-- -- Now use these 2 objects to construct the new EscortPlanes object.
+-- EscortPlanes = ESCORT:New( EscortClient, EscortGroup, "Desert", "Welcome to the mission. You are escorted by a plane with code name 'Desert', which can be instructed through the F10 radio menu." )
function ESCORT:New( EscortClient, EscortGroup, EscortName, EscortBriefing )
local self = BASE:Inherit( self, BASE:New() )
self:F( { EscortClient, EscortGroup, EscortName } )
@@ -18148,8 +18167,6 @@ function ESCORT:New( EscortClient, EscortGroup, EscortName, EscortBriefing )
self.EscortName = EscortName
self.EscortBriefing = EscortBriefing
- self:T( EscortGroup:GetClassNameAndID() )
-
-- Set EscortGroup known at EscortClient.
if not self.EscortClient._EscortGroups then
self.EscortClient._EscortGroups = {}
@@ -18160,10 +18177,8 @@ function ESCORT:New( EscortClient, EscortGroup, EscortName, EscortBriefing )
self.EscortClient._EscortGroups[EscortGroup:GetName()].EscortGroup = self.EscortGroup
self.EscortClient._EscortGroups[EscortGroup:GetName()].EscortName = self.EscortName
self.EscortClient._EscortGroups[EscortGroup:GetName()].Targets = {}
- self.EscortMode = ESCORT.MODE.FOLLOW
end
-
self.EscortMenu = MENU_CLIENT:New( self.EscortClient, self.EscortName )
self.EscortGroup:WayPointInitialize(1)
@@ -18177,9 +18192,24 @@ function ESCORT:New( EscortClient, EscortGroup, EscortName, EscortBriefing )
60, EscortClient
)
+ self.FollowDistance = 100
+ self.CT1 = 0
+ self.GT1 = 0
+ self.FollowScheduler = SCHEDULER:New( self, self._FollowScheduler, {}, 1, .5, .01 )
+ self.EscortMode = ESCORT.MODE.MISSION
+ self.FollowScheduler:Stop()
+
return self
end
+--- This function is for test, it will put on the frequency of the FollowScheduler a red smoke at the direction vector calculated for the escort to fly to.
+-- This allows to visualize where the escort is flying to.
+-- @param #ESCORT self
+-- @param #boolean SmokeDirection If true, then the direction vector will be smoked.
+function ESCORT:TestSmokeDirectionVector( SmokeDirection )
+ self.SmokeDirectionVector = ( SmokeDirection == true ) and true or false
+end
+
--- Defines the default menus
-- @param #ESCORT self
@@ -18206,6 +18236,7 @@ function ESCORT:Menus()
self:MenuEvasion()
self:MenuResumeMission()
+
return self
end
@@ -18616,7 +18647,7 @@ function ESCORT._HoldPosition( MenuParam )
local OrbitHeight = MenuParam.ParamHeight
local OrbitSeconds = MenuParam.ParamSeconds -- Not implemented yet
- routines.removeFunction( self.FollowScheduler )
+ self.FollowScheduler:Stop()
local PointFrom = {}
local GroupPoint = EscortGroup:GetUnit(1):GetPointVec3()
@@ -18645,6 +18676,7 @@ function ESCORT._HoldPosition( MenuParam )
EscortGroup:SetTask( EscortGroup:TaskRoute( Points ) )
EscortGroup:MessageToClient( "Orbiting at location.", 10, EscortClient )
+
end
--- @param #MENUPARAM MenuParam
@@ -18667,9 +18699,7 @@ end
function ESCORT:JoinUpAndFollow( EscortGroup, EscortClient, Distance )
self:F( { EscortGroup, EscortClient, Distance } )
- if self.FollowScheduler then
- routines.removeFunction( self.FollowScheduler )
- end
+ self.FollowScheduler:Stop()
EscortGroup:OptionROEHoldFire()
EscortGroup:OptionROTPassiveDefense()
@@ -18678,8 +18708,8 @@ function ESCORT:JoinUpAndFollow( EscortGroup, EscortClient, Distance )
self.CT1 = 0
self.GT1 = 0
- --self.FollowScheduler = routines.scheduleFunction( self._FollowScheduler, { self, Distance }, timer.getTime() + 1, .5 )
- self.FollowScheduler = SCHEDULER:New( self, self._FollowScheduler, { Distance }, 1, .5, .1 )
+ self.FollowScheduler:Start()
+
EscortGroup:MessageToClient( "Rejoining and Following at " .. Distance .. "!", 30, EscortClient )
end
@@ -18751,11 +18781,7 @@ function ESCORT._ScanTargets( MenuParam )
local ScanDuration = MenuParam.ParamScanDuration
- if self.FollowScheduler then
- routines.removeFunction( self.FollowScheduler )
- end
-
- self:T( { "FollowScheduler after removefunction: ", self.FollowScheduler } )
+ self.FollowScheduler:Stop()
if EscortGroup:IsHelicopter() then
SCHEDULER:New( EscortGroup, EscortGroup.PushTask,
@@ -18780,16 +18806,16 @@ function ESCORT._ScanTargets( MenuParam )
EscortGroup:MessageToClient( "Scanning targets for " .. ScanDuration .. " seconds.", ScanDuration, EscortClient )
if self.EscortMode == ESCORT.MODE.FOLLOW then
- --self.FollowScheduler = routines.scheduleFunction( self._FollowScheduler, { self, Distance }, timer.getTime() + ScanDuration, 1 )
self.FollowScheduler:Start()
end
end
+--- @param Group#GROUP EscortGroup
function _Resume( EscortGroup )
env.info( '_Resume' )
- local Escort = EscortGroup.Escort -- #ESCORT
+ local Escort = EscortGroup:GetState( EscortGroup, "Escort" )
env.info( "EscortMode = " .. Escort.EscortMode )
if Escort.EscortMode == ESCORT.MODE.FOLLOW then
Escort:JoinUpAndFollow( EscortGroup, Escort.EscortClient, Escort.Distance )
@@ -18802,19 +18828,18 @@ function ESCORT._AttackTarget( MenuParam )
local self = MenuParam.ParamSelf
local EscortGroup = self.EscortGroup
+
local EscortClient = self.EscortClient
local AttackUnit = MenuParam.ParamUnit -- Unit#UNIT
- if self.FollowScheduler then
- routines.removeFunction( self.FollowScheduler )
- end
+ self.FollowScheduler:Stop()
self:T( AttackUnit )
if EscortGroup:IsAir() then
EscortGroup:OptionROEOpenFire()
EscortGroup:OptionROTPassiveDefense()
- EscortGroup.Escort = self -- Need to do this trick to get the reference for the escort in the _Resume function.
+ EscortGroup:SetState( EscortGroup, "Escort", self )
-- routines.scheduleFunction(
-- EscortGroup.PushTask,
-- { EscortGroup,
@@ -18829,7 +18854,7 @@ function ESCORT._AttackTarget( MenuParam )
EscortGroup.PushTask,
{ EscortGroup:TaskCombo(
{ EscortGroup:TaskAttackUnit( AttackUnit ),
- EscortGroup:TaskFunction( 1, 2, "_Resume", {"''"} )
+ EscortGroup:TaskFunction( 1, 2, "_Resume", { "''" } )
}
)
}, 10
@@ -18853,9 +18878,9 @@ function ESCORT._AttackTarget( MenuParam )
}, 10
)
end
+
EscortGroup:MessageToClient( "Engaging Designated Unit!", 10, EscortClient )
-
end
--- @param #MENUPARAM MenuParam
@@ -18867,10 +18892,7 @@ function ESCORT._AssistTarget( MenuParam )
local EscortGroupAttack = MenuParam.ParamEscortGroup
local AttackUnit = MenuParam.ParamUnit -- Unit#UNIT
- if self.FollowScheduler then
- routines.removeFunction( self.FollowScheduler )
- end
-
+ self.FollowScheduler:Stop()
self:T( AttackUnit )
@@ -18956,8 +18978,7 @@ function ESCORT._ResumeMission( MenuParam )
local WayPoint = MenuParam.ParamWayPoint
- routines.removeFunction( self.FollowScheduler )
- self.FollowScheduler = nil
+ self.FollowScheduler:Stop()
local WayPoints = EscortGroup:GetTaskRoute()
self:T( WayPoint, WayPoints )
@@ -18988,16 +19009,21 @@ function ESCORT:RegisterRoute()
end
--- @param Escort#ESCORT self
-function ESCORT:_FollowScheduler( FollowDistance )
- self:F( { FollowDistance })
+function ESCORT:_FollowScheduler()
+ self:F( { self.FollowDistance } )
+ self:T( {self.EscortClient.UnitName, self.EscortGroup.GroupName } )
if self.EscortGroup:IsAlive() and self.EscortClient:IsAlive() then
local ClientUnit = self.EscortClient:GetClientGroupUnit()
local GroupUnit = self.EscortGroup:GetUnit( 1 )
+ local FollowDistance = self.FollowDistance
+
+ self:T( {ClientUnit.UnitName, GroupUnit.UnitName } )
if self.CT1 == 0 and self.GT1 == 0 then
self.CV1 = ClientUnit:GetPointVec3()
+ self:T( { "self.CV1", self.CV1 } )
self.CT1 = timer.getTime()
self.GV1 = GroupUnit:GetPointVec3()
self.GT1 = timer.getTime()
@@ -19057,7 +19083,10 @@ function ESCORT:_FollowScheduler( FollowDistance )
-- Now we can calculate the group destination vector GDV.
local GDV = { x = DVu.x * CS * 8 + CVI.x, y = CVI.y, z = DVu.z * CS * 8 + CVI.z }
- --trigger.action.smoke( GDV, trigger.smokeColor.Red )
+ if self.SmokeDirectionVector == true then
+ trigger.action.smoke( GDV, trigger.smokeColor.Red )
+ end
+
self:T2( { "CV2:", CV2 } )
self:T2( { "CVI:", CVI } )
self:T2( { "GDV:", GDV } )
@@ -19075,11 +19104,12 @@ function ESCORT:_FollowScheduler( FollowDistance )
Speed = 0
end
- self:T( { "Client Speed, Escort Speed, Speed, FlyDistance, Time:", CS, GS, Speed, Distance, Time } )
+ self:T( { "Client Speed, Escort Speed, Speed, FollowDistance, Time:", CS, GS, Speed, FollowDistance, Time } )
-- Now route the escort to the desired point with the desired speed.
self.EscortGroup:TaskRouteToVec3( GDV, Speed / 3.6 ) -- DCS models speed in Mps (Miles per second)
end
+
return true
end
@@ -19261,6 +19291,7 @@ function ESCORT:_ReportTargetsScheduler()
MENU_CLIENT_COMMAND:New( self.EscortClient, "Waypoint " .. WayPointID .. " at " .. string.format( "%.2f", Distance ).. "km", self.EscortMenuResumeMission, ESCORT._ResumeMission, { ParamSelf = self, ParamWayPoint = WayPointID } )
end
end
+
return true
end
diff --git a/Moose Test Missions/Moose_Test_AIBALANCER/Moose_Test_AIBALANCER.miz b/Moose Test Missions/Moose_Test_AIBALANCER/Moose_Test_AIBALANCER.miz
index c21694b02..3015a87c1 100644
Binary files a/Moose Test Missions/Moose_Test_AIBALANCER/Moose_Test_AIBALANCER.miz and b/Moose Test Missions/Moose_Test_AIBALANCER/Moose_Test_AIBALANCER.miz differ
diff --git a/Moose Test Missions/Moose_Test_CLEANUP/Moose_Test_CLEANUP.miz b/Moose Test Missions/Moose_Test_CLEANUP/Moose_Test_CLEANUP.miz
index 47c6aeae9..05404f569 100644
Binary files a/Moose Test Missions/Moose_Test_CLEANUP/Moose_Test_CLEANUP.miz and b/Moose Test Missions/Moose_Test_CLEANUP/Moose_Test_CLEANUP.miz differ
diff --git a/Moose Test Missions/Moose_Test_DESTROY/MOOSE_Test_DESTROY.miz b/Moose Test Missions/Moose_Test_DESTROY/MOOSE_Test_DESTROY.miz
index b6c19b6b2..f4921fb20 100644
Binary files a/Moose Test Missions/Moose_Test_DESTROY/MOOSE_Test_DESTROY.miz and b/Moose Test Missions/Moose_Test_DESTROY/MOOSE_Test_DESTROY.miz differ
diff --git a/Moose Test Missions/Moose_Test_ESCORT/MOOSE_Test_ESCORT.lua b/Moose Test Missions/Moose_Test_ESCORT/MOOSE_Test_ESCORT.lua
index 732b5b5ac..0af903907 100644
--- a/Moose Test Missions/Moose_Test_ESCORT/MOOSE_Test_ESCORT.lua
+++ b/Moose Test Missions/Moose_Test_ESCORT/MOOSE_Test_ESCORT.lua
@@ -19,6 +19,11 @@ do
:MenuReportTargets( 60, 20 )
:MenuResumeMission()
:MenuAssistedAttack()
+
+ local EscortGroupArtillery = SpawnEscortArtillery:ReSpawn(1)
+ local EscortArtillery = ESCORT
+ :New( Client, EscortGroupArtillery, "Escort Artillery" )
+ :Menus()
end
local function EventAlivePlane( Client )
@@ -52,6 +57,7 @@ do
SpawnEscortPlane = SPAWN:New( "Escort Plane" )
SpawnEscortGround = SPAWN:New( "Escort Ground" )
SpawnEscortShip = SPAWN:New( "Escort Ship" )
+ SpawnEscortArtillery = SPAWN:New( "Ground Attack Assistance" )
EscortClientHeli = CLIENT:FindByName( "Lead Helicopter", "Fly around and observe the behaviour of the escort helicopter" ):Alive( EventAliveHelicopter )
EscortClientPlane = CLIENT:FindByName( "Lead Plane", "Fly around and observe the behaviour of the escort airplane. Select Navigate->Joun-Up and airplane should follow you. Change speed and directions." )
diff --git a/Moose Test Missions/Moose_Test_ESCORT/MOOSE_Test_ESCORT.miz b/Moose Test Missions/Moose_Test_ESCORT/MOOSE_Test_ESCORT.miz
index d41754fea..5148b617f 100644
Binary files a/Moose Test Missions/Moose_Test_ESCORT/MOOSE_Test_ESCORT.miz and b/Moose Test Missions/Moose_Test_ESCORT/MOOSE_Test_ESCORT.miz differ
diff --git a/Moose Test Missions/Moose_Test_MISSILETRAINER/Moose_Test_MISSILETRAINER.miz b/Moose Test Missions/Moose_Test_MISSILETRAINER/Moose_Test_MISSILETRAINER.miz
index 1159ed374..39844d015 100644
Binary files a/Moose Test Missions/Moose_Test_MISSILETRAINER/Moose_Test_MISSILETRAINER.miz and b/Moose Test Missions/Moose_Test_MISSILETRAINER/Moose_Test_MISSILETRAINER.miz differ
diff --git a/Moose Test Missions/Moose_Test_SEAD/MOOSE_Test_SEAD.miz b/Moose Test Missions/Moose_Test_SEAD/MOOSE_Test_SEAD.miz
index 434a9bfa9..04636f1ff 100644
Binary files a/Moose Test Missions/Moose_Test_SEAD/MOOSE_Test_SEAD.miz and b/Moose Test Missions/Moose_Test_SEAD/MOOSE_Test_SEAD.miz differ
diff --git a/Moose Test Missions/Moose_Test_SET_CLIENT/Moose_Test_SET_CLIENT.miz b/Moose Test Missions/Moose_Test_SET_CLIENT/Moose_Test_SET_CLIENT.miz
index 2be17fd06..bffbff8d9 100644
Binary files a/Moose Test Missions/Moose_Test_SET_CLIENT/Moose_Test_SET_CLIENT.miz and b/Moose Test Missions/Moose_Test_SET_CLIENT/Moose_Test_SET_CLIENT.miz differ
diff --git a/Moose Test Missions/Moose_Test_SET_GROUP/Moose_Test_SET_GROUP.miz b/Moose Test Missions/Moose_Test_SET_GROUP/Moose_Test_SET_GROUP.miz
index a540aa486..af00c7c4b 100644
Binary files a/Moose Test Missions/Moose_Test_SET_GROUP/Moose_Test_SET_GROUP.miz and b/Moose Test Missions/Moose_Test_SET_GROUP/Moose_Test_SET_GROUP.miz differ
diff --git a/Moose Test Missions/Moose_Test_SPAWN/MOOSE_Test_SPAWN.miz b/Moose Test Missions/Moose_Test_SPAWN/MOOSE_Test_SPAWN.miz
index 3993273fc..2027b24b1 100644
Binary files a/Moose Test Missions/Moose_Test_SPAWN/MOOSE_Test_SPAWN.miz and b/Moose Test Missions/Moose_Test_SPAWN/MOOSE_Test_SPAWN.miz differ
diff --git a/Moose Test Missions/Moose_Test_SPAWN_Repeat/MOOSE_Test_SPAWN_Repeat.miz b/Moose Test Missions/Moose_Test_SPAWN_Repeat/MOOSE_Test_SPAWN_Repeat.miz
index 3c2b20441..cbd9f04e9 100644
Binary files a/Moose Test Missions/Moose_Test_SPAWN_Repeat/MOOSE_Test_SPAWN_Repeat.miz and b/Moose Test Missions/Moose_Test_SPAWN_Repeat/MOOSE_Test_SPAWN_Repeat.miz differ
diff --git a/Moose Test Missions/Moose_Test_TASK_Pickup_and_Deploy/MOOSE_Test_TASK_Pickup_and_Deploy.miz b/Moose Test Missions/Moose_Test_TASK_Pickup_and_Deploy/MOOSE_Test_TASK_Pickup_and_Deploy.miz
index 67b00dcdc..3c39ea44a 100644
Binary files a/Moose Test Missions/Moose_Test_TASK_Pickup_and_Deploy/MOOSE_Test_TASK_Pickup_and_Deploy.miz and b/Moose Test Missions/Moose_Test_TASK_Pickup_and_Deploy/MOOSE_Test_TASK_Pickup_and_Deploy.miz differ
diff --git a/Moose Test Missions/Moose_Test_WRAPPER/Moose_Test_WRAPPER.miz b/Moose Test Missions/Moose_Test_WRAPPER/Moose_Test_WRAPPER.miz
index 32c402323..892aa245e 100644
Binary files a/Moose Test Missions/Moose_Test_WRAPPER/Moose_Test_WRAPPER.miz and b/Moose Test Missions/Moose_Test_WRAPPER/Moose_Test_WRAPPER.miz differ
diff --git a/Moose Test Missions/Moose_Test_ZONE/Moose_Test_ZONE.miz b/Moose Test Missions/Moose_Test_ZONE/Moose_Test_ZONE.miz
index 7983e03c9..b5de3f3b1 100644
Binary files a/Moose Test Missions/Moose_Test_ZONE/Moose_Test_ZONE.miz and b/Moose Test Missions/Moose_Test_ZONE/Moose_Test_ZONE.miz differ
diff --git a/Moose Test Missions/Moose_Test_ZONE_POLYGON/Moose_Test_ZONE_POLYGON.miz b/Moose Test Missions/Moose_Test_ZONE_POLYGON/Moose_Test_ZONE_POLYGON.miz
index d6e5f0e3b..ed16e4e08 100644
Binary files a/Moose Test Missions/Moose_Test_ZONE_POLYGON/Moose_Test_ZONE_POLYGON.miz and b/Moose Test Missions/Moose_Test_ZONE_POLYGON/Moose_Test_ZONE_POLYGON.miz differ
diff --git a/Moose Test Missions/Moose_Test_ZONE_RADIUS/Moose_Test_ZONE_RADIUS.miz b/Moose Test Missions/Moose_Test_ZONE_RADIUS/Moose_Test_ZONE_RADIUS.miz
index 6491eabea..d9f084d81 100644
Binary files a/Moose Test Missions/Moose_Test_ZONE_RADIUS/Moose_Test_ZONE_RADIUS.miz and b/Moose Test Missions/Moose_Test_ZONE_RADIUS/Moose_Test_ZONE_RADIUS.miz differ
diff --git a/Moose Test Missions/Moose_Test_ZONE_UNIT/Moose_Test_ZONE_UNIT.miz b/Moose Test Missions/Moose_Test_ZONE_UNIT/Moose_Test_ZONE_UNIT.miz
index 0ddb42abd..d88d022e2 100644
Binary files a/Moose Test Missions/Moose_Test_ZONE_UNIT/Moose_Test_ZONE_UNIT.miz and b/Moose Test Missions/Moose_Test_ZONE_UNIT/Moose_Test_ZONE_UNIT.miz differ
diff --git a/Moose Training/Documentation/AIBalancer.html b/Moose Training/Documentation/AIBalancer.html
new file mode 100644
index 000000000..12bf002c5
--- /dev/null
+++ b/Moose Training/Documentation/AIBalancer.html
@@ -0,0 +1,253 @@
+
+
+
The AIBalancer#AIBALANCER class controls the dynamic spawning of AI GROUPS depending on a SETCLIENT.
+There will be as many AI GROUPS spawned as there at CLIENTS in SETCLIENT not spawned.
+
+
1.1) AIBALANCER construction method:
+
Create a new AIBALANCER object with the AIBALANCER.New method:
@@ -175,6 +176,20 @@ Note that this is really fantastic, as you now have the dynamic of taking contro
+
+
Usage:
+
-- Declare a new EscortPlanes object as follows:
+
+-- First find the GROUP object and the CLIENT object.
+local EscortClient = CLIENT:FindByName( "Unit Name" ) -- The Unit Name is the name of the unit flagged with the skill Client in the mission editor.
+local EscortGroup = GROUP:FindByName( "Group Name" ) -- The Group Name is the name of the group that will escort the Escort Client.
+
+-- Now use these 2 objects to construct the new EscortPlanes object.
+EscortPlanes = ESCORT:New( EscortClient, EscortGroup, "Desert", "Welcome to the mission. You are escorted by a plane with code name 'Desert', which can be instructed through the F10 radio menu." )
+
+
+
+
Global(s)
@@ -430,12 +445,18 @@ Note that this is really fantastic, as you now have the dynamic of taking contro
-- Declare a new EscortPlanes object as follows:
+
+-- First find the GROUP object and the CLIENT object.
+local EscortClient = CLIENT:FindByName( "Unit Name" ) -- The Unit Name is the name of the unit flagged with the skill Client in the mission editor.
+local EscortGroup = GROUP:FindByName( "Group Name" ) -- The Group Name is the name of the group that will escort the Escort Client.
+
+-- Now use these 2 objects to construct the new EscortPlanes object.
+EscortPlanes = ESCORT:New( EscortClient, EscortGroup, "Desert", "Welcome to the mission. You are escorted by a plane with code name 'Desert', which can be instructed through the F10 radio menu." )
Once the filters have been defined and the SETUNIT has been built, you can iterate the SETUNIT with the available iterator methods.
The iterator methods will walk the SETUNIT set, and call for each element within the set a function that you provide.
The following iterator methods are currently available within the SETUNIT:
SET_UNIT.ForEachUnit: Calls a function for each alive unit it finds within the SET_UNIT.
+
SET_GROUP.ForEachGroupCompletelyInZone: Iterate the SET_GROUP and call an iterator function for each alive GROUP presence completely in a Zone, providing the GROUP and optional parameters to the called function.
+
SET_GROUP.ForEachGroupNotInZone: Iterate the SET_GROUP and call an iterator function for each alive GROUP presence not in a Zone, providing the GROUP and optional parameters to the called function.
Planned iterators methods in development are (so these are not yet available):
SET_UNIT.ForEachUnitCompletelyInZone: Iterate and call an iterator function for each alive UNIT presence completely in a Zone, providing the UNIT and optional parameters to the called function.
+
SET_UNIT.ForEachUnitNotInZone: Iterate and call an iterator function for each alive UNIT presence not in a Zone, providing the UNIT and optional parameters to the called function.
Once the filters have been defined and the SETCLIENT has been built, you can iterate the SETCLIENT with the available iterator methods.
+The iterator methods will walk the SETCLIENT set, and call for each element within the set a function that you provide.
+The following iterator methods are currently available within the SETCLIENT:
+
+
+
SET_CLIENT.ForEachClient: Calls a function for each alive client it finds within the SET_CLIENT.
+
@@ -220,6 +281,12 @@ The following iterator methods are currently available within the SETUNIT:<
Iterate the SET_CLIENT and call an iterator function for each alive CLIENT presence completely in a Zone, providing the CLIENT and optional parameters to the called function.
Iterate the SET_CLIENT and call an iterator function for each alive CLIENT presence not in a Zone, providing the CLIENT and optional parameters to the called function.
Iterate the SET_UNIT and call an iterator function for each alive UNIT presence completely in a Zone, providing the UNIT and optional parameters to the called function.
Iterate the SET_UNIT and call an iterator function for each alive UNIT presence not in a Zone, providing the UNIT and optional parameters to the called function.
@@ -543,6 +746,12 @@ The following iterator methods are currently available within the SETUNIT:<
Interate the SET_CLIENT and call an interator function for each alive CLIENT, providing the CLIENT and optional parameters.
+
+
Parameters
+
+
+
+
#function IteratorFunction :
+The function that will be called when there is an alive CLIENT in the SET_CLIENT. The function needs to accept a CLIENT parameter.
Iterate the SET_CLIENT and call an iterator function for each alive CLIENT presence completely in a Zone, providing the CLIENT and optional parameters to the called function.
+
+
Parameters
+
+
+
+
Zone#ZONE ZoneObject :
+The Zone to be tested for.
+
+
+
+
+
#function IteratorFunction :
+The function that will be called when there is an alive CLIENT in the SET_CLIENT. The function needs to accept a CLIENT parameter.
Iterate the SET_CLIENT and call an iterator function for each alive CLIENT presence not in a Zone, providing the CLIENT and optional parameters to the called function.
+
+
Parameters
+
+
+
+
Zone#ZONE ZoneObject :
+The Zone to be tested for.
+
+
+
+
+
#function IteratorFunction :
+The function that will be called when there is an alive CLIENT in the SET_CLIENT. The function needs to accept a CLIENT parameter.
Iterate the SET_UNIT and call an iterator function for each alive UNIT presence completely in a Zone, providing the UNIT and optional parameters to the called function.
+
+
Parameters
+
+
+
+
Zone#ZONE ZoneObject :
+The Zone to be tested for.
+
+
+
+
+
#function IteratorFunction :
+The function that will be called when there is an alive UNIT in the SET_UNIT. The function needs to accept a UNIT parameter.
Iterate the SET_UNIT and call an iterator function for each alive UNIT presence not in a Zone, providing the UNIT and optional parameters to the called function.
+
+
Parameters
+
+
+
+
Zone#ZONE ZoneObject :
+The Zone to be tested for.
+
+
+
+
+
#function IteratorFunction :
+The function that will be called when there is an alive UNIT in the SET_UNIT. The function needs to accept a UNIT parameter.