MOOSE/Moose Development/Moose/PatrolZone.lua
2016-07-03 07:49:26 +02:00

265 lines
11 KiB
Lua

--- This module contains the PATROLZONE class.
--
-- ===
--
-- 1) @{Patrol#PATROLZONE} class, extends @{Base#BASE}
-- ===================================================
-- The @{Patrol#PATROLZONE} class implements the core functions to patrol a @{Zone}.
--
-- 1.1) PATROLZONE constructor:
-- ----------------------------
-- @{PatrolZone#PATROLZONE.New}(): Creates a new PATROLZONE object.
--
-- 1.2) Modify the PATROLZONE parameters:
-- --------------------------------------
-- The following methods are available to modify the parameters of a PATROLZONE object:
--
-- * @{PatrolZone#PATROLZONE.SetGroup}(): Set the AI Patrol Group.
-- * @{PatrolZone#PATROLZONE.SetSpeed}(): Set the patrol speed of the AI, for the next patrol.
-- * @{PatrolZone#PATROLZONE.SetAltitude}(): Set altitude of the AI, for the next patrol.
--
-- 1.3) Manage the out of fuel in the PATROLZONE:
-- ----------------------------------------------
-- When the PatrolGroup is out of fuel, it is required that a new PatrolGroup is started, before the old PatrolGroup can return to the home base.
-- Therefore, with a parameter and a calculation of the distance to the home base, the fuel treshold is calculated.
-- When the fuel treshold is reached, the PatrolGroup will continue for a given time its patrol task in orbit, while a new PatrolGroup is targetted to the PATROLZONE.
-- Once the time is finished, the old PatrolGroup will return to the base.
-- Use the method @{PatrolZone#PATROLZONE.ManageFuel}() to have this proces in place.
--
-- ===
--
-- @module PatrolZone
-- @author FlightControl
--- PATROLZONE class
-- @type PATROLZONE
-- @field Group#GROUP PatrolGroup The @{Group} patrolling.
-- @field Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
-- @field DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
-- @field DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
-- @field DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Group} in km/h.
-- @field DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Group} in km/h.
-- @extends Base#BASE
PATROLZONE = {
ClassName = "PATROLZONE",
}
--- Creates a new PATROLZONE object, taking a @{Group} object as a parameter. The GROUP needs to be alive.
-- @param #PATROLZONE self
-- @param Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
-- @param DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
-- @param DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
-- @param DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Group} in km/h.
-- @param DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Group} in km/h.
-- @return #PATROLZONE self
-- @usage
-- -- Define a new PATROLZONE Object. This PatrolArea will patrol a group within PatrolZone between 3000 and 6000 meters, with a variying speed between 600 and 900 km/h.
-- PatrolZone = ZONE:New( 'PatrolZone' )
-- PatrolGroup = GROUP:FindByName( "Patrol Group" )
-- PatrolArea = PATROLZONE:New( PatrolGroup, PatrolZone, 3000, 6000, 600, 900 )
function PATROLZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed )
-- Inherits from BASE
local self = BASE:Inherit( self, BASE:New() )
self.PatrolZone = PatrolZone
self.PatrolFloorAltitude = PatrolFloorAltitude
self.PatrolCeilingAltitude = PatrolCeilingAltitude
self.PatrolMinSpeed = PatrolMinSpeed
self.PatrolMaxSpeed = PatrolMaxSpeed
return self
end
--- Set the @{Group} to act as the Patroller.
-- @param #PATROLZONE self
-- @param Group#GROUP PatrolGroup The @{Group} patrolling.
-- @return #PATROLZONE self
function PATROLZONE:SetGroup( PatrolGroup )
self.PatrolGroup = PatrolGroup
self.PatrolGroupTemplateName = PatrolGroup:GetName()
self:NewPatrolRoute()
if not self.PatrolOutOfFuelMonitor then
self.PatrolOutOfFuelMonitor = SCHEDULER:New( nil, _MonitorOutOfFuelScheduled, { self }, 1, 120, 0 )
self.SpawnPatrolGroup = SPAWN:New( self.PatrolGroupTemplateName )
end
return self
end
--- Sets (modifies) the minimum and maximum speed of the patrol.
-- @param #PATROLZONE self
-- @param DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Group} in km/h.
-- @param DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Group} in km/h.
-- @return #PATROLZONE self
function PATROLZONE:SetSpeed( PatrolMinSpeed, PatrolMaxSpeed )
self:F2( { PatrolMinSpeed, PatrolMaxSpeed } )
self.PatrolMinSpeed = PatrolMinSpeed
self.PatrolMaxSpeed = PatrolMaxSpeed
end
--- Sets the floor and ceiling altitude of the patrol.
-- @param #PATROLZONE self
-- @param DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
-- @param DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
-- @return #PATROLZONE self
function PATROLZONE:SetAltitude( PatrolFloorAltitude, PatrolCeilingAltitude )
self:F2( { PatrolFloorAltitude, PatrolCeilingAltitude } )
self.PatrolFloorAltitude = PatrolFloorAltitude
self.PatrolCeilingAltitude = PatrolCeilingAltitude
end
--- @param Group#GROUP PatrolGroup
function _NewPatrolRoute( PatrolGroup )
PatrolGroup:T( "NewPatrolRoute" )
local PatrolZone = PatrolGroup:GetState( PatrolGroup, "PatrolZone" ) -- PatrolZone#PATROLZONE
PatrolZone:NewPatrolRoute()
end
--- Defines a new patrol route using the @{PatrolZone} parameters and settings.
-- @param #PATROLZONE self
-- @return #PATROLZONE self
function PATROLZONE:NewPatrolRoute()
self:F2()
local PatrolRoute = {}
if self.PatrolGroup:IsAlive() then
--- Determine if the PatrolGroup is within the PatrolZone.
-- If not, make a waypoint within the to that the PatrolGroup will fly at maximum speed to that point.
-- --- Calculate the current route point.
-- local CurrentVec2 = self.PatrolGroup:GetVec2()
-- local CurrentAltitude = self.PatrolGroup:GetUnit(1):GetAltitude()
-- local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
-- local CurrentRoutePoint = CurrentPointVec3:RoutePointAir(
-- POINT_VEC3.RoutePointAltType.BARO,
-- POINT_VEC3.RoutePointType.TurningPoint,
-- POINT_VEC3.RoutePointAction.TurningPoint,
-- ToPatrolZoneSpeed,
-- true
-- )
--
-- PatrolRoute[#PatrolRoute+1] = CurrentRoutePoint
self:T2( PatrolRoute )
if self.PatrolGroup:IsNotInZone( self.PatrolZone ) then
--- Find a random 2D point in PatrolZone.
local ToPatrolZoneVec2 = self.PatrolZone:GetRandomVec2()
self:T2( ToPatrolZoneVec2 )
--- Define Speed and Altitude.
local ToPatrolZoneAltitude = math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude )
local ToPatrolZoneSpeed = self.PatrolMaxSpeed
self:T2( ToPatrolZoneSpeed )
--- Obtain a 3D @{Point} from the 2D point + altitude.
local ToPatrolZonePointVec3 = POINT_VEC3:New( ToPatrolZoneVec2.x, ToPatrolZoneAltitude, ToPatrolZoneVec2.y )
--- Create a route point of type air.
local ToPatrolZoneRoutePoint = ToPatrolZonePointVec3:RoutePointAir(
POINT_VEC3.RoutePointAltType.BARO,
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
ToPatrolZoneSpeed,
true
)
PatrolRoute[#PatrolRoute+1] = ToPatrolZoneRoutePoint
end
--- Define a random point in the @{Zone}. The AI will fly to that point within the zone.
--- Find a random 2D point in PatrolZone.
local ToTargetVec2 = self.PatrolZone:GetRandomVec2()
self:T2( ToTargetVec2 )
--- Define Speed and Altitude.
local ToTargetAltitude = math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude )
local ToTargetSpeed = math.random( self.PatrolMinSpeed, self.PatrolMaxSpeed )
self:T2( { self.PatrolMinSpeed, self.PatrolMaxSpeed, ToTargetSpeed } )
--- Obtain a 3D @{Point} from the 2D point + altitude.
local ToTargetPointVec3 = POINT_VEC3:New( ToTargetVec2.x, ToTargetAltitude, ToTargetVec2.y )
--- Create a route point of type air.
local ToTargetRoutePoint = ToTargetPointVec3:RoutePointAir(
POINT_VEC3.RoutePointAltType.BARO,
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
ToTargetSpeed,
true
)
--ToTargetPointVec3:SmokeRed()
PatrolRoute[#PatrolRoute+1] = ToTargetRoutePoint
--- Now we're going to do something special, we're going to call a function from a waypoint action at the PatrolGroup...
self.PatrolGroup:WayPointInitialize( PatrolRoute )
--- Do a trick, link the NewPatrolRoute function of the PATROLGROUP object to the PatrolGroup in a temporary variable ...
self.PatrolGroup:SetState( self.PatrolGroup, "PatrolZone", self )
self.PatrolGroup:WayPointFunction( #PatrolRoute, 1, "_NewPatrolRoute" )
--- NOW ROUTE THE GROUP!
self.PatrolGroup:WayPointExecute( 1, 2 )
end
end
--- When the PatrolGroup is out of fuel, it is required that a new PatrolGroup is started, before the old PatrolGroup can return to the home base.
-- Therefore, with a parameter and a calculation of the distance to the home base, the fuel treshold is calculated.
-- When the fuel treshold is reached, the PatrolGroup will continue for a given time its patrol task in orbit, while a new PatrolGroup is targetted to the PATROLZONE.
-- Once the time is finished, the old PatrolGroup will return to the base.
-- @param #PATROLZONE self
-- @param #number PatrolFuelTresholdPercentage The treshold in percentage (between 0 and 1) when the PatrolGroup is considered to get out of fuel.
-- @param #number PatrolOutOfFuelOrbitTime The amount of seconds the out of fuel PatrolGroup will orbit before returning to the base.
-- @return #PATROLZONE self
function PATROLZONE:ManageFuel( PatrolFuelTresholdPercentage, PatrolOutOfFuelOrbitTime )
self.PatrolManageFuel = true
self.PatrolFuelTresholdPercentage = PatrolFuelTresholdPercentage
self.PatrolOutOfFuelOrbitTime = PatrolOutOfFuelOrbitTime
if self.PatrolGroup then
self.PatrolOutOfFuelMonitor = SCHEDULER:New( self, self._MonitorOutOfFuelScheduled, {}, 1, 120, 0 )
self.SpawnPatrolGroup = SPAWN:New( self.PatrolGroupTemplateName )
end
return self
end
--- @param #PATROLZONE self
function _MonitorOutOfFuelScheduled( self )
self:F2( "_MonitorOutOfFuelScheduled" )
if self.PatrolGroup and self.PatrolGroup:IsAlive() then
local Fuel = self.PatrolGroup:GetUnit(1):GetFuel()
if Fuel < self.PatrolFuelTresholdPercentage then
local OldPatrolGroup = self.PatrolGroup
local PatrolGroupTemplate = self.PatrolGroup:GetTemplate()
local OrbitTask = OldPatrolGroup:TaskOrbitCircle( math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ), self.PatrolMinSpeed )
local TimedOrbitTask = OldPatrolGroup:TaskControlled( OrbitTask, OldPatrolGroup:TaskCondition(nil,nil,nil,nil,self.PatrolOutOfFuelOrbitTime,nil ) )
OldPatrolGroup:SetTask( TimedOrbitTask, 10 )
local NewPatrolGroup = self.SpawnPatrolGroup:Spawn()
self.PatrolGroup = NewPatrolGroup
self:NewPatrolRoute()
end
else
self.PatrolOutOfFuelMonitor:Stop()
end
end