From 07d666b030c683c5622205d086335e76808b3371 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Thu, 18 Oct 2018 07:27:09 +0200 Subject: [PATCH 1/9] Optimized the boarding and unboarding of cargo. fixed bug when in defence of APC, cargo would not be loaded. The boarding and unboarding has become much more stable now. --- Moose Development/Moose/AI/AI_Cargo.lua | 3 +- Moose Development/Moose/AI/AI_Cargo_APC.lua | 78 ++++++--- .../Moose/AI/AI_Cargo_Dispatcher.lua | 2 +- Moose Development/Moose/Cargo/CargoGroup.lua | 61 +++---- Moose Development/Moose/Cargo/CargoUnit.lua | 153 +++++++++--------- .../Moose/Wrapper/Controllable.lua | 18 +++ Moose Development/Moose/Wrapper/Unit.lua | 23 ++- 7 files changed, 187 insertions(+), 151 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Cargo.lua b/Moose Development/Moose/AI/AI_Cargo.lua index c0c9fa8a7..d51149fbc 100644 --- a/Moose Development/Moose/AI/AI_Cargo.lua +++ b/Moose Development/Moose/AI/AI_Cargo.lua @@ -307,7 +307,7 @@ function AI_CARGO:onafterBoard( Carrier, From, Event, To, Cargo, CarrierUnit, Pi if Carrier and Carrier:IsAlive() then self:F({ IsLoaded = Cargo:IsLoaded(), Cargo:GetName(), Carrier:GetName() } ) - if not Cargo:IsLoaded() then + if not Cargo:IsLoaded() and not Cargo:IsDestroyed() then self:__Board( -10, Cargo, CarrierUnit, PickupZone ) return end @@ -487,6 +487,7 @@ function AI_CARGO:onafterDeployed( Carrier, From, Event, To, DeployZone, Defend self.Transporting = false else self:F( "Defending" ) + end end diff --git a/Moose Development/Moose/AI/AI_Cargo_APC.lua b/Moose Development/Moose/AI/AI_Cargo_APC.lua index b390f28d0..21fa5d3ba 100644 --- a/Moose Development/Moose/AI/AI_Cargo_APC.lua +++ b/Moose Development/Moose/AI/AI_Cargo_APC.lua @@ -276,34 +276,36 @@ function AI_CARGO_APC:onafterMonitor( APC, From, Event, To ) if self.CarrierCoordinate then if self:IsTransporting() == true then local Coordinate = APC:GetCoordinate() - self.Zone:Scan( { Object.Category.UNIT } ) - if self.Zone:IsAllInZoneOfCoalition( self.Coalition ) then - if self:Is( "Unloaded" ) or self:Is( "Following" ) then - -- There are no enemies within combat radius. Load the CargoCarrier. - self:Load() - end - else - if self:Is( "Loaded" ) then - -- There are enemies within combat radius. Unload the CargoCarrier. - self:__Unload( 1, nil, true ) -- The 2nd parameter is true, which means that the unload is for defending the carrier, not to deploy! - else + if self:Is( "Unloaded" ) or self:Is( "Loaded" ) then + self.Zone:Scan( { Object.Category.UNIT } ) + if self.Zone:IsAllInZoneOfCoalition( self.Coalition ) then if self:Is( "Unloaded" ) then - self:Follow() + -- There are no enemies within combat radius. Load the CargoCarrier. + self:Load() end - self:F( "I am here" .. self:GetCurrentState() ) - if self:Is( "Following" ) then - for Cargo, APCUnit in pairs( self.Carrier_Cargo ) do - local Cargo = Cargo -- Cargo.Cargo#CARGO - local APCUnit = APCUnit -- Wrapper.Unit#UNIT - if Cargo:IsAlive() then - if not Cargo:IsNear( APCUnit, 40 ) then - APCUnit:RouteStop() - self.CarrierStopped = true - else - if self.CarrierStopped then - if Cargo:IsNear( APCUnit, 25 ) then - APCUnit:RouteResume() - self.CarrierStopped = nil + else + if self:Is( "Loaded" ) then + -- There are enemies within combat radius. Unload the CargoCarrier. + self:__Unload( 1, nil, true ) -- The 2nd parameter is true, which means that the unload is for defending the carrier, not to deploy! + else + if self:Is( "Unloaded" ) then + --self:Follow() + end + self:F( "I am here" .. self:GetCurrentState() ) + if self:Is( "Following" ) then + for Cargo, APCUnit in pairs( self.Carrier_Cargo ) do + local Cargo = Cargo -- Cargo.Cargo#CARGO + local APCUnit = APCUnit -- Wrapper.Unit#UNIT + if Cargo:IsAlive() then + if not Cargo:IsNear( APCUnit, 40 ) then + APCUnit:RouteStop() + self.CarrierStopped = true + else + if self.CarrierStopped then + if Cargo:IsNear( APCUnit, 25 ) then + APCUnit:RouteResume() + self.CarrierStopped = nil + end end end end @@ -455,6 +457,30 @@ function AI_CARGO_APC:onafterDeployed( APC, From, Event, To, DeployZone, Defend self:__Guard( 0.1 ) self:GetParent( self, AI_CARGO_APC ).onafterDeployed( self, APC, From, Event, To, DeployZone, Defend ) + + -- If Defend == true then we need to scan for possible enemies within combat zone and engage only ground forces. + if Defend == true then + self.Zone:Scan( { Object.Category.UNIT } ) + if not self.Zone:IsAllInZoneOfCoalition( self.Coalition ) then + -- OK, enemies nearby, now find the enemies and attack them. + local AttackUnits = self.Zone:GetScannedUnits() -- #list + local Move = {} + for CargoId, CargoData in pairs( self.CargoSet:GetSet() ) do + local CargoGroup = CargoData.CargoObject -- Wrapper.Group#GROUP + Move[#Move+1] = CargoGroup:GetCoordinate():WaypointGround( 70, "Custom" ) + for UnitId, AttackUnit in pairs( AttackUnits ) do + local MooseUnit = UNIT:Find( AttackUnit ) + if MooseUnit:GetCoalition() ~= CargoGroup:GetCoalition() then + Move[#Move+1] = MooseUnit:GetCoordinate():WaypointGround( 70, "Line abreast" ) + --MoveTo.Task = CargoGroup:TaskCombo( CargoGroup:TaskAttackUnit( MooseUnit, true ) ) + self:F( { MooseUnit = MooseUnit:GetName(), CargoGroup = CargoGroup:GetName() } ) + end + end + CargoGroup:RoutePush( Move, 0.1 ) + end + end + + end end diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua index fd4a03d52..2f212f189 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua @@ -1143,7 +1143,7 @@ function AI_CARGO_DISPATCHER:onafterMonitor() LargestLoadCapacity = LoadCapacity end end - -- So if there is aa carrier that has the required load capacity to load the total weight of the cargo, dispatch the carrier. + -- So if there is a carrier that has the required load capacity to load the total weight of the cargo, dispatch the carrier. -- Otherwise break and go to the next carrier. -- This will skip cargo which is too large to be able to be loaded by carriers -- and will secure an efficient dispatching scheme. diff --git a/Moose Development/Moose/Cargo/CargoGroup.lua b/Moose Development/Moose/Cargo/CargoGroup.lua index bbfa83025..7e4a524d7 100644 --- a/Moose Development/Moose/Cargo/CargoGroup.lua +++ b/Moose Development/Moose/Cargo/CargoGroup.lua @@ -20,9 +20,9 @@ do -- CARGO_GROUP --- @type CARGO_GROUP - -- @extends Cargo.Cargo#CARGO_REPORTABLE -- @field Core.Set#SET_CARGO CargoSet The collection of derived CARGO objects. -- @field #string GroupName The name of the CargoGroup. + -- @extends Cargo.Cargo#CARGO_REPORTABLE --- Defines a cargo that is represented by a @{Wrapper.Group} object within the simulator. -- The cargo can be Loaded, UnLoaded, Boarded, UnBoarded to and from Carriers. @@ -291,29 +291,27 @@ do -- CARGO_GROUP end - --- Enter Boarding State. + --- After Board Event. -- @param #CARGO_GROUP self -- @param #string Event -- @param #string From -- @param #string To -- @param Wrapper.Unit#UNIT CargoCarrier -- @param #number NearRadius If distance is smaller than this number, cargo is loaded into the carrier. - function CARGO_GROUP:onenterBoarding( From, Event, To, CargoCarrier, NearRadius, ... ) + function CARGO_GROUP:onafterBoard( From, Event, To, CargoCarrier, NearRadius, ... ) self:F( { CargoCarrier.UnitName, From, Event, To, NearRadius = NearRadius } ) NearRadius = NearRadius or self.NearRadius - if From == "UnLoaded" then - - -- For each Cargo object within the CARGO_GROUPED, route each object to the CargoLoadPointVec2 - self.CargoSet:ForEach( - function( Cargo, ... ) - Cargo:__Board( 1, CargoCarrier, NearRadius, ... ) - end, ... - ) - - self:__Boarding( 1, CargoCarrier, NearRadius, ... ) - end + -- For each Cargo object within the CARGO_GROUPED, route each object to the CargoLoadPointVec2 + self.CargoSet:ForEach( + function( Cargo, ... ) + self:F( { "Board Unit", Cargo:GetName( ), Cargo:IsDestroyed(), Cargo.CargoObject:IsAlive() } ) + Cargo:__Board( 1, CargoCarrier, NearRadius, ... ) + end, ... + ) + + self:__Boarding( -1, CargoCarrier, NearRadius, ... ) end @@ -323,13 +321,15 @@ do -- CARGO_GROUP -- @param #string From -- @param #string To -- @param Wrapper.Unit#UNIT CargoCarrier - function CARGO_GROUP:onenterLoaded( From, Event, To, CargoCarrier, ... ) + function CARGO_GROUP:onafterLoad( From, Event, To, CargoCarrier, ... ) --self:F( { From, Event, To, CargoCarrier, ...} ) if From == "UnLoaded" then -- For each Cargo object within the CARGO_GROUP, load each cargo to the CargoCarrier. for CargoID, Cargo in pairs( self.CargoSet:GetSet() ) do - Cargo:Load( CargoCarrier ) + if not Cargo:IsDestroyed() then + Cargo:Load( CargoCarrier ) + end end end @@ -360,7 +360,7 @@ do -- CARGO_GROUP --self:T( { Cargo:GetName(), Cargo.current } ) - if not Cargo:is( "Loaded" ) + if not Cargo:is( "Loaded" ) and (not Cargo:is( "Destroyed" )) then -- If one or more units of a group defined as CARGO_GROUP died, the CARGO_GROUP:Board() command does not trigger the CARGO_GRUOP:OnEnterLoaded() function. Boarded = false end @@ -400,7 +400,7 @@ do -- CARGO_GROUP -- @param #string To -- @param Core.Point#POINT_VEC2 ToPointVec2 -- @param #number NearRadius If distance is smaller than this number, cargo is loaded into the carrier. - function CARGO_GROUP:onenterUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... ) + function CARGO_GROUP:onafterUnBoard( From, Event, To, ToPointVec2, NearRadius, ... ) self:F( {From, Event, To, ToPointVec2, NearRadius } ) NearRadius = NearRadius or 25 @@ -443,7 +443,7 @@ do -- CARGO_GROUP -- @param #string To -- @param Core.Point#POINT_VEC2 ToPointVec2 -- @param #number NearRadius If distance is smaller than this number, cargo is loaded into the carrier. - function CARGO_GROUP:onleaveUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... ) + function CARGO_GROUP:onafterUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... ) --self:F( { From, Event, To, ToPointVec2, NearRadius } ) --local NearRadius = NearRadius or 25 @@ -464,7 +464,7 @@ do -- CARGO_GROUP end if UnBoarded then - return true + self:__UnLoad( 1, ToPointVec2, ... ) else self:__UnBoarding( 1, ToPointVec2, NearRadius, ... ) end @@ -474,30 +474,13 @@ do -- CARGO_GROUP end - --- UnBoard Event. - -- @param #CARGO_GROUP self - -- @param #string Event - -- @param #string From - -- @param #string To - -- @param Core.Point#POINT_VEC2 ToPointVec2 - -- @param #number NearRadius If distance is smaller than this number, cargo is loaded into the carrier. - function CARGO_GROUP:onafterUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... ) - --self:F( { From, Event, To, ToPointVec2, NearRadius } ) - - --local NearRadius = NearRadius or 25 - - self:__UnLoad( 1, ToPointVec2, ... ) - end - - - --- Enter UnLoaded State. -- @param #CARGO_GROUP self -- @param #string Event -- @param #string From -- @param #string To -- @param Core.Point#POINT_VEC2 - function CARGO_GROUP:onenterUnLoaded( From, Event, To, ToPointVec2, ... ) + function CARGO_GROUP:onafterUnLoad( From, Event, To, ToPointVec2, ... ) --self:F( { From, Event, To, ToPointVec2 } ) if From == "Loaded" then @@ -507,7 +490,7 @@ do -- CARGO_GROUP function( Cargo ) --Cargo:UnLoad( ToPointVec2 ) local RandomVec2=ToPointVec2:GetRandomPointVec2InRadius(20, 10) - Cargo:UnLoad( RandomVec2 ) + Cargo:UnBoard( RandomVec2 ) end ) diff --git a/Moose Development/Moose/Cargo/CargoUnit.lua b/Moose Development/Moose/Cargo/CargoUnit.lua index bbdce8c57..a3714c443 100644 --- a/Moose Development/Moose/Cargo/CargoUnit.lua +++ b/Moose Development/Moose/Cargo/CargoUnit.lua @@ -233,46 +233,47 @@ do -- CARGO_UNIT --self:F({Unit=self.CargoObject:GetName()}) - -- Only move the group to the carrier when the cargo is not in the air - -- (eg. cargo can be on a oil derrick, moving the cargo on the oil derrick will drop the cargo on the sea). - if not self.CargoInAir then - -- If NearRadius is given, then use the given NearRadius, otherwise calculate the NearRadius - -- based upon the Carrier bounding radius, which is calculated from the bounding rectangle on the Y axis. - local NearRadius = NearRadius or CargoCarrier:GetBoundingRadius() + 5 - if self:IsNear( CargoCarrier:GetPointVec2(), NearRadius ) then - self:Load( CargoCarrier, NearRadius, ... ) - else - if MaxSpeed and MaxSpeed == 0 or TypeName and TypeName == "Stinger comm" then + -- A cargo unit can only be boarded if it is not dead + + -- Only move the group to the carrier when the cargo is not in the air + -- (eg. cargo can be on a oil derrick, moving the cargo on the oil derrick will drop the cargo on the sea). + if not self.CargoInAir then + -- If NearRadius is given, then use the given NearRadius, otherwise calculate the NearRadius + -- based upon the Carrier bounding radius, which is calculated from the bounding rectangle on the Y axis. + local NearRadius = NearRadius or CargoCarrier:GetBoundingRadius() + 5 + if self:IsNear( CargoCarrier:GetPointVec2(), NearRadius ) then self:Load( CargoCarrier, NearRadius, ... ) else + if MaxSpeed and MaxSpeed == 0 or TypeName and TypeName == "Stinger comm" then + self:Load( CargoCarrier, NearRadius, ... ) + else + + local Speed = 90 + local Angle = 180 + local Distance = 0 + + local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2() + local CargoCarrierHeading = CargoCarrier:GetHeading() -- Get Heading of object in degrees. + local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) + local CargoDeployPointVec2 = CargoCarrierPointVec2:Translate( Distance, CargoDeployHeading ) + + -- Set the CargoObject to state Green to ensure it is boarding! + self.CargoObject:OptionAlarmStateGreen() + + local Points = {} - local Speed = 90 - local Angle = 180 - local Distance = 0 + local PointStartVec2 = self.CargoObject:GetPointVec2() - local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2() - local CargoCarrierHeading = CargoCarrier:GetHeading() -- Get Heading of object in degrees. - local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) - local CargoDeployPointVec2 = CargoCarrierPointVec2:Translate( Distance, CargoDeployHeading ) - - -- Set the CargoObject to state Green to ensure it is boarding! - self.CargoObject:OptionAlarmStateGreen() - - local Points = {} - - local PointStartVec2 = self.CargoObject:GetPointVec2() - - Points[#Points+1] = PointStartVec2:WaypointGround( Speed ) - Points[#Points+1] = CargoDeployPointVec2:WaypointGround( Speed ) - - local TaskRoute = self.CargoObject:TaskRoute( Points ) - self.CargoObject:SetTask( TaskRoute, 2 ) - self:__Boarding( -5, CargoCarrier, NearRadius, ... ) - self.RunCount = 0 + Points[#Points+1] = PointStartVec2:WaypointGround( Speed ) + Points[#Points+1] = CargoDeployPointVec2:WaypointGround( Speed ) + + local TaskRoute = self.CargoObject:TaskRoute( Points ) + self.CargoObject:SetTask( TaskRoute, 2 ) + self:__Boarding( -5, CargoCarrier, NearRadius, ... ) + self.RunCount = 0 + end end end - end - end @@ -286,53 +287,53 @@ do -- CARGO_UNIT function CARGO_UNIT:onafterBoarding( From, Event, To, CargoCarrier, NearRadius, ... ) self:F( { From, Event, To, CargoCarrier:GetName(), NearRadius = NearRadius } ) - --self:F({Unit=self.CargoObject:GetName()}) + self:F( { IsAlive=self.CargoObject:IsAlive() } ) - if CargoCarrier and CargoCarrier:IsAlive() then -- and self.CargoObject and self.CargoObject:IsAlive() then - if (CargoCarrier:IsAir() and not CargoCarrier:InAir()) or true then - local NearRadius = NearRadius or CargoCarrier:GetBoundingRadius( NearRadius ) + 5 - if self:IsNear( CargoCarrier:GetPointVec2(), NearRadius ) then - self:__Load( 1, CargoCarrier, ... ) - else - if self:IsNear( CargoCarrier:GetPointVec2(), 20 ) then - self:__Boarding( 1, CargoCarrier, NearRadius, ... ) - self.RunCount = self.RunCount + 1 + if CargoCarrier and CargoCarrier:IsAlive() then -- and self.CargoObject and self.CargoObject:IsAlive() then + if (CargoCarrier:IsAir() and not CargoCarrier:InAir()) or true then + local NearRadius = NearRadius or CargoCarrier:GetBoundingRadius( NearRadius ) + 5 + if self:IsNear( CargoCarrier:GetPointVec2(), NearRadius ) then + self:__Load( -1, CargoCarrier, ... ) else - self:__Boarding( 2, CargoCarrier, NearRadius, ... ) - self.RunCount = self.RunCount + 2 - end - if self.RunCount >= 40 then - self.RunCount = 0 - local Speed = 90 - local Angle = 180 - local Distance = 0 + if self:IsNear( CargoCarrier:GetPointVec2(), 20 ) then + self:__Boarding( -1, CargoCarrier, NearRadius, ... ) + self.RunCount = self.RunCount + 1 + else + self:__Boarding( -2, CargoCarrier, NearRadius, ... ) + self.RunCount = self.RunCount + 2 + end + if self.RunCount >= 40 then + self.RunCount = 0 + local Speed = 90 + local Angle = 180 + local Distance = 0 + + --self:F({Unit=self.CargoObject:GetName()}) + + local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2() + local CargoCarrierHeading = CargoCarrier:GetHeading() -- Get Heading of object in degrees. + local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) + local CargoDeployPointVec2 = CargoCarrierPointVec2:Translate( Distance, CargoDeployHeading ) - --self:F({Unit=self.CargoObject:GetName()}) - - local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2() - local CargoCarrierHeading = CargoCarrier:GetHeading() -- Get Heading of object in degrees. - local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) - local CargoDeployPointVec2 = CargoCarrierPointVec2:Translate( Distance, CargoDeployHeading ) - - -- Set the CargoObject to state Green to ensure it is boarding! - self.CargoObject:OptionAlarmStateGreen() - - local Points = {} - - local PointStartVec2 = self.CargoObject:GetPointVec2() - - Points[#Points+1] = PointStartVec2:WaypointGround( Speed, "Off road" ) - Points[#Points+1] = CargoDeployPointVec2:WaypointGround( Speed, "Off road" ) - - local TaskRoute = self.CargoObject:TaskRoute( Points ) - self.CargoObject:SetTask( TaskRoute, 0.2 ) + -- Set the CargoObject to state Green to ensure it is boarding! + self.CargoObject:OptionAlarmStateGreen() + + local Points = {} + + local PointStartVec2 = self.CargoObject:GetPointVec2() + + Points[#Points+1] = PointStartVec2:WaypointGround( Speed, "Off road" ) + Points[#Points+1] = CargoDeployPointVec2:WaypointGround( Speed, "Off road" ) + + local TaskRoute = self.CargoObject:TaskRoute( Points ) + self.CargoObject:SetTask( TaskRoute, 0.2 ) + end end + else + self.CargoObject:MessageToGroup( "Cancelling Boarding... Get back on the ground!", 5, CargoCarrier:GetGroup(), self:GetName() ) + self:CancelBoarding( CargoCarrier, NearRadius, ... ) + self.CargoObject:SetCommand( self.CargoObject:CommandStopRoute( true ) ) end - else - self.CargoObject:MessageToGroup( "Cancelling Boarding... Get back on the ground!", 5, CargoCarrier:GetGroup(), self:GetName() ) - self:CancelBoarding( CargoCarrier, NearRadius, ... ) - self.CargoObject:SetCommand( self.CargoObject:CommandStopRoute( true ) ) - end else self:E("Something is wrong") end diff --git a/Moose Development/Moose/Wrapper/Controllable.lua b/Moose Development/Moose/Wrapper/Controllable.lua index 4ab481021..e20badf89 100644 --- a/Moose Development/Moose/Wrapper/Controllable.lua +++ b/Moose Development/Moose/Wrapper/Controllable.lua @@ -1975,6 +1975,24 @@ do -- Route methods return nil end + --- Make the controllable to push follow a given route. + -- @param #CONTROLLABLE self + -- @param #table Route A table of Route Points. + -- @param #number DelaySeconds (Optional) Wait for the specified seconds before executing the Route. Default is one second. + -- @return #CONTROLLABLE The CONTROLLABLE. + function CONTROLLABLE:RoutePush( Route, DelaySeconds ) + self:F2( Route ) + + local DCSControllable = self:GetDCSObject() + if DCSControllable then + local RouteTask = self:TaskRoute( Route ) -- Create a RouteTask, that will route the CONTROLLABLE to the Route. + self:PushTask( RouteTask, DelaySeconds or 1 ) -- Execute the RouteTask after the specified seconds (default is 1). + return self + end + + return nil + end + --- Stops the movement of the vehicle on the route. -- @param #CONTROLLABLE self diff --git a/Moose Development/Moose/Wrapper/Unit.lua b/Moose Development/Moose/Wrapper/Unit.lua index 5487ef3b6..d24a0b0b0 100644 --- a/Moose Development/Moose/Wrapper/Unit.lua +++ b/Moose Development/Moose/Wrapper/Unit.lua @@ -908,16 +908,23 @@ function UNIT:InAir() -- Implementation of workaround. The original code is below. -- This to simulate the landing on buildings. --- local UnitInAir = DCSUnit:inAir() local UnitInAir = true - local VelocityVec3 = DCSUnit:getVelocity() - local Velocity = ( VelocityVec3.x ^ 2 + VelocityVec3.y ^ 2 + VelocityVec3.z ^ 2 ) ^ 0.5 -- in meters / sec - local Coordinate = DCSUnit:getPoint() - local LandHeight = land.getHeight( { x = Coordinate.x, y = Coordinate.z } ) - local Height = Coordinate.y - LandHeight - if Velocity < 1 and Height <= 60 then - UnitInAir = false + + local UnitCategory = DCSUnit:getDesc().category + if UnitCategory == Unit.Category.HELICOPTER then + local VelocityVec3 = DCSUnit:getVelocity() + local Velocity = ( VelocityVec3.x ^ 2 + VelocityVec3.y ^ 2 + VelocityVec3.z ^ 2 ) ^ 0.5 -- in meters / sec + local Coordinate = DCSUnit:getPoint() + local LandHeight = land.getHeight( { x = Coordinate.x, y = Coordinate.z } ) + local Height = Coordinate.y - LandHeight + if Velocity < 1 and Height <= 60 then + UnitInAir = false + end + else + UnitInAir = DCSUnit:inAir() end + + self:T3( UnitInAir ) return UnitInAir end From 65c28d66280aa81dfe6306c81853f45807a98418 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Thu, 18 Oct 2018 18:24:25 +0200 Subject: [PATCH 2/9] Optimized the boarding and unboarding of cargo. fixed bug when in defence of APC, cargo would not be loaded. The boarding and unboarding has become much more stable now. --- Moose Development/Moose/AI/AI_Cargo_APC.lua | 63 +++++++++++++-------- Moose Development/Moose/Cargo/CargoUnit.lua | 20 ------- 2 files changed, 39 insertions(+), 44 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_APC.lua b/Moose Development/Moose/AI/AI_Cargo_APC.lua index 21fa5d3ba..0f76bdda1 100644 --- a/Moose Development/Moose/AI/AI_Cargo_APC.lua +++ b/Moose Development/Moose/AI/AI_Cargo_APC.lua @@ -444,6 +444,45 @@ function AI_CARGO_APC:onafterDeploy( APC, From, Event, To, Coordinate, Speed, He end +--- On after Unloaded event. +-- @param #AI_CARGO_APC self +-- @param Wrapper.Group#GROUP Carrier +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +-- @param #string Cargo.Cargo#CARGO Cargo Cargo object. +-- @param #boolean Deployed Cargo is deployed. +-- @param Core.Zone#ZONE DeployZone The zone wherein the cargo is deployed. This can be any zone type, like a ZONE, ZONE_GROUP, ZONE_AIRBASE. +function AI_CARGO_APC:onafterUnloaded( Carrier, From, Event, To, Cargo, CarrierUnit, DeployZone, Defend ) + self:F( { Carrier, From, Event, To, DeployZone = DeployZone, Defend = Defend } ) + + + self:GetParent( self, AI_CARGO_APC ).onafterUnloaded( self, Carrier, From, Event, To, Cargo, CarrierUnit, DeployZone, Defend ) + + -- If Defend == true then we need to scan for possible enemies within combat zone and engage only ground forces. + if Defend == true then + self.Zone:Scan( { Object.Category.UNIT } ) + if not self.Zone:IsAllInZoneOfCoalition( self.Coalition ) then + -- OK, enemies nearby, now find the enemies and attack them. + local AttackUnits = self.Zone:GetScannedUnits() -- #list + local Move = {} + local CargoGroup = Cargo.CargoObject -- Wrapper.Group#GROUP + Move[#Move+1] = CargoGroup:GetCoordinate():WaypointGround( 70, "Custom" ) + for UnitId, AttackUnit in pairs( AttackUnits ) do + local MooseUnit = UNIT:Find( AttackUnit ) + if MooseUnit:GetCoalition() ~= CargoGroup:GetCoalition() then + Move[#Move+1] = MooseUnit:GetCoordinate():WaypointGround( 70, "Line abreast" ) + --MoveTo.Task = CargoGroup:TaskCombo( CargoGroup:TaskAttackUnit( MooseUnit, true ) ) + self:F( { MooseUnit = MooseUnit:GetName(), CargoGroup = CargoGroup:GetName() } ) + end + end + CargoGroup:RoutePush( Move, 0.1 ) + end + + end + +end + --- On after Deployed event. -- @param #AI_CARGO_APC self -- @param Wrapper.Group#GROUP Carrier @@ -457,30 +496,6 @@ function AI_CARGO_APC:onafterDeployed( APC, From, Event, To, DeployZone, Defend self:__Guard( 0.1 ) self:GetParent( self, AI_CARGO_APC ).onafterDeployed( self, APC, From, Event, To, DeployZone, Defend ) - - -- If Defend == true then we need to scan for possible enemies within combat zone and engage only ground forces. - if Defend == true then - self.Zone:Scan( { Object.Category.UNIT } ) - if not self.Zone:IsAllInZoneOfCoalition( self.Coalition ) then - -- OK, enemies nearby, now find the enemies and attack them. - local AttackUnits = self.Zone:GetScannedUnits() -- #list - local Move = {} - for CargoId, CargoData in pairs( self.CargoSet:GetSet() ) do - local CargoGroup = CargoData.CargoObject -- Wrapper.Group#GROUP - Move[#Move+1] = CargoGroup:GetCoordinate():WaypointGround( 70, "Custom" ) - for UnitId, AttackUnit in pairs( AttackUnits ) do - local MooseUnit = UNIT:Find( AttackUnit ) - if MooseUnit:GetCoalition() ~= CargoGroup:GetCoalition() then - Move[#Move+1] = MooseUnit:GetCoordinate():WaypointGround( 70, "Line abreast" ) - --MoveTo.Task = CargoGroup:TaskCombo( CargoGroup:TaskAttackUnit( MooseUnit, true ) ) - self:F( { MooseUnit = MooseUnit:GetName(), CargoGroup = CargoGroup:GetName() } ) - end - end - CargoGroup:RoutePush( Move, 0.1 ) - end - end - - end end diff --git a/Moose Development/Moose/Cargo/CargoUnit.lua b/Moose Development/Moose/Cargo/CargoUnit.lua index a3714c443..61319476d 100644 --- a/Moose Development/Moose/Cargo/CargoUnit.lua +++ b/Moose Development/Moose/Cargo/CargoUnit.lua @@ -341,26 +341,6 @@ do -- CARGO_UNIT end - --- Enter Boarding State. - -- @param #CARGO_UNIT self - -- @param #string Event - -- @param #string From - -- @param #string To - -- @param Wrapper.Unit#UNIT CargoCarrier - -- @param #number NearRadius Default 25 m. - function CARGO_UNIT:onenterBoarding( From, Event, To, CargoCarrier, NearRadius, ... ) - --self:F( { From, Event, To, CargoCarrier.UnitName, NearRadius } ) - - local Speed = 90 - local Angle = 180 - local Distance = 5 - - if From == "UnLoaded" or From == "Boarding" then - - end - - end - --- Loaded State. -- @param #CARGO_UNIT self -- @param #string Event From ce9d1837a7f4bc2e9d1e6016e55217ab98391db5 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Thu, 18 Oct 2018 20:11:31 +0200 Subject: [PATCH 3/9] Optimized the boarding and unboarding of cargo. fixed bug when in defence of APC, cargo would not be loaded. The boarding and unboarding has become much more stable now. --- Moose Development/Moose/AI/AI_Cargo.lua | 74 ++++++++++++++++++++ Moose Development/Moose/AI/AI_Cargo_APC.lua | 5 +- Moose Development/Moose/Cargo/CargoGroup.lua | 2 + 3 files changed, 79 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Cargo.lua b/Moose Development/Moose/AI/AI_Cargo.lua index d51149fbc..ed76eca7b 100644 --- a/Moose Development/Moose/AI/AI_Cargo.lua +++ b/Moose Development/Moose/AI/AI_Cargo.lua @@ -293,6 +293,80 @@ function AI_CARGO:onbeforeLoad( Carrier, From, Event, To, PickupZone ) end + +--- On before Reload event. +-- @param #AI_CARGO self +-- @param Wrapper.Group#GROUP Carrier +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +-- @param Core.Zone#ZONE PickupZone (optional) The zone where the cargo will be picked up. The PickupZone can be nil, if there wasn't any PickupZoneSet provided. +function AI_CARGO:onbeforeReload( Carrier, From, Event, To ) + self:F( { Carrier, From, Event, To } ) + + local Boarding = false + + local LoadInterval = 2 + local LoadDelay = 1 + local Carrier_List = {} + local Carrier_Weight = {} + + if Carrier and Carrier:IsAlive() then + for _, CarrierUnit in pairs( Carrier:GetUnits() ) do + local CarrierUnit = CarrierUnit -- Wrapper.Unit#UNIT + + Carrier_List[#Carrier_List+1] = CarrierUnit + end + + local Carrier_Count = #Carrier_List + local Carrier_Index = 1 + + local Loaded = false + + for Cargo, CarrierUnit in pairs( self.Carrier_Cargo ) do + local Cargo = Cargo -- Cargo.Cargo#CARGO + + self:F( { IsUnLoaded = Cargo:IsUnLoaded(), IsDeployed = Cargo:IsDeployed(), Cargo:GetName(), Carrier:GetName() } ) + + -- Try all Carriers, but start from the one according the Carrier_Index + for Carrier_Loop = 1, #Carrier_List do + + local CarrierUnit = Carrier_List[Carrier_Index] -- Wrapper.Unit#UNIT + + -- This counters loop through the available Carriers. + Carrier_Index = Carrier_Index + 1 + if Carrier_Index > Carrier_Count then + Carrier_Index = 1 + end + + if Cargo:IsUnLoaded() and not Cargo:IsDeployed() then + Carrier:RouteStop() + Cargo:__Board( -LoadDelay, CarrierUnit ) + self:__Board( LoadDelay, Cargo, CarrierUnit ) + + LoadDelay = LoadDelay + Cargo:GetCount() * LoadInterval + + -- So now this CarrierUnit has Cargo that is being loaded. + -- This will be used further in the logic to follow and to check cargo status. + self.Carrier_Cargo[Cargo] = CarrierUnit + Boarding = true + Loaded = true + end + + end + + end + + if not Loaded == true then + -- No loading happened, so we need to pickup something else. + self.Relocating = false + end + end + + return Boarding + +end + --- On after Board event. -- @param #AI_CARGO self -- @param Wrapper.Group#GROUP Carrier diff --git a/Moose Development/Moose/AI/AI_Cargo_APC.lua b/Moose Development/Moose/AI/AI_Cargo_APC.lua index 0f76bdda1..4929f2d46 100644 --- a/Moose Development/Moose/AI/AI_Cargo_APC.lua +++ b/Moose Development/Moose/AI/AI_Cargo_APC.lua @@ -97,6 +97,7 @@ function AI_CARGO_APC:New( APC, CargoSet, CombatRadius ) self:AddTransition( "*", "Follow", "Following" ) self:AddTransition( "*", "Guard", "Unloaded" ) self:AddTransition( "*", "Home", "*" ) + self:AddTransition( "*", "Reload", "Boarding" ) self:AddTransition( "*", "Destroyed", "Destroyed" ) @@ -280,8 +281,8 @@ function AI_CARGO_APC:onafterMonitor( APC, From, Event, To ) self.Zone:Scan( { Object.Category.UNIT } ) if self.Zone:IsAllInZoneOfCoalition( self.Coalition ) then if self:Is( "Unloaded" ) then - -- There are no enemies within combat radius. Load the CargoCarrier. - self:Load() + -- There are no enemies within combat radius. Reload the CargoCarrier. + self:Reload() end else if self:Is( "Loaded" ) then diff --git a/Moose Development/Moose/Cargo/CargoGroup.lua b/Moose Development/Moose/Cargo/CargoGroup.lua index 7e4a524d7..b64d205c2 100644 --- a/Moose Development/Moose/Cargo/CargoGroup.lua +++ b/Moose Development/Moose/Cargo/CargoGroup.lua @@ -307,6 +307,8 @@ do -- CARGO_GROUP self.CargoSet:ForEach( function( Cargo, ... ) self:F( { "Board Unit", Cargo:GetName( ), Cargo:IsDestroyed(), Cargo.CargoObject:IsAlive() } ) + local CargoGroup = Cargo.CargoObject --Wrapper.Group#GROUP + CargoGroup:OptionAlarmStateGreen() Cargo:__Board( 1, CargoCarrier, NearRadius, ... ) end, ... ) From 90e7688cea4174e45f5affcaf18d49b2a1c52226 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Thu, 18 Oct 2018 20:25:21 +0200 Subject: [PATCH 4/9] Optimized the boarding and unboarding of cargo. fixed bug when in defence of APC, cargo would not be loaded. The boarding and unboarding has become much more stable now. --- Moose Development/Moose/AI/AI_Cargo_APC.lua | 27 +++++++++++---------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_APC.lua b/Moose Development/Moose/AI/AI_Cargo_APC.lua index 4929f2d46..c20475711 100644 --- a/Moose Development/Moose/AI/AI_Cargo_APC.lua +++ b/Moose Development/Moose/AI/AI_Cargo_APC.lua @@ -119,7 +119,6 @@ function AI_CARGO_APC:SetCarrier( CargoCarrier ) self.CargoCarrier:SetState( self.CargoCarrier, "AI_CARGO_APC", self ) CargoCarrier:HandleEvent( EVENTS.Dead ) - CargoCarrier:HandleEvent( EVENTS.Hit ) function CargoCarrier:OnEventDead( EventData ) self:F({"dead"}) @@ -133,18 +132,20 @@ function AI_CARGO_APC:SetCarrier( CargoCarrier ) end end end - - function CargoCarrier:OnEventHit( EventData ) - self:F({"hit"}) - local AICargoTroops = self:GetState( self, "AI_CARGO_APC" ) - if AICargoTroops then - self:F( { OnHitLoaded = AICargoTroops:Is( "Loaded" ) } ) - if AICargoTroops:Is( "Loaded" ) or AICargoTroops:Is( "Boarding" ) then - -- There are enemies within combat radius. Unload the CargoCarrier. - AICargoTroops:Unload( false ) - end - end - end + +-- CargoCarrier:HandleEvent( EVENTS.Hit ) +-- +-- function CargoCarrier:OnEventHit( EventData ) +-- self:F({"hit"}) +-- local AICargoTroops = self:GetState( self, "AI_CARGO_APC" ) +-- if AICargoTroops then +-- self:F( { OnHitLoaded = AICargoTroops:Is( "Loaded" ) } ) +-- if AICargoTroops:Is( "Loaded" ) or AICargoTroops:Is( "Boarding" ) then +-- -- There are enemies within combat radius. Unload the CargoCarrier. +-- AICargoTroops:Unload( false ) +-- end +-- end +-- end self.Zone = ZONE_UNIT:New( self.CargoCarrier:GetName() .. "-Zone", self.CargoCarrier, self.CombatRadius ) self.Coalition = self.CargoCarrier:GetCoalition() From e4606b4d0520ab64918d5a37466066bc6beddb7d Mon Sep 17 00:00:00 2001 From: FlightControl Date: Fri, 19 Oct 2018 17:00:43 +0200 Subject: [PATCH 5/9] Fixing path calculation. Direct route when the length between the two coordinates is less than 1 km. --- Moose Development/Moose/Wrapper/Controllable.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/Wrapper/Controllable.lua b/Moose Development/Moose/Wrapper/Controllable.lua index e20badf89..bac4e209e 100644 --- a/Moose Development/Moose/Wrapper/Controllable.lua +++ b/Moose Development/Moose/Wrapper/Controllable.lua @@ -2136,7 +2136,7 @@ do -- Route methods local canroad=false -- Check if a valid path on road could be found. - if PathOnRoad then + if PathOnRoad and LengthOffRoad > 1000 then -- if the length of the movement is less than 1 km, drive directly. -- Check whether the road is very long compared to direct path. if LongRoad and Shortcut then From b378ad28852a58eca235959018a58d1de780bdab Mon Sep 17 00:00:00 2001 From: FlightControl Date: Sat, 20 Oct 2018 04:26:45 +0200 Subject: [PATCH 6/9] Fixing path calculation. Direct route when the length between the two coordinates is less than 2 km. --- Moose Development/Moose/Wrapper/Controllable.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/Wrapper/Controllable.lua b/Moose Development/Moose/Wrapper/Controllable.lua index bac4e209e..1fb50baa5 100644 --- a/Moose Development/Moose/Wrapper/Controllable.lua +++ b/Moose Development/Moose/Wrapper/Controllable.lua @@ -2136,7 +2136,7 @@ do -- Route methods local canroad=false -- Check if a valid path on road could be found. - if PathOnRoad and LengthOffRoad > 1000 then -- if the length of the movement is less than 1 km, drive directly. + if PathOnRoad and LengthDirect > 2000 then -- if the length of the movement is less than 1 km, drive directly. -- Check whether the road is very long compared to direct path. if LongRoad and Shortcut then From e4334cccb327f2b5cd6dbcf8e402d0e1377d21a2 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Sun, 21 Oct 2018 13:12:20 +0200 Subject: [PATCH 7/9] Fixing back to the inclusion of inactive units. --- Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua index 2f212f189..311a07b59 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua @@ -899,7 +899,7 @@ function AI_CARGO_DISPATCHER:onafterMonitor() for CarrierGroupName, Carrier in pairs( self.SetCarrier:GetSet() ) do local Carrier = Carrier -- Wrapper.Group#GROUP - if Carrier:IsAlive() == true then + if Carrier:IsAlive() ~= nil then local AI_Cargo = self.AI_Cargo[Carrier] if not AI_Cargo then From 1c6c0c4d81a4bd2da5210aba18e8c364203d2c9f Mon Sep 17 00:00:00 2001 From: FlightControl Date: Sun, 21 Oct 2018 14:36:05 +0200 Subject: [PATCH 8/9] Fixing resuming task after refuelling. --- Moose Development/Moose/AI/AI_A2A.lua | 2 +- Moose Development/Moose/AI/AI_A2A_Cap.lua | 9 ++++----- Moose Development/Moose/AI/AI_A2A_Patrol.lua | 9 ++++----- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/Moose Development/Moose/AI/AI_A2A.lua b/Moose Development/Moose/AI/AI_A2A.lua index d9b61970f..33ee16ace 100644 --- a/Moose Development/Moose/AI/AI_A2A.lua +++ b/Moose Development/Moose/AI/AI_A2A.lua @@ -635,7 +635,7 @@ end --- @param Wrapper.Group#GROUP AIGroup function AI_A2A.Resume( AIGroup, Fsm ) - AIGroup:F( { "AI_A2A.Resume:", AIGroup:GetName() } ) + AIGroup:I( { "AI_A2A.Resume:", AIGroup:GetName() } ) if AIGroup:IsAlive() then Fsm:__RTB( 0.5 ) end diff --git a/Moose Development/Moose/AI/AI_A2A_Cap.lua b/Moose Development/Moose/AI/AI_A2A_Cap.lua index 41c8c8a5e..de9e184da 100644 --- a/Moose Development/Moose/AI/AI_A2A_Cap.lua +++ b/Moose Development/Moose/AI/AI_A2A_Cap.lua @@ -476,13 +476,12 @@ function AI_A2A_CAP:OnEventDead( EventData ) end --- @param Wrapper.Group#GROUP AICap -function AI_A2A_CAP.Resume( AICap ) +function AI_A2A_CAP.Resume( AICap, Fsm ) - AICap:F( { "AI_A2A_CAP.Resume:", AICap:GetName() } ) + AICap:I( { "AI_A2A_CAP.Resume:", AICap:GetName() } ) if AICap:IsAlive() then - local _AI_A2A = AICap:GetState( AICap, "AI_A2A" ) -- #AI_A2A - _AI_A2A:__Reset( 1 ) - _AI_A2A:__Route( 5 ) + Fsm:__Reset( 1 ) + Fsm:__Route( 5 ) end end diff --git a/Moose Development/Moose/AI/AI_A2A_Patrol.lua b/Moose Development/Moose/AI/AI_A2A_Patrol.lua index 3ff3cfa69..7b44c14fb 100644 --- a/Moose Development/Moose/AI/AI_A2A_Patrol.lua +++ b/Moose Development/Moose/AI/AI_A2A_Patrol.lua @@ -351,13 +351,12 @@ function AI_A2A_PATROL:onafterRoute( AIPatrol, From, Event, To ) end --- @param Wrapper.Group#GROUP AIPatrol -function AI_A2A_PATROL.Resume( AIPatrol ) +function AI_A2A_PATROL.Resume( AIPatrol, Fsm ) - AIPatrol:F( { "AI_A2A_PATROL.Resume:", AIPatrol:GetName() } ) + AIPatrol:I( { "AI_A2A_PATROL.Resume:", AIPatrol:GetName() } ) if AIPatrol:IsAlive() then - local _AI_A2A = AIPatrol:GetState( AIPatrol, "AI_A2A" ) -- AI.AI_A2A#AI_A2A - _AI_A2A:__Reset( 1 ) - _AI_A2A:__Route( 5 ) + Fsm:__Reset( 1 ) + Fsm:__Route( 5 ) end end From f2eafe03020dfc004c1d9a88c2dafd7d7a032407 Mon Sep 17 00:00:00 2001 From: Chris Date: Wed, 24 Oct 2018 00:17:26 -0400 Subject: [PATCH 9/9] Honor the GotPath return value from COORDINATE PathOnRoad is always defined, at least as an empty table. Use the 3rd return value instead, which indicates whether a road route was found --- Moose Development/Moose/Wrapper/Controllable.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Moose Development/Moose/Wrapper/Controllable.lua b/Moose Development/Moose/Wrapper/Controllable.lua index 1fb50baa5..9b2942514 100644 --- a/Moose Development/Moose/Wrapper/Controllable.lua +++ b/Moose Development/Moose/Wrapper/Controllable.lua @@ -2101,7 +2101,7 @@ do -- Route methods FromCoordinate = FromCoordinate or self:GetCoordinate() -- Get path and path length on road including the end points (From and To). - local PathOnRoad, LengthOnRoad=FromCoordinate:GetPathOnRoad(ToCoordinate, true) + local PathOnRoad, LengthOnRoad, GotPath =FromCoordinate:GetPathOnRoad(ToCoordinate, true) -- Get the length only(!) on the road. local _,LengthRoad=FromCoordinate:GetPathOnRoad(ToCoordinate, false) @@ -2113,7 +2113,7 @@ do -- Route methods -- Calculate the direct distance between the initial and final points. local LengthDirect=FromCoordinate:Get2DDistance(ToCoordinate) - if PathOnRoad then + if GotPath then -- Off road part of the rout: Total=OffRoad+OnRoad. LengthOffRoad=LengthOnRoad-LengthRoad @@ -2136,7 +2136,7 @@ do -- Route methods local canroad=false -- Check if a valid path on road could be found. - if PathOnRoad and LengthDirect > 2000 then -- if the length of the movement is less than 1 km, drive directly. + if GotPath and LengthDirect > 2000 then -- if the length of the movement is less than 1 km, drive directly. -- Check whether the road is very long compared to direct path. if LongRoad and Shortcut then