diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua index dd03c258e..ad72a1cff 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua @@ -113,6 +113,125 @@ function AI_CARGO_DISPATCHER:SetHomeZone( HomeZone ) end +--- Sets or randomizes the pickup location for the carrier around the cargo coordinate in a radius defined an outer and optional inner radius. +-- This radius is influencing the location where the carrier will land to pickup the cargo. +-- There are two aspects that are very important to remember and take into account: +-- +-- - Ensure that the outer and inner radius are within reporting radius set by the cargo. +-- For example, if the cargo has a reporting radius of 400 meters, and the outer and inner radius is set to 500 and 450 respectively, +-- then no cargo will be loaded!!! +-- - Also take care of the potential cargo position and possible reasons to crash the carrier. This is especially important +-- for locations which are crowded with other objects, like in the middle of villages or cities. +-- So, for the best operation of cargo operations, always ensure that the cargo is located at open spaces. +-- +-- The default radius is 0, so the center. In case of a polygon zone, a random location will be selected as the center in the zone. +-- @param #AI_CARGO_DISPATCHER self +-- @param #number OuterRadius The outer radius in meters around the cargo coordinate. +-- @param #number InnerRadius (optional) The inner radius in meters around the cargo coordinate. +-- @return #AI_CARGO_DISPATCHER +-- @usage +-- +-- -- Create a new cargo dispatcher +-- AICargoDispatcher = AI_CARGO_DISPATCHER:New( SetAPC, SetCargo, SetDeployZone ) +-- +-- -- Set the carrier to land within a band around the cargo coordinate between 500 and 300 meters! +-- AICargoDispatcher:SetPickupRadius( 500, 300 ) +-- +function AI_CARGO_DISPATCHER:SetPickupRadius( OuterRadius, InnerRadius ) + + OuterRadius = OuterRadius or 0 + InnerRadius = InnerRadius or OuterRadius + + self.PickupOuterRadius = OuterRadius + self.PickupInnerRadius = InnerRadius + + return self +end + + +--- Set the speed or randomizes the speed in km/h to pickup the cargo. +-- @param #AI_CARGO_DISPATCHER self +-- @param #number MaxSpeed (optional) The maximum speed to move to the cargo pickup location. +-- @param #number MinSpeed The minimum speed to move to the cargo pickup location. +-- @return #AI_CARGO_DISPATCHER +-- @usage +-- +-- -- Create a new cargo dispatcher +-- AICargoDispatcher = AI_CARGO_DISPATCHER:New( SetAPC, SetCargo, SetDeployZone ) +-- +-- -- Set the minimum pickup speed to be 100 km/h and the maximum speed to be 200 km/h. +-- AICargoDispatcher:SetPickupSpeed( 200, 100 ) +-- +function AI_CARGO_DISPATCHER:SetPickupSpeed( MaxSpeed, MinSpeed ) + + MaxSpeed = MaxSpeed or 999 + MinSpeed = MinSpeed or MaxSpeed + + self.PickupMinSpeed = MinSpeed + self.PickupMaxSpeed = MaxSpeed + + return self +end + + +--- Sets or randomizes the deploy location for the carrier around the cargo coordinate in a radius defined an outer and an optional inner radius. +-- This radius is influencing the location where the carrier will land to deploy the cargo. +-- There is an aspect that is very important to remember and take into account: +-- +-- - Take care of the potential cargo position and possible reasons to crash the carrier. This is especially important +-- for locations which are crowded with other objects, like in the middle of villages or cities. +-- So, for the best operation of cargo operations, always ensure that the cargo is located at open spaces. +-- +-- The default radius is 0, so the center. In case of a polygon zone, a random location will be selected as the center in the zone. +-- @param #AI_CARGO_DISPATCHER self +-- @param #number OuterRadius The outer radius in meters around the cargo coordinate. +-- @param #number InnerRadius (optional) The inner radius in meters around the cargo coordinate. +-- @return #AI_CARGO_DISPATCHER +-- @usage +-- +-- -- Create a new cargo dispatcher +-- AICargoDispatcher = AI_CARGO_DISPATCHER:New( SetAPC, SetCargo, SetDeployZone ) +-- +-- -- Set the carrier to land within a band around the cargo coordinate between 500 and 300 meters! +-- AICargoDispatcher:SetDeployRadius( 500, 300 ) +-- +function AI_CARGO_DISPATCHER:SetDeployRadius( OuterRadius, InnerRadius ) + + OuterRadius = OuterRadius or 0 + InnerRadius = InnerRadius or OuterRadius + + self.DeployOuterRadius = OuterRadius + self.DeployInnerRadius = InnerRadius + + return self +end + + +--- Sets or randomizes the speed in km/h to deploy the cargo. +-- @param #AI_CARGO_DISPATCHER self +-- @param #number MaxSpeed The maximum speed to move to the cargo deploy location. +-- @param #number MinSpeed (optional) The minimum speed to move to the cargo deploy location. +-- @return #AI_CARGO_DISPATCHER +-- @usage +-- +-- -- Create a new cargo dispatcher +-- AICargoDispatcher = AI_CARGO_DISPATCHER:New( SetAPC, SetCargo, SetDeployZone ) +-- +-- -- Set the minimum deploy speed to be 100 km/h and the maximum speed to be 200 km/h. +-- AICargoDispatcher:SetDeploySpeed( 200, 100 ) +-- +function AI_CARGO_DISPATCHER:SetDeploySpeed( MaxSpeed, MinSpeed ) + + MaxSpeed = MaxSpeed or 999 + MinSpeed = MinSpeed or MaxSpeed + + self.DeployMinSpeed = MinSpeed + self.DeployMaxSpeed = MaxSpeed + + return self +end + + --- The Start trigger event, which actually takes action at the specified time interval. -- @param #AI_CARGO_DISPATCHER self @@ -168,16 +287,16 @@ function AI_CARGO_DISPATCHER:onafterMonitor() local Cargo = Cargo -- Cargo.Cargo#CARGO self:F( { Cargo = Cargo:GetName(), UnLoaded = Cargo:IsUnLoaded(), Deployed = Cargo:IsDeployed(), PickupCargo = self.PickupCargo[Cargo] ~= nil } ) if Cargo:IsUnLoaded() and not Cargo:IsDeployed() then - local CargoVec2 = { x = Cargo:GetX(), y = Cargo:GetY() } - local LocationFound = false - for APC, Vec2 in pairs( self.PickupCargo ) do - if Vec2.x == CargoVec2.x and Vec2.y == CargoVec2.y then - LocationFound = true + local CargoCoordinate = Cargo:GetCoordinate() + local CoordinateFree = true + for APC, Coordinate in pairs( self.PickupCargo ) do + if CargoCoordinate:Get2DDistance( Coordinate ) <= 25 then + CoordinateFree = false break end end - if LocationFound == false then - self.PickupCargo[Carrier] = CargoVec2 + if CoordinateFree == true then + self.PickupCargo[Carrier] = CargoCoordinate PickupCargo = Cargo break end @@ -185,13 +304,14 @@ function AI_CARGO_DISPATCHER:onafterMonitor() end if PickupCargo then self.CarrierHome[Carrier] = nil - AI_Cargo:Pickup( PickupCargo:GetCoordinate() ) + local PickupCoordinate = PickupCargo:GetCoordinate():GetRandomCoordinateInRadius( self.PickupOuterRadius, self.PickupInnerRadius ) + AI_Cargo:Pickup( PickupCoordinate, math.random( self.PickupMinSpeed, self.PickupMaxSpeed ) ) break else if self.HomeZone then if not self.CarrierHome[Carrier] then self.CarrierHome[Carrier] = true - AI_Cargo:Home( self.HomeZone:GetRandomPointVec2() ) + AI_Cargo:__Home( 10, self.HomeZone:GetRandomPointVec2() ) end end end @@ -220,10 +340,11 @@ end function AI_CARGO_DISPATCHER:OnAfterLoaded( From, Event, To, APC, Cargo ) self:I( { "Loaded Dispatcher", APC } ) - local RandomZone = self.SetDeployZones:GetRandomZone() - self:I( { RandomZone = RandomZone } ) + local DeployZone = self.SetDeployZones:GetRandomZone() + self:I( { RandomZone = DeployZone } ) - self.AI_Cargo[APC]:Deploy( RandomZone:GetCoordinate(), 70 ) + local DeployCoordinate = DeployZone:GetCoordinate():GetRandomCoordinateInRadius( self.DeployOuterRadius, self.DeployInnerRadius ) + self.AI_Cargo[APC]:Deploy( DeployCoordinate, math.random( self.DeployMinSpeed, self.DeployMaxSpeed ) ) self.PickupCargo[APC] = nil diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua index 67d2a2c92..7081bd45e 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua @@ -50,6 +50,11 @@ function AI_CARGO_DISPATCHER_APC:New( SetAPC, SetCargo, SetDeployZones ) self.CombatRadius = 500 + self:SetDeploySpeed( 70, 120 ) + self:SetPickupSpeed( 70, 120 ) + self:SetPickupRadius( 0, 0 ) + self:SetDeployRadius( 0, 0 ) + self:Monitor( 1 ) return self diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua index 56c4dae78..062b696a1 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua @@ -48,6 +48,11 @@ function AI_CARGO_DISPATCHER_HELICOPTER:New( SetHelicopter, SetCargo, SetDeployZ local self = BASE:Inherit( self, AI_CARGO_DISPATCHER:New( SetHelicopter, SetCargo, SetDeployZones ) ) -- #AI_CARGO_DISPATCHER_HELICOPTER + self:SetDeploySpeed( 200, 150 ) + self:SetPickupSpeed( 200, 150 ) + self:SetPickupRadius( 0, 0 ) + self:SetDeployRadius( 0, 0 ) + self:Monitor( 1 ) return self diff --git a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua index 695deb248..44ef641f5 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua @@ -22,7 +22,7 @@ AI_CARGO_HELICOPTER = { Coordinate = nil -- Core.Point#COORDINATE, } -AI_CARGO_HELICOPTER_QUEUE = {} +AI_CARGO_QUEUE = {} --- Creates a new AI_CARGO_HELICOPTER object. -- @param #AI_CARGO_HELICOPTER self @@ -225,43 +225,31 @@ function AI_CARGO_HELICOPTER:onafterQueue( Helicopter, From, Event, To, Coordina local HelicopterInZone = false - --- @param Wrapper.Unit#UNIT ZoneUnit - local function EvaluateZone( ZoneUnit ) - - if ZoneUnit:IsAlive() then - local ZoneUnitCategory = ZoneUnit:GetDesc().category - local ZoneGroup = ZoneUnit:GetGroup() - if ZoneUnitCategory == Unit.Category.HELICOPTER then - local State = ZoneGroup:GetState( ZoneGroup, "Landing" ) - self:F({ZoneUnit=ZoneUnit:GetName(), State=State, UnitCategory = Unit.Category.HELICOPTER } ) - if State == true then - HelicopterInZone = true - return false - end - end - end - - return true - end - if Helicopter and Helicopter:IsAlive() then local Distance = Coordinate:DistanceFromPointVec2( Helicopter:GetCoordinate() ) - if Distance > 300 then + if Distance > 500 then self:__Queue( -10, Coordinate ) else - -- This will search the zone and will call the local function "EvaluateZone", which passes a UNIT object. - local Zone = ZONE_RADIUS:New( "Deploy", Coordinate:GetVec2(), 300 ) - Zone:SearchZone( EvaluateZone ) + local ZoneFree = true + + for Helicopter, ZoneQueue in pairs( AI_CARGO_QUEUE ) do + local ZoneQueue = ZoneQueue -- Core.Zone#ZONE_RADIUS + if ZoneQueue:IsCoordinateInZone( Coordinate ) then + ZoneFree = false + end + end - self:F({HelicopterInZone=HelicopterInZone}) + self:F({ZoneFree=ZoneFree}) - if HelicopterInZone == false then + if ZoneFree == true then - Helicopter:SetState( Helicopter, "Landing", true ) - + local ZoneQueue = ZONE_RADIUS:New( Helicopter:GetName(), Coordinate:GetVec2(), 100 ) + + AI_CARGO_QUEUE[Helicopter] = ZoneQueue + local Route = {} -- local CoordinateFrom = Helicopter:GetCoordinate() @@ -310,8 +298,6 @@ function AI_CARGO_HELICOPTER:onafterOrbit( Helicopter, From, Event, To, Coordina if Helicopter and Helicopter:IsAlive() then - Helicopter:ClearState( Helicopter, "Landing" ) - if not self:IsTransporting() then local Route = {} @@ -436,6 +422,7 @@ function AI_CARGO_HELICOPTER:onafterUnload( Helicopter, From, Event, To, Deploye local HelicopterUnit = HelicopterUnit -- Wrapper.Unit#UNIT for _, Cargo in pairs( HelicopterUnit:GetCargo() ) do Cargo:UnBoard() + Cargo:SetDeployed( true ) self:__Unboard( 10, Cargo, Deployed ) end end @@ -483,7 +470,6 @@ function AI_CARGO_HELICOPTER:onbeforeUnloaded( Helicopter, From, Event, To, Carg if Deployed == true then for HelicopterUnit, Cargo in pairs( self.Helicopter_Cargo ) do local Cargo = Cargo -- Cargo.Cargo#CARGO - Cargo:SetDeployed( true ) end self.Helicopter_Cargo = {} end @@ -500,7 +486,9 @@ end -- @param Wrapper.Group#GROUP Helicopter function AI_CARGO_HELICOPTER:onafterUnloaded( Helicopter, From, Event, To, Cargo, Deployed ) - self:Orbit( Helicopter:GetCoordinate(), 50 ) + self:Orbit( Helicopter:GetCoordinate(), 50 ) + + AI_CARGO_QUEUE[Helicopter] = nil end @@ -515,7 +503,6 @@ function AI_CARGO_HELICOPTER:onafterPickup( Helicopter, From, Event, To, Coordin if Helicopter and Helicopter:IsAlive() ~= nil then - self:ScheduleOnce( 10, Helicopter.ClearState, Helicopter, Helicopter, "Landing" ) Helicopter:Activate() self.RoutePickup = true @@ -690,7 +677,7 @@ function AI_CARGO_HELICOPTER:onafterHome( Helicopter, From, Event, To, Coordinat Route[#Route+1] = WaypointTo -- Now route the helicopter - Helicopter:Route( Route, 1 ) + Helicopter:Route( Route, 0 ) end diff --git a/Moose Development/Moose/Core/Zone.lua b/Moose Development/Moose/Core/Zone.lua index 36571c15b..cdc58b48a 100644 --- a/Moose Development/Moose/Core/Zone.lua +++ b/Moose Development/Moose/Core/Zone.lua @@ -151,10 +151,16 @@ end -- @param Dcs.DCSTypes#Vec3 Vec3 The point to test. -- @return #boolean true if the Vec3 is within the zone. function ZONE_BASE:IsVec3InZone( Vec3 ) - self:F2( Vec3 ) - local InZone = self:IsVec2InZone( { x = Vec3.x, y = Vec3.z } ) + return InZone +end +--- Returns if a Coordinate is within the zone. +-- @param #ZONE_BASE self +-- @param Core.Point#COORDINATE Coordinate The coordinate to test. +-- @return #boolean true if the coordinate is within the zone. +function ZONE_BASE:IsCoordinateInZone( Coordinate ) + local InZone = self:IsVec2InZone( Coordinate:GetVec2() ) return InZone end @@ -163,10 +169,7 @@ end -- @param Core.Point#POINT_VEC2 PointVec2 The PointVec2 to test. -- @return #boolean true if the PointVec2 is within the zone. function ZONE_BASE:IsPointVec2InZone( PointVec2 ) - self:F2( PointVec2 ) - local InZone = self:IsVec2InZone( PointVec2:GetVec2() ) - return InZone end @@ -175,10 +178,7 @@ end -- @param Core.Point#POINT_VEC3 PointVec3 The PointVec3 to test. -- @return #boolean true if the PointVec3 is within the zone. function ZONE_BASE:IsPointVec3InZone( PointVec3 ) - self:F2( PointVec3 ) - local InZone = self:IsPointVec2InZone( PointVec3 ) - return InZone end @@ -187,8 +187,6 @@ end -- @param #ZONE_BASE self -- @return #nil. function ZONE_BASE:GetVec2() - self:F2( self.ZoneName ) - return nil end