* Final version

* Monitor off taxi way
  * Monitor maximum speed
  * Monitor kick speed
This commit is contained in:
FlightControl_Master 2017-10-23 15:30:40 +02:00
parent 140f81b695
commit a8c5ccd4ad
10 changed files with 766 additions and 68 deletions

View File

@ -3326,6 +3326,405 @@ function SET_CLIENT:IsIncludeObject( MClient )
return MClientInclude
end
--- SET_PLAYER
--- @type SET_PLAYER
-- @extends Core.Set#SET_BASE
--- # 4) SET_PLAYER class, extends @{Set#SET_BASE}
--
-- Mission designers can use the @{Set#SET_PLAYER} class to build sets of units belonging to alive players:
--
-- ## 4.1) SET_PLAYER constructor
--
-- Create a new SET_PLAYER object with the @{#SET_PLAYER.New} method:
--
-- * @{#SET_PLAYER.New}: Creates a new SET_PLAYER object.
--
-- ## 4.3) SET_PLAYER filter criteria
--
-- You can set filter criteria to define the set of clients within the SET_PLAYER.
-- Filter criteria are defined by:
--
-- * @{#SET_PLAYER.FilterCoalitions}: Builds the SET_PLAYER with the clients belonging to the coalition(s).
-- * @{#SET_PLAYER.FilterCategories}: Builds the SET_PLAYER with the clients belonging to the category(ies).
-- * @{#SET_PLAYER.FilterTypes}: Builds the SET_PLAYER with the clients belonging to the client type(s).
-- * @{#SET_PLAYER.FilterCountries}: Builds the SET_PLAYER with the clients belonging to the country(ies).
-- * @{#SET_PLAYER.FilterPrefixes}: Builds the SET_PLAYER with the clients starting with the same prefix string(s).
--
-- Once the filter criteria have been set for the SET_PLAYER, you can start filtering using:
--
-- * @{#SET_PLAYER.FilterStart}: Starts the filtering of the clients within the SET_PLAYER.
--
-- Planned filter criteria within development are (so these are not yet available):
--
-- * @{#SET_PLAYER.FilterZones}: Builds the SET_PLAYER with the clients within a @{Zone#ZONE}.
--
-- ## 4.4) SET_PLAYER iterators
--
-- Once the filters have been defined and the SET_PLAYER has been built, you can iterate the SET_PLAYER with the available iterator methods.
-- The iterator methods will walk the SET_PLAYER set, and call for each element within the set a function that you provide.
-- The following iterator methods are currently available within the SET_PLAYER:
--
-- * @{#SET_PLAYER.ForEachClient}: Calls a function for each alive client it finds within the SET_PLAYER.
--
-- ===
-- @field #SET_PLAYER SET_PLAYER
SET_PLAYER = {
ClassName = "SET_PLAYER",
Clients = {},
Filter = {
Coalitions = nil,
Categories = nil,
Types = nil,
Countries = nil,
ClientPrefixes = nil,
},
FilterMeta = {
Coalitions = {
red = coalition.side.RED,
blue = coalition.side.BLUE,
neutral = coalition.side.NEUTRAL,
},
Categories = {
plane = Unit.Category.AIRPLANE,
helicopter = Unit.Category.HELICOPTER,
ground = Unit.Category.GROUND_UNIT,
ship = Unit.Category.SHIP,
structure = Unit.Category.STRUCTURE,
},
},
}
--- Creates a new SET_PLAYER object, building a set of clients belonging to a coalitions, categories, countries, types or with defined prefix names.
-- @param #SET_PLAYER self
-- @return #SET_PLAYER
-- @usage
-- -- Define a new SET_PLAYER Object. This DBObject will contain a reference to all Clients.
-- DBObject = SET_PLAYER:New()
function SET_PLAYER:New()
-- Inherits from BASE
local self = BASE:Inherit( self, SET_BASE:New( _DATABASE.PLAYERS ) )
return self
end
--- Add CLIENT(s) to SET_PLAYER.
-- @param Core.Set#SET_PLAYER self
-- @param #string AddClientNames A single name or an array of CLIENT names.
-- @return self
function SET_PLAYER:AddClientsByName( AddClientNames )
local AddClientNamesArray = ( type( AddClientNames ) == "table" ) and AddClientNames or { AddClientNames }
for AddClientID, AddClientName in pairs( AddClientNamesArray ) do
self:Add( AddClientName, CLIENT:FindByName( AddClientName ) )
end
return self
end
--- Remove CLIENT(s) from SET_PLAYER.
-- @param Core.Set#SET_PLAYER self
-- @param Wrapper.Client#CLIENT RemoveClientNames A single name or an array of CLIENT names.
-- @return self
function SET_PLAYER:RemoveClientsByName( RemoveClientNames )
local RemoveClientNamesArray = ( type( RemoveClientNames ) == "table" ) and RemoveClientNames or { RemoveClientNames }
for RemoveClientID, RemoveClientName in pairs( RemoveClientNamesArray ) do
self:Remove( RemoveClientName.ClientName )
end
return self
end
--- Finds a Client based on the Player Name.
-- @param #SET_PLAYER self
-- @param #string PlayerName
-- @return Wrapper.Client#CLIENT The found Client.
function SET_PLAYER:FindClient( PlayerName )
local ClientFound = self.Set[PlayerName]
return ClientFound
end
--- Builds a set of clients of coalitions joined by specific players.
-- Possible current coalitions are red, blue and neutral.
-- @param #SET_PLAYER self
-- @param #string Coalitions Can take the following values: "red", "blue", "neutral".
-- @return #SET_PLAYER self
function SET_PLAYER:FilterCoalitions( Coalitions )
if not self.Filter.Coalitions then
self.Filter.Coalitions = {}
end
if type( Coalitions ) ~= "table" then
Coalitions = { Coalitions }
end
for CoalitionID, Coalition in pairs( Coalitions ) do
self.Filter.Coalitions[Coalition] = Coalition
end
return self
end
--- Builds a set of clients out of categories joined by players.
-- Possible current categories are plane, helicopter, ground, ship.
-- @param #SET_PLAYER self
-- @param #string Categories Can take the following values: "plane", "helicopter", "ground", "ship".
-- @return #SET_PLAYER self
function SET_PLAYER:FilterCategories( Categories )
if not self.Filter.Categories then
self.Filter.Categories = {}
end
if type( Categories ) ~= "table" then
Categories = { Categories }
end
for CategoryID, Category in pairs( Categories ) do
self.Filter.Categories[Category] = Category
end
return self
end
--- Builds a set of clients of defined client types joined by players.
-- Possible current types are those types known within DCS world.
-- @param #SET_PLAYER self
-- @param #string Types Can take those type strings known within DCS world.
-- @return #SET_PLAYER self
function SET_PLAYER:FilterTypes( Types )
if not self.Filter.Types then
self.Filter.Types = {}
end
if type( Types ) ~= "table" then
Types = { Types }
end
for TypeID, Type in pairs( Types ) do
self.Filter.Types[Type] = Type
end
return self
end
--- Builds a set of clients of defined countries.
-- Possible current countries are those known within DCS world.
-- @param #SET_PLAYER self
-- @param #string Countries Can take those country strings known within DCS world.
-- @return #SET_PLAYER self
function SET_PLAYER:FilterCountries( Countries )
if not self.Filter.Countries then
self.Filter.Countries = {}
end
if type( Countries ) ~= "table" then
Countries = { Countries }
end
for CountryID, Country in pairs( Countries ) do
self.Filter.Countries[Country] = Country
end
return self
end
--- Builds a set of clients of defined client prefixes.
-- All the clients starting with the given prefixes will be included within the set.
-- @param #SET_PLAYER self
-- @param #string Prefixes The prefix of which the client name starts with.
-- @return #SET_PLAYER self
function SET_PLAYER:FilterPrefixes( Prefixes )
if not self.Filter.ClientPrefixes then
self.Filter.ClientPrefixes = {}
end
if type( Prefixes ) ~= "table" then
Prefixes = { Prefixes }
end
for PrefixID, Prefix in pairs( Prefixes ) do
self.Filter.ClientPrefixes[Prefix] = Prefix
end
return self
end
--- Starts the filtering.
-- @param #SET_PLAYER self
-- @return #SET_PLAYER self
function SET_PLAYER:FilterStart()
if _DATABASE then
self:_FilterStart()
end
return self
end
--- Handles the Database to check on an event (birth) that the Object was added in the Database.
-- This is required, because sometimes the _DATABASE birth event gets called later than the SET_BASE birth event!
-- @param #SET_PLAYER self
-- @param Core.Event#EVENTDATA Event
-- @return #string The name of the CLIENT
-- @return #table The CLIENT
function SET_PLAYER:AddInDatabase( Event )
self:F3( { Event } )
return Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName]
end
--- Handles the Database to check on any event that Object exists in the Database.
-- This is required, because sometimes the _DATABASE event gets called later than the SET_BASE event or vise versa!
-- @param #SET_PLAYER self
-- @param Core.Event#EVENTDATA Event
-- @return #string The name of the CLIENT
-- @return #table The CLIENT
function SET_PLAYER:FindInDatabase( Event )
self:F3( { Event } )
return Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName]
end
--- Iterate the SET_PLAYER and call an interator function for each **alive** CLIENT, providing the CLIENT and optional parameters.
-- @param #SET_PLAYER self
-- @param #function IteratorFunction The function that will be called when there is an alive CLIENT in the SET_PLAYER. The function needs to accept a CLIENT parameter.
-- @return #SET_PLAYER self
function SET_PLAYER:ForEachPlayer( IteratorFunction, ... )
self:F2( arg )
self:ForEach( IteratorFunction, arg, self.Set )
return self
end
--- Iterate the SET_PLAYER and call an iterator function for each **alive** CLIENT presence completely in a @{Zone}, providing the CLIENT and optional parameters to the called function.
-- @param #SET_PLAYER self
-- @param Core.Zone#ZONE ZoneObject The Zone to be tested for.
-- @param #function IteratorFunction The function that will be called when there is an alive CLIENT in the SET_PLAYER. The function needs to accept a CLIENT parameter.
-- @return #SET_PLAYER self
function SET_PLAYER:ForEachPlayerInZone( ZoneObject, IteratorFunction, ... )
self:F2( arg )
self:ForEach( IteratorFunction, arg, self.Set,
--- @param Core.Zone#ZONE_BASE ZoneObject
-- @param Wrapper.Client#CLIENT ClientObject
function( ZoneObject, ClientObject )
if ClientObject:IsInZone( ZoneObject ) then
return true
else
return false
end
end, { ZoneObject } )
return self
end
--- Iterate the SET_PLAYER and call an iterator function for each **alive** CLIENT presence not in a @{Zone}, providing the CLIENT and optional parameters to the called function.
-- @param #SET_PLAYER self
-- @param Core.Zone#ZONE ZoneObject The Zone to be tested for.
-- @param #function IteratorFunction The function that will be called when there is an alive CLIENT in the SET_PLAYER. The function needs to accept a CLIENT parameter.
-- @return #SET_PLAYER self
function SET_PLAYER:ForEachPlayerNotInZone( ZoneObject, IteratorFunction, ... )
self:F2( arg )
self:ForEach( IteratorFunction, arg, self.Set,
--- @param Core.Zone#ZONE_BASE ZoneObject
-- @param Wrapper.Client#CLIENT ClientObject
function( ZoneObject, ClientObject )
if ClientObject:IsNotInZone( ZoneObject ) then
return true
else
return false
end
end, { ZoneObject } )
return self
end
---
-- @param #SET_PLAYER self
-- @param Wrapper.Client#CLIENT MClient
-- @return #SET_PLAYER self
function SET_PLAYER:IsIncludeObject( MClient )
self:F2( MClient )
local MClientInclude = true
if MClient then
local MClientName = MClient.UnitName
if self.Filter.Coalitions then
local MClientCoalition = false
for CoalitionID, CoalitionName in pairs( self.Filter.Coalitions ) do
local ClientCoalitionID = _DATABASE:GetCoalitionFromClientTemplate( MClientName )
self:T3( { "Coalition:", ClientCoalitionID, self.FilterMeta.Coalitions[CoalitionName], CoalitionName } )
if self.FilterMeta.Coalitions[CoalitionName] and self.FilterMeta.Coalitions[CoalitionName] == ClientCoalitionID then
MClientCoalition = true
end
end
self:T( { "Evaluated Coalition", MClientCoalition } )
MClientInclude = MClientInclude and MClientCoalition
end
if self.Filter.Categories then
local MClientCategory = false
for CategoryID, CategoryName in pairs( self.Filter.Categories ) do
local ClientCategoryID = _DATABASE:GetCategoryFromClientTemplate( MClientName )
self:T3( { "Category:", ClientCategoryID, self.FilterMeta.Categories[CategoryName], CategoryName } )
if self.FilterMeta.Categories[CategoryName] and self.FilterMeta.Categories[CategoryName] == ClientCategoryID then
MClientCategory = true
end
end
self:T( { "Evaluated Category", MClientCategory } )
MClientInclude = MClientInclude and MClientCategory
end
if self.Filter.Types then
local MClientType = false
for TypeID, TypeName in pairs( self.Filter.Types ) do
self:T3( { "Type:", MClient:GetTypeName(), TypeName } )
if TypeName == MClient:GetTypeName() then
MClientType = true
end
end
self:T( { "Evaluated Type", MClientType } )
MClientInclude = MClientInclude and MClientType
end
if self.Filter.Countries then
local MClientCountry = false
for CountryID, CountryName in pairs( self.Filter.Countries ) do
local ClientCountryID = _DATABASE:GetCountryFromClientTemplate(MClientName)
self:T3( { "Country:", ClientCountryID, country.id[CountryName], CountryName } )
if country.id[CountryName] and country.id[CountryName] == ClientCountryID then
MClientCountry = true
end
end
self:T( { "Evaluated Country", MClientCountry } )
MClientInclude = MClientInclude and MClientCountry
end
if self.Filter.ClientPrefixes then
local MClientPrefix = false
for ClientPrefixId, ClientPrefix in pairs( self.Filter.ClientPrefixes ) do
self:T3( { "Prefix:", string.find( MClient.UnitName, ClientPrefix, 1 ), ClientPrefix } )
if string.find( MClient.UnitName, ClientPrefix, 1 ) then
MClientPrefix = true
end
end
self:T( { "Evaluated Prefix", MClientPrefix } )
MClientInclude = MClientInclude and MClientPrefix
end
end
self:T2( MClientInclude )
return MClientInclude
end
--- @type SET_AIRBASE
-- @extends Core.Set#SET_BASE

View File

@ -0,0 +1,184 @@
--- **Core** -- VELOCITY models a speed, which can be expressed in various formats according the Settings.
--
-- ===
--
-- ### Author: **Sven Van de Velde (FlightControl)**
-- ### Contributions:
--
-- ====
--
-- @module Base
do -- Velocity
--- @type VELOCITY
-- @extends Core.Base#BASE
--- # VELOCITY class, extends @{Base#BASE}
--
-- VELOCITY models a speed, which can be expressed in various formats according the Settings.
--
-- ## 1. VELOCITY constructor
--
-- * @{#VELOCITY.New}(): Creates a new VELOCITY object.
--
-- @field #VELOCITY
VELOCITY = {
ClassName = "VELOCITY",
}
--- VELOCITY Constructor.
-- @param #VELOCITY self
-- @param #number VelocityMps The velocity in meters per second.
-- @return #VELOCITY
function VELOCITY:New( VelocityMps )
local self = BASE:Inherit( self, BASE:New() ) -- #VELOCITY
self:F( {} )
self.Velocity = VelocityMps
return self
end
--- Set the velocity in Mps (meters per second).
-- @param #VELOCITY self
-- @param #number VelocityMps The velocity in meters per second.
-- @return #VELOCITY
function VELOCITY:Set( VelocityMps )
self.Velocity = VelocityMps
return self
end
--- Get the velocity in Mps (meters per second).
-- @param #VELOCITY self
-- @return #number The velocity in meters per second.
function VELOCITY:Get()
return self.Velocity
end
--- Set the velocity in Kmph (kilometers per hour).
-- @param #VELOCITY self
-- @param #number VelocityKmph The velocity in kilometers per hour.
-- @return #VELOCITY
function VELOCITY:SetKmph( VelocityKmph )
self.Velocity = UTILS.KmphToMps( VelocityKmph )
return self
end
--- Get the velocity in Kmph (kilometers per hour).
-- @param #VELOCITY self
-- @return #number The velocity in kilometers per hour.
function VELOCITY:GetKmph()
return UTILS.MpsToKmph( self.Velocity )
end
--- Set the velocity in Miph (miles per hour).
-- @param #VELOCITY self
-- @param #number VelocityMiph The velocity in miles per hour.
-- @return #VELOCITY
function VELOCITY:SetMiph( VelocityMiph )
self.Velocity = UTILS.MiphToMps( VelocityMiph )
return self
end
--- Get the velocity in Miph (miles per hour).
-- @param #VELOCITY self
-- @return #number The velocity in miles per hour.
function VELOCITY:GetMiph()
return UTILS.MpsToMiph( self.Velocity )
end
--- Get the velocity in text, according the player @{Settings}.
-- @param #VELOCITY self
-- @param Core.Settings#SETTINGS Settings
-- @return #string The velocity in text.
function VELOCITY:GetText( Settings )
local Settings = Settings or _SETTINGS
if self.Velocity ~= 0 then
if Settings:IsMetric() then
return string.format( "%d km/h", UTILS.MpsToKmph( self.Velocity ) )
else
return string.format( "%d mi/h", UTILS.MpsToMiph( self.Velocity ) )
end
else
return "stationary"
end
end
--- Get the velocity in text, according the player or default @{Settings}.
-- @param #VELOCITY self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
-- @param Core.Settings#SETTINGS Settings
-- @return #string The velocity in text according the player or default @{Settings}
function VELOCITY:ToString( VelocityGroup, Settings ) -- R2.3
self:F( { Group = VelocityGroup and VelocityGroup:GetName() } )
local Settings = Settings or ( VelocityGroup and _DATABASE:GetPlayerSettings( VelocityGroup:GetPlayerName() ) ) or _SETTINGS
return self:GetText( Settings )
end
end
do -- VELOCITY_POSITIONABLE
--- @type VELOCITY_POSITIONABLE
-- @extends Core.Base#BASE
--- # VELOCITY_POSITIONABLE class, extends @{Base#BASE}
--
-- VELOCITY_POSITIONABLE monitors the speed of an @{Positionable} in the simulation, which can be expressed in various formats according the Settings.
--
-- ## 1. VELOCITY_POSITIONABLE constructor
--
-- * @{#VELOCITY_POSITIONABLE.New}(): Creates a new VELOCITY_POSITIONABLE object.
--
-- @field #VELOCITY_POSITIONABLE
VELOCITY_POSITIONABLE = {
ClassName = "VELOCITY_POSITIONABLE",
}
--- VELOCITY_POSITIONABLE Constructor.
-- @param #VELOCITY_POSITIONABLE self
-- @param Wrapper.Positionable#POSITIONABLE Positionable The Positionable to monitor the speed.
-- @return #VELOCITY_POSITIONABLE
function VELOCITY_POSITIONABLE:New( Positionable )
local self = BASE:Inherit( self, VELOCITY:New() ) -- #VELOCITY_POSITIONABLE
self:F( {} )
self.Positionable = Positionable
return self
end
--- Get the velocity in Mps (meters per second).
-- @param #VELOCITY_POSITIONABLE self
-- @return #number The velocity in meters per second.
function VELOCITY_POSITIONABLE:Get()
return self.Positionable:GetVelocityMPS() or 0
end
--- Get the velocity in Kmph (kilometers per hour).
-- @param #VELOCITY_POSITIONABLE self
-- @return #number The velocity in kilometers per hour.
function VELOCITY_POSITIONABLE:GetKmph()
return UTILS.MpsToKmph( self.Positionable:GetVelocityMPS() or 0)
end
--- Get the velocity in Miph (miles per hour).
-- @param #VELOCITY_POSITIONABLE self
-- @return #number The velocity in miles per hour.
function VELOCITY_POSITIONABLE:GetMiph()
return UTILS.MpsToMiph( self.Positionable:GetVelocityMPS() or 0 )
end
--- Get the velocity in text, according the player or default @{Settings}.
-- @param #VELOCITY_POSITIONABLE self
-- @return #string The velocity in text according the player or default @{Settings}
function VELOCITY_POSITIONABLE:ToString() -- R2.3
self:F( { Group = self.Positionable and self.Positionable:GetName() } )
local Settings = Settings or ( self.Positionable and _DATABASE:GetPlayerSettings( self.Positionable:GetPlayerName() ) ) or _SETTINGS
self.Velocity = self.Positionable:GetVelocityMPS()
return self:GetText( Settings )
end
end

View File

@ -29,19 +29,19 @@ AIRBASEPOLICE_BASE = {
--- Creates a new AIRBASEPOLICE_BASE object.
-- @param #AIRBASEPOLICE_BASE self
-- @param SetClient A SET_CLIENT object that will contain the CLIENT objects to be monitored if they follow the rules of the airbase.
-- @param Airbases A table of Airbase Names.
-- @return #AIRBASEPOLICE_BASE self
function AIRBASEPOLICE_BASE:New( SetClient, Airbases, AirbaseList )
function AIRBASEPOLICE_BASE:New( Airbases, AirbaseList )
-- Inherits from BASE
local self = BASE:Inherit( self, BASE:New() )
self:E( { self.ClassName, SetClient, Airbases } )
local self = BASE:Inherit( self, BASE:New() ) -- #AIRBASEPOLICE_BASE
self:E( { self.ClassName, Airbases } )
self.SetClient = SetClient
self.Airbases = Airbases
self.AirbaseList = AirbaseList
self.SetClient = SET_CLIENT:New():FilterCategories( "plane" ):FilterStart()
for AirbaseID, Airbase in pairs( self.Airbases ) do
Airbase.ZoneBoundary = _DATABASE:FindAirbase( AirbaseID ):GetZone()
@ -69,15 +69,19 @@ function AIRBASEPOLICE_BASE:New( SetClient, Airbases, AirbaseList )
function( Client )
Client:SetState( self, "Speeding", false )
Client:SetState( self, "Warnings", 0)
Client:SetState( self, "IsOffRunway", false )
Client:SetState( self, "OffRunwayWarnings", 0 )
Client:SetState( self, "Taxi", false )
end
)
self.AirbaseMonitor = SCHEDULER:New( self, self._AirbaseMonitor, {}, 0, 2, 0.05 )
self.AirbaseMonitor = SCHEDULER:New( self, self._AirbaseMonitor, {self }, 0, 2, 0.05 )
-- This is simple slot blocker is used on the server.
SSB = USERFLAG:New( "SSB" )
SSB:Set( 100 )
self:SetKickSpeedKmph( 100 )
return self
end
@ -97,14 +101,36 @@ function AIRBASEPOLICE_BASE:SmokeRunways( SmokeColor )
end
--- Set the maximum speed in Kmph until the player gets kicked.
-- @param #AIRBASEPOLICE_BASE self
-- @param #number KickSpeed Set the maximum speed in Kmph until the player gets kicked.
-- @return #AIRBASEPOLICE_BASE self
function AIRBASEPOLICE_BASE:SetKickSpeedKmph( KickSpeed )
self.KickSpeed = UTILS.KmphToMps( KickSpeed )
end
--- Set the maximum speed in Miph until the player gets kicked.
-- @param #AIRBASEPOLICE_BASE self
-- @param #number KickSpeedMiph Set the maximum speed in Mph until the player gets kicked.
-- @return #AIRBASEPOLICE_BASE self
function AIRBASEPOLICE_BASE:SetKickSpeedMiph( KickSpeedMiph )
self.KickSpeed = UTILS.MiphToMps( KickSpeedMiph )
end
--- @param #AIRBASEPOLICE_BASE self
function AIRBASEPOLICE_BASE:_AirbaseMonitor()
self:E( "In Scheduler")
for AirbaseID, AirbaseMeta in pairs( self.Airbases ) do
if AirbaseMeta.Monitor == true then
self:E( AirbaseID )
self:E( AirbaseID, AirbaseMeta.MaximumSpeed )
self.SetClient:ForEachClientInZone( AirbaseMeta.ZoneBoundary,
@ -112,32 +138,40 @@ function AIRBASEPOLICE_BASE:_AirbaseMonitor()
function( Client )
self:E( Client.UnitName )
if Client:IsAlive() then
if Client and Client:IsAlive() then
local NotInRunwayZone = true
for ZoneRunwayID, ZoneRunway in pairs( AirbaseMeta.ZoneRunways ) do
NotInRunwayZone = ( Client:IsNotInZone( ZoneRunway ) == true ) and NotInRunwayZone or false
end
if NotInRunwayZone then
local Taxi = self:GetState( self, "Taxi" )
local Taxi = Client:GetState( self, "Taxi" )
self:E( Taxi )
if Taxi == false then
Client:Message( "Welcome at " .. AirbaseID .. ". The maximum taxiing speed is " .. AirbaseMeta.MaximumSpeed " km/h.", 20, "ATC" )
self:SetState( self, "Taxi", true )
Client:Message( "Welcome at " .. AirbaseID .. ". The maximum taxiing speed is " .. AirbaseMeta.MaximumSpeed .. " km/h.", 20, "ATC" )
Client:SetState( self, "Taxi", true )
end
-- TODO: GetVelocityKMH function usage
local VelocityVec3 = Client:GetVelocity()
local Velocity = ( VelocityVec3.x ^ 2 + VelocityVec3.y ^ 2 + VelocityVec3.z ^ 2 ) ^ 0.5 -- in meters / sec
local Velocity = Velocity * 3.6 -- now it is in km/h.
-- MESSAGE:New( "Velocity = " .. Velocity, 1 ):ToAll()
local Velocity = VELOCITY_POSITIONABLE:New( Client )
--MESSAGE:New( "Velocity = " .. Velocity:ToString(), 1 ):ToAll()
local IsAboveRunway = Client:IsAboveRunway()
local IsOnGround = Client:InAir() == false
self:T( IsAboveRunway, IsOnGround )
if IsAboveRunway and IsOnGround then
if IsOnGround then
if Velocity:Get() > self.KickSpeed then
MESSAGE:New( "Penalty! Player " .. Client:GetPlayerName() .. " is kicked, due to a severe airbase traffic rule violation ...", 10, "ATC" ):ToAll()
Client:Destroy()
Client:SetState( self, "Speeding", false )
Client:SetState( self, "Warnings", 0 )
end
end
if Velocity > AirbaseMeta.MaximumSpeed then
if IsOnGround then
if Velocity:GetKmph() > AirbaseMeta.MaximumSpeed then
local IsSpeeding = Client:GetState( self, "Speeding" )
if IsSpeeding == true then
@ -146,7 +180,7 @@ function AIRBASEPOLICE_BASE:_AirbaseMonitor()
if SpeedingWarnings <= 3 then
Client:Message( "Warning " .. SpeedingWarnings .. "/3! Airbase traffic rule violation! Slow down now! Your speed is " ..
string.format( "%2.0f km/h", Velocity ), 5, "ATC" )
string.format( "%s", Velocity:ToString() ), 5, "ATC" )
Client:SetState( self, "Warnings", SpeedingWarnings + 1 )
else
MESSAGE:New( "Penalty! Player " .. Client:GetPlayerName() .. " is kicked, due to a severe airbase traffic rule violation ...", 10, "ATC" ):ToAll()
@ -157,7 +191,7 @@ function AIRBASEPOLICE_BASE:_AirbaseMonitor()
end
else
Client:Message( "Attention! You are speeding on the taxiway, slow down! Your speed is " .. string.format( "%2.0f km/h", Velocity ), 5, "ATC" )
Client:Message( "Attention! You are speeding on the taxiway, slow down! Your speed is " .. string.format( "%s", Velocity:ToString() ), 5, "ATC" )
Client:SetState( self, "Speeding", true )
Client:SetState( self, "Warnings", 1 )
end
@ -168,13 +202,45 @@ function AIRBASEPOLICE_BASE:_AirbaseMonitor()
end
end
if IsOnGround and not IsAboveRunway then
local IsOffRunway = Client:GetState( self, "IsOffRunway" )
if IsOffRunway == true then
local OffRunwayWarnings = Client:GetState( self, "OffRunwayWarnings" )
self:T( OffRunwayWarnings )
if OffRunwayWarnings <= 3 then
Client:Message( "Warning " .. OffRunwayWarnings .. "/3! Airbase traffic rule violation! Get back on the taxi immediately!", 5, "ATC" )
Client:SetState( self, "OffRunwayWarnings", OffRunwayWarnings + 1 )
else
MESSAGE:New( "Penalty! Player " .. Client:GetPlayerName() .. " is kicked, due to a severe airbase traffic rule violation ...", 10, "ATC" ):ToAll()
--- @param Wrapper.Client#CLIENT Client
Client:Destroy()
Client:SetState( self, "IsOffRunway", false )
Client:SetState( self, "OffRunwayWarnings", 0 )
end
else
Client:Message( "Attention! You are off the taxiway. Get back on the taxiway immediately!", 5, "ATC" )
Client:SetState( self, "IsOffRunway", true )
Client:SetState( self, "OffRunwayWarnings", 1 )
end
else
Client:SetState( self, "IsOffRunway", false )
Client:SetState( self, "OffRunwayWarnings", 0 )
end
else
Client:SetState( self, "Speeding", false )
Client:SetState( self, "Warnings", 0 )
local Taxi = self:GetState( self, "Taxi" )
Client:SetState( self, "IsOffRunway", false )
Client:SetState( self, "OffRunwayWarnings", 0 )
local Taxi = Client:GetState( self, "Taxi" )
if Taxi == true then
Client:Message( "You have progressed to the runway ... Await take-off clearance ...", 20, "ATC" )
self:SetState( self, "Taxi", false )
Client:SetState( self, "Taxi", false )
end
end
end
@ -257,11 +323,8 @@ end
--
-- -- This creates a new AIRBASEPOLICE_CAUCASUS object.
--
-- -- Create a set of all clients in the mission.
-- AllClientsSet = SET_CLIENT:New():FilterStart()
--
-- -- Monitor for these clients the airbases.
-- AirbasePoliceCaucasus = AIRBASEPOLICE_CAUCASUS:New( AllClientsSet )
-- AirbasePoliceCaucasus = AIRBASEPOLICE_CAUCASUS:New()
--
-- @field #AIRBASEPOLICE_CAUCASUS
AIRBASEPOLICE_CAUCASUS = {
@ -554,13 +617,12 @@ AIRBASEPOLICE_CAUCASUS = {
--- Creates a new AIRBASEPOLICE_CAUCASUS object.
-- @param #AIRBASEPOLICE_CAUCASUS self
-- @param SetClient A SET_CLIENT object that will contain the CLIENT objects to be monitored if they follow the rules of the airbase.
-- @param AirbaseNames A list {} of airbase names (Use AIRBASE.Caucasus enumerator).
-- @return #AIRBASEPOLICE_CAUCASUS self
function AIRBASEPOLICE_CAUCASUS:New( SetClient, AirbaseNames )
function AIRBASEPOLICE_CAUCASUS:New( AirbaseNames )
-- Inherits from BASE
local self = BASE:Inherit( self, AIRBASEPOLICE_BASE:New( SetClient, self.Airbases, AirbaseNames ) )
local self = BASE:Inherit( self, AIRBASEPOLICE_BASE:New( self.Airbases, AirbaseNames ) )
@ -828,16 +890,25 @@ end
--
-- -- This creates a new AIRBASEPOLICE_NEVADA object.
--
-- -- Create a set of all clients in the mission.
-- AllClientsSet = SET_CLIENT:New():FilterStart()
--
-- -- Monitor for these clients the airbases.
-- AirbasePoliceCaucasus = AIRBASEPOLICE_NEVADA:New( AllClientsSet )
-- AirbasePoliceCaucasus = AIRBASEPOLICE_NEVADA:New()
--
-- @field #AIRBASEPOLICE_NEVADA
AIRBASEPOLICE_NEVADA = {
ClassName = "AIRBASEPOLICE_NEVADA",
Airbases = {
[AIRBASE.Nevada.Beatty_Airport] = {
PointsRunways = {
[1] = {
[1]={["y"]=-174950.05857143,["x"]=-329679.65,},
[2]={["y"]=-174946.53828571,["x"]=-331394.03885715,},
[3]={["y"]=-174967.10971429,["x"]=-331394.32457143,},
[4]={["y"]=-174971.01828571,["x"]=-329682.59171429,},
},
},
MaximumSpeed = 50,
},
[AIRBASE.Nevada.Boulder_City_Airport] = {
PointsRunways = {
[1] = {
@ -951,6 +1022,17 @@ AIRBASEPOLICE_NEVADA = {
},
MaximumSpeed = 50,
},
[AIRBASE.Nevada.Lincoln_County] = {
PointsRunways = {
[1] = {
[1]={["y"]=33222.34171429,["x"]=-223959.40171429,},
[2]={["y"]=33200.040000004,["x"]=-225369.36828572,},
[3]={["y"]=33177.634571428,["x"]=-225369.21485715,},
[4]={["y"]=33201.198857147,["x"]=-223960.54457143,},
},
},
MaximumSpeed = 50,
},
[AIRBASE.Nevada.McCarran_International_Airport] = {
PointsRunways = {
[1] = {
@ -1085,13 +1167,12 @@ AIRBASEPOLICE_NEVADA = {
--- Creates a new AIRBASEPOLICE_NEVADA object.
-- @param #AIRBASEPOLICE_NEVADA self
-- @param SetClient A SET_CLIENT object that will contain the CLIENT objects to be monitored if they follow the rules of the airbase.
-- @param AirbaseNames A list {} of airbase names (Use AIRBASE.Nevada enumerator).
-- @return #AIRBASEPOLICE_NEVADA self
function AIRBASEPOLICE_NEVADA:New( SetClient, AirbaseNames )
function AIRBASEPOLICE_NEVADA:New( AirbaseNames )
-- Inherits from BASE
local self = BASE:Inherit( self, AIRBASEPOLICE_BASE:New( SetClient, self.Airbases, AirbaseNames ) )
local self = BASE:Inherit( self, AIRBASEPOLICE_BASE:New( self.Airbases, AirbaseNames ) )
@ -1107,6 +1188,13 @@ function AIRBASEPOLICE_NEVADA:New( SetClient, AirbaseNames )
--[[
-- Beatty
do
local VillagePrefix = "Beatty"
local Runway1 = GROUP:FindByName( VillagePrefix .. " 1" )
local Zone1 = ZONE_POLYGON:New( VillagePrefix .. " 1", Runway1 ):SmokeZone(SMOKECOLOR.Red):Flush()
end
-- Boulder
do
local VillagePrefix = "Boulder"
@ -1168,7 +1256,7 @@ function AIRBASEPOLICE_NEVADA:New( SetClient, AirbaseNames )
-- Lincoln
do
local VillagePrefix = "Laughlin"
local VillagePrefix = "Lincoln"
local Runway1 = GROUP:FindByName( VillagePrefix .. " 1" )
local Zone1 = ZONE_POLYGON:New( VillagePrefix .. " 1", Runway1 ):SmokeZone(SMOKECOLOR.Red):Flush()
end
@ -1299,11 +1387,8 @@ end
--
-- -- This creates a new AIRBASEPOLICE_NORMANDY object.
--
-- -- Create a set of all clients in the mission.
-- AllClientsSet = SET_CLIENT:New():FilterStart()
--
-- -- Monitor for these clients the airbases.
-- AirbasePoliceCaucasus = AIRBASEPOLICE_NORMANDY:New( AllClientsSet )
-- AirbasePoliceCaucasus = AIRBASEPOLICE_NORMANDY:New()
--
-- @field #AIRBASEPOLICE_NORMANDY
AIRBASEPOLICE_NORMANDY = {
@ -1701,13 +1786,12 @@ AIRBASEPOLICE_NORMANDY = {
--- Creates a new AIRBASEPOLICE_NORMANDY object.
-- @param #AIRBASEPOLICE_NORMANDY self
-- @param SetClient A SET_CLIENT object that will contain the CLIENT objects to be monitored if they follow the rules of the airbase.
-- @param AirbaseNames A list {} of airbase names (Use AIRBASE.Normandy enumerator).
-- @return #AIRBASEPOLICE_NORMANDY self
function AIRBASEPOLICE_NORMANDY:New( SetClient, AirbaseNames )
function AIRBASEPOLICE_NORMANDY:New( AirbaseNames )
-- Inherits from BASE
local self = BASE:Inherit( self, AIRBASEPOLICE_BASE:New( SetClient, self.Airbases, AirbaseNames ) )
local self = BASE:Inherit( self, AIRBASEPOLICE_BASE:New( self.Airbases, AirbaseNames ) )
-- These lines here are for the demonstration mission.
-- They create in the dcs.log the coordinates of the runway polygons, that are then

View File

@ -544,7 +544,7 @@ do -- TASK_A2G_BAI
local TargetCoordinate = self:GetInfo( "Coordinate" ) -- Core.Point#COORDINATE
local Velocity = self.TargetSetUnit:GetVelocity()
local Velocity = self.TargetSetUnit:GetVelocityVec3()
local Heading = self.TargetSetUnit:GetHeading()
TargetCoordinate:SetHeading( Heading )

View File

@ -236,26 +236,36 @@ UTILS.FeetToMeters = function(feet)
return feet*0.3048
end
UTILS.MpsToKnots = function(mps)
return mps*3600/1852
end
UTILS.MpsToKmph = function(mps)
return mps*3.6
end
UTILS.KnotsToMps = function(knots)
return knots*1852/3600
end
UTILS.KnotsToKmph = function(knots)
return knots* 1.852
end
UTILS.KmphToMps = function(kmph)
return kmph/3.6
UTILS.KmphToMps = function( kmph )
return kmph / 3.6
end
UTILS.MpsToKmph = function( mps )
return mps * 3.6
end
UTILS.MiphToMps = function( miph )
return miph * 0.44704
end
UTILS.MpsToMiph = function( mps )
return mps / 0.44704
end
UTILS.MpsToKnots = function( mps )
return mps * 3600 / 1852
end
UTILS.KnotsToMps = function( knots )
return knots * 1852 / 3600
end
--[[acc:
in DM: decimal point of minutes.
In DMS: decimal point of seconds.

View File

@ -326,16 +326,35 @@ function POSITIONABLE:InAir()
return nil
end
--- Returns the POSITIONABLE velocity vector.
--- Returns the a @{Velocity} object from the positionable.
-- @param Wrapper.Positionable#POSITIONABLE self
-- @return Dcs.DCSTypes#Vec3 The velocity vector
-- @return Core.Velocity#VELOCITY Velocity The Velocity object.
-- @return #nil The POSITIONABLE is not existing or alive.
function POSITIONABLE:GetVelocity()
self:F2( self.PositionableName )
local DCSPositionable = self:GetDCSObject()
if DCSPositionable then
local Velocity = VELOCITY:New( self )
return Velocity
end
return nil
end
--- Returns the POSITIONABLE velocity Vec3 vector.
-- @param Wrapper.Positionable#POSITIONABLE self
-- @return Dcs.DCSTypes#Vec3 The velocity Vec3 vector
-- @return #nil The POSITIONABLE is not existing or alive.
function POSITIONABLE:GetVelocityVec3()
self:F2( self.PositionableName )
local DCSPositionable = self:GetDCSObject()
if DCSPositionable then
local PositionableVelocityVec3 = DCSPositionable:getVelocity()
self:T3( PositionableVelocityVec3 )
@ -377,7 +396,7 @@ function POSITIONABLE:GetVelocityKMH()
local DCSPositionable = self:GetDCSObject()
if DCSPositionable then
local VelocityVec3 = self:GetVelocity()
local VelocityVec3 = self:GetVelocityVec3()
local Velocity = ( VelocityVec3.x ^ 2 + VelocityVec3.y ^ 2 + VelocityVec3.z ^ 2 ) ^ 0.5 -- in meters / sec
local Velocity = Velocity * 3.6 -- now it is in km/h.
self:T3( Velocity )
@ -396,7 +415,7 @@ function POSITIONABLE:GetVelocityMPS()
local DCSPositionable = self:GetDCSObject()
if DCSPositionable then
local VelocityVec3 = self:GetVelocity()
local VelocityVec3 = self:GetVelocityVec3()
local Velocity = ( VelocityVec3.x ^ 2 + VelocityVec3.y ^ 2 + VelocityVec3.z ^ 2 ) ^ 0.5 -- in meters / sec
self:T3( Velocity )
return Velocity

View File

@ -761,10 +761,9 @@ function UNIT:IsInZone( Zone )
if self:IsAlive() then
local IsInZone = Zone:IsVec3InZone( self:GetVec3() )
self:T2( { IsInZone } )
self:E( { Unit = self.UnitName, IsInZone = IsInZone } )
return IsInZone
end
return false
end

View File

@ -14,6 +14,7 @@ Core/Zone.lua
Core/Database.lua
Core/Set.lua
Core/Point.lua
Core/Velocity.lua
Core/Message.lua
Core/Fsm.lua
Core/Radio.lua

View File

@ -1,5 +1,5 @@
env.info( '*** MOOSE DYNAMIC INCLUDE START *** ' )
env.info( 'Moose Generation Timestamp: 20171021_1203' )
env.info( 'Moose Generation Timestamp: 20171023_1007' )
local base = _G
@ -36,6 +36,7 @@ __Moose.Include( 'Core/Zone.lua' )
__Moose.Include( 'Core/Database.lua' )
__Moose.Include( 'Core/Set.lua' )
__Moose.Include( 'Core/Point.lua' )
__Moose.Include( 'Core/Velocity.lua' )
__Moose.Include( 'Core/Message.lua' )
__Moose.Include( 'Core/Fsm.lua' )
__Moose.Include( 'Core/Radio.lua' )

View File

@ -1,5 +1,5 @@
env.info('*** MOOSE DYNAMIC INCLUDE START *** ')
env.info('Moose Generation Timestamp: 20171021_1203')
env.info('Moose Generation Timestamp: 20171023_1007')
local base=_G
__Moose={}
__Moose.Include=function(IncludeFile)
@ -31,6 +31,7 @@ __Moose.Include('Core/Zone.lua')
__Moose.Include('Core/Database.lua')
__Moose.Include('Core/Set.lua')
__Moose.Include('Core/Point.lua')
__Moose.Include('Core/Velocity.lua')
__Moose.Include('Core/Message.lua')
__Moose.Include('Core/Fsm.lua')
__Moose.Include('Core/Radio.lua')