Updated the Escort class

- Registering each excort at the client internally.
- Each escort known at the client can exchange targets.
- Each escort can acquire attack assistance from other escorts known at
the client.
- Made the MENU class more slick. Now menus are removed recursively for
CLIENTS.
- Added a few more types and fine tuned the documentation.
This commit is contained in:
FlightControl 2016-04-07 17:34:44 +02:00
parent 2812339cc1
commit ab332f22e7
8 changed files with 489 additions and 146 deletions

10
Dcs/DCSCommand.lua Normal file
View File

@ -0,0 +1,10 @@
--- @module DCSCommand
--- @type Command
-- @field #string id
-- @field #Command.params params
--- @type Command.params
env.info( "Command defined" )

View File

@ -1,10 +1,10 @@
--- @module DCSTask --- @module DCSTask
--- @type DCSTask --- @type Task
-- @field #string id -- @field #string id
-- @field #DCSTask.param param -- @field #Task.param param
--- @type DCSTask.param --- @type Task.param
env.info( "DCSTask defined" ) env.info( "Task defined" )

View File

@ -67,6 +67,7 @@ Include.File( "Database" )
Include.File( "Group" ) Include.File( "Group" )
Include.File( "Zone" ) Include.File( "Zone" )
--- ESCORT class --- ESCORT class
-- @type ESCORT -- @type ESCORT
-- @extends Base#BASE -- @extends Base#BASE
@ -77,6 +78,7 @@ Include.File( "Zone" )
-- @field #boolean ReportTargets If true, nearby targets are reported. -- @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.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. -- @field DCSTypes#AI.Option.Air.val.REACTION_ON_THREAT OptionReactionOnThreat Which REACTION_ON_THREAT is set to the EscortGroup.
-- @field Menu#MENU_CLIENT EscortMenuResumeMission
ESCORT = { ESCORT = {
ClassName = "ESCORT", ClassName = "ESCORT",
EscortName = nil, -- The Escort Name EscortName = nil, -- The Escort Name
@ -97,7 +99,7 @@ ESCORT = {
-- @field #string ParamMessage -- @field #string ParamMessage
--- ESCORT class constructor for an AI group --- ESCORT class constructor for an AI group
-- @param self -- @param #ESCORT self
-- @param Client#CLIENT EscortClient The client escorted by the EscortGroup. -- @param Client#CLIENT EscortClient The client escorted by the EscortGroup.
-- @param Group#GROUP EscortGroup The group AI escorting the EscortClient. -- @param Group#GROUP EscortGroup The group AI escorting the EscortClient.
-- @param #string EscortName Name of the escort. -- @param #string EscortName Name of the escort.
@ -111,6 +113,20 @@ function ESCORT:New( EscortClient, EscortGroup, EscortName, EscortBriefing )
self.EscortName = EscortName self.EscortName = EscortName
self.EscortBriefing = EscortBriefing self.EscortBriefing = EscortBriefing
-- Set EscortGroup known at EscortClient.
if not self.EscortClient._EscortGroups then
self.EscortClient._EscortGroups = {}
end
if not self.EscortClient._EscortGroups[EscortGroup:GetName()] then
self.EscortClient._EscortGroups[EscortGroup:GetName()] = {}
self.EscortClient._EscortGroups[EscortGroup:GetName()].EscortGroup = self.EscortGroup
self.EscortClient._EscortGroups[EscortGroup:GetName()].EscortName = self.EscortName
self.EscortClient._EscortGroups[EscortGroup:GetName()].Targets = {}
end
self.EscortMenu = MENU_CLIENT:New( self.EscortClient, self.EscortName ) self.EscortMenu = MENU_CLIENT:New( self.EscortClient, self.EscortName )
self.EscortMenuReportNavigation = MENU_CLIENT:New( self.EscortClient, "Navigation", self.EscortMenu ) self.EscortMenuReportNavigation = MENU_CLIENT:New( self.EscortClient, "Navigation", self.EscortMenu )
@ -155,8 +171,6 @@ function ESCORT:New( EscortClient, EscortGroup, EscortName, EscortBriefing )
-- Attack Targets -- Attack Targets
self.EscortMenuAttackNearbyTargets = MENU_CLIENT:New( self.EscortClient, "Attack nearby targets", self.EscortMenu ) self.EscortMenuAttackNearbyTargets = MENU_CLIENT:New( self.EscortClient, "Attack nearby targets", self.EscortMenu )
self.EscortMenuAttackTargets = {}
self.Targets = {}
-- Rules of Engagement -- Rules of Engagement
self.EscortMenuROE = MENU_CLIENT:New( self.EscortClient, "ROE", self.EscortMenu ) self.EscortMenuROE = MENU_CLIENT:New( self.EscortClient, "ROE", self.EscortMenu )
@ -188,13 +202,11 @@ function ESCORT:New( EscortClient, EscortGroup, EscortName, EscortBriefing )
self.EscortMenuOptionEvasionVertical = MENU_CLIENT_COMMAND:New( self.EscortClient, "Go below radar and evade fire", self.EscortMenuEvasion, ESCORT._ROT, { ParamSelf = self, ParamFunction = EscortGroup:OptionROTVertical(), ParamMessage = "Evading on enemy fire with vertical manoeuvres!" } ) self.EscortMenuOptionEvasionVertical = MENU_CLIENT_COMMAND:New( self.EscortClient, "Go below radar and evade fire", self.EscortMenuEvasion, ESCORT._ROT, { ParamSelf = self, ParamFunction = EscortGroup:OptionROTVertical(), ParamMessage = "Evading on enemy fire with vertical manoeuvres!" } )
end end
-- Cancel current Task -- Mission Resume Menu Root
self.EscortMenuResumeMission = MENU_CLIENT:New( self.EscortClient, "Resume Mission", self.EscortMenu ) self.EscortMenuResumeMission = MENU_CLIENT:New( self.EscortClient, "Resume the escort mission", self.EscortMenu )
self.EscortMenuResumeWayPoints = {}
local TaskPoints = self:RegisterRoute() -- Exchange targets with other escorts of the CLIENT. This is very useful to let f.e. an escorting ship attack a target detected by an escorting plane...
for WayPointID, WayPoint in pairs( TaskPoints ) do self.EscortMenuTargetAssistance = MENU_CLIENT:New( self.EscortClient, "Target assistance from other escorts", self.EscortMenu )
self.EscortMenuResumeWayPoints[WayPointID] = MENU_CLIENT_COMMAND:New( self.EscortClient, "Resume from waypoint " .. WayPointID, self.EscortMenuResumeMission, ESCORT._ResumeMission, { ParamSelf = self, ParamWayPoint = WayPointID } )
end
-- Initialize the EscortGroup -- Initialize the EscortGroup
@ -207,9 +219,7 @@ function ESCORT:New( EscortClient, EscortGroup, EscortName, EscortBriefing )
EscortGroup:MessageToClient( EscortGroup:GetCategoryName() .. " '" .. EscortName .. "' (" .. EscortGroup:GetCallsign() .. ") reporting! " .. EscortGroup:MessageToClient( EscortGroup:GetCategoryName() .. " '" .. EscortName .. "' (" .. EscortGroup:GetCallsign() .. ") reporting! " ..
"We're escorting your flight. " .. "We're escorting your flight. " ..
"You can communicate with us through the radio menu. " .. "Use the Radio Menu and F10 and use the options under + " .. EscortName .. "\n",
"Use the Radio Menu and F10 and use the options under + " .. EscortName .. "\n" ..
"We are continuing our way, but you can request to join-up your flight under the Navigation menu\n",
60, EscortClient 60, EscortClient
) )
end end
@ -351,16 +361,40 @@ function ESCORT._ScanTargets( MenuParam )
local ScanDuration = MenuParam.ParamScanDuration local ScanDuration = MenuParam.ParamScanDuration
if self.FollowScheduler then
routines.removeFunction( self.FollowScheduler ) routines.removeFunction( self.FollowScheduler )
self.FollowScheduler = nil end
EscortGroup:PushTask( self:T( { "FollowScheduler after removefunction: ", self.FollowScheduler } )
if EscortGroup:IsHelicopter() then
routines.scheduleFunction( EscortGroup.PushTask,
{ EscortGroup,
EscortGroup:TaskControlled( EscortGroup:TaskControlled(
EscortGroup:TaskOrbitCircle( 200, 20 ), EscortGroup:TaskOrbitCircle( 200, 20 ),
EscortGroup:TaskCondition( nil, nil, nil, nil, ScanDuration, nil ) EscortGroup:TaskCondition( nil, nil, nil, nil, ScanDuration, nil )
) )
},
timer.getTime() + 1
) )
elseif EscortGroup:IsAirPlane() then
routines.scheduleFunction( EscortGroup.PushTask,
{ EscortGroup,
EscortGroup:TaskControlled(
EscortGroup:TaskOrbitCircle( 1000, 500 ),
EscortGroup:TaskCondition( nil, nil, nil, nil, ScanDuration, nil )
)
},
timer.getTime() + 1
)
end
EscortGroup:MessageToClient( "Scanning targets for " .. ScanDuration .. " seconds.", ScanDuration, EscortClient ) EscortGroup:MessageToClient( "Scanning targets for " .. ScanDuration .. " seconds.", ScanDuration, EscortClient )
if self.FollowScheduler then
self.FollowScheduler = routines.scheduleFunction( self._FollowScheduler, { self, Distance }, timer.getTime() + ScanDuration, 1 )
end
end end
--- @param #MENUPARAM MenuParam --- @param #MENUPARAM MenuParam
@ -369,18 +403,89 @@ function ESCORT._AttackTarget( MenuParam )
local self = MenuParam.ParamSelf local self = MenuParam.ParamSelf
local EscortGroup = self.EscortGroup local EscortGroup = self.EscortGroup
local EscortClient = self.EscortClient local EscortClient = self.EscortClient
local AttackUnit = MenuParam.ParamUnit local AttackUnit = MenuParam.ParamUnit -- Unit#UNIT
if self.FollowScheduler then
routines.removeFunction( self.FollowScheduler ) routines.removeFunction( self.FollowScheduler )
self.FollowScheduler = nil end
EscortGroup:OptionROEOpenFire()
EscortGroup:OptionROTVertical()
self:T( AttackUnit ) self:T( AttackUnit )
EscortGroup:PushTask( EscortGroup:TaskAttackUnit( AttackUnit ) ) if EscortGroup:IsAir() then
EscortGroup:OptionROEOpenFire()
EscortGroup:OptionROTVertical()
routines.scheduleFunction(
EscortGroup.PushTask,
{ EscortGroup,
EscortGroup:TaskCombo(
{ EscortGroup:TaskAttackUnit( AttackUnit ),
EscortGroup:TaskOrbitCircle( 500, 350 )
}
)
}, timer.getTime() + 10
)
else
routines.scheduleFunction(
EscortGroup.PushTask,
{ EscortGroup,
EscortGroup:TaskCombo(
{ EscortGroup:TaskFireAtPoint( AttackUnit:GetPointVec2(), 50 )
}
)
}, timer.getTime() + 10
)
end
EscortGroup:MessageToClient( "Engaging Designated Unit!", 10, EscortClient ) EscortGroup:MessageToClient( "Engaging Designated Unit!", 10, EscortClient )
if self.FollowScheduler then
self.FollowScheduler = routines.scheduleFunction( self._FollowScheduler, { self, Distance }, timer.getTime() + ScanDuration, 1 )
end
end
--- @param #MENUPARAM MenuParam
function ESCORT._AssistTarget( MenuParam )
local self = MenuParam.ParamSelf
local EscortGroup = self.EscortGroup
local EscortClient = self.EscortClient
local EscortGroupAttack = MenuParam.ParamEscortGroup
local AttackUnit = MenuParam.ParamUnit -- Unit#UNIT
if self.FollowScheduler then
routines.removeFunction( self.FollowScheduler )
end
self:T( AttackUnit )
if EscortGroupAttack:IsAir() then
EscortGroupAttack:OptionROEOpenFire()
EscortGroupAttack:OptionROTVertical()
routines.scheduleFunction(
EscortGroupAttack.PushTask,
{ EscortGroupAttack,
EscortGroupAttack:TaskCombo(
{ EscortGroupAttack:TaskAttackUnit( AttackUnit ),
EscortGroupAttack:TaskOrbitCircle( 500, 350 )
}
)
}, timer.getTime() + 10
)
else
routines.scheduleFunction(
EscortGroupAttack.PushTask,
{ EscortGroupAttack,
EscortGroupAttack:TaskCombo(
{ EscortGroupAttack:TaskFireAtPoint( AttackUnit:GetPointVec2(), 50 )
}
)
}, timer.getTime() + 10
)
end
EscortGroupAttack:MessageToClient( "Assisting with the destroying the enemy unit!", 10, EscortClient )
end end
--- @param #MENUPARAM MenuParam --- @param #MENUPARAM MenuParam
@ -430,11 +535,15 @@ function ESCORT._ResumeMission( MenuParam )
table.remove( WayPoints, 1 ) table.remove( WayPoints, 1 )
end end
EscortGroup:SetTask( EscortGroup:TaskRoute( WayPoints ) ) routines.scheduleFunction( EscortGroup.SetTask, {EscortGroup, EscortGroup:TaskRoute( WayPoints ) }, timer.getTime() + 1 )
EscortGroup:MessageToClient( "Resuming mission from waypoint " .. WayPoint .. ".", 10, EscortClient ) EscortGroup:MessageToClient( "Resuming mission from waypoint " .. WayPoint .. ".", 10, EscortClient )
end end
--- Registers the waypoints
-- @param #ESCORT self
function ESCORT:RegisterRoute() function ESCORT:RegisterRoute()
self:F()
local EscortGroup = self.EscortGroup -- Group#GROUP local EscortGroup = self.EscortGroup -- Group#GROUP
@ -442,9 +551,11 @@ function ESCORT:RegisterRoute()
self:T( TaskPoints ) self:T( TaskPoints )
for TaskPointID, TaskPoint in pairs( TaskPoints ) do for TaskPointID, TaskPoint in pairs( TaskPoints ) do
self:T( TaskPointID ) self:T( { "TaskPoint:", TaskPointID, #TaskPoint.task.params.tasks+1, TaskPoint } )
if TaskPointID > 1 then
TaskPoint.task.params.tasks[#TaskPoint.task.params.tasks+1] = EscortGroup:TaskRegisterWayPoint( TaskPointID ) TaskPoint.task.params.tasks[#TaskPoint.task.params.tasks+1] = EscortGroup:TaskRegisterWayPoint( TaskPointID )
self:T( TaskPoint.task.params.tasks[#TaskPoint.task.params.tasks] ) end
self:T( TaskPoint )
end end
self:T( TaskPoints ) self:T( TaskPoints )
@ -530,7 +641,7 @@ function ESCORT:_FollowScheduler( FollowDistance )
-- The calculation of the Speed would simulate that the group would take 30 seconds to overcome -- The calculation of the Speed would simulate that the group would take 30 seconds to overcome
-- the requested Distance). -- the requested Distance).
local Time = 30 local Time = 10
local CatchUpSpeed = ( CatchUpDistance - ( CS * 2 ) ) / Time local CatchUpSpeed = ( CatchUpDistance - ( CS * 2 ) ) / Time
local Speed = CS + CatchUpSpeed local Speed = CS + CatchUpSpeed
@ -555,110 +666,165 @@ end
function ESCORT:_ReportTargetsScheduler() function ESCORT:_ReportTargetsScheduler()
self:F() self:F()
self.Targets = {}
if self.EscortGroup:IsAlive() then if self.EscortGroup:IsAlive() then
local EscortGroupName = self.EscortGroup:GetName()
local EscortTargets = self.EscortGroup:GetDetectedTargets() local EscortTargets = self.EscortGroup:GetDetectedTargets()
local ClientEscortTargets = self.EscortClient._EscortGroups[EscortGroupName].Targets
local EscortTargetMessages = "" local EscortTargetMessages = ""
for EscortTargetID, EscortTarget in pairs( EscortTargets ) do for EscortTargetID, EscortTarget in pairs( EscortTargets ) do
local EscortObject = EscortTarget.object local EscortObject = EscortTarget.object
self:T( EscortObject ) self:T( EscortObject )
if EscortObject and EscortObject:isExist() and EscortObject.id_ < 50000000 then if EscortObject and EscortObject:isExist() and EscortObject.id_ < 50000000 then
local EscortTargetMessage = ""
local EscortTargetUnit = UNIT:New( EscortObject ) local EscortTargetUnit = UNIT:New( EscortObject )
local EscortTargetUnitName = EscortTargetUnit:GetName()
local EscortTargetCategoryName = EscortTargetUnit:GetCategoryName()
local EscortTargetCategoryType = EscortTargetUnit:GetTypeName()
-- local EscortTargetIsDetected,
-- EscortTargetIsVisible,
-- EscortTargetLastTime,
-- EscortTargetKnowType,
-- EscortTargetKnowDistance,
-- EscortTargetLastPos,
-- EscortTargetLastVelocity
-- = self.EscortGroup:IsTargetDetected( EscortObject )
--
-- self:T( { EscortTargetIsDetected,
-- EscortTargetIsVisible,
-- EscortTargetLastTime,
-- EscortTargetKnowType,
-- EscortTargetKnowDistance,
-- EscortTargetLastPos,
-- EscortTargetLastVelocity } )
if EscortTarget.distance then -- local EscortTargetIsDetected,
-- EscortTargetIsVisible,
-- EscortTargetLastTime,
-- EscortTargetKnowType,
-- EscortTargetKnowDistance,
-- EscortTargetLastPos,
-- EscortTargetLastVelocity
-- = self.EscortGroup:IsTargetDetected( EscortObject )
--
-- self:T( { EscortTargetIsDetected,
-- EscortTargetIsVisible,
-- EscortTargetLastTime,
-- EscortTargetKnowType,
-- EscortTargetKnowDistance,
-- EscortTargetLastPos,
-- EscortTargetLastVelocity } )
local EscortTargetUnitPositionVec3 = EscortTargetUnit:GetPositionVec3() local EscortTargetUnitPositionVec3 = EscortTargetUnit:GetPositionVec3()
local EscortPositionVec3 = self.EscortGroup:GetPositionVec3() local EscortPositionVec3 = self.EscortGroup:GetPositionVec3()
local Distance = routines.utils.get3DDist( EscortTargetUnitPositionVec3, EscortPositionVec3 ) / 1000 local Distance = ( ( EscortTargetUnitPositionVec3.x - EscortPositionVec3.x )^2 +
self:T( { self.EscortGroup:GetName(), EscortTargetUnit:GetName(), Distance, EscortTarget.visible } ) ( EscortTargetUnitPositionVec3.y - EscortPositionVec3.y )^2 +
( EscortTargetUnitPositionVec3.z - EscortPositionVec3.z )^2
) ^ 0.5 / 1000
if Distance <= 8 then self:T( { self.EscortGroup:GetName(), EscortTargetUnit:GetName(), Distance, EscortTarget } )
if EscortTarget.type then if Distance <= 15 then
EscortTargetMessage = EscortTargetMessage .. " - " .. EscortTargetCategoryName .. " (" .. EscortTargetCategoryType .. ") at "
else if not ClientEscortTargets[EscortTargetUnitName] then
EscortTargetMessage = EscortTargetMessage .. " - Unknown target at " ClientEscortTargets[EscortTargetUnitName] = {}
end
ClientEscortTargets[EscortTargetUnitName].AttackUnit = EscortTargetUnit
ClientEscortTargets[EscortTargetUnitName].visible = EscortTarget.visible
ClientEscortTargets[EscortTargetUnitName].type = EscortTarget.type
ClientEscortTargets[EscortTargetUnitName].distance = EscortTarget.distance
end
end
end end
EscortTargetMessage = EscortTargetMessage .. string.format( "%.2f", Distance ) .. " km" self:T( { "Sorting Targets Table:", ClientEscortTargets } )
table.sort( ClientEscortTargets, function( a, b ) return a.Distance < b.Distance end )
self:T( { "Sorted Targets Table:", ClientEscortTargets } )
if EscortTarget.visible then -- Remove the sub menus of the Attack menu of the Escort for the EscortGroup.
self.EscortMenuAttackNearbyTargets:RemoveSubMenus()
self.EscortMenuTargetAssistance:RemoveSubMenus()
--for MenuIndex = 1, #self.EscortMenuAttackTargets do
-- self:T( { "Remove Menu:", self.EscortMenuAttackTargets[MenuIndex] } )
-- self.EscortMenuAttackTargets[MenuIndex] = self.EscortMenuAttackTargets[MenuIndex]:Remove()
--end
if ClientEscortTargets then
for ClientEscortTargetUnitName, ClientEscortTargetData in pairs( ClientEscortTargets ) do
for ClientEscortGroupName, EscortGroupData in pairs( self.EscortClient._EscortGroups ) do
if ClientEscortTargetData and ClientEscortTargetData.AttackUnit:IsAlive() then
local EscortTargetMessage = ""
local EscortTargetCategoryName = ClientEscortTargetData.AttackUnit:GetCategoryName()
local EscortTargetCategoryType = ClientEscortTargetData.AttackUnit:GetTypeName()
if ClientEscortTargetData.type then
EscortTargetMessage = EscortTargetMessage .. EscortTargetCategoryName .. " (" .. EscortTargetCategoryType .. ") at "
else
EscortTargetMessage = EscortTargetMessage .. "Unknown target at "
end
local EscortTargetUnitPositionVec3 = ClientEscortTargetData.AttackUnit:GetPositionVec3()
local EscortPositionVec3 = self.EscortGroup:GetPositionVec3()
local Distance = ( ( EscortTargetUnitPositionVec3.x - EscortPositionVec3.x )^2 +
( EscortTargetUnitPositionVec3.y - EscortPositionVec3.y )^2 +
( EscortTargetUnitPositionVec3.z - EscortPositionVec3.z )^2
) ^ 0.5 / 1000
self:T( { self.EscortGroup:GetName(), ClientEscortTargetData.AttackUnit:GetName(), Distance, ClientEscortTargetData.AttackUnit } )
if ClientEscortTargetData.visible == false then
EscortTargetMessage = EscortTargetMessage .. string.format( "%.2f", Distance ) .. " estimated km"
else
EscortTargetMessage = EscortTargetMessage .. string.format( "%.2f", Distance ) .. " km"
end
if ClientEscortTargetData.visible then
EscortTargetMessage = EscortTargetMessage .. ", visual" EscortTargetMessage = EscortTargetMessage .. ", visual"
end end
local TargetIndex = Distance*1000 if ClientEscortGroupName == EscortGroupName then
self.Targets[TargetIndex] = {}
self.Targets[TargetIndex].AttackMessage = EscortTargetMessage
self.Targets[TargetIndex].AttackUnit = EscortTargetUnit
end
end
if EscortTargetMessage ~= "" then MENU_CLIENT_COMMAND:New( self.EscortClient,
EscortTargetMessages = EscortTargetMessages .. EscortTargetMessage .. "\n" EscortTargetMessage,
self.EscortMenuAttackNearbyTargets,
ESCORT._AttackTarget,
{ ParamSelf = self,
ParamUnit = ClientEscortTargetData.AttackUnit
}
)
EscortTargetMessages = EscortTargetMessages .. "\n - " .. EscortTargetMessage
else
local MenuTargetAssistance = MENU_CLIENT:New( self.EscortClient, EscortGroupData.EscortName, self.EscortMenuTargetAssistance )
MENU_CLIENT_COMMAND:New( self.EscortClient,
EscortTargetMessage,
MenuTargetAssistance,
ESCORT._AssistTarget,
{ ParamSelf = self,
ParamEscortGroup = EscortGroupData.EscortGroup,
ParamUnit = ClientEscortTargetData.AttackUnit
}
)
end
else
ClientEscortTargetData = nil
end end
end end
end end
if EscortTargetMessages ~= "" and self.ReportTargets == true then if EscortTargetMessages ~= "" and self.ReportTargets == true then
self.EscortGroup:MessageToClient( EscortTargetMessages:gsub("\n$",""), 20, self.EscortClient ) self.EscortGroup:MessageToClient( "Detected targets within 15 km range:" .. EscortTargetMessages:gsub("\n$",""), 20, self.EscortClient )
else else
self.EscortGroup:MessageToClient( "No targets detected!", 20, self.EscortClient ) self.EscortGroup:MessageToClient( "No targets detected!", 20, self.EscortClient )
end end
self:T()
self:T( { "Sorting Targets Table:", self.Targets } )
table.sort( self.Targets )
self:T( { "Sorted Targets Table:", self.Targets } )
for MenuIndex = 1, #self.EscortMenuAttackTargets do
self:T( { "Remove Menu:", self.EscortMenuAttackTargets[MenuIndex] } )
self.EscortMenuAttackTargets[MenuIndex] = self.EscortMenuAttackTargets[MenuIndex]:Remove()
end end
local MenuIndex = 1 self.EscortMenuResumeMission:RemoveSubMenus()
for TargetID, TargetData in pairs( self.Targets ) do
self:T( { "Adding menu:", TargetID, "for Unit", self.Targets[TargetID].AttackUnit } ) -- if self.EscortMenuResumeWayPoints then
if MenuIndex <= 10 then -- for MenuIndex = 1, #self.EscortMenuResumeWayPoints do
self.EscortMenuAttackTargets[MenuIndex] = -- self:T( { "Remove Menu:", self.EscortMenuResumeWayPoints[MenuIndex] } )
MENU_CLIENT_COMMAND:New( self.EscortClient, -- self.EscortMenuResumeWayPoints[MenuIndex] = self.EscortMenuResumeWayPoints[MenuIndex]:Remove()
self.Targets[TargetID].AttackMessage, -- end
self.EscortMenuAttackNearbyTargets, -- end
ESCORT._AttackTarget,
{ ParamSelf = self, local TaskPoints = self:RegisterRoute()
ParamUnit = self.Targets[TargetID].AttackUnit for WayPointID, WayPoint in pairs( TaskPoints ) do
} local EscortPositionVec3 = self.EscortGroup:GetPositionVec3()
) local Distance = ( ( WayPoint.x - EscortPositionVec3.x )^2 +
self:T( { "New Menu:", self.EscortMenuAttackTargets[TargetID] } ) ( WayPoint.y - EscortPositionVec3.z )^2
MenuIndex = MenuIndex + 1 ) ^ 0.5 / 1000
else MENU_CLIENT_COMMAND:New( self.EscortClient, "Waypoint " .. WayPointID .. " at " .. string.format( "%.2f", Distance ).. "km", self.EscortMenuResumeMission, ESCORT._ResumeMission, { ParamSelf = self, ParamWayPoint = WayPointID } )
break
end
end end
else else

View File

@ -399,7 +399,7 @@ end
-- @param #GROUP self -- @param #GROUP self
-- @return Group#GROUP self -- @return Group#GROUP self
function GROUP:SetTask( DCSTask ) function GROUP:SetTask( DCSTask )
self:F() self:F( { DCSTask } )
local Controller = self:_GetController() local Controller = self:_GetController()
@ -417,7 +417,7 @@ end
-- @param #string condition -- @param #string condition
-- @param #Time duration -- @param #Time duration
-- @param #number lastWayPoint -- @param #number lastWayPoint
-- return #DCSTask -- return DCSTask#Task
function GROUP:TaskCondition( time, userFlag, userFlagValue, condition, duration, lastWayPoint ) function GROUP:TaskCondition( time, userFlag, userFlagValue, condition, duration, lastWayPoint )
self:F( { time, userFlag, userFlagValue, condition, duration, lastWayPoint } ) self:F( { time, userFlag, userFlagValue, condition, duration, lastWayPoint } )
@ -435,9 +435,9 @@ end
--- Return a Controlled Task taking a Task and a TaskCondition --- Return a Controlled Task taking a Task and a TaskCondition
-- @param #GROUP self -- @param #GROUP self
-- @param #DCSTask DCSTask -- @param DCSTask#Task DCSTask
-- @param #DCSStopCondition DCSStopCondition -- @param #DCSStopCondition DCSStopCondition
-- @return #DCSTask -- @return DCSTask#Task
function GROUP:TaskControlled( DCSTask, DCSStopCondition ) function GROUP:TaskControlled( DCSTask, DCSStopCondition )
self:F( { DCSTask, DCSStopCondition } ) self:F( { DCSTask, DCSStopCondition } )
@ -447,7 +447,7 @@ function GROUP:TaskControlled( DCSTask, DCSStopCondition )
id = 'ControlledTask', id = 'ControlledTask',
params = { params = {
task = DCSTask, task = DCSTask,
stopCondition = DCSStopCondition, stopCondition = DCSStopCondition
} }
} }
@ -455,6 +455,47 @@ function GROUP:TaskControlled( DCSTask, DCSStopCondition )
return DCSTaskControlled return DCSTaskControlled
end end
--- Return a Combo Task taking an array of Tasks
-- @param #GROUP self
-- @param #list<DCSTask#Task> DCSTasks
-- @return DCSTask#Task
function GROUP:TaskCombo( DCSTasks )
self:F( { DCSTasks } )
local DCSTaskCombo
DCSTaskCombo = {
id = 'ComboTask',
params = {
tasks = DCSTasks
}
}
self:T( { DCSTaskCombo } )
return DCSTaskCombo
end
--- Return a WrappedAction Task taking a Command
-- @param #GROUP self
-- @param DCSCommand#Command DCSCommand
-- @return DCSTask#Task
function GROUP:TaskWrappedAction( DCSCommand )
self:F( { DCSCommand } )
local DCSTaskWrappedAction
DCSTaskWrappedAction = {
id = "WrappedAction",
enabled = true,
params = {
action = DCSCommand
}
}
self:T( { DCSTaskWrappedAction } )
return DCSTaskWrappedAction
end
--- Orbit at a specified position at a specified alititude during a specified duration with a specified speed. --- Orbit at a specified position at a specified alititude during a specified duration with a specified speed.
-- @param #GROUP self -- @param #GROUP self
-- @param #Vec2 Point The point to hold the position. -- @param #Vec2 Point The point to hold the position.
@ -566,7 +607,7 @@ end
--- Attack the Unit. --- Attack the Unit.
-- @param #GROUP self -- @param #GROUP self
-- @param Unit#UNIT The unit. -- @param Unit#UNIT The unit.
-- @return #DCSTask The DCS task structure. -- @return DCSTask#Task The DCS task structure.
function GROUP:TaskAttackUnit( AttackUnit ) function GROUP:TaskAttackUnit( AttackUnit )
self:F( { self.GroupName, AttackUnit } ) self:F( { self.GroupName, AttackUnit } )
@ -595,6 +636,33 @@ function GROUP:TaskAttackUnit( AttackUnit )
return DCSTask return DCSTask
end end
--- Fires at a VEC2 point.
-- @param #GROUP self
-- @param DCSTypes#Vec2 The point to fire at.
-- @param DCSTypes#Distance Radius The radius of the zone to deploy the fire at.
-- @return DCSTask#Task The DCS task structure.
function GROUP:TaskFireAtPoint( PointVec2, Radius )
self:F( { self.GroupName, PointVec2, Radius } )
-- FireAtPoint = {
-- id = 'FireAtPoint',
-- params = {
-- point = Vec2,
-- radius = Distance,
-- }
-- }
local DCSTask
DCSTask = { id = 'FireAtPoint',
params = { point = PointVec2,
radius = Radius,
}
}
self:T( { DCSTask } )
return DCSTask
end
--- Move the group to a Vec2 Point, wait for a defined duration and embark a group. --- Move the group to a Vec2 Point, wait for a defined duration and embark a group.
@ -602,7 +670,7 @@ end
-- @param #Vec2 Point The point where to wait. -- @param #Vec2 Point The point where to wait.
-- @param #number Duration The duration in seconds to wait. -- @param #number Duration The duration in seconds to wait.
-- @param #GROUP EmbarkingGroup The group to be embarked. -- @param #GROUP EmbarkingGroup The group to be embarked.
-- @return #DCSTask The DCS task structure -- @return DCSTask#Task The DCS task structure
function GROUP:TaskEmbarkingAtVec2( Point, Duration, EmbarkingGroup ) function GROUP:TaskEmbarkingAtVec2( Point, Duration, EmbarkingGroup )
self:F( { self.GroupName, Point, Duration, EmbarkingGroup.DCSGroup } ) self:F( { self.GroupName, Point, Duration, EmbarkingGroup.DCSGroup } )
@ -626,11 +694,11 @@ end
-- @param #GROUP self -- @param #GROUP self
-- @param #Vec2 Point The point where to wait. -- @param #Vec2 Point The point where to wait.
-- @param #number Radius The radius of the embarking zone around the Point. -- @param #number Radius The radius of the embarking zone around the Point.
-- @return #DCSTask The DCS task structure. -- @return DCSTask#Task The DCS task structure.
function GROUP:TaskEmbarkToTransportAtVec2( Point, Radius ) function GROUP:TaskEmbarkToTransportAtVec2( Point, Radius )
self:F( { self.GroupName, Point, Radius } ) self:F( { self.GroupName, Point, Radius } )
local DCSTask --#DCSTask local DCSTask --DCSTask#Task
DCSTask = { id = 'EmbarkToTransport', DCSTask = { id = 'EmbarkToTransport',
params = { x = Point.x, params = { x = Point.x,
y = Point.y, y = Point.y,
@ -645,7 +713,7 @@ end
--- Return a Misson task from a mission template. --- Return a Misson task from a mission template.
-- @param #GROUP self -- @param #GROUP self
-- @param #table TaskMission A table containing the mission task. -- @param #table TaskMission A table containing the mission task.
-- @return #DCSTask -- @return DCSTask#Task
function GROUP:TaskMission( TaskMission ) function GROUP:TaskMission( TaskMission )
self:F( Points ) self:F( Points )
@ -659,7 +727,7 @@ end
--- Return a Misson task to follow a given route defined by Points. --- Return a Misson task to follow a given route defined by Points.
-- @param #GROUP self -- @param #GROUP self
-- @param #table Points A table of route points. -- @param #table Points A table of route points.
-- @return #DCSTask -- @return DCSTask#Task
function GROUP:TaskRoute( Points ) function GROUP:TaskRoute( Points )
self:F( Points ) self:F( Points )
@ -722,28 +790,22 @@ function GROUP:Route( GoPoints )
return self return self
end end
--- Registers a Task to be executed at a waypoint.
-- @param #GROUP self
-- @param #number WayPoint The waypoint where to execute the task.
-- @return #string The task.
function GROUP:TaskRegisterWayPoint( WayPoint ) function GROUP:TaskRegisterWayPoint( WayPoint )
local DCSTask local DCSTask
DCSTask = { id = "WrappedAction", DCSTask = self:TaskWrappedAction(
enabled = true, self:CommandDoScript(
auto = false, "local MissionGroup = GROUP:New( ... ) " ..
number = 1,
params =
{
action =
{
id = "Script",
params =
{
command = "local MissionGroup = GROUP.FindGroup( ... ) " ..
"env.info( MissionGroup:GetName() ) " .. "env.info( MissionGroup:GetName() ) " ..
"MissionGroup:RegisterWayPoint ( " .. WayPoint .. " )", "MissionGroup:RegisterWayPoint ( " .. WayPoint .. " )"
}, -- end of ["params"] )
}, -- end of ["action"] )
}, -- end of ["params"]
}
self:T( DCSTask ) self:T( DCSTask )
return DCSTask return DCSTask
@ -805,6 +867,26 @@ function GROUP:TaskRouteToZone( Zone, Randomize, Speed, Formation )
return self return self
end end
-- Commands
--- Do Script command
-- @param #GROUP self
-- @param #string DoScript
-- @return #DCSCommand
function GROUP:CommandDoScript( DoScript )
local DCSDoScript = {
id = "Script",
params = {
command = DoScript
}
}
self:T( DCSDoScript )
return DCSDoScript
end
--- Return the mission template of the group. --- Return the mission template of the group.
-- @param #GROUP self -- @param #GROUP self
-- @return #table The MissionTemplate -- @return #table The MissionTemplate
@ -891,7 +973,14 @@ end
function GROUP:IsTargetDetected( DCSObject ) function GROUP:IsTargetDetected( DCSObject )
local TargetIsDetected, TargetIsVisible, TargetLastTime, TargetKnowType, TargetKnowDistance, TargetLastPos, TargetLastVelocity local TargetIsDetected, TargetIsVisible, TargetLastTime, TargetKnowType, TargetKnowDistance, TargetLastPos, TargetLastVelocity
= self:_GetController():isTargetDetected( DCSObject ) = self:_GetController().isTargetDetected( self:_GetController(), DCSObject,
Controller.Detection.VISUAL,
Controller.Detection.OPTIC,
Controller.Detection.RADAR,
Controller.Detection.IRST,
Controller.Detection.RWR,
Controller.Detection.DLINK
)
return TargetIsDetected, TargetIsVisible, TargetLastTime, TargetKnowType, TargetKnowDistance, TargetLastPos, TargetLastVelocity return TargetIsDetected, TargetIsVisible, TargetLastTime, TargetKnowType, TargetKnowDistance, TargetLastPos, TargetLastVelocity

View File

@ -108,6 +108,9 @@ function MENU_CLIENT:New( MenuClient, MenuText, ParentMenu )
self.MenuClientGroupID = MenuClient:GetClientGroupID() self.MenuClientGroupID = MenuClient:GetClientGroupID()
self.MenuParentPath = MenuParentPath self.MenuParentPath = MenuParentPath
self.MenuText = MenuText self.MenuText = MenuText
self.ParentMenu = ParentMenu
self.Menus = {}
if not _MENUCLIENTS[self.MenuClientGroupID] then if not _MENUCLIENTS[self.MenuClientGroupID] then
_MENUCLIENTS[self.MenuClientGroupID] = {} _MENUCLIENTS[self.MenuClientGroupID] = {}
@ -124,9 +127,49 @@ function MENU_CLIENT:New( MenuClient, MenuText, ParentMenu )
self.MenuPath = MenuPath[table.concat(MenuParentPath) .. "/" .. MenuText] self.MenuPath = MenuPath[table.concat(MenuParentPath) .. "/" .. MenuText]
end end
self:T( { MenuClient:GetClientGroupName(), self.MenuPath } )
if ParentMenu and ParentMenu.Menus then
ParentMenu.Menus[self.MenuPath] = self
end
return self return self
end end
--- Removes the sub menus recursively of this MENU_CLIENT.
-- @param #MENU_CLIENT self
-- @return #MENU_CLIENT self
function MENU_CLIENT:RemoveSubMenus()
self:F( self.MenuPath )
for MenuID, Menu in pairs( self.Menus ) do
Menu:Remove()
end
end
--- Removes the sub menus recursively of this MENU_CLIENT.
-- @param #MENU_CLIENT self
-- @return #MENU_CLIENT self
function MENU_CLIENT:Remove()
self:F( self.MenuPath )
self:RemoveSubMenus()
if not _MENUCLIENTS[self.MenuClientGroupID] then
_MENUCLIENTS[self.MenuClientGroupID] = {}
end
local MenuPath = _MENUCLIENTS[self.MenuClientGroupID]
if MenuPath[table.concat(self.MenuParentPath) .. "/" .. self.MenuText] then
MenuPath[table.concat(self.MenuParentPath) .. "/" .. self.MenuText] = nil
end
missionCommands.removeItemForGroup( self.MenuClient:GetClientGroupID(), self.MenuPath )
self.ParentMenu.Menus[self.MenuPath] = nil
return nil
end
--- The MENU_CLIENT_COMMAND class --- The MENU_CLIENT_COMMAND class
-- @type MENU_CLIENT_COMMAND -- @type MENU_CLIENT_COMMAND
@ -158,6 +201,7 @@ function MENU_CLIENT_COMMAND:New( MenuClient, MenuText, ParentMenu, CommandMenuF
self.MenuClientGroupID = MenuClient:GetClientGroupID() self.MenuClientGroupID = MenuClient:GetClientGroupID()
self.MenuParentPath = MenuParentPath self.MenuParentPath = MenuParentPath
self.MenuText = MenuText self.MenuText = MenuText
self.ParentMenu = ParentMenu
if not _MENUCLIENTS[self.MenuClientGroupID] then if not _MENUCLIENTS[self.MenuClientGroupID] then
_MENUCLIENTS[self.MenuClientGroupID] = {} _MENUCLIENTS[self.MenuClientGroupID] = {}
@ -176,10 +220,14 @@ function MENU_CLIENT_COMMAND:New( MenuClient, MenuText, ParentMenu, CommandMenuF
self.CommandMenuFunction = CommandMenuFunction self.CommandMenuFunction = CommandMenuFunction
self.CommandMenuArgument = CommandMenuArgument self.CommandMenuArgument = CommandMenuArgument
ParentMenu.Menus[self.MenuPath] = self
return self return self
end end
function MENU_CLIENT_COMMAND:Remove() function MENU_CLIENT_COMMAND:Remove()
self:F( self.MenuPath )
if not _MENUCLIENTS[self.MenuClientGroupID] then if not _MENUCLIENTS[self.MenuClientGroupID] then
_MENUCLIENTS[self.MenuClientGroupID] = {} _MENUCLIENTS[self.MenuClientGroupID] = {}
@ -191,5 +239,6 @@ function MENU_CLIENT_COMMAND:Remove()
MenuPath[table.concat(self.MenuParentPath) .. "/" .. self.MenuText] = nil MenuPath[table.concat(self.MenuParentPath) .. "/" .. self.MenuText] = nil
end end
missionCommands.removeItemForGroup( self.MenuClient:GetClientGroupID(), self.MenuPath ) missionCommands.removeItemForGroup( self.MenuClient:GetClientGroupID(), self.MenuPath )
self.ParentMenu.Menus[self.MenuPath] = nil
return nil return nil
end end

View File

@ -473,6 +473,13 @@ do
rep - time between repetitions of this function (OPTIONAL) rep - time between repetitions of this function (OPTIONAL)
st - time when repetitions of this function will stop automatically (OPTIONAL) st - time when repetitions of this function will stop automatically (OPTIONAL)
]] ]]
--- Schedule a function
-- @param #function f
-- @param #table parameters
-- @param #Time t
-- @param #Time rep seconds
-- @param #Time st
routines.scheduleFunction = function(f, vars, t, rep, st) routines.scheduleFunction = function(f, vars, t, rep, st)
--verify correct types --verify correct types
assert(type(f) == 'function', 'variable 1, expected function, got ' .. type(f)) assert(type(f) == 'function', 'variable 1, expected function, got ' .. type(f))

View File

@ -49,6 +49,11 @@ UNIT = {
-- @field Orange -- @field Orange
-- @field Blue -- @field Blue
--- Create a new UNIT from DCSUnit.
-- @param #UNIT self
-- @param DCSUnit#Unit DCSUnit
-- @return Unit#UNIT
function UNIT:New( DCSUnit ) function UNIT:New( DCSUnit )
local self = BASE:Inherit( self, BASE:New() ) local self = BASE:Inherit( self, BASE:New() )
self:F( DCSUnit:getName() ) self:F( DCSUnit:getName() )
@ -231,4 +236,21 @@ function UNIT:SmokeBlue()
trigger.action.smoke( self:GetPositionVec3(), trigger.smokeColor.Blue ) trigger.action.smoke( self:GetPositionVec3(), trigger.smokeColor.Blue )
end end
-- Is methods
--- Returns if the unit is of an air category.
-- If the unit is a helicopter or a plane, then this method will return true, otherwise false.
-- @param #UNIT self
-- @return #boolean Air category evaluation result.
function UNIT:IsAir()
self:F()
local UnitDescriptor = self.DCSUnit:getDesc()
self:T( { UnitDescriptor.category, Unit.Category.AIRPLANE, Unit.Category.HELICOPTER } )
local IsAirResult = ( UnitDescriptor.category == Unit.Category.AIRPLANE ) or ( UnitDescriptor.category == Unit.Category.HELICOPTER )
self:T( IsAirResult )
return IsAirResult
end