mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-10-29 16:58:06 +00:00
Updates, new classes and fixes
**AI_FORMATION** - Performance improvents. This also affects the **RESCUEHELO** class. **EVENT** - Added events when object is of category BASE. **FSM** - Removed a few tracing calls. - Updated docs. **POINT** - Added Update Vec functions to COORDINATE. - Added *overwrite* option to COORDINATE:Translate() function. - Removed second COORDINATE:Translate() function. - Optimized COORDINATE:GetClosestAirbase() function. - Added *Offset* parameter to COORDINATE:IsLOS() function. **RADIO** - Updated BEACON type and system enums. **RADIOQUEUE** - Use Vec3 instead of COORDINATE. Performance improvement. **SET** - Added some functions. **TIMER** - Added new class. Little sister of SCHEDULER class. **DCS** - Minor changes regarding docs. **ATIS** - Added "Miles.ogg", "StatuteMiles.ogg", "Zulu.ogg". **ENUMS** - Added ENUMS.Formation.Vehicle - Added ENUMS.AlarmState ** PROFILER** - Added new lua profiler. **UTILS** - Minor changes and additions. **AIRBASE** - Improved Registration. - Improved Parking spot handling. - Aded :IsAirdrome(), IsHelipad(), IsShip() functions. - Improved :GetRunwayData() for Syria airports. **CONTROLLABLE** - Fixed bug in :CommandSetFrequency() fuction (Hz vs. MHz). - Updated/fixed :TaskFAC_AttackGroup() function. **GROUP** - Added :GetThreatLevel() function. - Added :IsInZone() function to check if any unit is in the zone. **MARKER** - Added new class handling F10 markers using FSM.
This commit is contained in:
@@ -26,8 +26,6 @@
|
||||
-- @module Core.Base
|
||||
-- @image Core_Base.JPG
|
||||
|
||||
|
||||
|
||||
local _TraceOnOff = true
|
||||
local _TraceLevel = 1
|
||||
local _TraceAll = false
|
||||
@@ -256,6 +254,8 @@ end
|
||||
-- @param #BASE Parent is the Parent class that the Child inherits from.
|
||||
-- @return #BASE Child
|
||||
function BASE:Inherit( Child, Parent )
|
||||
|
||||
-- Create child.
|
||||
local Child = routines.utils.deepCopy( Child )
|
||||
|
||||
if Child ~= nil then
|
||||
@@ -271,6 +271,7 @@ function BASE:Inherit( Child, Parent )
|
||||
|
||||
--Child:_SetDestructor()
|
||||
end
|
||||
|
||||
return Child
|
||||
end
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
--- **Core** - Manages several databases containing templates, mission objects, and mission information.
|
||||
--
|
||||
--- **Core** - Manages several databases containing templates, mission objects, and mission information.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
--
|
||||
-- ## Features:
|
||||
--
|
||||
--
|
||||
-- * During mission startup, scan the mission environment, and create / instantiate intelligently the different objects as defined within the mission.
|
||||
-- * Manage database of DCS Group templates (as modelled using the mission editor).
|
||||
-- - Group templates.
|
||||
@@ -20,14 +20,14 @@
|
||||
-- * Manage database of hits to units and statics.
|
||||
-- * Manage database of destroys of units and statics.
|
||||
-- * Manage database of @{Core.Zone#ZONE_BASE} objects.
|
||||
--
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
--
|
||||
-- ### Author: **FlightControl**
|
||||
-- ### Contributions:
|
||||
--
|
||||
-- ### Contributions:
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
--
|
||||
-- @module Core.Database
|
||||
-- @image Core_Database.JPG
|
||||
|
||||
@@ -36,9 +36,9 @@
|
||||
-- @extends Core.Base#BASE
|
||||
|
||||
--- Contains collections of wrapper objects defined within MOOSE that reflect objects within the simulator.
|
||||
--
|
||||
--
|
||||
-- Mission designers can use the DATABASE class to refer to:
|
||||
--
|
||||
--
|
||||
-- * STATICS
|
||||
-- * UNITS
|
||||
-- * GROUPS
|
||||
@@ -47,12 +47,12 @@
|
||||
-- * PLAYERSJOINED
|
||||
-- * PLAYERS
|
||||
-- * CARGOS
|
||||
--
|
||||
--
|
||||
-- On top, for internal MOOSE administration purposes, the DATBASE administers the Unit and Group TEMPLATES as defined within the Mission Editor.
|
||||
--
|
||||
--
|
||||
-- The singleton object **_DATABASE** is automatically created by MOOSE, that administers all objects within the mission.
|
||||
-- Moose refers to **_DATABASE** within the framework extensively, but you can also refer to the _DATABASE object within your missions if required.
|
||||
--
|
||||
--
|
||||
-- @field #DATABASE
|
||||
DATABASE = {
|
||||
ClassName = "DATABASE",
|
||||
@@ -82,6 +82,9 @@ DATABASE = {
|
||||
DESTROYS = {},
|
||||
ZONES = {},
|
||||
ZONES_GOAL = {},
|
||||
WAREHOUSES = {},
|
||||
FLIGHTGROUPS = {},
|
||||
FLIGHTCONTROLS = {},
|
||||
}
|
||||
|
||||
local _DATABASECoalition =
|
||||
@@ -113,7 +116,7 @@ function DATABASE:New()
|
||||
local self = BASE:Inherit( self, BASE:New() ) -- #DATABASE
|
||||
|
||||
self:SetEventPriority( 1 )
|
||||
|
||||
|
||||
self:HandleEvent( EVENTS.Birth, self._EventOnBirth )
|
||||
self:HandleEvent( EVENTS.Dead, self._EventOnDeadOrCrash )
|
||||
self:HandleEvent( EVENTS.Crash, self._EventOnDeadOrCrash )
|
||||
@@ -123,11 +126,11 @@ function DATABASE:New()
|
||||
self:HandleEvent( EVENTS.DeleteCargo )
|
||||
self:HandleEvent( EVENTS.NewZone )
|
||||
self:HandleEvent( EVENTS.DeleteZone )
|
||||
|
||||
|
||||
-- Follow alive players and clients
|
||||
--self:HandleEvent( EVENTS.PlayerEnterUnit, self._EventOnPlayerEnterUnit ) -- This is not working anymore!, handling this through the birth event.
|
||||
self:HandleEvent( EVENTS.PlayerLeaveUnit, self._EventOnPlayerLeaveUnit )
|
||||
|
||||
|
||||
self:_RegisterTemplates()
|
||||
self:_RegisterGroupsAndUnits()
|
||||
self:_RegisterClients()
|
||||
@@ -136,16 +139,16 @@ function DATABASE:New()
|
||||
self:_RegisterAirbases()
|
||||
|
||||
self.UNITS_Position = 0
|
||||
|
||||
|
||||
--- @param #DATABASE self
|
||||
local function CheckPlayers( self )
|
||||
|
||||
|
||||
local CoalitionsData = { AlivePlayersRed = coalition.getPlayers( coalition.side.RED ), AlivePlayersBlue = coalition.getPlayers( coalition.side.BLUE ), AlivePlayersNeutral = coalition.getPlayers( coalition.side.NEUTRAL )}
|
||||
for CoalitionId, CoalitionData in pairs( CoalitionsData ) do
|
||||
--self:E( { "CoalitionData:", CoalitionData } )
|
||||
for UnitId, UnitData in pairs( CoalitionData ) do
|
||||
if UnitData and UnitData:isExist() then
|
||||
|
||||
|
||||
local UnitName = UnitData:getName()
|
||||
local PlayerName = UnitData:getPlayerName()
|
||||
local PlayerUnit = UNIT:Find( UnitData )
|
||||
@@ -164,10 +167,10 @@ function DATABASE:New()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--self:E( "Scheduling" )
|
||||
--PlayerCheckSchedule = SCHEDULER:New( nil, CheckPlayers, { self }, 1, 1 )
|
||||
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -190,10 +193,10 @@ function DATABASE:AddUnit( DCSUnitName )
|
||||
self:T( { "Add UNIT:", DCSUnitName } )
|
||||
local UnitRegister = UNIT:Register( DCSUnitName )
|
||||
self.UNITS[DCSUnitName] = UNIT:Register( DCSUnitName )
|
||||
|
||||
|
||||
table.insert( self.UNITS_Index, DCSUnitName )
|
||||
end
|
||||
|
||||
|
||||
return self.UNITS[DCSUnitName]
|
||||
end
|
||||
|
||||
@@ -202,7 +205,7 @@ end
|
||||
-- @param #DATABASE self
|
||||
function DATABASE:DeleteUnit( DCSUnitName )
|
||||
|
||||
self.UNITS[DCSUnitName] = nil
|
||||
self.UNITS[DCSUnitName] = nil
|
||||
end
|
||||
|
||||
--- Adds a Static based on the Static Name in the DATABASE.
|
||||
@@ -213,7 +216,7 @@ function DATABASE:AddStatic( DCSStaticName )
|
||||
self.STATICS[DCSStaticName] = STATIC:Register( DCSStaticName )
|
||||
return self.STATICS[DCSStaticName]
|
||||
end
|
||||
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
@@ -222,7 +225,7 @@ end
|
||||
-- @param #DATABASE self
|
||||
function DATABASE:DeleteStatic( DCSStaticName )
|
||||
|
||||
--self.STATICS[DCSStaticName] = nil
|
||||
--self.STATICS[DCSStaticName] = nil
|
||||
end
|
||||
|
||||
--- Finds a STATIC based on the StaticName.
|
||||
@@ -254,7 +257,7 @@ function DATABASE:AddAirbase( AirbaseName )
|
||||
if not self.AIRBASES[AirbaseName] then
|
||||
self.AIRBASES[AirbaseName] = AIRBASE:Register( AirbaseName )
|
||||
end
|
||||
|
||||
|
||||
return self.AIRBASES[AirbaseName]
|
||||
end
|
||||
|
||||
@@ -264,7 +267,7 @@ end
|
||||
-- @param #string AirbaseName The name of the airbase
|
||||
function DATABASE:DeleteAirbase( AirbaseName )
|
||||
|
||||
self.AIRBASES[AirbaseName] = nil
|
||||
self.AIRBASES[AirbaseName] = nil
|
||||
end
|
||||
|
||||
--- Finds an AIRBASE based on the AirbaseName.
|
||||
@@ -285,29 +288,29 @@ do -- Zones
|
||||
-- @param #string ZoneName The name of the zone.
|
||||
-- @return Core.Zone#ZONE_BASE The found ZONE.
|
||||
function DATABASE:FindZone( ZoneName )
|
||||
|
||||
|
||||
local ZoneFound = self.ZONES[ZoneName]
|
||||
return ZoneFound
|
||||
end
|
||||
|
||||
|
||||
--- Adds a @{Zone} based on the zone name in the DATABASE.
|
||||
-- @param #DATABASE self
|
||||
-- @param #string ZoneName The name of the zone.
|
||||
-- @param Core.Zone#ZONE_BASE Zone The zone.
|
||||
function DATABASE:AddZone( ZoneName, Zone )
|
||||
|
||||
|
||||
if not self.ZONES[ZoneName] then
|
||||
self.ZONES[ZoneName] = Zone
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
--- Deletes a @{Zone} from the DATABASE based on the zone name.
|
||||
-- @param #DATABASE self
|
||||
-- @param #string ZoneName The name of the zone.
|
||||
function DATABASE:DeleteZone( ZoneName )
|
||||
|
||||
self.ZONES[ZoneName] = nil
|
||||
|
||||
self.ZONES[ZoneName] = nil
|
||||
end
|
||||
|
||||
|
||||
@@ -324,20 +327,20 @@ do -- Zones
|
||||
self.ZONENAMES[ZoneName] = ZoneName
|
||||
self:AddZone( ZoneName, Zone )
|
||||
end
|
||||
|
||||
|
||||
for ZoneGroupName, ZoneGroup in pairs( self.GROUPS ) do
|
||||
if ZoneGroupName:match("#ZONE_POLYGON") then
|
||||
local ZoneName1 = ZoneGroupName:match("(.*)#ZONE_POLYGON")
|
||||
local ZoneName2 = ZoneGroupName:match(".*#ZONE_POLYGON(.*)")
|
||||
local ZoneName = ZoneName1 .. ( ZoneName2 or "" )
|
||||
|
||||
|
||||
self:I( { "Register ZONE_POLYGON:", Name = ZoneName } )
|
||||
local Zone_Polygon = ZONE_POLYGON:New( ZoneName, ZoneGroup )
|
||||
self.ZONENAMES[ZoneName] = ZoneName
|
||||
self:AddZone( ZoneName, Zone_Polygon )
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
@@ -350,29 +353,29 @@ do -- Zone_Goal
|
||||
-- @param #string ZoneName The name of the zone.
|
||||
-- @return Core.Zone#ZONE_BASE The found ZONE.
|
||||
function DATABASE:FindZoneGoal( ZoneName )
|
||||
|
||||
|
||||
local ZoneFound = self.ZONES_GOAL[ZoneName]
|
||||
return ZoneFound
|
||||
end
|
||||
|
||||
|
||||
--- Adds a @{Zone} based on the zone name in the DATABASE.
|
||||
-- @param #DATABASE self
|
||||
-- @param #string ZoneName The name of the zone.
|
||||
-- @param Core.Zone#ZONE_BASE Zone The zone.
|
||||
function DATABASE:AddZoneGoal( ZoneName, Zone )
|
||||
|
||||
|
||||
if not self.ZONES_GOAL[ZoneName] then
|
||||
self.ZONES_GOAL[ZoneName] = Zone
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
--- Deletes a @{Zone} from the DATABASE based on the zone name.
|
||||
-- @param #DATABASE self
|
||||
-- @param #string ZoneName The name of the zone.
|
||||
function DATABASE:DeleteZoneGoal( ZoneName )
|
||||
|
||||
self.ZONES_GOAL[ZoneName] = nil
|
||||
|
||||
self.ZONES_GOAL[ZoneName] = nil
|
||||
end
|
||||
|
||||
end -- Zone_Goal
|
||||
@@ -382,31 +385,31 @@ do -- cargo
|
||||
-- @param #DATABASE self
|
||||
-- @param #string CargoName The name of the airbase
|
||||
function DATABASE:AddCargo( Cargo )
|
||||
|
||||
|
||||
if not self.CARGOS[Cargo.Name] then
|
||||
self.CARGOS[Cargo.Name] = Cargo
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
--- Deletes a Cargo from the DATABASE based on the Cargo Name.
|
||||
-- @param #DATABASE self
|
||||
-- @param #string CargoName The name of the airbase
|
||||
function DATABASE:DeleteCargo( CargoName )
|
||||
|
||||
self.CARGOS[CargoName] = nil
|
||||
|
||||
self.CARGOS[CargoName] = nil
|
||||
end
|
||||
|
||||
|
||||
--- Finds an CARGO based on the CargoName.
|
||||
-- @param #DATABASE self
|
||||
-- @param #string CargoName
|
||||
-- @return Wrapper.Cargo#CARGO The found CARGO.
|
||||
function DATABASE:FindCargo( CargoName )
|
||||
|
||||
|
||||
local CargoFound = self.CARGOS[CargoName]
|
||||
return CargoFound
|
||||
end
|
||||
|
||||
|
||||
--- Checks if the Template name has a #CARGO tag.
|
||||
-- If yes, the group is a cargo.
|
||||
-- @param #DATABASE self
|
||||
@@ -415,10 +418,10 @@ do -- cargo
|
||||
function DATABASE:IsCargo( TemplateName )
|
||||
|
||||
TemplateName = env.getValueDictByKey( TemplateName )
|
||||
|
||||
|
||||
local Cargo = TemplateName:match( "#(CARGO)" )
|
||||
|
||||
return Cargo and Cargo == "CARGO"
|
||||
return Cargo and Cargo == "CARGO"
|
||||
end
|
||||
|
||||
--- Private method that registers new Static Templates within the DATABASE Object.
|
||||
@@ -427,7 +430,7 @@ do -- cargo
|
||||
function DATABASE:_RegisterCargos()
|
||||
|
||||
local Groups = UTILS.DeepCopy( self.GROUPS ) -- This is a very important statement. CARGO_GROUP:New creates a new _DATABASE.GROUP entry, which will confuse the loop. I searched 4 hours on this to find the bug!
|
||||
|
||||
|
||||
for CargoGroupName, CargoGroup in pairs( Groups ) do
|
||||
self:I( { Cargo = CargoGroupName } )
|
||||
if self:IsCargo( CargoGroupName ) then
|
||||
@@ -440,12 +443,12 @@ do -- cargo
|
||||
local Name = CargoParam and CargoParam:match( "N=([%a%d]+),?") or CargoName
|
||||
local LoadRadius = CargoParam and tonumber( CargoParam:match( "RR=([%a%d]+),?") )
|
||||
local NearRadius = CargoParam and tonumber( CargoParam:match( "NR=([%a%d]+),?") )
|
||||
|
||||
|
||||
self:I({"Register CargoGroup:",Type=Type,Name=Name,LoadRadius=LoadRadius,NearRadius=NearRadius})
|
||||
CARGO_GROUP:New( CargoGroup, Type, Name, LoadRadius, NearRadius )
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
for CargoStaticName, CargoStatic in pairs( self.STATICS ) do
|
||||
if self:IsCargo( CargoStaticName ) then
|
||||
local CargoInfo = CargoStaticName:match("#CARGO(.*)")
|
||||
@@ -456,7 +459,7 @@ do -- cargo
|
||||
local Name = CargoParam and CargoParam:match( "N=([%a%d]+),?") or CargoName
|
||||
local LoadRadius = CargoParam and tonumber( CargoParam:match( "RR=([%a%d]+),?") )
|
||||
local NearRadius = CargoParam and tonumber( CargoParam:match( "NR=([%a%d]+),?") )
|
||||
|
||||
|
||||
if Category == "SLING" then
|
||||
self:I({"Register CargoSlingload:",Type=Type,Name=Name,LoadRadius=LoadRadius,NearRadius=NearRadius})
|
||||
CARGO_SLINGLOAD:New( CargoStatic, Type, Name, LoadRadius, NearRadius )
|
||||
@@ -468,7 +471,7 @@ do -- cargo
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
end -- cargo
|
||||
@@ -514,9 +517,9 @@ function DATABASE:AddGroup( GroupName )
|
||||
if not self.GROUPS[GroupName] then
|
||||
self:T( { "Add GROUP:", GroupName } )
|
||||
self.GROUPS[GroupName] = GROUP:Register( GroupName )
|
||||
end
|
||||
|
||||
return self.GROUPS[GroupName]
|
||||
end
|
||||
|
||||
return self.GROUPS[GroupName]
|
||||
end
|
||||
|
||||
--- Adds a player based on the Player Name in the DATABASE.
|
||||
@@ -618,7 +621,7 @@ function DATABASE:Spawn( SpawnTemplate )
|
||||
for UnitID, UnitData in pairs( SpawnTemplate.units ) do
|
||||
self:AddUnit( UnitData.name )
|
||||
end
|
||||
|
||||
|
||||
return SpawnGroup
|
||||
end
|
||||
|
||||
@@ -650,21 +653,21 @@ end
|
||||
function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionSide, CategoryID, CountryID, GroupName )
|
||||
|
||||
local GroupTemplateName = GroupName or env.getValueDictByKey( GroupTemplate.name )
|
||||
|
||||
|
||||
if not self.Templates.Groups[GroupTemplateName] then
|
||||
self.Templates.Groups[GroupTemplateName] = {}
|
||||
self.Templates.Groups[GroupTemplateName].Status = nil
|
||||
end
|
||||
|
||||
|
||||
-- Delete the spans from the route, it is not needed and takes memory.
|
||||
if GroupTemplate.route and GroupTemplate.route.spans then
|
||||
if GroupTemplate.route and GroupTemplate.route.spans then
|
||||
GroupTemplate.route.spans = nil
|
||||
end
|
||||
|
||||
|
||||
GroupTemplate.CategoryID = CategoryID
|
||||
GroupTemplate.CoalitionID = CoalitionSide
|
||||
GroupTemplate.CountryID = CountryID
|
||||
|
||||
|
||||
self.Templates.Groups[GroupTemplateName].GroupName = GroupTemplateName
|
||||
self.Templates.Groups[GroupTemplateName].Template = GroupTemplate
|
||||
self.Templates.Groups[GroupTemplateName].groupId = GroupTemplate.groupId
|
||||
@@ -679,7 +682,7 @@ function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionSide, Category
|
||||
for unit_num, UnitTemplate in pairs( GroupTemplate.units ) do
|
||||
|
||||
UnitTemplate.name = env.getValueDictByKey(UnitTemplate.name)
|
||||
|
||||
|
||||
self.Templates.Units[UnitTemplate.name] = {}
|
||||
self.Templates.Units[UnitTemplate.name].UnitName = UnitTemplate.name
|
||||
self.Templates.Units[UnitTemplate.name].Template = UnitTemplate
|
||||
@@ -697,8 +700,8 @@ function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionSide, Category
|
||||
self.Templates.ClientsByName[UnitTemplate.name].CountryID = CountryID
|
||||
self.Templates.ClientsByID[UnitTemplate.unitId] = UnitTemplate
|
||||
end
|
||||
|
||||
UnitNames[#UnitNames+1] = self.Templates.Units[UnitTemplate.name].UnitName
|
||||
|
||||
UnitNames[#UnitNames+1] = self.Templates.Units[UnitTemplate.name].UnitName
|
||||
end
|
||||
|
||||
self:T( { Group = self.Templates.Groups[GroupTemplateName].GroupName,
|
||||
@@ -727,13 +730,13 @@ function DATABASE:_RegisterStaticTemplate( StaticTemplate, CoalitionID, Category
|
||||
local StaticTemplate = UTILS.DeepCopy( StaticTemplate )
|
||||
|
||||
local StaticTemplateName = env.getValueDictByKey(StaticTemplate.name)
|
||||
|
||||
|
||||
self.Templates.Statics[StaticTemplateName] = self.Templates.Statics[StaticTemplateName] or {}
|
||||
|
||||
|
||||
StaticTemplate.CategoryID = CategoryID
|
||||
StaticTemplate.CoalitionID = CoalitionID
|
||||
StaticTemplate.CountryID = CountryID
|
||||
|
||||
|
||||
self.Templates.Statics[StaticTemplateName].StaticName = StaticTemplateName
|
||||
self.Templates.Statics[StaticTemplateName].GroupTemplate = StaticTemplate
|
||||
self.Templates.Statics[StaticTemplateName].UnitTemplate = StaticTemplate.units[1]
|
||||
@@ -744,12 +747,12 @@ function DATABASE:_RegisterStaticTemplate( StaticTemplate, CoalitionID, Category
|
||||
self:I( { Static = self.Templates.Statics[StaticTemplateName].StaticName,
|
||||
Coalition = self.Templates.Statics[StaticTemplateName].CoalitionID,
|
||||
Category = self.Templates.Statics[StaticTemplateName].CategoryID,
|
||||
Country = self.Templates.Statics[StaticTemplateName].CountryID
|
||||
Country = self.Templates.Statics[StaticTemplateName].CountryID
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
self:AddStatic( StaticTemplateName )
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
@@ -817,7 +820,7 @@ function DATABASE:_RegisterPlayers()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -833,12 +836,12 @@ function DATABASE:_RegisterGroupsAndUnits()
|
||||
|
||||
if DCSGroup:isExist() then
|
||||
local DCSGroupName = DCSGroup:getName()
|
||||
|
||||
|
||||
self:I( { "Register Group:", DCSGroupName } )
|
||||
self:AddGroup( DCSGroupName )
|
||||
|
||||
for DCSUnitId, DCSUnit in pairs( DCSGroup:getUnits() ) do
|
||||
|
||||
|
||||
local DCSUnitName = DCSUnit:getName()
|
||||
self:I( { "Register Unit:", DCSUnitName } )
|
||||
self:AddUnit( DCSUnitName )
|
||||
@@ -846,10 +849,10 @@ function DATABASE:_RegisterGroupsAndUnits()
|
||||
else
|
||||
self:E( { "Group does not exist: ", DCSGroup } )
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
self:T("Groups:")
|
||||
for GroupName, Group in pairs( self.GROUPS ) do
|
||||
self:T( { "Group:", GroupName } )
|
||||
@@ -867,7 +870,7 @@ function DATABASE:_RegisterClients()
|
||||
self:T( { "Register Client:", ClientName } )
|
||||
self:AddClient( ClientName )
|
||||
end
|
||||
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -881,7 +884,7 @@ function DATABASE:_RegisterStatics()
|
||||
|
||||
if DCSStatic:isExist() then
|
||||
local DCSStaticName = DCSStatic:getName()
|
||||
|
||||
|
||||
self:T( { "Register Static:", DCSStaticName } )
|
||||
self:AddStatic( DCSStaticName )
|
||||
else
|
||||
@@ -893,32 +896,26 @@ function DATABASE:_RegisterStatics()
|
||||
return self
|
||||
end
|
||||
|
||||
--- @param #DATABASE self
|
||||
--- Register all world airbases.
|
||||
-- @param #DATABASE self
|
||||
-- @return #DATABASE self
|
||||
function DATABASE:_RegisterAirbases()
|
||||
|
||||
--[[
|
||||
local CoalitionsData = { AirbasesRed = coalition.getAirbases( coalition.side.RED ), AirbasesBlue = coalition.getAirbases( coalition.side.BLUE ), AirbasesNeutral = coalition.getAirbases( coalition.side.NEUTRAL ) }
|
||||
for CoalitionId, CoalitionData in pairs( CoalitionsData ) do
|
||||
for DCSAirbaseId, DCSAirbase in pairs( CoalitionData ) do
|
||||
|
||||
local DCSAirbaseName = DCSAirbase:getName()
|
||||
|
||||
self:T( { "Register Airbase:", DCSAirbaseName, DCSAirbase:getID() } )
|
||||
self:AddAirbase( DCSAirbaseName )
|
||||
end
|
||||
end
|
||||
]]
|
||||
|
||||
for DCSAirbaseId, DCSAirbase in pairs(world.getAirbases()) do
|
||||
local DCSAirbaseName = DCSAirbase:getName()
|
||||
|
||||
-- This gives the incorrect value to be inserted into the airdromeID for DCS 2.5.6!
|
||||
local airbaseID=DCSAirbase:getID()
|
||||
|
||||
local airbase=self:AddAirbase( DCSAirbaseName )
|
||||
|
||||
self:I(string.format("Register Airbase: %s, getID=%d, GetID=%d (unique=%d)", DCSAirbaseName, DCSAirbase:getID(), airbase:GetID(), airbase:GetID(true)))
|
||||
end
|
||||
|
||||
-- Get the airbase name.
|
||||
local DCSAirbaseName = DCSAirbase:getName()
|
||||
|
||||
-- This gave the incorrect value to be inserted into the airdromeID for DCS 2.5.6. Is fixed now.
|
||||
local airbaseID=DCSAirbase:getID()
|
||||
|
||||
-- Add and register airbase.
|
||||
local airbase=self:AddAirbase( DCSAirbaseName )
|
||||
|
||||
-- Debug output.
|
||||
self:I(string.format("Register Airbase: %s, getID=%d, GetID=%d (unique=%d)", DCSAirbaseName, DCSAirbase:getID(), airbase:GetID(), airbase:GetID(true)))
|
||||
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
@@ -934,7 +931,7 @@ function DATABASE:_EventOnBirth( Event )
|
||||
|
||||
if Event.IniDCSUnit then
|
||||
if Event.IniObjectCategory == 3 then
|
||||
self:AddStatic( Event.IniDCSUnitName )
|
||||
self:AddStatic( Event.IniDCSUnitName )
|
||||
else
|
||||
if Event.IniObjectCategory == 1 then
|
||||
self:AddUnit( Event.IniDCSUnitName )
|
||||
@@ -976,7 +973,7 @@ function DATABASE:_EventOnDeadOrCrash( Event )
|
||||
if Event.IniObjectCategory == 3 then
|
||||
if self.STATICS[Event.IniDCSUnitName] then
|
||||
self:DeleteStatic( Event.IniDCSUnitName )
|
||||
end
|
||||
end
|
||||
else
|
||||
if Event.IniObjectCategory == 1 then
|
||||
if self.UNITS[Event.IniDCSUnitName] then
|
||||
@@ -985,7 +982,7 @@ function DATABASE:_EventOnDeadOrCrash( Event )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
self:AccountDestroys( Event )
|
||||
end
|
||||
|
||||
@@ -1039,7 +1036,7 @@ end
|
||||
-- @return #DATABASE self
|
||||
function DATABASE:ForEach( IteratorFunction, FinalizeFunction, arg, Set )
|
||||
self:F2( arg )
|
||||
|
||||
|
||||
local function CoRoutine()
|
||||
local Count = 0
|
||||
for ObjectID, Object in pairs( Set ) do
|
||||
@@ -1048,20 +1045,20 @@ function DATABASE:ForEach( IteratorFunction, FinalizeFunction, arg, Set )
|
||||
Count = Count + 1
|
||||
-- if Count % 100 == 0 then
|
||||
-- coroutine.yield( false )
|
||||
-- end
|
||||
-- end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
-- local co = coroutine.create( CoRoutine )
|
||||
local co = CoRoutine
|
||||
|
||||
|
||||
local function Schedule()
|
||||
|
||||
|
||||
-- local status, res = coroutine.resume( co )
|
||||
local status, res = co()
|
||||
self:T3( { status, res } )
|
||||
|
||||
|
||||
if status == false then
|
||||
error( res )
|
||||
end
|
||||
@@ -1076,7 +1073,7 @@ function DATABASE:ForEach( IteratorFunction, FinalizeFunction, arg, Set )
|
||||
|
||||
--local Scheduler = SCHEDULER:New( self, Schedule, {}, 0.001, 0.001, 0 )
|
||||
Schedule()
|
||||
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -1087,7 +1084,7 @@ end
|
||||
-- @return #DATABASE self
|
||||
function DATABASE:ForEachStatic( IteratorFunction, FinalizeFunction, ... ) --R2.1
|
||||
self:F2( arg )
|
||||
|
||||
|
||||
self:ForEach( IteratorFunction, FinalizeFunction, arg, self.STATICS )
|
||||
|
||||
return self
|
||||
@@ -1100,7 +1097,7 @@ end
|
||||
-- @return #DATABASE self
|
||||
function DATABASE:ForEachUnit( IteratorFunction, FinalizeFunction, ... )
|
||||
self:F2( arg )
|
||||
|
||||
|
||||
self:ForEach( IteratorFunction, FinalizeFunction, arg, self.UNITS )
|
||||
|
||||
return self
|
||||
@@ -1113,7 +1110,7 @@ end
|
||||
-- @return #DATABASE self
|
||||
function DATABASE:ForEachGroup( IteratorFunction, FinalizeFunction, ... )
|
||||
self:F2( arg )
|
||||
|
||||
|
||||
self:ForEach( IteratorFunction, FinalizeFunction, arg, self.GROUPS )
|
||||
|
||||
return self
|
||||
@@ -1126,9 +1123,9 @@ end
|
||||
-- @return #DATABASE self
|
||||
function DATABASE:ForEachPlayer( IteratorFunction, FinalizeFunction, ... )
|
||||
self:F2( arg )
|
||||
|
||||
|
||||
self:ForEach( IteratorFunction, FinalizeFunction, arg, self.PLAYERS )
|
||||
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -1139,9 +1136,9 @@ end
|
||||
-- @return #DATABASE self
|
||||
function DATABASE:ForEachPlayerJoined( IteratorFunction, FinalizeFunction, ... )
|
||||
self:F2( arg )
|
||||
|
||||
|
||||
self:ForEach( IteratorFunction, FinalizeFunction, arg, self.PLAYERSJOINED )
|
||||
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -1151,9 +1148,9 @@ end
|
||||
-- @return #DATABASE self
|
||||
function DATABASE:ForEachPlayerUnit( IteratorFunction, FinalizeFunction, ... )
|
||||
self:F2( arg )
|
||||
|
||||
|
||||
self:ForEach( IteratorFunction, FinalizeFunction, arg, self.PLAYERUNITS )
|
||||
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -1164,7 +1161,7 @@ end
|
||||
-- @return #DATABASE self
|
||||
function DATABASE:ForEachClient( IteratorFunction, ... )
|
||||
self:F2( arg )
|
||||
|
||||
|
||||
self:ForEach( IteratorFunction, arg, self.CLIENTS )
|
||||
|
||||
return self
|
||||
@@ -1176,7 +1173,7 @@ end
|
||||
-- @return #DATABASE self
|
||||
function DATABASE:ForEachCargo( IteratorFunction, ... )
|
||||
self:F2( arg )
|
||||
|
||||
|
||||
self:ForEach( IteratorFunction, arg, self.CARGOS )
|
||||
|
||||
return self
|
||||
@@ -1252,8 +1249,44 @@ function DATABASE:SetPlayerSettings( PlayerName, Settings )
|
||||
self.PLAYERSETTINGS[PlayerName] = Settings
|
||||
end
|
||||
|
||||
--- Add a flight group to the data base.
|
||||
-- @param #DATABASE self
|
||||
-- @param Ops.FlightGroup#FLIGHTGROUP flightgroup
|
||||
function DATABASE:AddFlightGroup(flightgroup)
|
||||
self:I({NewFlightGroup=flightgroup.groupname})
|
||||
self.FLIGHTGROUPS[flightgroup.groupname]=flightgroup
|
||||
end
|
||||
|
||||
--- Get a flight group from the data base.
|
||||
-- @param #DATABASE self
|
||||
-- @param #string groupname Group name of the flight group. Can also be passed as GROUP object.
|
||||
-- @return Ops.FlightGroup#FLIGHTGROUP Flight group object.
|
||||
function DATABASE:GetFlightGroup(groupname)
|
||||
|
||||
-- Get group and group name.
|
||||
if type(groupname)=="string" then
|
||||
else
|
||||
groupname=groupname:GetName()
|
||||
end
|
||||
|
||||
return self.FLIGHTGROUPS[groupname]
|
||||
end
|
||||
|
||||
--- Add a flight control to the data base.
|
||||
-- @param #DATABASE self
|
||||
-- @param Ops.FlightControl#FLIGHTCONTROL flightcontrol
|
||||
function DATABASE:AddFlightControl(flightcontrol)
|
||||
self:F2( { flightcontrol } )
|
||||
self.FLIGHTCONTROLS[flightcontrol.airbasename]=flightcontrol
|
||||
end
|
||||
|
||||
--- Get a flight control object from the data base.
|
||||
-- @param #DATABASE self
|
||||
-- @param #string airbasename Name of the associated airbase.
|
||||
-- @return Ops.FlightControl#FLIGHTCONTROL The FLIGHTCONTROL object.s
|
||||
function DATABASE:GetFlightControl(airbasename)
|
||||
return self.FLIGHTCONTROLS[airbasename]
|
||||
end
|
||||
|
||||
--- @param #DATABASE self
|
||||
function DATABASE:_RegisterTemplates()
|
||||
@@ -1267,7 +1300,7 @@ function DATABASE:_RegisterTemplates()
|
||||
|
||||
if (CoalitionName == 'red' or CoalitionName == 'blue' or CoalitionName == 'neutrals') and type(coa_data) == 'table' then
|
||||
--self.Units[coa_name] = {}
|
||||
|
||||
|
||||
local CoalitionSide = coalition.side[string.upper(CoalitionName)]
|
||||
if CoalitionName=="red" then
|
||||
CoalitionSide=coalition.side.RED
|
||||
@@ -1300,10 +1333,10 @@ function DATABASE:_RegisterTemplates()
|
||||
|
||||
local CountryName = string.upper(cntry_data.name)
|
||||
local CountryID = cntry_data.id
|
||||
|
||||
|
||||
self.COUNTRY_ID[CountryName] = CountryID
|
||||
self.COUNTRY_NAME[CountryID] = CountryName
|
||||
|
||||
|
||||
--self.Units[coa_name][countryName] = {}
|
||||
--self.Units[coa_name][countryName]["countryId"] = cntry_data.id
|
||||
|
||||
@@ -1322,18 +1355,18 @@ function DATABASE:_RegisterTemplates()
|
||||
for group_num, Template in pairs(obj_type_data.group) do
|
||||
|
||||
if obj_type_name ~= "static" and Template and Template.units and type(Template.units) == 'table' then --making sure again- this is a valid group
|
||||
self:_RegisterGroupTemplate(
|
||||
Template,
|
||||
CoalitionSide,
|
||||
_DATABASECategory[string.lower(CategoryName)],
|
||||
CountryID
|
||||
self:_RegisterGroupTemplate(
|
||||
Template,
|
||||
CoalitionSide,
|
||||
_DATABASECategory[string.lower(CategoryName)],
|
||||
CountryID
|
||||
)
|
||||
else
|
||||
self:_RegisterStaticTemplate(
|
||||
Template,
|
||||
CoalitionSide,
|
||||
_DATABASECategory[string.lower(CategoryName)],
|
||||
CountryID
|
||||
self:_RegisterStaticTemplate(
|
||||
Template,
|
||||
CoalitionSide,
|
||||
_DATABASECategory[string.lower(CategoryName)],
|
||||
CountryID
|
||||
)
|
||||
end --if GroupTemplate and GroupTemplate.units then
|
||||
end --for group_num, GroupTemplate in pairs(obj_type_data.group) do
|
||||
@@ -1354,35 +1387,35 @@ end
|
||||
-- @param Core.Event#EVENTDATA Event
|
||||
function DATABASE:AccountHits( Event )
|
||||
self:F( { Event } )
|
||||
|
||||
|
||||
if Event.IniPlayerName ~= nil then -- It is a player that is hitting something
|
||||
self:T( "Hitting Something" )
|
||||
|
||||
|
||||
-- What is he hitting?
|
||||
if Event.TgtCategory then
|
||||
|
||||
|
||||
-- A target got hit
|
||||
self.HITS[Event.TgtUnitName] = self.HITS[Event.TgtUnitName] or {}
|
||||
local Hit = self.HITS[Event.TgtUnitName]
|
||||
|
||||
|
||||
Hit.Players = Hit.Players or {}
|
||||
Hit.Players[Event.IniPlayerName] = true
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- It is a weapon initiated by a player, that is hitting something
|
||||
-- This seems to occur only with scenery and static objects.
|
||||
if Event.WeaponPlayerName ~= nil then
|
||||
if Event.WeaponPlayerName ~= nil then
|
||||
self:T( "Hitting Scenery" )
|
||||
|
||||
|
||||
-- What is he hitting?
|
||||
if Event.TgtCategory then
|
||||
|
||||
|
||||
if Event.WeaponCoalition then -- A coalition object was hit, probably a static.
|
||||
-- A target got hit
|
||||
self.HITS[Event.TgtUnitName] = self.HITS[Event.TgtUnitName] or {}
|
||||
local Hit = self.HITS[Event.TgtUnitName]
|
||||
|
||||
|
||||
Hit.Players = Hit.Players or {}
|
||||
Hit.Players[Event.WeaponPlayerName] = true
|
||||
else -- A scenery object was hit.
|
||||
@@ -1390,13 +1423,13 @@ end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- Account the destroys.
|
||||
-- @param #DATABASE self
|
||||
-- @param Core.Event#EVENTDATA Event
|
||||
function DATABASE:AccountDestroys( Event )
|
||||
self:F( { Event } )
|
||||
|
||||
|
||||
local TargetUnit = nil
|
||||
local TargetGroup = nil
|
||||
local TargetUnitName = ""
|
||||
@@ -1408,26 +1441,26 @@ end
|
||||
local TargetUnitCoalition = nil
|
||||
local TargetUnitCategory = nil
|
||||
local TargetUnitType = nil
|
||||
|
||||
|
||||
if Event.IniDCSUnit then
|
||||
|
||||
|
||||
TargetUnit = Event.IniUnit
|
||||
TargetUnitName = Event.IniDCSUnitName
|
||||
TargetGroup = Event.IniDCSGroup
|
||||
TargetGroupName = Event.IniDCSGroupName
|
||||
TargetPlayerName = Event.IniPlayerName
|
||||
|
||||
|
||||
TargetCoalition = Event.IniCoalition
|
||||
--TargetCategory = TargetUnit:getCategory()
|
||||
--TargetCategory = TargetUnit:getDesc().category -- Workaround
|
||||
TargetCategory = Event.IniCategory
|
||||
TargetType = Event.IniTypeName
|
||||
|
||||
|
||||
TargetUnitType = TargetType
|
||||
|
||||
|
||||
self:T( { TargetUnitName, TargetGroupName, TargetPlayerName, TargetCoalition, TargetCategory, TargetType } )
|
||||
end
|
||||
|
||||
|
||||
local Destroyed = false
|
||||
|
||||
-- What is the player destroying?
|
||||
@@ -1436,8 +1469,3 @@ end
|
||||
self.DESTROYS[Event.IniUnitName] = true
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1001,6 +1001,16 @@ function EVENT:onEvent( Event )
|
||||
Event.IniCategory = Event.IniDCSUnit:getDesc().category
|
||||
Event.IniTypeName = Event.initiator:isExist() and Event.IniDCSUnit:getTypeName() or "SCENERY" -- TODO: Bug fix for 2.1!
|
||||
end
|
||||
|
||||
if Event.IniObjectCategory == Object.Category.BASE then
|
||||
Event.IniDCSUnit = Event.initiator
|
||||
Event.IniDCSUnitName = Event.IniDCSUnit:getName()
|
||||
Event.IniUnitName = Event.IniDCSUnitName
|
||||
Event.IniUnit = AIRBASE:FindByName(Event.IniDCSUnitName)
|
||||
Event.IniCoalition = Event.IniDCSUnit:getCoalition()
|
||||
Event.IniCategory = Event.IniDCSUnit:getDesc().category
|
||||
Event.IniTypeName = Event.IniDCSUnit:getTypeName()
|
||||
end
|
||||
end
|
||||
|
||||
if Event.target then
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
--
|
||||
--
|
||||
-- ### Author: **FlightControl**
|
||||
-- ### Contributions:
|
||||
-- ### Contributions: **funkyfranky**
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -81,6 +81,12 @@
|
||||
do -- FSM
|
||||
|
||||
--- @type FSM
|
||||
-- @field #string ClassName Name of the class.
|
||||
-- @field Core.Scheduler#SCHEDULER CallScheduler Call scheduler.
|
||||
-- @field #table options Options.
|
||||
-- @field #table subs Subs.
|
||||
-- @field #table Scores Scores.
|
||||
-- @field #string current Current state name.
|
||||
-- @extends Core.Base#BASE
|
||||
|
||||
|
||||
@@ -369,8 +375,7 @@ do -- FSM
|
||||
self._EventSchedules = {}
|
||||
|
||||
self.CallScheduler = SCHEDULER:New( self )
|
||||
|
||||
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -379,7 +384,6 @@ do -- FSM
|
||||
-- @param #FSM self
|
||||
-- @param #string State A string defining the start state.
|
||||
function FSM:SetStartState( State )
|
||||
|
||||
self._StartState = State
|
||||
self.current = State
|
||||
end
|
||||
@@ -389,7 +393,6 @@ do -- FSM
|
||||
-- @param #FSM self
|
||||
-- @return #string A string containing the start state.
|
||||
function FSM:GetStartState()
|
||||
|
||||
return self._StartState or {}
|
||||
end
|
||||
|
||||
@@ -406,6 +409,7 @@ do -- FSM
|
||||
Transition.Event = Event
|
||||
Transition.To = To
|
||||
|
||||
-- Debug message.
|
||||
self:T2( Transition )
|
||||
|
||||
self._Transitions[Transition] = Transition
|
||||
@@ -414,9 +418,9 @@ do -- FSM
|
||||
|
||||
|
||||
--- Returns a table of the transition rules defined within the FSM.
|
||||
-- @return #table
|
||||
function FSM:GetTransitions()
|
||||
|
||||
-- @param #FSM self
|
||||
-- @return #table Transitions.
|
||||
function FSM:GetTransitions()
|
||||
return self._Transitions or {}
|
||||
end
|
||||
|
||||
@@ -448,7 +452,8 @@ do -- FSM
|
||||
|
||||
|
||||
--- Returns a table of the SubFSM rules defined within the FSM.
|
||||
-- @return #table
|
||||
-- @param #FSM self
|
||||
-- @return #table Sub processes.
|
||||
function FSM:GetProcesses()
|
||||
|
||||
self:F( { Processes = self._Processes } )
|
||||
@@ -480,15 +485,17 @@ do -- FSM
|
||||
end
|
||||
|
||||
--- Adds an End state.
|
||||
function FSM:AddEndState( State )
|
||||
|
||||
-- @param #FSM self
|
||||
-- @param #string State The FSM state.
|
||||
function FSM:AddEndState( State )
|
||||
self._EndStates[State] = State
|
||||
self.endstates[State] = State
|
||||
end
|
||||
|
||||
--- Returns the End states.
|
||||
function FSM:GetEndStates()
|
||||
|
||||
-- @param #FSM self
|
||||
-- @return #table End states.
|
||||
function FSM:GetEndStates()
|
||||
return self._EndStates or {}
|
||||
end
|
||||
|
||||
@@ -532,18 +539,22 @@ do -- FSM
|
||||
end
|
||||
|
||||
--- Returns a table with the scores defined.
|
||||
function FSM:GetScores()
|
||||
|
||||
-- @param #FSM self
|
||||
-- @param #table Scores.
|
||||
function FSM:GetScores()
|
||||
return self._Scores or {}
|
||||
end
|
||||
|
||||
--- Returns a table with the Subs defined.
|
||||
function FSM:GetSubs()
|
||||
|
||||
-- @param #FSM self
|
||||
-- @return #table Sub processes.
|
||||
function FSM:GetSubs()
|
||||
return self.options.subs
|
||||
end
|
||||
|
||||
|
||||
--- Load call backs.
|
||||
-- @param #FSM self
|
||||
-- @param #table CallBackTable Table of call backs.
|
||||
function FSM:LoadCallBacks( CallBackTable )
|
||||
|
||||
for name, callback in pairs( CallBackTable or {} ) do
|
||||
@@ -551,21 +562,34 @@ do -- FSM
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- Event map.
|
||||
-- @param #FSM self
|
||||
-- @param #table Events Events.
|
||||
-- @param #table EventStructure Event structure.
|
||||
function FSM:_eventmap( Events, EventStructure )
|
||||
|
||||
local Event = EventStructure.Event
|
||||
local __Event = "__" .. EventStructure.Event
|
||||
|
||||
self[Event] = self[Event] or self:_create_transition(Event)
|
||||
self[__Event] = self[__Event] or self:_delayed_transition(Event)
|
||||
|
||||
-- Debug message.
|
||||
self:T2( "Added methods: " .. Event .. ", " .. __Event )
|
||||
|
||||
Events[Event] = self.Events[Event] or { map = {} }
|
||||
self:_add_to_map( Events[Event].map, EventStructure )
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- Sub maps.
|
||||
-- @param #FSM self
|
||||
-- @param #table subs Subs.
|
||||
-- @param #table sub Sub.
|
||||
-- @param #string name Name.
|
||||
function FSM:_submap( subs, sub, name )
|
||||
--self:F( { sub = sub, name = name } )
|
||||
|
||||
subs[sub.From] = subs[sub.From] or {}
|
||||
subs[sub.From][sub.Event] = subs[sub.From][sub.Event] or {}
|
||||
|
||||
@@ -578,22 +602,24 @@ do -- FSM
|
||||
subs[sub.From][sub.Event][sub].ReturnEvents = sub.ReturnEvents or {} -- these events need to be given to find the correct continue event ... if none given, the processing will stop.
|
||||
subs[sub.From][sub.Event][sub].name = name
|
||||
subs[sub.From][sub.Event][sub].fsmparent = self
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- Call handler.
|
||||
-- @param #FSM self
|
||||
-- @param #string step Step "onafter", "onbefore", "onenter", "onleave".
|
||||
-- @param #string trigger Trigger.
|
||||
-- @param #table params Parameters.
|
||||
-- @param #string EventName Event name.
|
||||
-- @return Value.
|
||||
function FSM:_call_handler( step, trigger, params, EventName )
|
||||
--env.info(string.format("FF T=%.3f _call_handler step=%s, trigger=%s, event=%s", timer.getTime(), step, trigger, EventName))
|
||||
|
||||
local handler = step .. trigger
|
||||
local ErrorHandler = function( errmsg )
|
||||
|
||||
env.info( "Error in SCHEDULER function:" .. errmsg )
|
||||
if BASE.Debug ~= nil then
|
||||
env.info( BASE.Debug.traceback() )
|
||||
end
|
||||
|
||||
return errmsg
|
||||
end
|
||||
|
||||
if self[handler] then
|
||||
|
||||
--[[
|
||||
if step == "onafter" or step == "OnAfter" then
|
||||
self:T( ":::>" .. step .. params[2] .. " : " .. params[1] .. " >> " .. params[2] .. ">" .. step .. params[2] .. "()" .. " >> " .. params[3] )
|
||||
elseif step == "onbefore" or step == "OnBefore" then
|
||||
@@ -604,14 +630,33 @@ do -- FSM
|
||||
self:T( ":::>" .. step .. params[1] .. " : " .. params[1] .. ">" .. step .. params[1] .. "()" .. " >> " .. params[2] .. " >> " .. params[3] )
|
||||
else
|
||||
self:T( ":::>" .. step .. " : " .. params[1] .. " >> " .. params[2] .. " >> " .. params[3] )
|
||||
end
|
||||
end
|
||||
]]
|
||||
|
||||
self._EventSchedules[EventName] = nil
|
||||
local Result, Value = xpcall( function() return self[handler]( self, unpack( params ) ) end, ErrorHandler )
|
||||
return Value
|
||||
|
||||
-- Error handler.
|
||||
local ErrorHandler = function( errmsg )
|
||||
env.info( "Error in SCHEDULER function:" .. errmsg )
|
||||
if BASE.Debug ~= nil then
|
||||
env.info( BASE.Debug.traceback() )
|
||||
end
|
||||
return errmsg
|
||||
end
|
||||
|
||||
--return self[handler](self, unpack( params ))
|
||||
|
||||
-- Protected call.
|
||||
local Result, Value = xpcall( function() return self[handler]( self, unpack( params ) ) end, ErrorHandler )
|
||||
return Value
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- @param #FSM self
|
||||
--- Handler.
|
||||
-- @param #FSM self
|
||||
-- @param #string EventName Event name.
|
||||
-- @param ... Arguments.
|
||||
function FSM._handler( self, EventName, ... )
|
||||
|
||||
local Can, To = self:can( EventName )
|
||||
@@ -621,7 +666,11 @@ do -- FSM
|
||||
end
|
||||
|
||||
if Can then
|
||||
|
||||
-- From state.
|
||||
local From = self.current
|
||||
|
||||
-- Parameters.
|
||||
local Params = { From, EventName, To, ... }
|
||||
|
||||
|
||||
@@ -632,8 +681,8 @@ do -- FSM
|
||||
self["onafter".. EventName] or
|
||||
self["OnAfter".. EventName] or
|
||||
self["onenter".. To] or
|
||||
self["OnEnter".. To]
|
||||
then
|
||||
self["OnEnter".. To] then
|
||||
|
||||
if self:_call_handler( "onbefore", EventName, Params, EventName ) == false then
|
||||
self:T( "*** FSM *** Cancel" .. " *** " .. self.current .. " --> " .. EventName .. " --> " .. To .. " *** onbefore" .. EventName )
|
||||
return false
|
||||
@@ -653,8 +702,11 @@ do -- FSM
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
local ClassName = self:GetClassName()
|
||||
|
||||
if ClassName == "FSM" then
|
||||
self:T( "*** FSM *** Transit *** " .. self.current .. " --> " .. EventName .. " --> " .. To )
|
||||
end
|
||||
@@ -672,46 +724,56 @@ do -- FSM
|
||||
end
|
||||
end
|
||||
|
||||
-- New current state.
|
||||
self.current = To
|
||||
|
||||
local execute = true
|
||||
|
||||
local subtable = self:_gosub( From, EventName )
|
||||
|
||||
for _, sub in pairs( subtable ) do
|
||||
|
||||
--if sub.nextevent then
|
||||
-- self:F2( "nextevent = " .. sub.nextevent )
|
||||
-- self[sub.nextevent]( self )
|
||||
--end
|
||||
|
||||
self:T( "*** FSM *** Sub *** " .. sub.StartEvent )
|
||||
|
||||
sub.fsm.fsmparent = self
|
||||
sub.fsm.ReturnEvents = sub.ReturnEvents
|
||||
sub.fsm[sub.StartEvent]( sub.fsm )
|
||||
|
||||
execute = false
|
||||
end
|
||||
|
||||
local fsmparent, Event = self:_isendstate( To )
|
||||
|
||||
if fsmparent and Event then
|
||||
|
||||
self:T( "*** FSM *** End *** " .. Event )
|
||||
|
||||
self:_call_handler("onenter", To, Params, EventName )
|
||||
self:_call_handler("OnEnter", To, Params, EventName )
|
||||
self:_call_handler("onafter", EventName, Params, EventName )
|
||||
self:_call_handler("OnAfter", EventName, Params, EventName )
|
||||
self:_call_handler("onstate", "change", Params, EventName )
|
||||
|
||||
fsmparent[Event]( fsmparent )
|
||||
|
||||
execute = false
|
||||
end
|
||||
|
||||
if execute then
|
||||
self:_call_handler("onafter", EventName, Params, EventName )
|
||||
self:_call_handler("OnAfter", EventName, Params, EventName )
|
||||
|
||||
-- only execute the call if the From state is not equal to the To state! Otherwise this function should never execute!
|
||||
--if from ~= to then
|
||||
self:_call_handler("onenter", To, Params, EventName )
|
||||
self:_call_handler("OnEnter", To, Params, EventName )
|
||||
--end
|
||||
self:_call_handler("onafter", EventName, Params, EventName )
|
||||
self:_call_handler("OnAfter", EventName, Params, EventName )
|
||||
|
||||
self:_call_handler("onenter", To, Params, EventName )
|
||||
self:_call_handler("OnEnter", To, Params, EventName )
|
||||
|
||||
self:_call_handler("onstate", "change", Params, EventName )
|
||||
|
||||
end
|
||||
else
|
||||
self:T( "*** FSM *** NO Transition *** " .. self.current .. " --> " .. EventName .. " --> ? " )
|
||||
@@ -719,37 +781,68 @@ do -- FSM
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
--- Delayed transition.
|
||||
-- @param #FSM self
|
||||
-- @param #string EventName Event name.
|
||||
-- @return #function Function.
|
||||
function FSM:_delayed_transition( EventName )
|
||||
|
||||
return function( self, DelaySeconds, ... )
|
||||
|
||||
-- Debug.
|
||||
self:T2( "Delayed Event: " .. EventName )
|
||||
|
||||
local CallID = 0
|
||||
if DelaySeconds ~= nil then
|
||||
|
||||
if DelaySeconds < 0 then -- Only call the event ONCE!
|
||||
|
||||
DelaySeconds = math.abs( DelaySeconds )
|
||||
if not self._EventSchedules[EventName] then
|
||||
|
||||
if not self._EventSchedules[EventName] then
|
||||
|
||||
-- Call _handler.
|
||||
CallID = self.CallScheduler:Schedule( self, self._handler, { EventName, ... }, DelaySeconds or 1, nil, nil, nil, 4, true )
|
||||
|
||||
-- Set call ID.
|
||||
self._EventSchedules[EventName] = CallID
|
||||
|
||||
-- Debug output.
|
||||
self:T2(string.format("NEGATIVE Event %s delayed by %.1f sec SCHEDULED with CallID=%s", EventName, DelaySeconds, tostring(CallID)))
|
||||
else
|
||||
self:T2(string.format("NEGATIVE Event %s delayed by %.1f sec CANCELLED as we already have such an event in the queue.", EventName, DelaySeconds))
|
||||
-- reschedule
|
||||
end
|
||||
else
|
||||
|
||||
CallID = self.CallScheduler:Schedule( self, self._handler, { EventName, ... }, DelaySeconds or 1, nil, nil, nil, 4, true )
|
||||
|
||||
self:T2(string.format("Event %s delayed by %.1f sec SCHEDULED with CallID=%s", EventName, DelaySeconds, tostring(CallID)))
|
||||
end
|
||||
else
|
||||
error( "FSM: An asynchronous event trigger requires a DelaySeconds parameter!!! This can be positive or negative! Sorry, but will not process this." )
|
||||
end
|
||||
|
||||
-- Debug.
|
||||
self:T2( { CallID = CallID } )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- Create transition.
|
||||
-- @param #FSM self
|
||||
-- @param #string EventName Event name.
|
||||
-- @return #function Function.
|
||||
function FSM:_create_transition( EventName )
|
||||
return function( self, ... ) return self._handler( self, EventName , ... ) end
|
||||
end
|
||||
|
||||
|
||||
--- Go sub.
|
||||
-- @param #FSM self
|
||||
-- @param #string ParentFrom Parent from state.
|
||||
-- @param #string ParentEvent Parent event name.
|
||||
-- @return #table Subs.
|
||||
function FSM:_gosub( ParentFrom, ParentEvent )
|
||||
local fsmtable = {}
|
||||
if self.subs[ParentFrom] and self.subs[ParentFrom][ParentEvent] then
|
||||
@@ -759,9 +852,15 @@ do -- FSM
|
||||
return {}
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- Is end state.
|
||||
-- @param #FSM self
|
||||
-- @param #string Current Current state name.
|
||||
-- @return #table FSM parent.
|
||||
-- @return #string Event name.
|
||||
function FSM:_isendstate( Current )
|
||||
local FSMParent = self.fsmparent
|
||||
|
||||
if FSMParent and self.endstates[Current] then
|
||||
--self:T( { state = Current, endstates = self.endstates, endstate = self.endstates[Current] } )
|
||||
FSMParent.current = Current
|
||||
@@ -778,9 +877,14 @@ do -- FSM
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
--- Add to map.
|
||||
-- @param #FSM self
|
||||
-- @param #table Map Map.
|
||||
-- @param #table Event Event table.
|
||||
function FSM:_add_to_map( Map, Event )
|
||||
self:F3( { Map, Event } )
|
||||
|
||||
if type(Event.From) == 'string' then
|
||||
Map[Event.From] = Event.To
|
||||
else
|
||||
@@ -788,33 +892,60 @@ do -- FSM
|
||||
Map[From] = Event.To
|
||||
end
|
||||
end
|
||||
|
||||
self:T3( { Map, Event } )
|
||||
end
|
||||
|
||||
|
||||
--- Get current state.
|
||||
-- @param #FSM self
|
||||
-- @return #string Current FSM state.
|
||||
function FSM:GetState()
|
||||
return self.current
|
||||
end
|
||||
|
||||
|
||||
--- Get current state.
|
||||
-- @param #FSM self
|
||||
-- @return #string Current FSM state.
|
||||
function FSM:GetCurrentState()
|
||||
return self.current
|
||||
end
|
||||
|
||||
|
||||
--- Check if FSM is in state.
|
||||
-- @param #FSM self
|
||||
-- @param #string State State name.
|
||||
-- @param #boolean If true, FSM is in this state.
|
||||
function FSM:Is( State )
|
||||
return self.current == State
|
||||
end
|
||||
|
||||
|
||||
--- Check if FSM is in state.
|
||||
-- @param #FSM self
|
||||
-- @param #string State State name.
|
||||
-- @param #boolean If true, FSM is in this state.
|
||||
function FSM:is(state)
|
||||
return self.current == state
|
||||
end
|
||||
|
||||
|
||||
--- Check if can do an event.
|
||||
-- @param #FSM self
|
||||
-- @param #string e Event name.
|
||||
-- @return #boolean If true, FSM can do the event.
|
||||
-- @return #string To state.
|
||||
function FSM:can(e)
|
||||
|
||||
local Event = self.Events[e]
|
||||
self:F3( { self.current, Event } )
|
||||
|
||||
--self:F3( { self.current, Event } )
|
||||
|
||||
local To = Event and Event.map[self.current] or Event.map['*']
|
||||
|
||||
return To ~= nil, To
|
||||
end
|
||||
|
||||
|
||||
--- Check if cannot do an event.
|
||||
-- @param #FSM self
|
||||
-- @param #string e Event name.
|
||||
-- @return #boolean If true, FSM cannot do the event.
|
||||
function FSM:cannot(e)
|
||||
return not self:can(e)
|
||||
end
|
||||
|
||||
@@ -175,10 +175,6 @@ do -- COORDINATE
|
||||
-- In order to use the most optimal road system to transport vehicles, the method @{#COORDINATE.GetPathOnRoad}() will calculate
|
||||
-- the most optimal path following the road between two coordinates.
|
||||
--
|
||||
--
|
||||
--
|
||||
--
|
||||
--
|
||||
-- ## 8) Metric or imperial system
|
||||
--
|
||||
-- * @{#COORDINATE.IsMetric}(): Returns if the 3D point is Metric or Nautical Miles.
|
||||
@@ -204,23 +200,23 @@ do -- COORDINATE
|
||||
|
||||
--- @field COORDINATE.WaypointAction
|
||||
COORDINATE.WaypointAction = {
|
||||
TurningPoint = "Turning Point",
|
||||
FlyoverPoint = "Fly Over Point",
|
||||
FromParkingArea = "From Parking Area",
|
||||
TurningPoint = "Turning Point",
|
||||
FlyoverPoint = "Fly Over Point",
|
||||
FromParkingArea = "From Parking Area",
|
||||
FromParkingAreaHot = "From Parking Area Hot",
|
||||
FromRunway = "From Runway",
|
||||
Landing = "Landing",
|
||||
LandingReFuAr = "LandingReFuAr",
|
||||
FromRunway = "From Runway",
|
||||
Landing = "Landing",
|
||||
LandingReFuAr = "LandingReFuAr",
|
||||
}
|
||||
|
||||
--- @field COORDINATE.WaypointType
|
||||
COORDINATE.WaypointType = {
|
||||
TakeOffParking = "TakeOffParking",
|
||||
TakeOffParking = "TakeOffParking",
|
||||
TakeOffParkingHot = "TakeOffParkingHot",
|
||||
TakeOff = "TakeOffParkingHot",
|
||||
TurningPoint = "Turning Point",
|
||||
Land = "Land",
|
||||
LandingReFuAr = "LandingReFuAr",
|
||||
TakeOff = "TakeOffParkingHot",
|
||||
TurningPoint = "Turning Point",
|
||||
Land = "Land",
|
||||
LandingReFuAr = "LandingReFuAr",
|
||||
}
|
||||
|
||||
|
||||
@@ -232,6 +228,7 @@ do -- COORDINATE
|
||||
-- @return #COORDINATE
|
||||
function COORDINATE:New( x, y, z )
|
||||
|
||||
--env.info("FF COORDINATE New")
|
||||
local self = BASE:Inherit( self, BASE:New() ) -- #COORDINATE
|
||||
self.x = x
|
||||
self.y = y
|
||||
@@ -303,6 +300,45 @@ do -- COORDINATE
|
||||
return { x = self.x, y = self.z }
|
||||
end
|
||||
|
||||
--- Update x,y,z coordinates from a given 3D vector.
|
||||
-- @param #COORDINATE self
|
||||
-- @param DCS#Vec3 Vec3 The 3D vector with x,y,z components.
|
||||
-- @return #COORDINATE The modified COORDINATE itself.
|
||||
function COORDINATE:UpdateFromVec3(Vec3)
|
||||
|
||||
self.x=Vec3.x
|
||||
self.y=Vec3.y
|
||||
self.z=Vec3.z
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Update x,y,z coordinates from another given COORDINATE.
|
||||
-- @param #COORDINATE self
|
||||
-- @param #COORDINATE Coordinate The coordinate with the new x,y,z positions.
|
||||
-- @return #COORDINATE The modified COORDINATE itself.
|
||||
function COORDINATE:UpdateFromCoordinate(Coordinate)
|
||||
|
||||
self.x=Coordinate.x
|
||||
self.y=Coordinate.y
|
||||
self.z=Coordinate.z
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Update x and z coordinates from a given 2D vector.
|
||||
-- @param #COORDINATE self
|
||||
-- @param DCS#Vec2 Vec2 The 2D vector with x,y components. x is overwriting COORDINATE.x while y is overwriting COORDINATE.z.
|
||||
-- @return #COORDINATE The modified COORDINATE itself.
|
||||
function COORDINATE:UpdateFromVec2(Vec2)
|
||||
|
||||
self.x=Vec2.x
|
||||
self.z=Vec2.y
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Returns the coordinate from the latitude and longitude given in decimal degrees.
|
||||
-- @param #COORDINATE self
|
||||
-- @param #number latitude Latitude in decimal degrees.
|
||||
@@ -506,19 +542,28 @@ do -- COORDINATE
|
||||
-- @param DCS#Distance Distance The Distance to be added in meters.
|
||||
-- @param DCS#Angle Angle The Angle in degrees. Defaults to 0 if not specified (nil).
|
||||
-- @param #boolean Keepalt If true, keep altitude of original coordinate. Default is that the new coordinate is created at the translated land height.
|
||||
-- @return Core.Point#COORDINATE The new calculated COORDINATE.
|
||||
function COORDINATE:Translate( Distance, Angle, Keepalt )
|
||||
local SX = self.x
|
||||
local SY = self.z
|
||||
local Radians = (Angle or 0) / 180 * math.pi
|
||||
local TX = Distance * math.cos( Radians ) + SX
|
||||
local TY = Distance * math.sin( Radians ) + SY
|
||||
|
||||
if Keepalt then
|
||||
return COORDINATE:NewFromVec3( { x = TX, y=self.y, z = TY } )
|
||||
-- @param #boolean Overwrite If true, overwrite the original COORDINATE with the translated one. Otherwise, create a new COODINATE.
|
||||
-- @return #COORDINATE The new calculated COORDINATE.
|
||||
function COORDINATE:Translate( Distance, Angle, Keepalt, Overwrite )
|
||||
|
||||
-- Angle in rad.
|
||||
local alpha = math.rad((Angle or 0))
|
||||
|
||||
local x = Distance * math.cos(alpha) + self.x -- New x
|
||||
local z = Distance * math.sin(alpha) + self.z -- New z
|
||||
|
||||
local y=Keepalt and self.y or land.getHeight({x=x, y=z})
|
||||
|
||||
if Overwrite then
|
||||
self.x=x
|
||||
self.y=y
|
||||
self.z=z
|
||||
return self
|
||||
else
|
||||
return COORDINATE:NewFromVec2( { x = TX, y = TY } )
|
||||
--env.info("FF translate with NEW coordinate T="..timer.getTime())
|
||||
return COORDINATE:New(x, y, z)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- Rotate coordinate in 2D (x,z) space.
|
||||
@@ -721,12 +766,18 @@ do -- COORDINATE
|
||||
|
||||
--- Return the 2D distance in meters between the target COORDINATE and the COORDINATE.
|
||||
-- @param #COORDINATE self
|
||||
-- @param #COORDINATE TargetCoordinate The target COORDINATE.
|
||||
-- @param #COORDINATE TargetCoordinate The target COORDINATE. Can also be a DCS#Vec3.
|
||||
-- @return DCS#Distance Distance The distance in meters.
|
||||
function COORDINATE:Get2DDistance( TargetCoordinate )
|
||||
local TargetVec3 = TargetCoordinate:GetVec3()
|
||||
local SourceVec3 = self:GetVec3()
|
||||
return ( ( TargetVec3.x - SourceVec3.x ) ^ 2 + ( TargetVec3.z - SourceVec3.z ) ^ 2 ) ^ 0.5
|
||||
|
||||
local a={x=TargetCoordinate.x-self.x, y=0, z=TargetCoordinate.z-self.z}
|
||||
|
||||
return UTILS.VecNorm(a)
|
||||
|
||||
--local TargetVec3 = TargetCoordinate:GetVec3()
|
||||
--local SourceVec3 = self:GetVec3()
|
||||
|
||||
--return ( ( TargetVec3.x - SourceVec3.x ) ^ 2 + ( TargetVec3.z - SourceVec3.z ) ^ 2 ) ^ 0.5
|
||||
end
|
||||
|
||||
--- Returns the temperature in Degrees Celsius.
|
||||
@@ -1086,23 +1137,6 @@ do -- COORDINATE
|
||||
return self
|
||||
end
|
||||
|
||||
--- Add a Distance in meters from the COORDINATE horizontal plane, with the given angle, and calculate the new COORDINATE.
|
||||
-- @param #COORDINATE self
|
||||
-- @param DCS#Distance Distance The Distance to be added in meters.
|
||||
-- @param DCS#Angle Angle The Angle in degrees.
|
||||
-- @return #COORDINATE The new calculated COORDINATE.
|
||||
function COORDINATE:Translate( Distance, Angle )
|
||||
local SX = self.x
|
||||
local SZ = self.z
|
||||
local Radians = Angle / 180 * math.pi
|
||||
local TX = Distance * math.cos( Radians ) + SX
|
||||
local TZ = Distance * math.sin( Radians ) + SZ
|
||||
|
||||
return COORDINATE:New( TX, self.y, TZ )
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Build an air type route point.
|
||||
-- @param #COORDINATE self
|
||||
-- @param #COORDINATE.WaypointAltType AltType The altitude type.
|
||||
@@ -1290,8 +1324,10 @@ do -- COORDINATE
|
||||
RoutePoint.x = self.x
|
||||
RoutePoint.y = self.z
|
||||
|
||||
RoutePoint.alt = self:GetLandHeight()+1 -- self.y
|
||||
RoutePoint.alt = self:GetLandHeight()+1
|
||||
RoutePoint.alt_type = COORDINATE.WaypointAltType.BARO
|
||||
|
||||
RoutePoint.type = "Turning Point"
|
||||
|
||||
RoutePoint.action = Formation or "Off Road"
|
||||
RoutePoint.formation_template=""
|
||||
@@ -1351,7 +1387,7 @@ do -- COORDINATE
|
||||
-- @param #number Coalition (Optional) Coalition of the airbase.
|
||||
-- @return Wrapper.Airbase#AIRBASE Closest Airbase to the given coordinate.
|
||||
-- @return #number Distance to the closest airbase in meters.
|
||||
function COORDINATE:GetClosestAirbase(Category, Coalition)
|
||||
function COORDINATE:GetClosestAirbase2(Category, Coalition)
|
||||
|
||||
-- Get all airbases of the map.
|
||||
local airbases=AIRBASE.GetAllAirbases(Coalition)
|
||||
@@ -1384,6 +1420,36 @@ do -- COORDINATE
|
||||
|
||||
return closest,distmin
|
||||
end
|
||||
|
||||
--- Gets the nearest airbase with respect to the current coordinates.
|
||||
-- @param #COORDINATE self
|
||||
-- @param #number Category (Optional) Category of the airbase. Enumerator of @{Wrapper.Airbase#AIRBASE.Category}.
|
||||
-- @param #number Coalition (Optional) Coalition of the airbase.
|
||||
-- @return Wrapper.Airbase#AIRBASE Closest Airbase to the given coordinate.
|
||||
-- @return #number Distance to the closest airbase in meters.
|
||||
function COORDINATE:GetClosestAirbase(Category, Coalition)
|
||||
|
||||
local a=self:GetVec3()
|
||||
|
||||
local distmin=math.huge
|
||||
local airbase=nil
|
||||
for DCSairbaseID, DCSairbase in pairs(world.getAirbases(Coalition)) do
|
||||
local b=DCSairbase:getPoint()
|
||||
|
||||
local c=UTILS.VecSubstract(a,b)
|
||||
local dist=UTILS.VecNorm(c)
|
||||
|
||||
--env.info(string.format("Airbase %s dist=%d category=%d", DCSairbase:getName(), dist, DCSairbase:getCategory()))
|
||||
|
||||
if dist<distmin and (Category==nil or Category==DCSairbase:getDesc().category) then
|
||||
distmin=dist
|
||||
airbase=DCSairbase
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return AIRBASE:Find(airbase)
|
||||
end
|
||||
|
||||
--- Gets the nearest parking spot.
|
||||
-- @param #COORDINATE self
|
||||
@@ -1526,27 +1592,8 @@ do -- COORDINATE
|
||||
local coord=COORDINATE:NewFromVec2(_vec2)
|
||||
|
||||
Path[#Path+1]=coord
|
||||
|
||||
if MarkPath then
|
||||
coord:MarkToAll(string.format("Path segment %d.", _i))
|
||||
end
|
||||
if SmokePath then
|
||||
coord:SmokeGreen()
|
||||
end
|
||||
end
|
||||
|
||||
-- Mark/smoke endpoints
|
||||
if IncludeEndpoints then
|
||||
if MarkPath then
|
||||
COORDINATE:NewFromVec2(path[1]):MarkToAll("Path Initinal Point")
|
||||
COORDINATE:NewFromVec2(path[1]):MarkToAll("Path Final Point")
|
||||
end
|
||||
if SmokePath then
|
||||
COORDINATE:NewFromVec2(path[1]):SmokeBlue()
|
||||
COORDINATE:NewFromVec2(path[#path]):SmokeBlue()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
else
|
||||
self:E("Path is nil. No valid path on road could be found.")
|
||||
GotPath=false
|
||||
@@ -1557,6 +1604,23 @@ do -- COORDINATE
|
||||
Path[#Path+1]=ToCoord
|
||||
end
|
||||
|
||||
-- Mark or smoke.
|
||||
if MarkPath or SmokePath then
|
||||
for i,c in pairs(Path) do
|
||||
local coord=c --#COORDINATE
|
||||
if MarkPath then
|
||||
coord:MarkToAll(string.format("Path segment %d", i))
|
||||
end
|
||||
if SmokePath then
|
||||
if i==1 or i==#Path then
|
||||
coord:SmokeBlue()
|
||||
else
|
||||
coord:SmokeGreen()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Sum up distances.
|
||||
if #Path>=2 then
|
||||
for i=1,#Path-1 do
|
||||
@@ -1564,7 +1628,7 @@ do -- COORDINATE
|
||||
end
|
||||
else
|
||||
-- There are cases where no path on road can be found.
|
||||
return nil,nil
|
||||
return nil,nil,false
|
||||
end
|
||||
|
||||
return Path, Way, GotPath
|
||||
@@ -1921,15 +1985,18 @@ do -- COORDINATE
|
||||
--- Returns if a Coordinate has Line of Sight (LOS) with the ToCoordinate.
|
||||
-- @param #COORDINATE self
|
||||
-- @param #COORDINATE ToCoordinate
|
||||
-- @param #number Offset Height offset in meters. Default 2 m.
|
||||
-- @return #boolean true If the ToCoordinate has LOS with the Coordinate, otherwise false.
|
||||
function COORDINATE:IsLOS( ToCoordinate )
|
||||
function COORDINATE:IsLOS( ToCoordinate, Offset )
|
||||
|
||||
Offset=Offset or 2
|
||||
|
||||
-- Measurement of visibility should not be from the ground, so Adding a hypotethical 2 meters to each Coordinate.
|
||||
local FromVec3 = self:GetVec3()
|
||||
FromVec3.y = FromVec3.y + 2
|
||||
FromVec3.y = FromVec3.y + Offset
|
||||
|
||||
local ToVec3 = ToCoordinate:GetVec3()
|
||||
ToVec3.y = ToVec3.y + 2
|
||||
ToVec3.y = ToVec3.y + Offset
|
||||
|
||||
local IsLOS = land.isVisible( FromVec3, ToVec3 )
|
||||
|
||||
|
||||
@@ -429,7 +429,7 @@ BEACON = {
|
||||
-- @field #number VOR
|
||||
-- @field #number DME
|
||||
-- @field #number VOR_DME
|
||||
-- @field #number TACAN
|
||||
-- @field #number TACAN TACtical Air Navigation system.
|
||||
-- @field #number VORTAC
|
||||
-- @field #number RSBN
|
||||
-- @field #number BROADCAST_STATION
|
||||
@@ -440,45 +440,74 @@ BEACON = {
|
||||
-- @field #number ILS_NEAR_HOMER
|
||||
-- @field #number ILS_LOCALIZER
|
||||
-- @field #number ILS_GLIDESLOPE
|
||||
-- @field #number PRMG_LOCALIZER
|
||||
-- @field #number PRMG_GLIDESLOPE
|
||||
-- @field #number ICLS Same as ICLS glideslope.
|
||||
-- @field #number ICLS_LOCALIZER
|
||||
-- @field #number ICLS_GLIDESLOPE
|
||||
-- @field #number NAUTICAL_HOMER
|
||||
-- @field #number ICLS
|
||||
BEACON.Type={
|
||||
NULL = 0,
|
||||
VOR = 1,
|
||||
DME = 2,
|
||||
VOR_DME = 3,
|
||||
TACAN = 4,
|
||||
VORTAC = 5,
|
||||
RSBN = 32,
|
||||
BROADCAST_STATION = 1024,
|
||||
HOMER = 8,
|
||||
AIRPORT_HOMER = 4104,
|
||||
NULL = 0,
|
||||
VOR = 1,
|
||||
DME = 2,
|
||||
VOR_DME = 3,
|
||||
TACAN = 4,
|
||||
VORTAC = 5,
|
||||
RSBN = 128,
|
||||
BROADCAST_STATION = 1024,
|
||||
HOMER = 8,
|
||||
AIRPORT_HOMER = 4104,
|
||||
AIRPORT_HOMER_WITH_MARKER = 4136,
|
||||
ILS_FAR_HOMER = 16408,
|
||||
ILS_NEAR_HOMER = 16456,
|
||||
ILS_LOCALIZER = 16640,
|
||||
ILS_GLIDESLOPE = 16896,
|
||||
NAUTICAL_HOMER = 32776,
|
||||
ICLS = 131584,
|
||||
ILS_FAR_HOMER = 16408,
|
||||
ILS_NEAR_HOMER = 16424,
|
||||
ILS_LOCALIZER = 16640,
|
||||
ILS_GLIDESLOPE = 16896,
|
||||
PRMG_LOCALIZER = 33024,
|
||||
PRMG_GLIDESLOPE = 33280,
|
||||
ICLS = 131584, --leaving this in here but it is the same as ICLS_GLIDESLOPE
|
||||
ICLS_LOCALIZER = 131328,
|
||||
ICLS_GLIDESLOPE = 131584,
|
||||
NAUTICAL_HOMER = 65536,
|
||||
|
||||
}
|
||||
|
||||
--- Beacon systems supported by DCS. https://wiki.hoggitworld.com/view/DCS_command_activateBeacon
|
||||
-- @type BEACON.System
|
||||
-- @field #number PAR_10
|
||||
-- @field #number RSBN_5
|
||||
-- @field #number TACAN
|
||||
-- @field #number TACAN_TANKER
|
||||
-- @field #number ILS_LOCALIZER (This is the one to be used for AA TACAN Tanker!)
|
||||
-- @field #number ILS_GLIDESLOPE
|
||||
-- @field #number BROADCAST_STATION
|
||||
-- @field #number PAR_10 ?
|
||||
-- @field #number RSBN_5 Russian VOR/DME system.
|
||||
-- @field #number TACAN TACtical Air Navigation system on ground.
|
||||
-- @field #number TACAN_TANKER_X TACtical Air Navigation system for tankers on X band.
|
||||
-- @field #number TACAN_TANKER_Y TACtical Air Navigation system for tankers on Y band.
|
||||
-- @field #number VOR Very High Frequency Omni-Directional Range
|
||||
-- @field #number ILS_LOCALIZER ILS localizer
|
||||
-- @field #number ILS_GLIDESLOPE ILS glideslope.
|
||||
-- @field #number PRGM_LOCALIZER PRGM localizer.
|
||||
-- @field #number PRGM_GLIDESLOPE PRGM glideslope.
|
||||
-- @field #number BROADCAST_STATION Broadcast station.
|
||||
-- @field #number VORTAC Radio-based navigational aid for aircraft pilots consisting of a co-located VHF omnidirectional range (VOR) beacon and a tactical air navigation system (TACAN) beacon.
|
||||
-- @field #number TACAN_AA_MODE_X TACtical Air Navigation for aircraft on X band.
|
||||
-- @field #number TACAN_AA_MODE_Y TACtical Air Navigation for aircraft on Y band.
|
||||
-- @field #number VORDME Radio beacon that combines a VHF omnidirectional range (VOR) with a distance measuring equipment (DME).
|
||||
-- @field #number ICLS_LOCALIZER Carrier landing system.
|
||||
-- @field #number ICLS_GLIDESLOPE Carrier landing system.
|
||||
BEACON.System={
|
||||
PAR_10 = 1,
|
||||
RSBN_5 = 2,
|
||||
TACAN = 3,
|
||||
TACAN_TANKER = 4,
|
||||
ILS_LOCALIZER = 5,
|
||||
ILS_GLIDESLOPE = 6,
|
||||
BROADCAST_STATION = 7,
|
||||
PAR_10 = 1,
|
||||
RSBN_5 = 2,
|
||||
TACAN = 3,
|
||||
TACAN_TANKER_X = 4,
|
||||
TACAN_TANKER_Y = 5,
|
||||
VOR = 6,
|
||||
ILS_LOCALIZER = 7,
|
||||
ILS_GLIDESLOPE = 8,
|
||||
PRMG_LOCALIZER = 9,
|
||||
PRMG_GLIDESLOPE = 10,
|
||||
BROADCAST_STATION = 11,
|
||||
VORTAC = 12,
|
||||
TACAN_AA_MODE_X = 13,
|
||||
TACAN_AA_MODE_Y = 14,
|
||||
VORDME = 15,
|
||||
ICLS_LOCALIZER = 16,
|
||||
ICLS_GLIDESLOPE = 17,
|
||||
}
|
||||
|
||||
--- Create a new BEACON Object. This doesn't activate the beacon, though, use @{#BEACON.ActivateTACAN} etc.
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
--
|
||||
-- @type RADIOQUEUE
|
||||
-- @field #string ClassName Name of the class "RADIOQUEUE".
|
||||
-- @field #boolean Debug Debug mode. More info.
|
||||
-- @field #boolean Debugmode Debug mode. More info.
|
||||
-- @field #string lid ID for dcs.log.
|
||||
-- @field #number frequency The radio frequency in Hz.
|
||||
-- @field #number modulation The radio modulation. Either radio.modulation.AM or radio.modulation.FM.
|
||||
@@ -38,7 +38,7 @@
|
||||
-- @extends Core.Base#BASE
|
||||
RADIOQUEUE = {
|
||||
ClassName = "RADIOQUEUE",
|
||||
Debug = nil,
|
||||
Debugmode = nil,
|
||||
lid = nil,
|
||||
frequency = nil,
|
||||
modulation = nil,
|
||||
@@ -55,7 +55,7 @@ RADIOQUEUE = {
|
||||
power = nil,
|
||||
numbers = {},
|
||||
checking = nil,
|
||||
schedonce = nil,
|
||||
schedonce = false,
|
||||
}
|
||||
|
||||
--- Radio queue transmission data.
|
||||
@@ -375,8 +375,10 @@ function RADIOQUEUE:Broadcast(transmission)
|
||||
sender:SetCommand(commandTransmit)
|
||||
|
||||
-- Debug message.
|
||||
local text=string.format("file=%s, freq=%.2f MHz, duration=%.2f sec, subtitle=%s", filename, self.frequency/1000000, transmission.duration, transmission.subtitle or "")
|
||||
MESSAGE:New(text, 2, "RADIOQUEUE "..self.alias):ToAllIf(self.Debug)
|
||||
if self.Debugmode then
|
||||
local text=string.format("file=%s, freq=%.2f MHz, duration=%.2f sec, subtitle=%s", filename, self.frequency/1000000, transmission.duration, transmission.subtitle or "")
|
||||
MESSAGE:New(text, 2, "RADIOQUEUE "..self.alias):ToAll()
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
@@ -388,10 +390,7 @@ function RADIOQUEUE:Broadcast(transmission)
|
||||
|
||||
-- Try to get positon from sender unit/static.
|
||||
if self.sendername then
|
||||
local coord=self:_GetRadioSenderCoord()
|
||||
if coord then
|
||||
vec3=coord:GetVec3()
|
||||
end
|
||||
vec3=self:_GetRadioSenderCoord()
|
||||
end
|
||||
|
||||
-- Try to get fixed positon.
|
||||
@@ -408,8 +407,10 @@ function RADIOQUEUE:Broadcast(transmission)
|
||||
trigger.action.radioTransmission(filename, vec3, self.modulation, false, self.frequency, self.power)
|
||||
|
||||
-- Debug message.
|
||||
local text=string.format("file=%s, freq=%.2f MHz, duration=%.2f sec, subtitle=%s", filename, self.frequency/1000000, transmission.duration, transmission.subtitle or "")
|
||||
MESSAGE:New(string.format(text, filename, transmission.duration, transmission.subtitle or ""), 5, "RADIOQUEUE "..self.alias):ToAllIf(self.Debug)
|
||||
if self.Debugmode then
|
||||
local text=string.format("file=%s, freq=%.2f MHz, duration=%.2f sec, subtitle=%s", filename, self.frequency/1000000, transmission.duration, transmission.subtitle or "")
|
||||
MESSAGE:New(string.format(text, filename, transmission.duration, transmission.subtitle or ""), 5, "RADIOQUEUE "..self.alias):ToAll()
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -532,6 +533,7 @@ function RADIOQUEUE:_GetRadioSender()
|
||||
|
||||
-- Try the general default.
|
||||
if self.sendername then
|
||||
|
||||
-- First try to find a unit
|
||||
sender=UNIT:FindByName(self.sendername)
|
||||
|
||||
@@ -547,7 +549,7 @@ end
|
||||
|
||||
--- Get unit from which we want to transmit a radio message. This has to be an aircraft for subtitles to work.
|
||||
-- @param #RADIOQUEUE self
|
||||
-- @return Core.Point#COORDINATE Coordinate of the sender unit.
|
||||
-- @return DCS#Vec3 Vector 3D.
|
||||
function RADIOQUEUE:_GetRadioSenderCoord()
|
||||
|
||||
local vec3=nil
|
||||
@@ -560,7 +562,7 @@ function RADIOQUEUE:_GetRadioSenderCoord()
|
||||
|
||||
-- Check that sender is alive and an aircraft.
|
||||
if sender and sender:IsAlive() then
|
||||
return sender:GetCoordinate()
|
||||
return sender:GetVec3()
|
||||
end
|
||||
|
||||
-- Now try a static.
|
||||
@@ -568,7 +570,7 @@ function RADIOQUEUE:_GetRadioSenderCoord()
|
||||
|
||||
-- Check that sender is alive and an aircraft.
|
||||
if sender then
|
||||
return sender:GetCoordinate()
|
||||
return sender:GetVec3()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
250
Moose Development/Moose/Core/Timer.lua
Normal file
250
Moose Development/Moose/Core/Timer.lua
Normal file
@@ -0,0 +1,250 @@
|
||||
--- **Core** - Timer scheduler.
|
||||
--
|
||||
-- **Main Features:**
|
||||
--
|
||||
-- * Delay function calls
|
||||
-- * Easy set up and little overhead
|
||||
-- * Set start, stop and time interval
|
||||
-- * Define max function calls
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **funkyfranky**
|
||||
-- @module Core.Timer
|
||||
-- @image CORE_Timer.png
|
||||
|
||||
|
||||
--- TIMER class.
|
||||
-- @type TIMER
|
||||
-- @field #string ClassName Name of the class.
|
||||
-- @field #string lid Class id string for output to DCS log file.
|
||||
-- @field #number tid Timer ID returned by the DCS API function.
|
||||
-- @field #function func Timer function.
|
||||
-- @field #table para Parameters passed to the timer function.
|
||||
-- @field #number Tstart Relative start time in seconds.
|
||||
-- @field #number Tstop Relative stop time in seconds.
|
||||
-- @field #number dT Time interval between function calls in seconds.
|
||||
-- @field #number ncalls Counter of function calls.
|
||||
-- @field #number ncallsMax Max number of function calls. If reached, timer is stopped.
|
||||
-- @extends Core.Base#BASE
|
||||
|
||||
--- *Better three hours too soon than a minute too late.* – William Shakespeare
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- # The TIMER Concept
|
||||
--
|
||||
-- The TIMER class is the little sister of the SCHEDULER class. It does the same thing but is a bit easier to use and has less overhead. It should be sufficient in many cases.
|
||||
--
|
||||
-- # Construction
|
||||
--
|
||||
-- A new TIMER is created by the @{#TIMER.New}(*func*, *...*) function
|
||||
--
|
||||
-- local mytimer=TIMER:New(myfunction, a, b)
|
||||
--
|
||||
-- The first parameter *func* is the function that is called followed by the necessary comma separeted parameters that are passed to that function.
|
||||
--
|
||||
-- ## Starting the Timer
|
||||
--
|
||||
-- The timer is started by the @{#TIMER.Start}(*Tstart*, *dT*, *Duration*) function
|
||||
--
|
||||
-- mytimer:Start(5, 1, 20)
|
||||
--
|
||||
-- where
|
||||
--
|
||||
-- * *Tstart* is the relative start time in seconds. In the example, the first function call happens after 5 sec.
|
||||
-- * *dT* is the time interval between function calls in seconds. Above, the function is called once per second.
|
||||
-- * *Duration* is the duration in seconds after which the timer is stopped. This is relative to the start time. Here, the timer will run for 20 seconds.
|
||||
--
|
||||
-- Note that
|
||||
--
|
||||
-- * if *Tstart* is not specified (*nil*), the first function call happens immediately.
|
||||
-- * if *dT* is not specified (*nil*), the function is called only once.
|
||||
-- * if *Duration* is not specified (*nil*), the timer runs forever or until stopped manually or until the max function calls are reached (see below).
|
||||
--
|
||||
-- For example,
|
||||
--
|
||||
-- mytimer:Start(3) -- Will call the function once after 3 seconds.
|
||||
-- mytimer:Start(nil, 0.5) -- Will call right now and then every 0.5 sec until all eternaty.
|
||||
-- mytimer:Start(nil, 2.0, 20) -- Will call right now and then every 2.0 sec for 20 sec.
|
||||
-- mytimer:Start(1.0, nil, 10) -- Does not make sense as the function is only called once anyway.
|
||||
--
|
||||
-- ## Stopping the Timer
|
||||
--
|
||||
-- The timer can be stopped manually by the @{#TIMER.Start}(*Delay*) function
|
||||
--
|
||||
-- mytimer:Stop()
|
||||
--
|
||||
-- If the optional paramter *Delay* is specified, the timer is stopped after *delay* seconds.
|
||||
--
|
||||
-- ## Limit Function Calls
|
||||
--
|
||||
-- The timer can be stopped after a certain amount of function calles with the @{#TIMER.SetMaxFunctionCalls}(*Nmax*) function
|
||||
--
|
||||
-- mytimer:SetMaxFunctionCalls(20)
|
||||
--
|
||||
-- where *Nmax* is the number of calls after which the timer is stopped, here 20.
|
||||
--
|
||||
-- For example,
|
||||
--
|
||||
-- mytimer:SetMaxFunctionCalls(66):Start(1.0, 0.1)
|
||||
--
|
||||
-- will start the timer after one second and call the function every 0.1 seconds. Once the function has been called 66 times, the timer is stopped.
|
||||
--
|
||||
--
|
||||
-- @field #TIMER
|
||||
TIMER = {
|
||||
ClassName = "TIMER",
|
||||
lid = nil,
|
||||
}
|
||||
|
||||
--- TIMER class version.
|
||||
-- @field #string version
|
||||
TIMER.version="0.1.0"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- TODO: A lot.
|
||||
-- TODO: Write docs.
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Constructor
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- Create a new TIMER object.
|
||||
-- @param #TIMER self
|
||||
-- @param #function Function The function to call.
|
||||
-- @param ... Parameters passed to the function if any.
|
||||
-- @return #TIMER self
|
||||
function TIMER:New(Function, ...)
|
||||
|
||||
-- Inherit BASE.
|
||||
local self=BASE:Inherit(self, BASE:New()) --#TIMER
|
||||
|
||||
self.lid="TIMER | "
|
||||
|
||||
-- Function to call.
|
||||
self.func=Function
|
||||
|
||||
-- Function arguments.
|
||||
self.para=arg or {}
|
||||
|
||||
-- Number of function calls.
|
||||
self.ncalls=0
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Create a new TIMER object.
|
||||
-- @param #TIMER self
|
||||
-- @param #number Tstart Relative start time in seconds.
|
||||
-- @param #number dT Interval between function calls in seconds. If not specified `nil`, the function is called only once.
|
||||
-- @param #number Duration Time in seconds for how long the timer is running. If not specified `nil`, the timer runs forever or until stopped manually by the `TIMER:Stop()` function.
|
||||
-- @return #TIMER self
|
||||
function TIMER:Start(Tstart, dT, Duration)
|
||||
|
||||
-- Current time.
|
||||
local Tnow=timer.getTime()
|
||||
|
||||
-- Start time in sec.
|
||||
self.Tstart=Tstart or Tnow
|
||||
|
||||
-- Set time interval.
|
||||
self.dT=dT
|
||||
|
||||
-- Stop time.
|
||||
if Duration then
|
||||
self.Tstop=self.Tstart+Duration
|
||||
end
|
||||
|
||||
-- Call DCS timer function.
|
||||
self.tid=timer.scheduleFunction(TIMER._Function, self, self.Tstart)
|
||||
|
||||
-- Set log id.
|
||||
self.lid=string.format("TIMER ID=%d | ", self.tid)
|
||||
|
||||
-- Debug info.
|
||||
self:T(self.lid..string.format("Starting Timer in %.3f sec, dT=%s, Tstop=%s", self.Tstart-Tnow, tostring(self.dT), tostring(self.Tstop)))
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Stop the timer by removing the timer function.
|
||||
-- @param #TIMER self
|
||||
-- @param #number Delay (Optional) Delay in seconds, before the timer is stopped.
|
||||
-- @return #TIMER self
|
||||
function TIMER:Stop(Delay)
|
||||
|
||||
if Delay and Delay>0 then
|
||||
|
||||
self.Tstop=timer.getTime()+Delay
|
||||
|
||||
else
|
||||
|
||||
if self.tid then
|
||||
self:T(self.lid..string.format("Stopping timer by removing timer function after %d calls!", self.ncalls))
|
||||
timer.removeFunction(self.tid)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set max number of function calls. When the function has been called this many times, the TIMER is stopped.
|
||||
-- @param #TIMER self
|
||||
-- @param #number Nmax Set number of max function calls.
|
||||
-- @return #TIMER self
|
||||
function TIMER:SetMaxFunctionCalls(Nmax)
|
||||
self.ncallsMax=Nmax
|
||||
return self
|
||||
end
|
||||
|
||||
--- Call timer function.
|
||||
-- @param #TIMER self
|
||||
-- @param #number time DCS model time in seconds.
|
||||
-- @return #number Time when the function is called again or `nil` if the timer is stopped.
|
||||
function TIMER:_Function(time)
|
||||
|
||||
-- Call function.
|
||||
self.func(unpack(self.para))
|
||||
|
||||
-- Increase number of calls.
|
||||
self.ncalls=self.ncalls+1
|
||||
|
||||
-- Next time.
|
||||
local Tnext=self.dT and time+self.dT or nil
|
||||
|
||||
-- Check if we stop the timer.
|
||||
local stopme=false
|
||||
if Tnext==nil then
|
||||
-- No next time.
|
||||
self:T(self.lid..string.format("No next time as dT=nil ==> Stopping timer after %d function calls", self.ncalls))
|
||||
stopme=true
|
||||
elseif self.Tstop and Tnext>self.Tstop then
|
||||
-- Stop time passed.
|
||||
self:T(self.lid..string.format("Stop time passed %.3f > %.3f ==> Stopping timer after %d function calls", Tnext, self.Tstop, self.ncalls))
|
||||
stopme=true
|
||||
elseif self.ncallsMax and self.ncalls>=self.ncallsMax then
|
||||
-- Number of max function calls reached.
|
||||
self:T(self.lid..string.format("Max function calls Nmax=%d reached ==> Stopping timer after %d function calls", self.ncallsMax, self.ncalls))
|
||||
stopme=true
|
||||
end
|
||||
|
||||
if stopme then
|
||||
-- Remove timer function.
|
||||
self:Stop()
|
||||
return nil
|
||||
else
|
||||
-- Call again in Tnext seconds.
|
||||
return Tnext
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
Reference in New Issue
Block a user