diff --git a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua index ced18e18e..643d4e529 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua @@ -115,7 +115,7 @@ function AI_CARGO_HELICOPTER:New( Helicopter, CargoSet ) -- We need to capture the Crash events for the helicopters. - -- The helicopter reference is used in the semaphore AI_CARGO_QUEUEU. + -- The helicopter reference is used in the semaphore AI_CARGO_QUEUE. -- So, we need to unlock this when the helo is not anymore ... Helicopter:HandleEvent( EVENTS.Crash, function( Helicopter, EventData ) @@ -123,6 +123,20 @@ function AI_CARGO_HELICOPTER:New( Helicopter, CargoSet ) end ) + -- We need to capture the Land events for the helicopters. + -- The helicopter reference is used in the semaphore AI_CARGO_QUEUE. + -- So, we need to unlock this when the helo has landed, which can be anywhere ... + -- But only free the landing coordinate after 1 minute, to ensure that all helos have left. + Helicopter:HandleEvent( EVENTS.Land, + function( Helicopter, EventData ) + self:ScheduleOnce( 60, + function( Helicopter ) + AI_CARGO_QUEUE[Helicopter] = nil + end, Helicopter + ) + end + ) + self:SetCarrier( Helicopter ) return self @@ -169,19 +183,6 @@ function AI_CARGO_HELICOPTER:SetCarrier( Helicopter ) end end - - function Helicopter:OnEventHit( EventData ) - local AICargoTroops = self:GetState( self, "AI_CARGO_HELICOPTER" ) - if AICargoTroops then - self:F( { OnHitLoaded = AICargoTroops:Is( "Loaded" ) } ) - if AICargoTroops:Is( "Loaded" ) or AICargoTroops:Is( "Boarding" ) then - -- There are enemies within combat range. Unload the Helicopter. - AICargoTroops:Unload() - end - end - end - - function Helicopter:OnEventLand( EventData ) AICargo:Landed() end @@ -203,19 +204,34 @@ end -- @param #number Speed function AI_CARGO_HELICOPTER:onafterLanded( Helicopter, From, Event, To ) + Helicopter:F( { Name = Helicopter:GetName() } ) + if Helicopter and Helicopter:IsAlive() then + -- S_EVENT_LAND is directly called in two situations: + -- 1 - When the helo lands normally on the ground. + -- 2 - when the helo is hit and goes RTB or even when it is destroyed. + -- For point 2, this is an issue, the infantry may not unload in this case! + -- So we check if the helo is on the ground, and velocity< 5. + -- Only then the infantry can unload (and load too, for consistency)! + + self:F( { Helicopter:GetName(), Height = Helicopter:GetHeight( true ), Velocity = Helicopter:GetVelocityKMH() } ) + if self.RoutePickup == true then - self:Load( Helicopter:GetPointVec2() ) - self.RoutePickup = false - self.Relocating = true + if Helicopter:GetHeight( true ) <= 2 and Helicopter:GetVelocityKMH() < 5 then + self:Load( Helicopter:GetPointVec2() ) + self.RoutePickup = false + self.Relocating = true + end end if self.RouteDeploy == true then - self:Unload( true ) - self.RouteDeploy = false - self.Transporting = false - self.Relocating = false + if Helicopter:GetHeight( true ) <= 2 and Helicopter:GetVelocityKMH() < 5 then + self:Unload( true ) + self.RouteDeploy = false + self.Transporting = false + self.Relocating = false + end end end @@ -498,7 +514,12 @@ function AI_CARGO_HELICOPTER:onafterUnloaded( Helicopter, From, Event, To, Cargo self:Orbit( Helicopter:GetCoordinate(), 50 ) - AI_CARGO_QUEUE[Helicopter] = nil + -- Free the coordinate zone after 30 seconds, so that the original helicopter can fly away first. + self:ScheduleOnce( 30, + function( Helicopter ) + AI_CARGO_QUEUE[Helicopter] = nil + end, Helicopter + ) end diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index c595a5dbb..6f45f873d 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -456,6 +456,78 @@ function GROUP:GetSize() return nil end + +--- Returns the average velocity Vec3 vector. +-- @param Wrapper.Group#GROUP self +-- @return Dcs.DCSTypes#Vec3 The velocity Vec3 vector +-- @return #nil The GROUP is not existing or alive. +function GROUP:GetVelocityVec3() + self:F2( self.GroupName ) + + local DCSGroup = self:GetDCSObject() + + if DCSGroup and DCSGroup:isExist() then + local GroupUnits = DCSGroup:getUnits() + local GroupCount = #GroupUnits + + local VelocityVec3 = { x = 0, y = 0, z = 0 } + + for _, DCSUnit in pairs( GroupUnits ) do + local UnitVelocityVec3 = DCSUnit:getVelocity() + VelocityVec3.x = VelocityVec3.x + UnitVelocityVec3.x + VelocityVec3.y = VelocityVec3.y + UnitVelocityVec3.y + VelocityVec3.z = VelocityVec3.z + UnitVelocityVec3.z + end + + VelocityVec3.x = VelocityVec3.x / GroupCount + VelocityVec3.y = VelocityVec3.y / GroupCount + VelocityVec3.z = VelocityVec3.z / GroupCount + + return VelocityVec3 + end + + BASE:E( { "Cannot GetVelocityVec3", Group = self, Alive = self:IsAlive() } ) + + return nil +end + + +--- Returns the average group height in meters. +-- @param Wrapper.Group#GROUP self +-- @param #boolean FromGround Measure from the ground or from sea level. Provide **true** for measuring from the ground. **false** or **nil** if you measure from sea level. +-- @return Dcs.DCSTypes#Vec3 The height of the group. +-- @return #nil The GROUP is not existing or alive. +function GROUP:GetHeight( FromGround ) + self:F2( self.GroupName ) + + local DCSGroup = self:GetDCSObject() + + if DCSGroup then + local GroupUnits = DCSGroup:getUnits() + local GroupCount = #GroupUnits + + local GroupHeight = 0 + + for _, DCSUnit in pairs( GroupUnits ) do + local GroupPosition = DCSUnit:getPosition() + + if FromGround == true then + local LandHeight = land.getHeight( { GroupPosition.p.x, GroupPosition.p.z } ) + GroupHeight = GroupHeight + ( GroupPosition.p.y - LandHeight ) + else + GroupHeight = GroupHeight + GroupPosition.p.y + end + end + + return GroupHeight / GroupCount + end + + return nil +end + + + + --- --- Returns the initial size of the DCS Group. -- If some of the DCS Units of the DCS Group are destroyed, the initial size of the DCS Group is unchanged.