diff --git a/Loaders/MOOSE-Template.miz b/Loaders/MOOSE-Template.miz new file mode 100644 index 000000000..108e949f1 Binary files /dev/null and b/Loaders/MOOSE-Template.miz differ diff --git a/Moose/Base.lua b/Moose/Base.lua index a01b9e2ee..278af6459 100644 --- a/Moose/Base.lua +++ b/Moose/Base.lua @@ -25,7 +25,7 @@ local _TraceClass = { --CLEANUP = true, --MENU_CLIENT = true, --MENU_CLIENT_COMMAND = true, - --ESCORT = true, + ESCORT = true, } --- The BASE Class diff --git a/Moose/Client.lua b/Moose/Client.lua index 1f671531a..d927f46bc 100644 --- a/Moose/Client.lua +++ b/Moose/Client.lua @@ -34,9 +34,10 @@ CLIENT = { --- Use this method to register new Clients within the MOF. --- @param string ClientName Name of the Group as defined within the Mission Editor. The Group must have a Unit with the type Client. --- @param string ClientBriefing Text that describes the briefing of the mission when a Player logs into the Client. --- @return CLIENT +-- @param #CLIENT self +-- @param #string ClientName Name of the Group as defined within the Mission Editor. The Group must have a Unit with the type Client. +-- @param #string ClientBriefing Text that describes the briefing of the mission when a Player logs into the Client. +-- @return #CLIENT -- @usage -- -- Create new Clients. -- local Mission = MISSIONSCHEDULER.AddMission( 'Russia Transport Troops SA-6', 'Operational', 'Transport troops from the control center to one of the SA-6 SAM sites to activate their operation.', 'Russia' ) @@ -169,7 +170,7 @@ function CLIENT:GetClientGroupName() end --- Returns the Unit of the @{CLIENT}. --- @return Unit +-- @return Unit#UNIT function CLIENT:GetClientGroupUnit() self:F() diff --git a/Moose/Escort.lua b/Moose/Escort.lua index 5f4c77ccc..fa402e00d 100644 --- a/Moose/Escort.lua +++ b/Moose/Escort.lua @@ -55,7 +55,8 @@ function ESCORT:New( EscortClient, EscortGroup, EscortName ) -- Escort Navigation self.EscortMenuReportNavigation = MENU_CLIENT:New( self.EscortClient, "Navigation", self.EscortMenu ) self.EscortMenuHoldPosition = MENU_CLIENT_COMMAND:New( self.EscortClient, "Hold Position and Stay Low", self.EscortMenuReportNavigation, ESCORT._HoldPosition, { ParamSelf = self } ) - self.EscortMenuHoldPosition = MENU_CLIENT_COMMAND:New( self.EscortClient, "Join-Up and Hold Position NearBy", self.EscortMenuReportNavigation, ESCORT._HoldPositionNearBy, { ParamSelf = self } ) + self.EscortMenuJoinUpAndHoldPosition = MENU_CLIENT_COMMAND:New( self.EscortClient, "Join-Up and Hold Position NearBy", self.EscortMenuReportNavigation, ESCORT._HoldPositionNearBy, { ParamSelf = self } ) + self.EscortMenuJoinUpAndFollow = MENU_CLIENT_COMMAND:New( self.EscortClient, "Join-Up and Follow", self.EscortMenuReportNavigation, ESCORT._JoinUpAndFollow, { ParamSelf = self } ) -- Report Targets self.EscortMenuReportNearbyTargets = MENU_CLIENT:New( self.EscortClient, "Report targets", self.EscortMenu ) @@ -65,6 +66,7 @@ function ESCORT:New( EscortClient, EscortGroup, EscortName ) -- Scanning Targets self.EscortMenuScanForTargets = MENU_CLIENT:New( self.EscortClient, "Scan targets", self.EscortMenu ) self.EscortMenuReportNearbyTargetsOn = MENU_CLIENT_COMMAND:New( self.EscortClient, "Scan targets 30 seconds", self.EscortMenuScanForTargets, ESCORT._ScanTargets30Seconds, { ParamSelf = self, ParamScanDuration = 30 } ) + self.EscortMenuReportNearbyTargetsOn = MENU_CLIENT_COMMAND:New( self.EscortClient, "Scan targets 60 seconds", self.EscortMenuScanForTargets, ESCORT._ScanTargets60Seconds, { ParamSelf = self, ParamScanDuration = 30 } ) -- Attack Targets self.EscortMenuAttackNearbyTargets = MENU_CLIENT:New( self.EscortClient, "Attack nearby targets", self.EscortMenu ) @@ -138,6 +140,20 @@ function ESCORT._HoldPositionNearBy( MenuParam ) MESSAGE:New( "Rejoining to your location. Please hold at your location.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/HoldPositionNearBy" ):ToClient( EscortClient ) end +--- @param #MENUPARAM MenuParam +function ESCORT._JoinUpAndFollow( MenuParam ) + + local self = MenuParam.ParamSelf + local EscortGroup = MenuParam.ParamSelf.EscortGroup + local EscortClient = MenuParam.ParamSelf.EscortClient + + self.CT1 = 0 + self.GT1 = 0 + self.FollowFunction = routines.scheduleFunction( self._Follower, { self }, timer.getTime() + 1, 1 ) + EscortGroup:MessageToClient( "Rejoining and following orders ...", 10, EscortClient ) +end + + function ESCORT._ReportNearbyTargets( MenuParam ) MenuParam.ParamSelf:T() @@ -280,6 +296,63 @@ function ESCORT._CancelCurrentTask( MenuParam ) MESSAGE:New( "Cancelling with current orders, continuing our mission.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/CancelCurrentTask" ):ToClient( EscortClient ) end +--- @param Escort#ESCORT self +function ESCORT:_Follower() + self:F() + + local ClientUnit = self.EscortClient:GetClientGroupUnit() + local GroupUnit = self.EscortGroup:GetUnit( 1 ) + + if self.EscortGroup:IsAlive() and ClientUnit:IsAlive() then + if self.CT1 == 0 and self.GT1 == 0 then + self.CV1 = ClientUnit:GetPositionVec3() + self.CT1 = timer.getTime() + self.GV1 = GroupUnit:GetPositionVec3() + self.GT1 = timer.getTime() + + else + local CT1 = self.CT1 + local CT2 = timer.getTime() + local CV1 = self.CV1 + local CV2 = ClientUnit:GetPositionVec3() + + local CD = ( ( CV2.x - CV1.x )^2 + ( CV2.y - CV1.y )^2 + ( CV2.z - CV1.z )^2 ) ^ 0.5 + local CT = CT2 - CT1 + + local CS = ( 3600 / CT ) * ( CD / 1000 ) + + self:T( { "Client:", CS, CD, CT, CV2, CV1, CT2, CT1 } ) + + local GT1 = self.GT1 + local GT2 = timer.getTime() + local GV1 = self.GV1 + local GV2 = GroupUnit:GetPositionVec3() + + local GD = ( ( GV2.x - GV1.x )^2 + ( GV2.y - GV1.y )^2 + ( GV2.z - GV1.z )^2 ) ^ 0.5 + local GT = GT2 - GT1 + + local GS = ( 3600 / GT ) * ( GD / 1000 ) + + self:T( { "Group:", GS, GD, GT, GV2, GV1, GT2, GT1 } ) + + -- Measure distance between client and group + local D = ( ( CV2.x - GV2.x )^2 + ( CV2.y - GV2.y )^2 + ( CV2.z - GV2.z )^2 ) ^ 0.5 - 200 + + local S = ( 3600 / 30 ) * ( D / 1000 ) -- We use a 2 second buffer to adjust the speed + local A = ( CS - GS ) + S -- Accelleration required = Client Speed - Group Speed + Speed to overcome distance (with 10 second time buffer) + local Speed = A -- Final speed is the current Group speed + Accelleration + + self:T( { "Speed:", S, A, Speed } ) + + -- Now route the escort to the desired point with the desired speed. + self.EscortGroup:TaskRouteToVec3( CV2, Speed ) + end + else + routines.removeFunction( self.FollowFunction ) + end + +end + function ESCORT:_ScanForTargets() self:F() diff --git a/Moose/Group.lua b/Moose/Group.lua index ede103434..e5144068c 100644 --- a/Moose/Group.lua +++ b/Moose/Group.lua @@ -199,9 +199,9 @@ end --- Gets the DCS Unit. --- @param self +-- @param #GROUP self -- @param #number UnitNumber The number of the Unit to be returned. --- @return #Unit The DCS Unit. +-- @return Unit#UNIT The DCS Unit. function GROUP:GetUnit( UnitNumber ) self:F( { self.GroupName, UnitNumber } ) return UNIT:New( self.DCSGroup:getUnit( UnitNumber ) ) @@ -558,7 +558,7 @@ end --- Return a Misson task to follow a given route. -- @param #GROUP self --- @param #table GoPoints A table of Route Points. +-- @param #table Points A table of Route Points. -- @return #DCSTask function GROUP:TaskMission( Points ) self:F( Points ) @@ -570,6 +570,39 @@ function GROUP:TaskMission( Points ) return DCSTask end +--- Make the group to fly to a given point and hover. +-- @param #GROUP self +-- @param #Vec3 Point The destination point. +-- @param #number Speed The speed to travel. +-- @return #GROUP self +function GROUP:TaskRouteToVec3( Point, Speed ) + self:F( { Point, Speed } ) + + local GroupPoint = self:GetUnit( 1 ):GetPositionVec3() + + local PointFrom = {} + PointFrom.x = GroupPoint.x + PointFrom.y = GroupPoint.z + PointFrom.alt = GroupPoint.y + PointFrom.type = "Turning Point" + + local PointTo = {} + PointTo.x = Point.x + PointTo.y = Point.z + PointTo.alt = Point.y + PointTo.type = "Turning Point" + PointTo.speed = Speed + + local Points = { PointFrom, PointTo } + + self:T( Points ) + + self:Route( Points ) + + return self +end + + --- Make the group to follow a given route. -- @param #GROUP self diff --git a/Moose/Unit.lua b/Moose/Unit.lua index 18b410ae9..67089077a 100644 --- a/Moose/Unit.lua +++ b/Moose/Unit.lua @@ -1,5 +1,5 @@ --- UNIT Classes --- @module UNIT +-- @module Unit Include.File( "Routines" ) Include.File( "Base" ) diff --git a/Test Missions/lua/MOOSE_Escort_Test_Follow.lua b/Test Missions/lua/MOOSE_Escort_Test_Follow.lua new file mode 100644 index 000000000..57b203189 --- /dev/null +++ b/Test Missions/lua/MOOSE_Escort_Test_Follow.lua @@ -0,0 +1,19 @@ +Include.File( "Mission" ) +Include.File( "Client" ) +Include.File( "Escort" ) + + +do + local EscortClient = CLIENT:New( "Lead Helicopter", "Fly around and observe the behaviour of the escort helicopter" ) + local EscortGroup = GROUP:NewFromName( "Escort Helicopter" ) + + local Escort = ESCORT:New( EscortClient, EscortGroup, "Escort Test" ) +end + + +-- MISSION SCHEDULER STARTUP +MISSIONSCHEDULER.Start() +MISSIONSCHEDULER.ReportMenu() +MISSIONSCHEDULER.ReportMissionsHide() + +env.info( "Test Mission loaded" ) diff --git a/Test Missions/MOOSE_Pickup_Test.lua b/Test Missions/lua/MOOSE_Pickup_Test.lua similarity index 100% rename from Test Missions/MOOSE_Pickup_Test.lua rename to Test Missions/lua/MOOSE_Pickup_Test.lua diff --git a/Test Missions/MOOSE_Spawn_Test.lua b/Test Missions/lua/MOOSE_Spawn_Test.lua similarity index 100% rename from Test Missions/MOOSE_Spawn_Test.lua rename to Test Missions/lua/MOOSE_Spawn_Test.lua diff --git a/Test Missions/miz/MOOSE_Escort_Test_Follow.miz b/Test Missions/miz/MOOSE_Escort_Test_Follow.miz new file mode 100644 index 000000000..4594f3756 Binary files /dev/null and b/Test Missions/miz/MOOSE_Escort_Test_Follow.miz differ diff --git a/Test Missions/MOOSE_Pickup_Test.miz b/Test Missions/miz/MOOSE_Pickup_Test.miz similarity index 100% rename from Test Missions/MOOSE_Pickup_Test.miz rename to Test Missions/miz/MOOSE_Pickup_Test.miz diff --git a/Test Missions/MOOSE_Spawn_Test.miz b/Test Missions/miz/MOOSE_Spawn_Test.miz similarity index 100% rename from Test Missions/MOOSE_Spawn_Test.miz rename to Test Missions/miz/MOOSE_Spawn_Test.miz