mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2026-08-13 01:06:45 +00:00
Merge branch 'FF/Develop' into FF/Fox2
This commit is contained in:
@@ -805,15 +805,17 @@ do -- Scheduling
|
||||
end
|
||||
|
||||
self.Scheduler.SchedulerObject = self.Scheduler
|
||||
--self.MasterObject = self
|
||||
|
||||
local ScheduleID = _SCHEDULEDISPATCHER:AddSchedule(
|
||||
local ScheduleID = self.Scheduler:Schedule(
|
||||
self,
|
||||
SchedulerFunction,
|
||||
{ ... },
|
||||
Start,
|
||||
Repeat,
|
||||
RandomizeFactor,
|
||||
Stop
|
||||
Stop,
|
||||
4
|
||||
)
|
||||
|
||||
self._.Schedules[#self._.Schedules+1] = ScheduleID
|
||||
@@ -889,6 +891,26 @@ end
|
||||
-- Log a trace (only shown when trace is on)
|
||||
-- TODO: Make trace function using variable parameters.
|
||||
|
||||
--- Set trace on.
|
||||
-- @param #BASE self
|
||||
-- @usage
|
||||
-- -- Switch the tracing On
|
||||
-- BASE:TraceOn()
|
||||
function BASE:TraceOn()
|
||||
self:TraceOnOff( true )
|
||||
end
|
||||
|
||||
--- Set trace off.
|
||||
-- @param #BASE self
|
||||
-- @usage
|
||||
-- -- Switch the tracing Off
|
||||
-- BASE:TraceOff()
|
||||
function BASE:TraceOff()
|
||||
self:TraceOnOff( false )
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Set trace on or off
|
||||
-- Note that when trace is off, no BASE.Debug statement is performed, increasing performance!
|
||||
-- When Moose is loaded statically, (as one file), tracing is switched off by default.
|
||||
@@ -903,7 +925,7 @@ end
|
||||
-- -- Switch the tracing Off
|
||||
-- BASE:TraceOnOff( false )
|
||||
function BASE:TraceOnOff( TraceOnOff )
|
||||
_TraceOnOff = TraceOnOff
|
||||
_TraceOnOff = TraceOnOff or true
|
||||
end
|
||||
|
||||
|
||||
@@ -923,8 +945,8 @@ end
|
||||
-- @param #BASE self
|
||||
-- @param #number Level
|
||||
function BASE:TraceLevel( Level )
|
||||
_TraceLevel = Level
|
||||
self:E( "Tracing level " .. Level )
|
||||
_TraceLevel = Level or 1
|
||||
self:I( "Tracing level " .. _TraceLevel )
|
||||
end
|
||||
|
||||
--- Trace all methods in MOOSE
|
||||
@@ -932,12 +954,12 @@ end
|
||||
-- @param #boolean TraceAll true = trace all methods in MOOSE.
|
||||
function BASE:TraceAll( TraceAll )
|
||||
|
||||
_TraceAll = TraceAll
|
||||
_TraceAll = TraceAll or true
|
||||
|
||||
if _TraceAll then
|
||||
self:E( "Tracing all methods in MOOSE " )
|
||||
self:I( "Tracing all methods in MOOSE " )
|
||||
else
|
||||
self:E( "Switched off tracing all methods in MOOSE" )
|
||||
self:I( "Switched off tracing all methods in MOOSE" )
|
||||
end
|
||||
end
|
||||
|
||||
@@ -947,7 +969,7 @@ end
|
||||
function BASE:TraceClass( Class )
|
||||
_TraceClass[Class] = true
|
||||
_TraceClassMethod[Class] = {}
|
||||
self:E( "Tracing class " .. Class )
|
||||
self:I( "Tracing class " .. Class )
|
||||
end
|
||||
|
||||
--- Set tracing for a specific method of class
|
||||
@@ -960,7 +982,7 @@ function BASE:TraceClassMethod( Class, Method )
|
||||
_TraceClassMethod[Class].Method = {}
|
||||
end
|
||||
_TraceClassMethod[Class].Method[Method] = true
|
||||
self:E( "Tracing method " .. Method .. " of class " .. Class )
|
||||
self:I( "Tracing method " .. Method .. " of class " .. Class )
|
||||
end
|
||||
|
||||
--- Trace a function call. This function is private.
|
||||
@@ -987,7 +1009,7 @@ function BASE:_F( Arguments, DebugInfoCurrentParam, DebugInfoFromParam )
|
||||
if DebugInfoFrom then
|
||||
LineFrom = DebugInfoFrom.currentline
|
||||
end
|
||||
env.info( string.format( "%6d(%6d)/%1s:%20s%05d.%s(%s)" , LineCurrent, LineFrom, "F", self.ClassName, self.ClassID, Function, routines.utils.oneLineSerialize( Arguments ) ) )
|
||||
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s(%s)" , LineCurrent, LineFrom, "F", self.ClassName, self.ClassID, Function, routines.utils.oneLineSerialize( Arguments ) ) )
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1062,7 +1084,7 @@ function BASE:_T( Arguments, DebugInfoCurrentParam, DebugInfoFromParam )
|
||||
if DebugInfoFrom then
|
||||
LineFrom = DebugInfoFrom.currentline
|
||||
end
|
||||
env.info( string.format( "%6d(%6d)/%1s:%20s%05d.%s" , LineCurrent, LineFrom, "T", self.ClassName, self.ClassID, routines.utils.oneLineSerialize( Arguments ) ) )
|
||||
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s" , LineCurrent, LineFrom, "T", self.ClassName, self.ClassID, routines.utils.oneLineSerialize( Arguments ) ) )
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1133,9 +1155,9 @@ function BASE:E( Arguments )
|
||||
LineFrom = DebugInfoFrom.currentline
|
||||
end
|
||||
|
||||
env.info( string.format( "%6d(%6d)/%1s:%20s%05d.%s(%s)" , LineCurrent, LineFrom, "E", self.ClassName, self.ClassID, Function, routines.utils.oneLineSerialize( Arguments ) ) )
|
||||
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s(%s)" , LineCurrent, LineFrom, "E", self.ClassName, self.ClassID, Function, routines.utils.oneLineSerialize( Arguments ) ) )
|
||||
else
|
||||
env.info( string.format( "%1s:%20s%05d(%s)" , "E", self.ClassName, self.ClassID, routines.utils.oneLineSerialize( Arguments ) ) )
|
||||
env.info( string.format( "%1s:%30s%05d(%s)" , "E", self.ClassName, self.ClassID, routines.utils.oneLineSerialize( Arguments ) ) )
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1161,9 +1183,9 @@ function BASE:I( Arguments )
|
||||
LineFrom = DebugInfoFrom.currentline
|
||||
end
|
||||
|
||||
env.info( string.format( "%6d(%6d)/%1s:%20s%05d.%s(%s)" , LineCurrent, LineFrom, "I", self.ClassName, self.ClassID, Function, routines.utils.oneLineSerialize( Arguments ) ) )
|
||||
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s(%s)" , LineCurrent, LineFrom, "I", self.ClassName, self.ClassID, Function, routines.utils.oneLineSerialize( Arguments ) ) )
|
||||
else
|
||||
env.info( string.format( "%1s:%20s%05d(%s)" , "I", self.ClassName, self.ClassID, routines.utils.oneLineSerialize( Arguments ) ) )
|
||||
env.info( string.format( "%1s:%30s%05d(%s)" , "I", self.ClassName, self.ClassID, routines.utils.oneLineSerialize( Arguments ) ) )
|
||||
end
|
||||
|
||||
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",
|
||||
@@ -81,6 +81,7 @@ DATABASE = {
|
||||
HITS = {},
|
||||
DESTROYS = {},
|
||||
ZONES = {},
|
||||
ZONES_GOAL = {},
|
||||
WAREHOUSES = {},
|
||||
FLIGHTGROUPS = {},
|
||||
FLIGHTCONTROLS = {},
|
||||
@@ -115,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 )
|
||||
@@ -125,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()
|
||||
@@ -138,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 )
|
||||
@@ -166,10 +167,10 @@ function DATABASE:New()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--self:E( "Scheduling" )
|
||||
--PlayerCheckSchedule = SCHEDULER:New( nil, CheckPlayers, { self }, 1, 1 )
|
||||
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -189,12 +190,13 @@ end
|
||||
function DATABASE:AddUnit( DCSUnitName )
|
||||
|
||||
if not self.UNITS[DCSUnitName] then
|
||||
self:I( { "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
|
||||
|
||||
@@ -203,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.
|
||||
@@ -214,7 +216,7 @@ function DATABASE:AddStatic( DCSStaticName )
|
||||
self.STATICS[DCSStaticName] = STATIC:Register( DCSStaticName )
|
||||
return self.STATICS[DCSStaticName]
|
||||
end
|
||||
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
@@ -223,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.
|
||||
@@ -262,7 +264,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.
|
||||
@@ -283,29 +285,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
|
||||
|
||||
|
||||
@@ -322,56 +324,89 @@ 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
|
||||
|
||||
|
||||
end -- zone
|
||||
|
||||
do -- Zone_Goal
|
||||
|
||||
--- Finds a @{Zone} based on the zone name.
|
||||
-- @param #DATABASE self
|
||||
-- @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
|
||||
end
|
||||
|
||||
end -- Zone_Goal
|
||||
do -- cargo
|
||||
|
||||
--- Adds a Cargo based on the Cargo Name in the DATABASE.
|
||||
-- @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
|
||||
@@ -380,10 +415,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.
|
||||
@@ -392,7 +427,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
|
||||
@@ -405,12 +440,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(.*)")
|
||||
@@ -421,7 +456,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 )
|
||||
@@ -433,7 +468,7 @@ do -- cargo
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
end -- cargo
|
||||
@@ -479,9 +514,9 @@ function DATABASE:AddGroup( GroupName )
|
||||
if not self.GROUPS[GroupName] then
|
||||
self:I( { "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.
|
||||
@@ -584,7 +619,7 @@ function DATABASE:Spawn( SpawnTemplate )
|
||||
for UnitID, UnitData in pairs( SpawnTemplate.units ) do
|
||||
self:AddUnit( UnitData.name )
|
||||
end
|
||||
|
||||
|
||||
return SpawnGroup
|
||||
end
|
||||
|
||||
@@ -616,21 +651,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
|
||||
@@ -645,7 +680,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
|
||||
@@ -663,8 +698,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:I( { Group = self.Templates.Groups[GroupTemplateName].GroupName,
|
||||
@@ -693,13 +728,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]
|
||||
@@ -710,12 +745,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
|
||||
|
||||
|
||||
@@ -783,7 +818,7 @@ function DATABASE:_RegisterPlayers()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -799,12 +834,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 )
|
||||
@@ -812,10 +847,10 @@ function DATABASE:_RegisterGroupsAndUnits()
|
||||
else
|
||||
self:E( { "Group does not exist: ", DCSGroup } )
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
self:I("Groups:")
|
||||
for GroupName, Group in pairs( self.GROUPS ) do
|
||||
self:I( { "Group:", GroupName } )
|
||||
@@ -833,7 +868,7 @@ function DATABASE:_RegisterClients()
|
||||
self:I( { "Register Client:", ClientName } )
|
||||
self:AddClient( ClientName )
|
||||
end
|
||||
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -847,7 +882,7 @@ function DATABASE:_RegisterStatics()
|
||||
|
||||
if DCSStatic:isExist() then
|
||||
local DCSStaticName = DCSStatic:getName()
|
||||
|
||||
|
||||
self:I( { "Register Static:", DCSStaticName } )
|
||||
self:AddStatic( DCSStaticName )
|
||||
else
|
||||
@@ -887,7 +922,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 )
|
||||
@@ -923,7 +958,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
|
||||
@@ -932,7 +967,7 @@ function DATABASE:_EventOnDeadOrCrash( Event )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
self:AccountDestroys( Event )
|
||||
end
|
||||
|
||||
@@ -986,7 +1021,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
|
||||
@@ -995,20 +1030,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
|
||||
@@ -1021,8 +1056,9 @@ function DATABASE:ForEach( IteratorFunction, FinalizeFunction, arg, Set )
|
||||
return false
|
||||
end
|
||||
|
||||
local Scheduler = SCHEDULER:New( self, Schedule, {}, 0.001, 0.001, 0 )
|
||||
|
||||
--local Scheduler = SCHEDULER:New( self, Schedule, {}, 0.001, 0.001, 0 )
|
||||
Schedule()
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -1033,7 +1069,7 @@ end
|
||||
-- @return #DATABASE self
|
||||
function DATABASE:ForEachStatic( IteratorFunction, FinalizeFunction, ... ) --R2.1
|
||||
self:F2( arg )
|
||||
|
||||
|
||||
self:ForEach( IteratorFunction, FinalizeFunction, arg, self.STATICS )
|
||||
|
||||
return self
|
||||
@@ -1046,7 +1082,7 @@ end
|
||||
-- @return #DATABASE self
|
||||
function DATABASE:ForEachUnit( IteratorFunction, FinalizeFunction, ... )
|
||||
self:F2( arg )
|
||||
|
||||
|
||||
self:ForEach( IteratorFunction, FinalizeFunction, arg, self.UNITS )
|
||||
|
||||
return self
|
||||
@@ -1059,7 +1095,7 @@ end
|
||||
-- @return #DATABASE self
|
||||
function DATABASE:ForEachGroup( IteratorFunction, FinalizeFunction, ... )
|
||||
self:F2( arg )
|
||||
|
||||
|
||||
self:ForEach( IteratorFunction, FinalizeFunction, arg, self.GROUPS )
|
||||
|
||||
return self
|
||||
@@ -1072,9 +1108,9 @@ end
|
||||
-- @return #DATABASE self
|
||||
function DATABASE:ForEachPlayer( IteratorFunction, FinalizeFunction, ... )
|
||||
self:F2( arg )
|
||||
|
||||
|
||||
self:ForEach( IteratorFunction, FinalizeFunction, arg, self.PLAYERS )
|
||||
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -1085,9 +1121,9 @@ end
|
||||
-- @return #DATABASE self
|
||||
function DATABASE:ForEachPlayerJoined( IteratorFunction, FinalizeFunction, ... )
|
||||
self:F2( arg )
|
||||
|
||||
|
||||
self:ForEach( IteratorFunction, FinalizeFunction, arg, self.PLAYERSJOINED )
|
||||
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -1097,9 +1133,9 @@ end
|
||||
-- @return #DATABASE self
|
||||
function DATABASE:ForEachPlayerUnit( IteratorFunction, FinalizeFunction, ... )
|
||||
self:F2( arg )
|
||||
|
||||
|
||||
self:ForEach( IteratorFunction, FinalizeFunction, arg, self.PLAYERUNITS )
|
||||
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -1110,7 +1146,7 @@ end
|
||||
-- @return #DATABASE self
|
||||
function DATABASE:ForEachClient( IteratorFunction, ... )
|
||||
self:F2( arg )
|
||||
|
||||
|
||||
self:ForEach( IteratorFunction, arg, self.CLIENTS )
|
||||
|
||||
return self
|
||||
@@ -1122,7 +1158,7 @@ end
|
||||
-- @return #DATABASE self
|
||||
function DATABASE:ForEachCargo( IteratorFunction, ... )
|
||||
self:F2( arg )
|
||||
|
||||
|
||||
self:ForEach( IteratorFunction, arg, self.CARGOS )
|
||||
|
||||
return self
|
||||
@@ -1244,10 +1280,10 @@ 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.NEUTRAL
|
||||
CoalitionSide=coalition.side.RED
|
||||
elseif CoalitionName=="blue" then
|
||||
CoalitionSide=coalition.side.BLUE
|
||||
else
|
||||
@@ -1277,10 +1313,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
|
||||
|
||||
@@ -1299,18 +1335,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
|
||||
@@ -1331,35 +1367,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.
|
||||
@@ -1367,13 +1403,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 = ""
|
||||
@@ -1385,26 +1421,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?
|
||||
@@ -1413,8 +1449,3 @@ end
|
||||
self.DESTROYS[Event.IniUnitName] = true
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -189,7 +189,9 @@ world.event.S_EVENT_NEW_CARGO = world.event.S_EVENT_MAX + 1000
|
||||
world.event.S_EVENT_DELETE_CARGO = world.event.S_EVENT_MAX + 1001
|
||||
world.event.S_EVENT_NEW_ZONE = world.event.S_EVENT_MAX + 1002
|
||||
world.event.S_EVENT_DELETE_ZONE = world.event.S_EVENT_MAX + 1003
|
||||
world.event.S_EVENT_REMOVE_UNIT = world.event.S_EVENT_MAX + 1004
|
||||
world.event.S_EVENT_NEW_ZONE_GOAL = world.event.S_EVENT_MAX + 1004
|
||||
world.event.S_EVENT_DELETE_ZONE_GOAL = world.event.S_EVENT_MAX + 1005
|
||||
world.event.S_EVENT_REMOVE_UNIT = world.event.S_EVENT_MAX + 1006
|
||||
|
||||
|
||||
--- The different types of events supported by MOOSE.
|
||||
@@ -226,6 +228,8 @@ EVENTS = {
|
||||
DeleteCargo = world.event.S_EVENT_DELETE_CARGO,
|
||||
NewZone = world.event.S_EVENT_NEW_ZONE,
|
||||
DeleteZone = world.event.S_EVENT_DELETE_ZONE,
|
||||
NewZoneGoal = world.event.S_EVENT_NEW_ZONE_GOAL,
|
||||
DeleteZoneGoal = world.event.S_EVENT_DELETE_ZONE_GOAL,
|
||||
RemoveUnit = world.event.S_EVENT_REMOVE_UNIT,
|
||||
}
|
||||
|
||||
@@ -462,6 +466,16 @@ local _EVENTMETA = {
|
||||
Event = "OnEventDeleteZone",
|
||||
Text = "S_EVENT_DELETE_ZONE"
|
||||
},
|
||||
[EVENTS.NewZoneGoal] = {
|
||||
Order = 1,
|
||||
Event = "OnEventNewZoneGoal",
|
||||
Text = "S_EVENT_NEW_ZONE_GOAL"
|
||||
},
|
||||
[EVENTS.DeleteZoneGoal] = {
|
||||
Order = 1,
|
||||
Event = "OnEventDeleteZoneGoal",
|
||||
Text = "S_EVENT_DELETE_ZONE_GOAL"
|
||||
},
|
||||
[EVENTS.RemoveUnit] = {
|
||||
Order = -1,
|
||||
Event = "OnEventRemoveUnit",
|
||||
@@ -800,6 +814,38 @@ do -- Event Creation
|
||||
world.onEvent( Event )
|
||||
end
|
||||
|
||||
--- Creation of a New ZoneGoal Event.
|
||||
-- @param #EVENT self
|
||||
-- @param Core.Functional#ZONE_GOAL ZoneGoal The ZoneGoal created.
|
||||
function EVENT:CreateEventNewZoneGoal( ZoneGoal )
|
||||
self:F( { ZoneGoal } )
|
||||
|
||||
local Event = {
|
||||
id = EVENTS.NewZoneGoal,
|
||||
time = timer.getTime(),
|
||||
ZoneGoal = ZoneGoal,
|
||||
}
|
||||
|
||||
world.onEvent( Event )
|
||||
end
|
||||
|
||||
|
||||
--- Creation of a ZoneGoal Deletion Event.
|
||||
-- @param #EVENT self
|
||||
-- @param Core.ZoneGoal#ZONE_GOAL ZoneGoal The ZoneGoal created.
|
||||
function EVENT:CreateEventDeleteZoneGoal( ZoneGoal )
|
||||
self:F( { ZoneGoal } )
|
||||
|
||||
local Event = {
|
||||
id = EVENTS.DeleteZoneGoal,
|
||||
time = timer.getTime(),
|
||||
ZoneGoal = ZoneGoal,
|
||||
}
|
||||
|
||||
world.onEvent( Event )
|
||||
end
|
||||
|
||||
|
||||
--- Creation of a S_EVENT_PLAYER_ENTER_UNIT Event.
|
||||
-- @param #EVENT self
|
||||
-- @param Wrapper.Unit#UNIT PlayerUnit.
|
||||
|
||||
@@ -594,7 +594,17 @@ do -- FSM
|
||||
return errmsg
|
||||
end
|
||||
if self[handler] then
|
||||
self:T( "*** FSM *** " .. step .. " *** " .. params[1] .. " --> " .. params[2] .. " --> " .. params[3] )
|
||||
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
|
||||
self:T( ":::>" .. step .. params[2] .. " : " .. params[1] .. " >> " .. step .. params[2] .. "()" .. ">" .. params[2] .. " >> " .. params[3] )
|
||||
elseif step == "onenter" or step == "OnEnter" then
|
||||
self:T( ":::>" .. step .. params[3] .. " : " .. params[1] .. " >> " .. params[2] .. " >> " .. step .. params[3] .. "()" .. ">" .. params[3] )
|
||||
elseif step == "onleave" or step == "OnLeave" then
|
||||
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
|
||||
self._EventSchedules[EventName] = nil
|
||||
local Result, Value = xpcall( function() return self[handler]( self, unpack( params ) ) end, ErrorHandler )
|
||||
return Value
|
||||
@@ -718,13 +728,13 @@ do -- FSM
|
||||
if DelaySeconds < 0 then -- Only call the event ONCE!
|
||||
DelaySeconds = math.abs( DelaySeconds )
|
||||
if not self._EventSchedules[EventName] then
|
||||
CallID = self.CallScheduler:Schedule( self, self._handler, { EventName, ... }, DelaySeconds or 1 )
|
||||
CallID = self.CallScheduler:Schedule( self, self._handler, { EventName, ... }, DelaySeconds or 1, nil, nil, nil, 4, true )
|
||||
self._EventSchedules[EventName] = CallID
|
||||
else
|
||||
-- reschedule
|
||||
end
|
||||
else
|
||||
CallID = self.CallScheduler:Schedule( self, self._handler, { EventName, ... }, DelaySeconds or 1 )
|
||||
CallID = self.CallScheduler:Schedule( self, self._handler, { EventName, ... }, DelaySeconds or 1, nil, nil, nil, 4, true )
|
||||
end
|
||||
else
|
||||
error( "FSM: An asynchronous event trigger requires a DelaySeconds parameter!!! This can be positive or negative! Sorry, but will not process this." )
|
||||
|
||||
@@ -2075,7 +2075,7 @@ do -- COORDINATE
|
||||
-- @return #string The coordinate Text in the configured coordinate system.
|
||||
function COORDINATE:ToString( Controllable, Settings, Task )
|
||||
|
||||
self:E( { Controllable = Controllable and Controllable:GetName() } )
|
||||
-- self:E( { Controllable = Controllable and Controllable:GetName() } )
|
||||
|
||||
local Settings = Settings or ( Controllable and _DATABASE:GetPlayerSettings( Controllable:GetPlayerName() ) ) or _SETTINGS
|
||||
|
||||
|
||||
@@ -800,470 +800,4 @@ function BEACON:_TACANToFrequency(TACANChannel, TACANMode)
|
||||
return (A + TACANChannel - B) * 1000000
|
||||
end
|
||||
|
||||
--- Manages radio transmissions.
|
||||
--
|
||||
-- @type RADIOQUEUE
|
||||
-- @field #string ClassName Name of the class "RADIOQUEUE".
|
||||
-- @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.
|
||||
-- @field Core.Scheduler#SCHEDULER scheduler The scheduler.
|
||||
-- @field #string RQid The radio queue scheduler ID.
|
||||
-- @field #table queue The queue of transmissions.
|
||||
-- @field #number Tlast Time (abs) when the last transmission finished.
|
||||
-- @field Core.Point#COORDINATE sendercoord Coordinate from where transmissions are broadcasted.
|
||||
-- @field #number sendername Name of the sending unit or static.
|
||||
-- @field Wrapper.Positionable#POSITIONABLE positionable The positionable to broadcast the message.
|
||||
-- @field #number power Power of radio station in Watts. Default 100 W.
|
||||
-- @field #table numbers Table of number transmission parameters.
|
||||
-- @extends Core.Base#BASE
|
||||
RADIOQUEUE = {
|
||||
ClassName = "RADIOQUEUE",
|
||||
lid=nil,
|
||||
frequency=nil,
|
||||
modulation=nil,
|
||||
scheduler=nil,
|
||||
RQid=nil,
|
||||
queue={},
|
||||
Tlast=nil,
|
||||
sendercoord=nil,
|
||||
sendername=nil,
|
||||
positionable=nil,
|
||||
power=100,
|
||||
numbers={},
|
||||
}
|
||||
|
||||
--- Radio queue transmission data.
|
||||
-- @type RADIOQUEUE.Transmission
|
||||
-- @field #string filename Name of the file to be transmitted.
|
||||
-- @field #string path Path in miz file where the file is located.
|
||||
-- @field #number duration Duration in seconds.
|
||||
-- @field #number Tstarted Mission time (abs) in seconds when the transmission started.
|
||||
-- @field #boolean isplaying If true, transmission is currently playing.
|
||||
-- @field #number Tplay Mission time (abs) in seconds when the transmission should be played.
|
||||
|
||||
|
||||
--- Create a new RADIOQUEUE object for a given radio frequency/modulation.
|
||||
-- @param #RADIOQUEUE self
|
||||
-- @param #number frequency The radio frequency in MHz.
|
||||
-- @param #number modulation (Optional) The radio modulation. Default radio.modulation.AM.
|
||||
-- @return #RADIOQUEUE self The RADIOQUEUE object.
|
||||
function RADIOQUEUE:New(frequency, modulation)
|
||||
|
||||
-- Inherit base
|
||||
local self=BASE:Inherit(self, BASE:New()) -- Core.Radio#RADIOQUEUE
|
||||
|
||||
self.lid="RADIOQUEUE | "
|
||||
|
||||
if frequency==nil then
|
||||
self:E(self.lid.."ERROR: No frequency specified as first parameter!")
|
||||
return nil
|
||||
end
|
||||
|
||||
-- Frequency in Hz.
|
||||
self.frequency=frequency*1000000
|
||||
|
||||
-- Modulation.
|
||||
self.modulation=modulation or radio.modulation.AM
|
||||
|
||||
-- Scheduler
|
||||
self.scheduler=SCHEDULER:New()
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Start the radio queue.
|
||||
-- @param #RADIOQUEUE self
|
||||
-- @param #number delay (Optional) Delay in seconds, before the radio queue is started. Default 1 sec.
|
||||
-- @param #number dt (Optional) Time step in seconds for checking the queue. Default 0.01 sec.
|
||||
-- @return #RADIOQUEUE self The RADIOQUEUE object.
|
||||
function RADIOQUEUE:Start(delay, dt)
|
||||
|
||||
delay=delay or 1
|
||||
|
||||
dt=dt or 0.01
|
||||
|
||||
self:I(self.lid..string.format("Starting RADIOQUEUE in %.1f seconds with interval dt=%.3f seconds.", delay, dt))
|
||||
|
||||
self.RQid=self.scheduler:Schedule(self, self._CheckRadioQueue, {}, delay, dt)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Stop the radio queue. Stop scheduler and delete queue.
|
||||
-- @param #RADIOQUEUE self
|
||||
-- @return #RADIOQUEUE self The RADIOQUEUE object.
|
||||
function RADIOQUEUE:Stop()
|
||||
self:I(self.lid.."Stopping RADIOQUEUE.")
|
||||
self.scheduler:Stop(self.RQid)
|
||||
self.queue={}
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set coordinate from where the transmission is broadcasted.
|
||||
-- @param #RADIOQUEUE self
|
||||
-- @param Core.Point#COORDINATE coordinate Coordinate of the sender.
|
||||
-- @return #RADIOQUEUE self The RADIOQUEUE object.
|
||||
function RADIOQUEUE:SetSenderCoordinate(coordinate)
|
||||
self.sendercoord=coordinate
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set name of unit or static from which transmissions are made.
|
||||
-- @param #RADIOQUEUE self
|
||||
-- @param #string name Name of the unit or static used for transmissions.
|
||||
-- @return #RADIOQUEUE self The RADIOQUEUE object.
|
||||
function RADIOQUEUE:SetSenderUnitName(name)
|
||||
self.sendername=name
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set parameters of a digit.
|
||||
-- @param #RADIOQUEUE self
|
||||
-- @param #number digit The digit 0-9.
|
||||
-- @param #string filename The name of the sound file.
|
||||
-- @param #number duration The duration of the sound file in seconds.
|
||||
-- @param #string path The directory within the miz file where the sound is located. Default "l10n/DEFAULT/".
|
||||
-- @return #RADIOQUEUE self The RADIOQUEUE object.
|
||||
function RADIOQUEUE:SetDigit(digit, filename, duration, path)
|
||||
|
||||
local transmission={} --#RADIOQUEUE.Transmission
|
||||
transmission.filename=filename
|
||||
transmission.duration=duration
|
||||
transmission.path=path or "l10n/DEFAULT/"
|
||||
|
||||
-- Convert digit to string in case it is given as a number.
|
||||
if type(digit)=="number" then
|
||||
digit=tostring(digit)
|
||||
end
|
||||
|
||||
-- Set transmission.
|
||||
self.numbers[digit]=transmission
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Add a transmission to the radio queue.
|
||||
-- @param #RADIOQUEUE self
|
||||
-- @param #RADIOQUEUE.Transmission transmission The transmission data table.
|
||||
-- @return #RADIOQUEUE self The RADIOQUEUE object.
|
||||
function RADIOQUEUE:AddTransmission(transmission)
|
||||
self:F({transmission=transmission})
|
||||
|
||||
-- Init.
|
||||
transmission.isplaying=false
|
||||
transmission.Tstarted=nil
|
||||
|
||||
-- Add to queue.
|
||||
table.insert(self.queue, transmission)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Add a transmission to the radio queue.
|
||||
-- @param #RADIOQUEUE self
|
||||
-- @param #string filename Name of the sound file. Usually an ogg or wav file type.
|
||||
-- @param #number duration Duration in seconds the file lasts.
|
||||
-- @param #number path Directory path inside the miz file where the sound file is located. Default "l10n/DEFAULT/".
|
||||
-- @param #number tstart Start time (abs) seconds. Default now.
|
||||
-- @param #number interval Interval in seconds after the last transmission finished.
|
||||
-- @return #RADIOQUEUE self The RADIOQUEUE object.
|
||||
function RADIOQUEUE:NewTransmission(filename, duration, path, tstart, interval)
|
||||
|
||||
-- Sanity checks.
|
||||
if not filename then
|
||||
self:E(self.lid.."ERROR: No filename specified.")
|
||||
return nil
|
||||
end
|
||||
if type(filename)~="string" then
|
||||
self:E(self.lid.."ERROR: Filename specified is NOT a string.")
|
||||
return nil
|
||||
end
|
||||
|
||||
if not duration then
|
||||
self:E(self.lid.."ERROR: No duration of transmission specified.")
|
||||
return nil
|
||||
end
|
||||
if type(duration)~="number" then
|
||||
self:E(self.lid.."ERROR: Duration specified is NOT a number.")
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
local transmission={} --#RADIOQUEUE.Transmission
|
||||
transmission.filename=filename
|
||||
transmission.duration=duration
|
||||
transmission.path=path or "l10n/DEFAULT/"
|
||||
transmission.Tplay=tstart or timer.getAbsTime()
|
||||
|
||||
-- Add transmission to queue.
|
||||
self:AddTransmission(transmission)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Convert a number (as string) into a radio transmission.
|
||||
-- E.g. for board number or headings.
|
||||
-- @param #RADIOQUEUE self
|
||||
-- @param #string number Number string, e.g. "032" or "183".
|
||||
-- @param #number delay Delay before transmission in seconds.
|
||||
-- @param #number interval Interval between the next call.
|
||||
-- @return #number Duration of the call in seconds.
|
||||
function RADIOQUEUE:Number2Transmission(number, delay, interval)
|
||||
|
||||
--- Split string into characters.
|
||||
local function _split(str)
|
||||
local chars={}
|
||||
for i=1,#str do
|
||||
local c=str:sub(i,i)
|
||||
table.insert(chars, c)
|
||||
end
|
||||
return chars
|
||||
end
|
||||
|
||||
-- Split string into characters.
|
||||
local numbers=_split(number)
|
||||
|
||||
local wait=0
|
||||
for i=1,#numbers do
|
||||
|
||||
-- Current number
|
||||
local n=numbers[i]
|
||||
|
||||
-- Radio call.
|
||||
local transmission=UTILS.DeepCopy(self.numbers[n]) --#RADIOQUEUE.Transmission
|
||||
|
||||
transmission.Tplay=timer.getAbsTime()+(delay or 0)
|
||||
|
||||
if interval and i==1 then
|
||||
transmission.interval=interval
|
||||
end
|
||||
|
||||
self:AddTransmission(transmission)
|
||||
|
||||
-- Add up duration of the number.
|
||||
wait=wait+transmission.duration
|
||||
end
|
||||
|
||||
-- Return the total duration of the call.
|
||||
return wait
|
||||
end
|
||||
|
||||
|
||||
--- Broadcast radio message.
|
||||
-- @param #RADIOQUEUE self
|
||||
-- @param #RADIOQUEUE.Transmission transmission The transmission.
|
||||
function RADIOQUEUE:Broadcast(transmission)
|
||||
|
||||
-- Get unit sending the transmission.
|
||||
local sender=self:_GetRadioSender()
|
||||
|
||||
-- Construct file name.
|
||||
local filename=string.format("%s%s", transmission.path, transmission.filename)
|
||||
|
||||
-- Create subtitle for transmission.
|
||||
--local subtitle=self:_RadioSubtitle(radio, call, loud)
|
||||
|
||||
if sender then
|
||||
|
||||
-- Broadcasting from aircraft. Only players tuned in to the right frequency will see the message.
|
||||
self:T(self.lid..string.format("Broadcasting from aircraft %s", sender:GetName()))
|
||||
|
||||
-- Command to set the Frequency for the transmission.
|
||||
local commandFrequency={
|
||||
id="SetFrequency",
|
||||
params={
|
||||
frequency=self.frequency, -- Frequency in Hz.
|
||||
modulation=self.modulation,
|
||||
}}
|
||||
|
||||
-- Command to tranmit the call.
|
||||
local commandTransmit={
|
||||
id = "TransmitMessage",
|
||||
params = {
|
||||
file=filename,
|
||||
duration=transmission.subduration or 5,
|
||||
subtitle=transmission.subtitle or "",
|
||||
loop=false,
|
||||
}}
|
||||
|
||||
-- Set commend for frequency
|
||||
sender:SetCommand(commandFrequency)
|
||||
|
||||
-- Set command for radio transmission.
|
||||
sender:SetCommand(commandTransmit)
|
||||
|
||||
else
|
||||
|
||||
-- Broadcasting from carrier. No subtitle possible. Need to send messages to players.
|
||||
self:T(self.lid..string.format("Broadcasting from carrier via trigger.action.radioTransmission()."))
|
||||
|
||||
-- Position from where to transmit.
|
||||
local vec3=nil
|
||||
|
||||
-- Try to get positon from sender unit/static.
|
||||
if self.sendername then
|
||||
local coord=self:_GetRadioSenderCoord()
|
||||
if coord then
|
||||
vec3=coord:GetVec3()
|
||||
end
|
||||
end
|
||||
|
||||
-- Try to get fixed positon.
|
||||
if self.sendercoord and not vec3 then
|
||||
vec3=self.sendercoord:GetVec3()
|
||||
end
|
||||
|
||||
-- Transmit via trigger.
|
||||
if vec3 then
|
||||
trigger.action.radioTransmission(filename, vec3, self.modulation, false, self.frequency, self.power)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
--- Check radio queue for transmissions to be broadcasted.
|
||||
-- @param #RADIOQUEUE self
|
||||
function RADIOQUEUE:_CheckRadioQueue()
|
||||
|
||||
-- Check if queue is empty.
|
||||
if #self.queue==0 then
|
||||
return
|
||||
end
|
||||
|
||||
-- Get current abs time.
|
||||
local time=timer.getAbsTime()
|
||||
|
||||
local playing=false
|
||||
local next=nil --#RADIOQUEUE.Transmission
|
||||
local remove=nil
|
||||
for i,_transmission in ipairs(self.queue) do
|
||||
local transmission=_transmission --#RADIOQUEUE.Transmission
|
||||
|
||||
-- Check if transmission time has passed.
|
||||
if time>=transmission.Tplay then
|
||||
|
||||
-- Check if transmission is currently playing.
|
||||
if transmission.isplaying then
|
||||
|
||||
-- Check if transmission is finished.
|
||||
if time>=transmission.Tstarted+transmission.duration then
|
||||
|
||||
-- Transmission over.
|
||||
transmission.isplaying=false
|
||||
|
||||
-- Remove ith element in queue.
|
||||
remove=i
|
||||
|
||||
-- Store time last transmission finished.
|
||||
self.Tlast=time
|
||||
|
||||
else -- still playing
|
||||
|
||||
-- Transmission is still playing.
|
||||
playing=true
|
||||
|
||||
end
|
||||
|
||||
else -- not playing yet
|
||||
|
||||
local Tlast=self.Tlast
|
||||
|
||||
if transmission.interval==nil then
|
||||
|
||||
-- Not playing ==> this will be next.
|
||||
if next==nil then
|
||||
next=transmission
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
if Tlast==nil or time-Tlast>=transmission.interval then
|
||||
next=transmission
|
||||
else
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
-- We got a transmission or one with an interval that is not due yet. No need for anything else.
|
||||
if next or Tlast then
|
||||
break
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
-- Transmission not due yet.
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
-- Found a new transmission.
|
||||
if next~=nil and not playing then
|
||||
self:Broadcast(next)
|
||||
next.isplaying=true
|
||||
next.Tstarted=time
|
||||
end
|
||||
|
||||
-- Remove completed calls from queue.
|
||||
if remove then
|
||||
table.remove(self.queue, remove)
|
||||
end
|
||||
|
||||
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 Wrapper.Unit#UNIT Sending aircraft unit or nil if was not setup, is not an aircraft or is not alive.
|
||||
function RADIOQUEUE:_GetRadioSender()
|
||||
|
||||
-- Check if we have a sending aircraft.
|
||||
local sender=nil --Wrapper.Unit#UNIT
|
||||
|
||||
-- Try the general default.
|
||||
if self.sendername then
|
||||
-- First try to find a unit
|
||||
sender=UNIT:FindByName(self.sendername)
|
||||
|
||||
-- Check that sender is alive and an aircraft.
|
||||
if sender and sender:IsAlive() and sender:IsAir() then
|
||||
return sender
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return nil
|
||||
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.
|
||||
function RADIOQUEUE:_GetRadioSenderCoord()
|
||||
|
||||
local vec3=nil
|
||||
|
||||
-- Try the general default.
|
||||
if self.sendername then
|
||||
|
||||
-- First try to find a unit
|
||||
local sender=UNIT:FindByName(self.sendername)
|
||||
|
||||
-- Check that sender is alive and an aircraft.
|
||||
if sender and sender:IsAlive() then
|
||||
return sender:GetCoodinate()
|
||||
end
|
||||
|
||||
-- Now try a static.
|
||||
local sender=STATIC:FindByName(self.sendername)
|
||||
|
||||
-- Check that sender is alive and an aircraft.
|
||||
if sender then
|
||||
return sender:GetCoodinate()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
@@ -0,0 +1,483 @@
|
||||
--- **Core** - Queues Radio Transmissions.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ## Features:
|
||||
--
|
||||
-- * Managed Radio Transmissions.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Authors: funkyfranky
|
||||
--
|
||||
-- @module Core.RadioQueue
|
||||
-- @image Core_Radio.JPG
|
||||
|
||||
--- Manages radio transmissions.
|
||||
--
|
||||
-- @type RADIOQUEUE
|
||||
-- @field #string ClassName Name of the class "RADIOQUEUE".
|
||||
-- @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.
|
||||
-- @field Core.Scheduler#SCHEDULER scheduler The scheduler.
|
||||
-- @field #string RQid The radio queue scheduler ID.
|
||||
-- @field #table queue The queue of transmissions.
|
||||
-- @field #number Tlast Time (abs) when the last transmission finished.
|
||||
-- @field Core.Point#COORDINATE sendercoord Coordinate from where transmissions are broadcasted.
|
||||
-- @field #number sendername Name of the sending unit or static.
|
||||
-- @field Wrapper.Positionable#POSITIONABLE positionable The positionable to broadcast the message.
|
||||
-- @field #number power Power of radio station in Watts. Default 100 W.
|
||||
-- @field #table numbers Table of number transmission parameters.
|
||||
-- @extends Core.Base#BASE
|
||||
RADIOQUEUE = {
|
||||
ClassName = "RADIOQUEUE",
|
||||
lid=nil,
|
||||
frequency=nil,
|
||||
modulation=nil,
|
||||
scheduler=nil,
|
||||
RQid=nil,
|
||||
queue={},
|
||||
Tlast=nil,
|
||||
sendercoord=nil,
|
||||
sendername=nil,
|
||||
positionable=nil,
|
||||
power=100,
|
||||
numbers={},
|
||||
}
|
||||
|
||||
--- Radio queue transmission data.
|
||||
-- @type RADIOQUEUE.Transmission
|
||||
-- @field #string filename Name of the file to be transmitted.
|
||||
-- @field #string path Path in miz file where the file is located.
|
||||
-- @field #number duration Duration in seconds.
|
||||
-- @field #number Tstarted Mission time (abs) in seconds when the transmission started.
|
||||
-- @field #boolean isplaying If true, transmission is currently playing.
|
||||
-- @field #number Tplay Mission time (abs) in seconds when the transmission should be played.
|
||||
|
||||
|
||||
--- Create a new RADIOQUEUE object for a given radio frequency/modulation.
|
||||
-- @param #RADIOQUEUE self
|
||||
-- @param #number frequency The radio frequency in MHz.
|
||||
-- @param #number modulation (Optional) The radio modulation. Default radio.modulation.AM.
|
||||
-- @return #RADIOQUEUE self The RADIOQUEUE object.
|
||||
function RADIOQUEUE:New(frequency, modulation)
|
||||
|
||||
-- Inherit base
|
||||
local self=BASE:Inherit(self, BASE:New()) -- #RADIOQUEUE
|
||||
|
||||
self.lid="RADIOQUEUE | "
|
||||
|
||||
if frequency==nil then
|
||||
self:E(self.lid.."ERROR: No frequency specified as first parameter!")
|
||||
return nil
|
||||
end
|
||||
|
||||
-- Frequency in Hz.
|
||||
self.frequency=frequency*1000000
|
||||
|
||||
-- Modulation.
|
||||
self.modulation=modulation or radio.modulation.AM
|
||||
|
||||
-- Scheduler
|
||||
self.scheduler=SCHEDULER:New()
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Start the radio queue.
|
||||
-- @param #RADIOQUEUE self
|
||||
-- @param #number delay (Optional) Delay in seconds, before the radio queue is started. Default 1 sec.
|
||||
-- @param #number dt (Optional) Time step in seconds for checking the queue. Default 0.01 sec.
|
||||
-- @return #RADIOQUEUE self The RADIOQUEUE object.
|
||||
function RADIOQUEUE:Start(delay, dt)
|
||||
|
||||
delay=delay or 1
|
||||
|
||||
dt=dt or 0.01
|
||||
|
||||
self:I(self.lid..string.format("Starting RADIOQUEUE in %.1f seconds with interval dt=%.3f seconds.", delay, dt))
|
||||
|
||||
self.RQid=self.scheduler:Schedule(self, self._CheckRadioQueue, {}, delay, dt)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Stop the radio queue. Stop scheduler and delete queue.
|
||||
-- @param #RADIOQUEUE self
|
||||
-- @return #RADIOQUEUE self The RADIOQUEUE object.
|
||||
function RADIOQUEUE:Stop()
|
||||
self:I(self.lid.."Stopping RADIOQUEUE.")
|
||||
self.scheduler:Stop(self.RQid)
|
||||
self.queue={}
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set coordinate from where the transmission is broadcasted.
|
||||
-- @param #RADIOQUEUE self
|
||||
-- @param Core.Point#COORDINATE coordinate Coordinate of the sender.
|
||||
-- @return #RADIOQUEUE self The RADIOQUEUE object.
|
||||
function RADIOQUEUE:SetSenderCoordinate(coordinate)
|
||||
self.sendercoord=coordinate
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set name of unit or static from which transmissions are made.
|
||||
-- @param #RADIOQUEUE self
|
||||
-- @param #string name Name of the unit or static used for transmissions.
|
||||
-- @return #RADIOQUEUE self The RADIOQUEUE object.
|
||||
function RADIOQUEUE:SetSenderUnitName(name)
|
||||
self.sendername=name
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set parameters of a digit.
|
||||
-- @param #RADIOQUEUE self
|
||||
-- @param #number digit The digit 0-9.
|
||||
-- @param #string filename The name of the sound file.
|
||||
-- @param #number duration The duration of the sound file in seconds.
|
||||
-- @param #string path The directory within the miz file where the sound is located. Default "l10n/DEFAULT/".
|
||||
-- @return #RADIOQUEUE self The RADIOQUEUE object.
|
||||
function RADIOQUEUE:SetDigit(digit, filename, duration, path)
|
||||
|
||||
local transmission={} --#RADIOQUEUE.Transmission
|
||||
transmission.filename=filename
|
||||
transmission.duration=duration
|
||||
transmission.path=path or "l10n/DEFAULT/"
|
||||
|
||||
-- Convert digit to string in case it is given as a number.
|
||||
if type(digit)=="number" then
|
||||
digit=tostring(digit)
|
||||
end
|
||||
|
||||
-- Set transmission.
|
||||
self.numbers[digit]=transmission
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Add a transmission to the radio queue.
|
||||
-- @param #RADIOQUEUE self
|
||||
-- @param #RADIOQUEUE.Transmission transmission The transmission data table.
|
||||
-- @return #RADIOQUEUE self The RADIOQUEUE object.
|
||||
function RADIOQUEUE:AddTransmission(transmission)
|
||||
self:F({transmission=transmission})
|
||||
|
||||
-- Init.
|
||||
transmission.isplaying=false
|
||||
transmission.Tstarted=nil
|
||||
|
||||
-- Add to queue.
|
||||
table.insert(self.queue, transmission)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Add a transmission to the radio queue.
|
||||
-- @param #RADIOQUEUE self
|
||||
-- @param #string filename Name of the sound file. Usually an ogg or wav file type.
|
||||
-- @param #number duration Duration in seconds the file lasts.
|
||||
-- @param #number path Directory path inside the miz file where the sound file is located. Default "l10n/DEFAULT/".
|
||||
-- @param #number tstart Start time (abs) seconds. Default now.
|
||||
-- @param #number interval Interval in seconds after the last transmission finished.
|
||||
-- @return #RADIOQUEUE self The RADIOQUEUE object.
|
||||
function RADIOQUEUE:NewTransmission(filename, duration, path, tstart, interval)
|
||||
|
||||
-- Sanity checks.
|
||||
if not filename then
|
||||
self:E(self.lid.."ERROR: No filename specified.")
|
||||
return nil
|
||||
end
|
||||
if type(filename)~="string" then
|
||||
self:E(self.lid.."ERROR: Filename specified is NOT a string.")
|
||||
return nil
|
||||
end
|
||||
|
||||
if not duration then
|
||||
self:E(self.lid.."ERROR: No duration of transmission specified.")
|
||||
return nil
|
||||
end
|
||||
if type(duration)~="number" then
|
||||
self:E(self.lid.."ERROR: Duration specified is NOT a number.")
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
local transmission={} --#RADIOQUEUE.Transmission
|
||||
transmission.filename=filename
|
||||
transmission.duration=duration
|
||||
transmission.path=path or "l10n/DEFAULT/"
|
||||
transmission.Tplay=tstart or timer.getAbsTime()
|
||||
|
||||
-- Add transmission to queue.
|
||||
self:AddTransmission(transmission)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Convert a number (as string) into a radio transmission.
|
||||
-- E.g. for board number or headings.
|
||||
-- @param #RADIOQUEUE self
|
||||
-- @param #string number Number string, e.g. "032" or "183".
|
||||
-- @param #number delay Delay before transmission in seconds.
|
||||
-- @param #number interval Interval between the next call.
|
||||
-- @return #number Duration of the call in seconds.
|
||||
function RADIOQUEUE:Number2Transmission(number, delay, interval)
|
||||
|
||||
--- Split string into characters.
|
||||
local function _split(str)
|
||||
local chars={}
|
||||
for i=1,#str do
|
||||
local c=str:sub(i,i)
|
||||
table.insert(chars, c)
|
||||
end
|
||||
return chars
|
||||
end
|
||||
|
||||
-- Split string into characters.
|
||||
local numbers=_split(number)
|
||||
|
||||
local wait=0
|
||||
for i=1,#numbers do
|
||||
|
||||
-- Current number
|
||||
local n=numbers[i]
|
||||
|
||||
-- Radio call.
|
||||
local transmission=UTILS.DeepCopy(self.numbers[n]) --#RADIOQUEUE.Transmission
|
||||
|
||||
transmission.Tplay=timer.getAbsTime()+(delay or 0)
|
||||
|
||||
if interval and i==1 then
|
||||
transmission.interval=interval
|
||||
end
|
||||
|
||||
self:AddTransmission(transmission)
|
||||
|
||||
-- Add up duration of the number.
|
||||
wait=wait+transmission.duration
|
||||
end
|
||||
|
||||
-- Return the total duration of the call.
|
||||
return wait
|
||||
end
|
||||
|
||||
|
||||
--- Broadcast radio message.
|
||||
-- @param #RADIOQUEUE self
|
||||
-- @param #RADIOQUEUE.Transmission transmission The transmission.
|
||||
function RADIOQUEUE:Broadcast(transmission)
|
||||
|
||||
-- Get unit sending the transmission.
|
||||
local sender=self:_GetRadioSender()
|
||||
|
||||
-- Construct file name.
|
||||
local filename=string.format("%s%s", transmission.path, transmission.filename)
|
||||
|
||||
-- Create subtitle for transmission.
|
||||
--local subtitle=self:_RadioSubtitle(radio, call, loud)
|
||||
|
||||
if sender then
|
||||
|
||||
-- Broadcasting from aircraft. Only players tuned in to the right frequency will see the message.
|
||||
self:T(self.lid..string.format("Broadcasting from aircraft %s", sender:GetName()))
|
||||
|
||||
-- Command to set the Frequency for the transmission.
|
||||
local commandFrequency={
|
||||
id="SetFrequency",
|
||||
params={
|
||||
frequency=self.frequency, -- Frequency in Hz.
|
||||
modulation=self.modulation,
|
||||
}}
|
||||
|
||||
-- Command to tranmit the call.
|
||||
local commandTransmit={
|
||||
id = "TransmitMessage",
|
||||
params = {
|
||||
file=filename,
|
||||
duration=transmission.subduration or 5,
|
||||
subtitle=transmission.subtitle or "",
|
||||
loop=false,
|
||||
}}
|
||||
|
||||
-- Set commend for frequency
|
||||
sender:SetCommand(commandFrequency)
|
||||
|
||||
-- Set command for radio transmission.
|
||||
sender:SetCommand(commandTransmit)
|
||||
|
||||
else
|
||||
|
||||
-- Broadcasting from carrier. No subtitle possible. Need to send messages to players.
|
||||
self:T(self.lid..string.format("Broadcasting from carrier via trigger.action.radioTransmission()."))
|
||||
|
||||
-- Position from where to transmit.
|
||||
local vec3=nil
|
||||
|
||||
-- Try to get positon from sender unit/static.
|
||||
if self.sendername then
|
||||
local coord=self:_GetRadioSenderCoord()
|
||||
if coord then
|
||||
vec3=coord:GetVec3()
|
||||
end
|
||||
end
|
||||
|
||||
-- Try to get fixed positon.
|
||||
if self.sendercoord and not vec3 then
|
||||
vec3=self.sendercoord:GetVec3()
|
||||
end
|
||||
|
||||
-- Transmit via trigger.
|
||||
if vec3 then
|
||||
self:E("Sending")
|
||||
self:E( { filename = filename, vec3 = vec3, modulation = self.modulation, frequency = self.frequency, power = self.power } )
|
||||
trigger.action.radioTransmission(filename, vec3, self.modulation, false, self.frequency, self.power)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
--- Check radio queue for transmissions to be broadcasted.
|
||||
-- @param #RADIOQUEUE self
|
||||
function RADIOQUEUE:_CheckRadioQueue()
|
||||
|
||||
-- Check if queue is empty.
|
||||
if #self.queue==0 then
|
||||
return
|
||||
end
|
||||
|
||||
-- Get current abs time.
|
||||
local time=timer.getAbsTime()
|
||||
|
||||
local playing=false
|
||||
local next=nil --#RADIOQUEUE.Transmission
|
||||
local remove=nil
|
||||
for i,_transmission in ipairs(self.queue) do
|
||||
local transmission=_transmission --#RADIOQUEUE.Transmission
|
||||
|
||||
-- Check if transmission time has passed.
|
||||
if time>=transmission.Tplay then
|
||||
|
||||
-- Check if transmission is currently playing.
|
||||
if transmission.isplaying then
|
||||
|
||||
-- Check if transmission is finished.
|
||||
if time>=transmission.Tstarted+transmission.duration then
|
||||
|
||||
-- Transmission over.
|
||||
transmission.isplaying=false
|
||||
|
||||
-- Remove ith element in queue.
|
||||
remove=i
|
||||
|
||||
-- Store time last transmission finished.
|
||||
self.Tlast=time
|
||||
|
||||
else -- still playing
|
||||
|
||||
-- Transmission is still playing.
|
||||
playing=true
|
||||
|
||||
end
|
||||
|
||||
else -- not playing yet
|
||||
|
||||
local Tlast=self.Tlast
|
||||
|
||||
if transmission.interval==nil then
|
||||
|
||||
-- Not playing ==> this will be next.
|
||||
if next==nil then
|
||||
next=transmission
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
if Tlast==nil or time-Tlast>=transmission.interval then
|
||||
next=transmission
|
||||
else
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
-- We got a transmission or one with an interval that is not due yet. No need for anything else.
|
||||
if next or Tlast then
|
||||
break
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
-- Transmission not due yet.
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
-- Found a new transmission.
|
||||
if next~=nil and not playing then
|
||||
self:Broadcast(next)
|
||||
next.isplaying=true
|
||||
next.Tstarted=time
|
||||
end
|
||||
|
||||
-- Remove completed calls from queue.
|
||||
if remove then
|
||||
table.remove(self.queue, remove)
|
||||
end
|
||||
|
||||
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 Wrapper.Unit#UNIT Sending aircraft unit or nil if was not setup, is not an aircraft or is not alive.
|
||||
function RADIOQUEUE:_GetRadioSender()
|
||||
|
||||
-- Check if we have a sending aircraft.
|
||||
local sender=nil --Wrapper.Unit#UNIT
|
||||
|
||||
-- Try the general default.
|
||||
if self.sendername then
|
||||
-- First try to find a unit
|
||||
sender=UNIT:FindByName(self.sendername)
|
||||
|
||||
-- Check that sender is alive and an aircraft.
|
||||
if sender and sender:IsAlive() and sender:IsAir() then
|
||||
return sender
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return nil
|
||||
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.
|
||||
function RADIOQUEUE:_GetRadioSenderCoord()
|
||||
|
||||
local vec3=nil
|
||||
|
||||
-- Try the general default.
|
||||
if self.sendername then
|
||||
|
||||
-- First try to find a unit
|
||||
local sender=UNIT:FindByName(self.sendername)
|
||||
|
||||
-- Check that sender is alive and an aircraft.
|
||||
if sender and sender:IsAlive() then
|
||||
return sender:GetCoordinate()
|
||||
end
|
||||
|
||||
-- Now try a static.
|
||||
local sender=STATIC:FindByName(self.sendername)
|
||||
|
||||
-- Check that sender is alive and an aircraft.
|
||||
if sender then
|
||||
return sender:GetCoordinate()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
@@ -52,8 +52,8 @@ end
|
||||
-- Nothing of this code should be modified without testing it thoroughly.
|
||||
-- @param #SCHEDULEDISPATCHER self
|
||||
-- @param Core.Scheduler#SCHEDULER Scheduler
|
||||
function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleArguments, Start, Repeat, Randomize, Stop )
|
||||
self:F2( { Scheduler, ScheduleFunction, ScheduleArguments, Start, Repeat, Randomize, Stop } )
|
||||
function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleArguments, Start, Repeat, Randomize, Stop, TraceLevel, Fsm )
|
||||
self:F2( { Scheduler, ScheduleFunction, ScheduleArguments, Start, Repeat, Randomize, Stop, TraceLevel } )
|
||||
|
||||
self.CallID = self.CallID + 1
|
||||
local CallID = self.CallID .. "#" .. ( Scheduler.MasterObject and Scheduler.MasterObject.GetClassNameAndID and Scheduler.MasterObject:GetClassNameAndID() or "" ) or ""
|
||||
@@ -84,11 +84,52 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
|
||||
self.Schedule[Scheduler][CallID].Repeat = Repeat or 0
|
||||
self.Schedule[Scheduler][CallID].Randomize = Randomize or 0
|
||||
self.Schedule[Scheduler][CallID].Stop = Stop
|
||||
|
||||
|
||||
-- This section handles the tracing of the scheduled calls.
|
||||
-- Because these calls will be executed with a delay, we inspect the place where these scheduled calls are initiated.
|
||||
-- The Info structure contains the output of the debug.getinfo() calls, which inspects the call stack for the function name, line number and source name.
|
||||
-- The call stack has many levels, and the correct semantical function call depends on where in the code AddSchedule was "used".
|
||||
-- - Using SCHEDULER:New()
|
||||
-- - Using Schedule:AddSchedule()
|
||||
-- - Using Fsm:__Func()
|
||||
-- - Using Class:ScheduleOnce()
|
||||
-- - Using Class:ScheduleRepeat()
|
||||
-- - ...
|
||||
-- So for each of these scheduled call variations, AddSchedule is the workhorse which will schedule the call.
|
||||
-- But the correct level with the correct semantical function location will differ depending on the above scheduled call invocation forms.
|
||||
-- That's where the field TraceLevel contains optionally the level in the call stack where the call information is obtained.
|
||||
-- The TraceLevel field indicates the correct level where the semantical scheduled call was invoked within the source, ensuring that function name, line number and source name are correct.
|
||||
-- There is one quick ...
|
||||
-- The FSM class models scheduled calls using the __Func syntax. However, these functions are "tailed".
|
||||
-- There aren't defined anywhere within the source code, but rather implemented as triggers within the FSM logic,
|
||||
-- and using the onbefore, onafter, onenter, onleave prefixes. (See the FSM for details).
|
||||
-- Therefore, in the call stack, at the TraceLevel these functions are mentioned as "tail calls", and the Info.name field will be nil as a result.
|
||||
-- To obtain the correct function name for FSM object calls, the function is mentioned in the call stack at a higher stack level.
|
||||
-- So when function name stored in Info.name is nil, then I inspect the function name within the call stack one level higher.
|
||||
-- So this little piece of code does its magic wonderfully, preformance overhead is neglectible, as scheduled calls don't happen that often.
|
||||
|
||||
local Info = {}
|
||||
|
||||
if debug then
|
||||
TraceLevel = TraceLevel or 2
|
||||
Info = debug.getinfo( TraceLevel, "nlS" )
|
||||
local name_fsm = debug.getinfo( TraceLevel - 1, "n" ).name -- #string
|
||||
if name_fsm then
|
||||
Info.name = name_fsm
|
||||
end
|
||||
--env.info( debug.traceback() )
|
||||
end
|
||||
|
||||
self:T3( self.Schedule[Scheduler][CallID] )
|
||||
|
||||
self.Schedule[Scheduler][CallID].CallHandler = function( CallID )
|
||||
--self:E( CallID )
|
||||
self.Schedule[Scheduler][CallID].CallHandler = function( Params )
|
||||
|
||||
local CallID = Params.CallID
|
||||
local Info = Params.Info
|
||||
local Source = Info.source or "?"
|
||||
local Line = Info.currentline or "?"
|
||||
local Name = Info.name or "?"
|
||||
|
||||
local ErrorHandler = function( errmsg )
|
||||
env.info( "Error in timer function: " .. errmsg )
|
||||
@@ -122,15 +163,19 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
|
||||
local Stop = Schedule.Stop or 0
|
||||
local ScheduleID = Schedule.ScheduleID
|
||||
|
||||
local Prefix = ( Repeat == 0 ) and "--->" or "+++>"
|
||||
|
||||
local Status, Result
|
||||
--self:E( { SchedulerObject = SchedulerObject } )
|
||||
if SchedulerObject then
|
||||
local function Timer()
|
||||
SchedulerObject:T( Prefix .. Name .. ":" .. Line .. " (" .. Source .. ")" )
|
||||
return ScheduleFunction( SchedulerObject, unpack( ScheduleArguments ) )
|
||||
end
|
||||
Status, Result = xpcall( Timer, ErrorHandler )
|
||||
else
|
||||
local function Timer()
|
||||
self:T( Prefix .. Name .. ":" .. Line .. " (" .. Source .. ")" )
|
||||
return ScheduleFunction( unpack( ScheduleArguments ) )
|
||||
end
|
||||
Status, Result = xpcall( Timer, ErrorHandler )
|
||||
@@ -161,13 +206,13 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
|
||||
self:Stop( Scheduler, CallID )
|
||||
end
|
||||
else
|
||||
self:E( "Scheduled obsolete call for CallID: " .. CallID )
|
||||
self:I( "<<<>" .. Name .. ":" .. Line .. " (" .. Source .. ")" )
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
self:Start( Scheduler, CallID )
|
||||
self:Start( Scheduler, CallID, Info )
|
||||
|
||||
return CallID
|
||||
end
|
||||
@@ -181,7 +226,7 @@ function SCHEDULEDISPATCHER:RemoveSchedule( Scheduler, CallID )
|
||||
end
|
||||
end
|
||||
|
||||
function SCHEDULEDISPATCHER:Start( Scheduler, CallID )
|
||||
function SCHEDULEDISPATCHER:Start( Scheduler, CallID, Info )
|
||||
self:F2( { Start = CallID, Scheduler = Scheduler } )
|
||||
|
||||
if CallID then
|
||||
@@ -192,13 +237,13 @@ function SCHEDULEDISPATCHER:Start( Scheduler, CallID )
|
||||
Schedule[CallID].StartTime = timer.getTime() -- Set the StartTime field to indicate when the scheduler started.
|
||||
Schedule[CallID].ScheduleID = timer.scheduleFunction(
|
||||
Schedule[CallID].CallHandler,
|
||||
CallID,
|
||||
{ CallID = CallID, Info = Info },
|
||||
timer.getTime() + Schedule[CallID].Start
|
||||
)
|
||||
end
|
||||
else
|
||||
for CallID, Schedule in pairs( self.Schedule[Scheduler] or {} ) do
|
||||
self:Start( Scheduler, CallID ) -- Recursive
|
||||
self:Start( Scheduler, CallID, Info ) -- Recursive
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -216,7 +216,7 @@ function SCHEDULER:New( SchedulerObject, SchedulerFunction, SchedulerArguments,
|
||||
self.MasterObject = SchedulerObject
|
||||
|
||||
if SchedulerFunction then
|
||||
ScheduleID = self:Schedule( SchedulerObject, SchedulerFunction, SchedulerArguments, Start, Repeat, RandomizeFactor, Stop )
|
||||
ScheduleID = self:Schedule( SchedulerObject, SchedulerFunction, SchedulerArguments, Start, Repeat, RandomizeFactor, Stop, 4 )
|
||||
end
|
||||
|
||||
return self, ScheduleID
|
||||
@@ -238,7 +238,7 @@ end
|
||||
-- @param #number RandomizeFactor Specifies a randomization factor between 0 and 1 to randomize the Repeat.
|
||||
-- @param #number Stop Specifies the amount of seconds when the scheduler will be stopped.
|
||||
-- @return #number The ScheduleID of the planned schedule.
|
||||
function SCHEDULER:Schedule( SchedulerObject, SchedulerFunction, SchedulerArguments, Start, Repeat, RandomizeFactor, Stop )
|
||||
function SCHEDULER:Schedule( SchedulerObject, SchedulerFunction, SchedulerArguments, Start, Repeat, RandomizeFactor, Stop, TraceLevel, Fsm )
|
||||
self:F2( { Start, Repeat, RandomizeFactor, Stop } )
|
||||
self:T3( { SchedulerArguments } )
|
||||
|
||||
@@ -256,7 +256,9 @@ function SCHEDULER:Schedule( SchedulerObject, SchedulerFunction, SchedulerArgume
|
||||
Start,
|
||||
Repeat,
|
||||
RandomizeFactor,
|
||||
Stop
|
||||
Stop,
|
||||
TraceLevel or 3,
|
||||
Fsm
|
||||
)
|
||||
|
||||
self.Schedules[#self.Schedules+1] = ScheduleID
|
||||
|
||||
@@ -384,7 +384,6 @@ do -- SET_BASE
|
||||
for ObjectName, Object in pairs( self.Database ) do
|
||||
|
||||
if self:IsIncludeObject( Object ) then
|
||||
self:E( { "Adding Object:", ObjectName } )
|
||||
self:Add( ObjectName, Object )
|
||||
end
|
||||
end
|
||||
@@ -5497,4 +5496,324 @@ do -- SET_ZONE
|
||||
return nil
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
do -- SET_ZONE_GOAL
|
||||
|
||||
--- @type SET_ZONE_GOAL
|
||||
-- @extends Core.Set#SET_BASE
|
||||
|
||||
--- Mission designers can use the @{Core.Set#SET_ZONE_GOAL} class to build sets of zones of various types.
|
||||
--
|
||||
-- ## SET_ZONE_GOAL constructor
|
||||
--
|
||||
-- Create a new SET_ZONE_GOAL object with the @{#SET_ZONE_GOAL.New} method:
|
||||
--
|
||||
-- * @{#SET_ZONE_GOAL.New}: Creates a new SET_ZONE_GOAL object.
|
||||
--
|
||||
-- ## Add or Remove ZONEs from SET_ZONE_GOAL
|
||||
--
|
||||
-- ZONEs can be added and removed using the @{Core.Set#SET_ZONE_GOAL.AddZonesByName} and @{Core.Set#SET_ZONE_GOAL.RemoveZonesByName} respectively.
|
||||
-- These methods take a single ZONE name or an array of ZONE names to be added or removed from SET_ZONE_GOAL.
|
||||
--
|
||||
-- ## SET_ZONE_GOAL filter criteria
|
||||
--
|
||||
-- You can set filter criteria to build the collection of zones in SET_ZONE_GOAL.
|
||||
-- Filter criteria are defined by:
|
||||
--
|
||||
-- * @{#SET_ZONE_GOAL.FilterPrefixes}: Builds the SET_ZONE_GOAL with the zones having a certain text pattern of prefix.
|
||||
--
|
||||
-- Once the filter criteria have been set for the SET_ZONE_GOAL, you can start filtering using:
|
||||
--
|
||||
-- * @{#SET_ZONE_GOAL.FilterStart}: Starts the filtering of the zones within the SET_ZONE_GOAL.
|
||||
--
|
||||
-- ## SET_ZONE_GOAL iterators
|
||||
--
|
||||
-- Once the filters have been defined and the SET_ZONE_GOAL has been built, you can iterate the SET_ZONE_GOAL with the available iterator methods.
|
||||
-- The iterator methods will walk the SET_ZONE_GOAL set, and call for each airbase within the set a function that you provide.
|
||||
-- The following iterator methods are currently available within the SET_ZONE_GOAL:
|
||||
--
|
||||
-- * @{#SET_ZONE_GOAL.ForEachZone}: Calls a function for each zone it finds within the SET_ZONE_GOAL.
|
||||
--
|
||||
-- ===
|
||||
-- @field #SET_ZONE_GOAL SET_ZONE_GOAL
|
||||
SET_ZONE_GOAL = {
|
||||
ClassName = "SET_ZONE_GOAL",
|
||||
Zones = {},
|
||||
Filter = {
|
||||
Prefixes = nil,
|
||||
},
|
||||
FilterMeta = {
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
--- Creates a new SET_ZONE_GOAL object, building a set of zones.
|
||||
-- @param #SET_ZONE_GOAL self
|
||||
-- @return #SET_ZONE_GOAL self
|
||||
-- @usage
|
||||
-- -- Define a new SET_ZONE_GOAL Object. The DatabaseSet will contain a reference to all Zones.
|
||||
-- DatabaseSet = SET_ZONE_GOAL:New()
|
||||
function SET_ZONE_GOAL:New()
|
||||
-- Inherits from BASE
|
||||
local self = BASE:Inherit( self, SET_BASE:New( _DATABASE.ZONES_GOAL ) )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Add ZONEs to SET_ZONE_GOAL.
|
||||
-- @param Core.Set#SET_ZONE_GOAL self
|
||||
-- @param Core.Zone#ZONE_BASE Zone A ZONE_BASE object.
|
||||
-- @return self
|
||||
function SET_ZONE_GOAL:AddZone( Zone )
|
||||
|
||||
self:Add( Zone:GetName(), Zone )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Remove ZONEs from SET_ZONE_GOAL.
|
||||
-- @param Core.Set#SET_ZONE_GOAL self
|
||||
-- @param Core.Zone#ZONE_BASE RemoveZoneNames A single name or an array of ZONE_BASE names.
|
||||
-- @return self
|
||||
function SET_ZONE_GOAL:RemoveZonesByName( RemoveZoneNames )
|
||||
|
||||
local RemoveZoneNamesArray = ( type( RemoveZoneNames ) == "table" ) and RemoveZoneNames or { RemoveZoneNames }
|
||||
|
||||
for RemoveZoneID, RemoveZoneName in pairs( RemoveZoneNamesArray ) do
|
||||
self:Remove( RemoveZoneName )
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Finds a Zone based on the Zone Name.
|
||||
-- @param #SET_ZONE_GOAL self
|
||||
-- @param #string ZoneName
|
||||
-- @return Core.Zone#ZONE_BASE The found Zone.
|
||||
function SET_ZONE_GOAL:FindZone( ZoneName )
|
||||
|
||||
local ZoneFound = self.Set[ZoneName]
|
||||
return ZoneFound
|
||||
end
|
||||
|
||||
|
||||
--- Get a random zone from the set.
|
||||
-- @param #SET_ZONE_GOAL self
|
||||
-- @return Core.Zone#ZONE_BASE The random Zone.
|
||||
-- @return #nil if no zone in the collection.
|
||||
function SET_ZONE_GOAL:GetRandomZone()
|
||||
|
||||
if self:Count() ~= 0 then
|
||||
|
||||
local Index = self.Index
|
||||
local ZoneFound = nil -- Core.Zone#ZONE_BASE
|
||||
|
||||
-- Loop until a zone has been found.
|
||||
-- The :GetZoneMaybe() call will evaluate the probability for the zone to be selected.
|
||||
-- If the zone is not selected, then nil is returned by :GetZoneMaybe() and the loop continues!
|
||||
while not ZoneFound do
|
||||
local ZoneRandom = math.random( 1, #Index )
|
||||
ZoneFound = self.Set[Index[ZoneRandom]]:GetZoneMaybe()
|
||||
end
|
||||
|
||||
return ZoneFound
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
--- Set a zone probability.
|
||||
-- @param #SET_ZONE_GOAL self
|
||||
-- @param #string ZoneName The name of the zone.
|
||||
function SET_ZONE_GOAL:SetZoneProbability( ZoneName, ZoneProbability )
|
||||
local Zone = self:FindZone( ZoneName )
|
||||
Zone:SetZoneProbability( ZoneProbability )
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
--- Builds a set of zones of defined zone prefixes.
|
||||
-- All the zones starting with the given prefixes will be included within the set.
|
||||
-- @param #SET_ZONE_GOAL self
|
||||
-- @param #string Prefixes The prefix of which the zone name starts with.
|
||||
-- @return #SET_ZONE_GOAL self
|
||||
function SET_ZONE_GOAL:FilterPrefixes( Prefixes )
|
||||
if not self.Filter.Prefixes then
|
||||
self.Filter.Prefixes = {}
|
||||
end
|
||||
if type( Prefixes ) ~= "table" then
|
||||
Prefixes = { Prefixes }
|
||||
end
|
||||
for PrefixID, Prefix in pairs( Prefixes ) do
|
||||
self.Filter.Prefixes[Prefix] = Prefix
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Starts the filtering.
|
||||
-- @param #SET_ZONE_GOAL self
|
||||
-- @return #SET_ZONE_GOAL self
|
||||
function SET_ZONE_GOAL:FilterStart()
|
||||
|
||||
if _DATABASE then
|
||||
|
||||
-- We initialize the first set.
|
||||
for ObjectName, Object in pairs( self.Database ) do
|
||||
if self:IsIncludeObject( Object ) then
|
||||
self:Add( ObjectName, Object )
|
||||
else
|
||||
self:RemoveZonesByName( ObjectName )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self:HandleEvent( EVENTS.NewZoneGoal )
|
||||
self:HandleEvent( EVENTS.DeleteZoneGoal )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Stops the filtering for the defined collection.
|
||||
-- @param #SET_ZONE_GOAL self
|
||||
-- @return #SET_ZONE_GOAL self
|
||||
function SET_ZONE_GOAL:FilterStop()
|
||||
|
||||
self:UnHandleEvent( EVENTS.NewZoneGoal )
|
||||
self:UnHandleEvent( EVENTS.DeleteZoneGoal )
|
||||
|
||||
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_ZONE_GOAL self
|
||||
-- @param Core.Event#EVENTDATA Event
|
||||
-- @return #string The name of the AIRBASE
|
||||
-- @return #table The AIRBASE
|
||||
function SET_ZONE_GOAL: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_ZONE_GOAL self
|
||||
-- @param Core.Event#EVENTDATA Event
|
||||
-- @return #string The name of the AIRBASE
|
||||
-- @return #table The AIRBASE
|
||||
function SET_ZONE_GOAL:FindInDatabase( Event )
|
||||
self:F3( { Event } )
|
||||
|
||||
return Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName]
|
||||
end
|
||||
|
||||
--- Iterate the SET_ZONE_GOAL and call an interator function for each ZONE, providing the ZONE and optional parameters.
|
||||
-- @param #SET_ZONE_GOAL self
|
||||
-- @param #function IteratorFunction The function that will be called when there is an alive ZONE in the SET_ZONE_GOAL. The function needs to accept a AIRBASE parameter.
|
||||
-- @return #SET_ZONE_GOAL self
|
||||
function SET_ZONE_GOAL:ForEachZone( IteratorFunction, ... )
|
||||
self:F2( arg )
|
||||
|
||||
self:ForEach( IteratorFunction, arg, self:GetSet() )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
---
|
||||
-- @param #SET_ZONE_GOAL self
|
||||
-- @param Core.Zone#ZONE_BASE MZone
|
||||
-- @return #SET_ZONE_GOAL self
|
||||
function SET_ZONE_GOAL:IsIncludeObject( MZone )
|
||||
self:F2( MZone )
|
||||
|
||||
local MZoneInclude = true
|
||||
|
||||
if MZone then
|
||||
local MZoneName = MZone:GetName()
|
||||
|
||||
if self.Filter.Prefixes then
|
||||
local MZonePrefix = false
|
||||
for ZonePrefixId, ZonePrefix in pairs( self.Filter.Prefixes ) do
|
||||
self:T3( { "Prefix:", string.find( MZoneName, ZonePrefix, 1 ), ZonePrefix } )
|
||||
if string.find( MZoneName, ZonePrefix, 1 ) then
|
||||
MZonePrefix = true
|
||||
end
|
||||
end
|
||||
self:T( { "Evaluated Prefix", MZonePrefix } )
|
||||
MZoneInclude = MZoneInclude and MZonePrefix
|
||||
end
|
||||
end
|
||||
|
||||
self:T2( MZoneInclude )
|
||||
return MZoneInclude
|
||||
end
|
||||
|
||||
--- Handles the OnEventNewZone event for the Set.
|
||||
-- @param #SET_ZONE_GOAL self
|
||||
-- @param Core.Event#EVENTDATA EventData
|
||||
function SET_ZONE_GOAL:OnEventNewZoneGoal( EventData )
|
||||
|
||||
self:I( { "New Zone Capture Coalition", EventData } )
|
||||
self:I( { "Zone Capture Coalition", EventData.ZoneGoal } )
|
||||
|
||||
if EventData.ZoneGoal then
|
||||
if EventData.ZoneGoal and self:IsIncludeObject( EventData.ZoneGoal ) then
|
||||
self:I( { "Adding Zone Capture Coalition", EventData.ZoneGoal.ZoneName, EventData.ZoneGoal } )
|
||||
self:Add( EventData.ZoneGoal.ZoneName , EventData.ZoneGoal )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Handles the OnDead or OnCrash event for alive units set.
|
||||
-- @param #SET_ZONE_GOAL self
|
||||
-- @param Core.Event#EVENTDATA EventData
|
||||
function SET_ZONE_GOAL:OnEventDeleteZoneGoal( EventData ) --R2.1
|
||||
self:F3( { EventData } )
|
||||
|
||||
if EventData.ZoneGoal then
|
||||
local Zone = _DATABASE:FindZone( EventData.ZoneGoal.ZoneName )
|
||||
if Zone and Zone.ZoneName then
|
||||
|
||||
-- When cargo was deleted, it may probably be because of an S_EVENT_DEAD.
|
||||
-- However, in the loading logic, an S_EVENT_DEAD is also generated after a Destroy() call.
|
||||
-- And this is a problem because it will remove all entries from the SET_ZONE_GOALs.
|
||||
-- To prevent this from happening, the Zone object has a flag NoDestroy.
|
||||
-- When true, the SET_ZONE_GOAL won't Remove the Zone object from the set.
|
||||
-- This flag is switched off after the event handlers have been called in the EVENT class.
|
||||
self:F( { ZoneNoDestroy=Zone.NoDestroy } )
|
||||
if Zone.NoDestroy then
|
||||
else
|
||||
self:Remove( Zone.ZoneName )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Validate if a coordinate is in one of the zones in the set.
|
||||
-- Returns the ZONE object where the coordiante is located.
|
||||
-- If zones overlap, the first zone that validates the test is returned.
|
||||
-- @param #SET_ZONE_GOAL self
|
||||
-- @param Core.Point#COORDINATE Coordinate The coordinate to be searched.
|
||||
-- @return Core.Zone#ZONE_BASE The zone that validates the coordinate location.
|
||||
-- @return #nil No zone has been found.
|
||||
function SET_ZONE_GOAL:IsCoordinateInZone( Coordinate )
|
||||
|
||||
for _, Zone in pairs( self:GetSet() ) do
|
||||
local Zone = Zone -- Core.Zone#ZONE_BASE
|
||||
if Zone:IsCoordinateInZone( Coordinate ) then
|
||||
return Zone
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
--- **Core** - Manages various settings for running missions, consumed by moose classes and provides a menu system for players to tweak settings in running missions.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
--
|
||||
-- ## Features:
|
||||
--
|
||||
--
|
||||
-- * Provide a settings menu system to the players.
|
||||
-- * Provide a player settings menu and an overall mission settings menu.
|
||||
-- * Mission settings provide default settings, while player settings override mission settings.
|
||||
@@ -11,19 +11,19 @@
|
||||
-- * Provide a menu to select between different coordinate formats for A2A coordinates.
|
||||
-- * Provide a menu to select between different message time duration options.
|
||||
-- * Provide a menu to select between different metric systems.
|
||||
--
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
--
|
||||
-- The documentation of the SETTINGS class can be found further in this document.
|
||||
--
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
--
|
||||
-- # **AUTHORS and CONTRIBUTIONS**
|
||||
--
|
||||
-- ### Contributions:
|
||||
--
|
||||
-- ### Authors:
|
||||
--
|
||||
--
|
||||
-- ### Contributions:
|
||||
--
|
||||
-- ### Authors:
|
||||
--
|
||||
-- * **FlightControl**: Design & Programming
|
||||
--
|
||||
-- @module Core.Settings
|
||||
@@ -34,168 +34,181 @@
|
||||
-- @extends Core.Base#BASE
|
||||
|
||||
--- Takes care of various settings that influence the behaviour of certain functionalities and classes within the MOOSE framework.
|
||||
--
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
--
|
||||
-- The SETTINGS class takes care of various settings that influence the behaviour of certain functionalities and classes within the MOOSE framework.
|
||||
-- SETTINGS can work on 2 levels:
|
||||
--
|
||||
-- - **Default settings**: A running mission has **Default settings**.
|
||||
--
|
||||
-- - **Default settings**: A running mission has **Default settings**.
|
||||
-- - **Player settings**: For each player its own **Player settings** can be defined, overriding the **Default settings**.
|
||||
--
|
||||
--
|
||||
-- So, when there isn't any **Player setting** defined for a player for a specific setting, or, the player cannot be identified, the **Default setting** will be used instead.
|
||||
--
|
||||
--
|
||||
-- # 1) \_SETTINGS object
|
||||
--
|
||||
--
|
||||
-- MOOSE defines by default a singleton object called **\_SETTINGS**. Use this object to modify all the **Default settings** for a running mission.
|
||||
-- For each player, MOOSE will automatically allocate also a **player settings** object, and will expose a radio menu to allow the player to adapt the settings to his own preferences.
|
||||
--
|
||||
--
|
||||
-- # 2) SETTINGS Menu
|
||||
--
|
||||
--
|
||||
-- Settings can be adapted by the Players and by the Mission Administrator through **radio menus, which are automatically available in the mission**.
|
||||
-- These menus can be found **on level F10 under "Settings"**. There are two kinds of menus generated by the system.
|
||||
--
|
||||
--
|
||||
-- ## 2.1) Default settings menu
|
||||
--
|
||||
--
|
||||
-- A menu is created automatically per Command Center that allows to modify the **Default** settings.
|
||||
-- So, when joining a CC unit, a menu will be available that allows to change the settings parameters **FOR ALL THE PLAYERS**!
|
||||
-- Note that the **Default settings** will only be used when a player has not choosen its own settings.
|
||||
--
|
||||
--
|
||||
-- ## 2.2) Player settings menu
|
||||
--
|
||||
--
|
||||
-- A menu is created automatically per Player Slot (group) that allows to modify the **Player** settings.
|
||||
-- So, when joining a slot, a menu wil be available that allows to change the settings parameters **FOR THE PLAYER ONLY**!
|
||||
-- Note that when a player has not chosen a specific setting, the **Default settings** will be used.
|
||||
--
|
||||
--
|
||||
-- ## 2.3) Show or Hide the Player Setting menus
|
||||
--
|
||||
--
|
||||
-- Of course, it may be requried not to show any setting menus. In this case, a method is available on the **\_SETTINGS object**.
|
||||
-- Use @{#SETTINGS.SetPlayerMenuOff}() to hide the player menus, and use @{#SETTINGS.SetPlayerMenuOn}() show the player menus.
|
||||
-- Note that when this method is used, any player already in a slot will not have its menus visibility changed.
|
||||
-- The option will only have effect when a player enters a new slot or changes a slot.
|
||||
--
|
||||
-- The option will only have effect when a player enters a new slot or changes a slot.
|
||||
--
|
||||
-- Example:
|
||||
--
|
||||
--
|
||||
-- _SETTINGS:SetPlayerMenuOff() -- will disable the player menus.
|
||||
-- _SETTINGS:SetPlayerMenuOn() -- will enable the player menus.
|
||||
-- -- But only when a player exits and reenters the slot these settings will have effect!
|
||||
--
|
||||
--
|
||||
--
|
||||
--
|
||||
-- # 3) Settings
|
||||
--
|
||||
--
|
||||
-- There are different settings that are managed and applied within the MOOSE framework.
|
||||
-- See below a comprehensive description of each.
|
||||
--
|
||||
--
|
||||
-- ## 3.1) **A2G coordinates** display formatting
|
||||
--
|
||||
--
|
||||
-- ### 3.1.1) A2G coordinates setting **types**
|
||||
--
|
||||
--
|
||||
-- Will customize which display format is used to indicate A2G coordinates in text as part of the Command Center communications.
|
||||
--
|
||||
--
|
||||
-- - A2G BR: [Bearing Range](https://en.wikipedia.org/wiki/Bearing_(navigation)).
|
||||
-- - A2G MGRS: The [Military Grid Reference System](https://en.wikipedia.org/wiki/Military_Grid_Reference_System). The accuracy can also be adapted.
|
||||
-- - A2G LL DMS: Lattitude Longitude [Degrees Minutes Seconds](https://en.wikipedia.org/wiki/Geographic_coordinate_conversion). The accuracy can also be adapted.
|
||||
-- - A2G LL DDM: Lattitude Longitude [Decimal Degrees Minutes](https://en.wikipedia.org/wiki/Decimal_degrees). The accuracy can also be adapted.
|
||||
--
|
||||
--
|
||||
-- ### 3.1.2) A2G coordinates setting **menu**
|
||||
--
|
||||
--
|
||||
-- The settings can be changed by using the **Default settings menu** on the Command Center or the **Player settings menu** on the Player Slot.
|
||||
--
|
||||
--
|
||||
-- ### 3.1.3) A2G coordinates setting **methods**
|
||||
--
|
||||
--
|
||||
-- There are different methods that can be used to change the **System settings** using the \_SETTINGS object.
|
||||
--
|
||||
--
|
||||
-- - @{#SETTINGS.SetA2G_BR}(): Enable the BR display formatting by default.
|
||||
-- - @{#SETTINGS.SetA2G_MGRS}(): Enable the MGRS display formatting by default. Use @{SETTINGS.SetMGRS_Accuracy}() to adapt the accuracy of the MGRS formatting.
|
||||
-- - @{#SETTINGS.SetA2G_LL_DMS}(): Enable the LL DMS display formatting by default. Use @{SETTINGS.SetLL_Accuracy}() to adapt the accuracy of the Seconds formatting.
|
||||
-- - @{#SETTINGS.SetA2G_LL_DMS}(): Enable the LL DMS display formatting by default. Use @{SETTINGS.SetLL_Accuracy}() to adapt the accuracy of the Seconds formatting.
|
||||
-- - @{#SETTINGS.SetA2G_LL_DDM}(): Enable the LL DDM display formatting by default. Use @{SETTINGS.SetLL_Accuracy}() to adapt the accuracy of the Seconds formatting.
|
||||
--
|
||||
--
|
||||
-- ### 3.1.4) A2G coordinates setting - additional notes
|
||||
--
|
||||
-- One additional note on BR. In a situation when a BR coordinate should be given,
|
||||
--
|
||||
-- One additional note on BR. In a situation when a BR coordinate should be given,
|
||||
-- but there isn't any player context (no player unit to reference from), the MGRS formatting will be applied!
|
||||
--
|
||||
--
|
||||
-- ## 3.2) **A2A coordinates** formatting
|
||||
--
|
||||
--
|
||||
-- ### 3.2.1) A2A coordinates setting **types**
|
||||
--
|
||||
--
|
||||
-- Will customize which display format is used to indicate A2A coordinates in text as part of the Command Center communications.
|
||||
--
|
||||
--
|
||||
-- - A2A BRAA: [Bearing Range Altitude Aspect](https://en.wikipedia.org/wiki/Bearing_(navigation)).
|
||||
-- - A2A MGRS: The [Military Grid Reference System](https://en.wikipedia.org/wiki/Military_Grid_Reference_System). The accuracy can also be adapted.
|
||||
-- - A2A LL DMS: Lattitude Longitude [Degrees Minutes Seconds](https://en.wikipedia.org/wiki/Geographic_coordinate_conversion). The accuracy can also be adapted.
|
||||
-- - A2A LL DDM: Lattitude Longitude [Decimal Degrees and Minutes](https://en.wikipedia.org/wiki/Decimal_degrees). The accuracy can also be adapted.
|
||||
-- - A2A BULLS: [Bullseye](http://falcon4.wikidot.com/concepts:bullseye).
|
||||
--
|
||||
--
|
||||
-- ### 3.2.2) A2A coordinates setting **menu**
|
||||
--
|
||||
--
|
||||
-- The settings can be changed by using the **Default settings menu** on the Command Center or the **Player settings menu** on the Player Slot.
|
||||
--
|
||||
--
|
||||
-- ### 3.2.3) A2A coordinates setting **methods**
|
||||
--
|
||||
--
|
||||
-- There are different methods that can be used to change the **System settings** using the \_SETTINGS object.
|
||||
--
|
||||
--
|
||||
-- - @{#SETTINGS.SetA2A_BRAA}(): Enable the BR display formatting by default.
|
||||
-- - @{#SETTINGS.SetA2A_MGRS}(): Enable the MGRS display formatting by default. Use @{SETTINGS.SetMGRS_Accuracy}() to adapt the accuracy of the MGRS formatting.
|
||||
-- - @{#SETTINGS.SetA2A_LL_DMS}(): Enable the LL DMS display formatting by default. Use @{SETTINGS.SetLL_Accuracy}() to adapt the accuracy of the Seconds formatting.
|
||||
-- - @{#SETTINGS.SetA2A_LL_DMS}(): Enable the LL DMS display formatting by default. Use @{SETTINGS.SetLL_Accuracy}() to adapt the accuracy of the Seconds formatting.
|
||||
-- - @{#SETTINGS.SetA2A_LL_DDM}(): Enable the LL DDM display formatting by default. Use @{SETTINGS.SetLL_Accuracy}() to adapt the accuracy of the Seconds formatting.
|
||||
-- - @{#SETTINGS.SetA2A_BULLS}(): Enable the BULLSeye display formatting by default.
|
||||
--
|
||||
--
|
||||
-- ### 3.2.4) A2A coordinates settings - additional notes
|
||||
--
|
||||
-- One additional note on BRAA. In a situation when a BRAA coordinate should be given,
|
||||
--
|
||||
-- One additional note on BRAA. In a situation when a BRAA coordinate should be given,
|
||||
-- but there isn't any player context (no player unit to reference from), the MGRS formatting will be applied!
|
||||
--
|
||||
--
|
||||
-- ## 3.3) **Measurements** formatting
|
||||
--
|
||||
--
|
||||
-- ### 3.3.1) Measurements setting **types**
|
||||
--
|
||||
--
|
||||
-- Will customize the measurements system being used as part as part of the Command Center communications.
|
||||
--
|
||||
--
|
||||
-- - **Metrics** system: Applies the [Metrics system](https://en.wikipedia.org/wiki/Metric_system) ...
|
||||
-- - **Imperial** system: Applies the [Imperial system](https://en.wikipedia.org/wiki/Imperial_units) ...
|
||||
--
|
||||
-- - **Imperial** system: Applies the [Imperial system](https://en.wikipedia.org/wiki/Imperial_units) ...
|
||||
--
|
||||
-- ### 3.3.2) Measurements setting **menu**
|
||||
--
|
||||
--
|
||||
-- The settings can be changed by using the **Default settings menu** on the Command Center or the **Player settings menu** on the Player Slot.
|
||||
--
|
||||
--
|
||||
-- ### 3.3.3) Measurements setting **methods**
|
||||
--
|
||||
--
|
||||
-- There are different methods that can be used to change the **Default settings** using the \_SETTINGS object.
|
||||
--
|
||||
--
|
||||
-- - @{#SETTINGS.SetMetric}(): Enable the Metric system.
|
||||
-- - @{#SETTINGS.SetImperial}(): Enable the Imperial system.
|
||||
--
|
||||
--
|
||||
-- ## 3.4) **Message** display times
|
||||
--
|
||||
--
|
||||
-- ### 3.4.1) Message setting **types**
|
||||
--
|
||||
--
|
||||
-- There are various **Message Types** that will influence the duration how long a message will appear as part of the Command Center communications.
|
||||
--
|
||||
--
|
||||
-- - **Update** message: A short update message.
|
||||
-- - **Information** message: Provides new information **while** executing a mission.
|
||||
-- - **Briefing** message: Provides a complete briefing **before** executing a mission.
|
||||
-- - **Overview report**: Provides a short report overview, the summary of the report.
|
||||
-- - **Detailed report**: Provides a complete report.
|
||||
--
|
||||
--
|
||||
-- ### 3.4.2) Message setting **menu**
|
||||
--
|
||||
--
|
||||
-- The settings can be changed by using the **Default settings menu** on the Command Center or the **Player settings menu** on the Player Slot.
|
||||
--
|
||||
--
|
||||
-- Each Message Type has specific timings that will be applied when the message is displayed.
|
||||
-- The Settings Menu will provide for each Message Type a selection of proposed durations from which can be choosen.
|
||||
-- So the player can choose its own amount of seconds how long a message should be displayed of a certain type.
|
||||
-- Note that **Update** messages can be chosen not to be displayed at all!
|
||||
--
|
||||
--
|
||||
-- ### 3.4.3) Message setting **methods**
|
||||
--
|
||||
--
|
||||
-- There are different methods that can be used to change the **System settings** using the \_SETTINGS object.
|
||||
--
|
||||
-- - @{#SETTINGS.SetMessageTime}(): Define for a specific @{Message.MESSAGE.MessageType} the duration to be displayed in seconds.
|
||||
-- - @{#SETTINGS.GetMessageTime}(): Retrieves for a specific @{Message.MESSAGE.MessageType} the duration to be displayed in seconds.
|
||||
--
|
||||
--
|
||||
-- - @{#SETTINGS.SetMessageTime}(): Define for a specific @{Message.MESSAGE.MessageType} the duration to be displayed in seconds.
|
||||
-- - @{#SETTINGS.GetMessageTime}(): Retrieves for a specific @{Message.MESSAGE.MessageType} the duration to be displayed in seconds.
|
||||
--
|
||||
-- ## 3.5) **Era** of the battle
|
||||
--
|
||||
-- The threat level metric is scaled according the era of the battle. A target that is AAA, will pose a much greather threat in WWII than on modern warfare.
|
||||
-- Therefore, there are 4 era that are defined within the settings:
|
||||
--
|
||||
-- - **WWII** era: Use for warfare with equipment during the world war II time.
|
||||
-- - **Korea** era: Use for warfare with equipment during the Korea war time.
|
||||
-- - **Cold War** era: Use for warfare with equipment during the cold war time.
|
||||
-- - **Modern** era: Use for warfare with modern equipment in the 2000s.
|
||||
--
|
||||
-- There are different API defined that you can use with the _SETTINGS object to configure your mission script to work in one of the 4 era:
|
||||
-- @{#SETTINGS.SetEraWWII}(), @{#SETTINGS.SetEraKorea}(), @{#SETTINGS.SetEraCold}(), @{#SETTINGS.SetEraModern}()
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
--
|
||||
-- @field #SETTINGS
|
||||
SETTINGS = {
|
||||
ClassName = "SETTINGS",
|
||||
@@ -204,6 +217,19 @@ SETTINGS = {
|
||||
MenuStatic = true,
|
||||
}
|
||||
|
||||
SETTINGS.__Enum = {}
|
||||
|
||||
--- @type SETTINGS.__Enum.Era
|
||||
-- @field #number WWII
|
||||
-- @field #number Korea
|
||||
-- @field #number Cold
|
||||
-- @field #number Modern
|
||||
SETTINGS.__Enum.Era = {
|
||||
WWII = 1,
|
||||
Korea = 2,
|
||||
Cold = 3,
|
||||
Modern = 4,
|
||||
}
|
||||
|
||||
|
||||
do -- SETTINGS
|
||||
@@ -211,7 +237,7 @@ do -- SETTINGS
|
||||
--- SETTINGS constructor.
|
||||
-- @param #SETTINGS self
|
||||
-- @return #SETTINGS
|
||||
function SETTINGS:Set( PlayerName )
|
||||
function SETTINGS:Set( PlayerName )
|
||||
|
||||
if PlayerName == nil then
|
||||
local self = BASE:Inherit( self, BASE:New() ) -- #SETTINGS
|
||||
@@ -225,6 +251,7 @@ do -- SETTINGS
|
||||
self:SetMessageTime( MESSAGE.Type.Information, 30 )
|
||||
self:SetMessageTime( MESSAGE.Type.Overview, 60 )
|
||||
self:SetMessageTime( MESSAGE.Type.Update, 15 )
|
||||
self:SetEraModern()
|
||||
self:SetMenutextShort(true)
|
||||
self:SetMenuStatic(true)
|
||||
return self
|
||||
@@ -245,20 +272,20 @@ do -- SETTINGS
|
||||
function SETTINGS:SetMenutextShort(onoff)
|
||||
self.MenuShort = onoff
|
||||
end
|
||||
|
||||
|
||||
--- Set menu to be static.
|
||||
-- @param #SETTINGS self
|
||||
-- @param #boolean onoff If *true* menu is static. If *false* menu will be updated after changes (default).
|
||||
function SETTINGS:SetMenuStatic(onoff)
|
||||
self.MenuStatic = onoff
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- Sets the SETTINGS metric.
|
||||
-- @param #SETTINGS self
|
||||
function SETTINGS:SetMetric()
|
||||
self.Metric = true
|
||||
end
|
||||
|
||||
|
||||
--- Gets if the SETTINGS is metric.
|
||||
-- @param #SETTINGS self
|
||||
-- @return #boolean true if metric.
|
||||
@@ -271,7 +298,7 @@ do -- SETTINGS
|
||||
function SETTINGS:SetImperial()
|
||||
self.Metric = false
|
||||
end
|
||||
|
||||
|
||||
--- Gets if the SETTINGS is imperial.
|
||||
-- @param #SETTINGS self
|
||||
-- @return #boolean true if imperial.
|
||||
@@ -308,7 +335,7 @@ do -- SETTINGS
|
||||
function SETTINGS:GetMGRS_Accuracy()
|
||||
return self.MGRS_Accuracy or _SETTINGS:GetMGRS_Accuracy()
|
||||
end
|
||||
|
||||
|
||||
--- Sets the SETTINGS Message Display Timing of a MessageType
|
||||
-- @param #SETTINGS self
|
||||
-- @param Core.Message#MESSAGE MessageType The type of the message.
|
||||
@@ -317,8 +344,8 @@ do -- SETTINGS
|
||||
self.MessageTypeTimings = self.MessageTypeTimings or {}
|
||||
self.MessageTypeTimings[MessageType] = MessageTime
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
--- Gets the SETTINGS Message Display Timing of a MessageType
|
||||
-- @param #SETTINGS self
|
||||
-- @param Core.Message#MESSAGE MessageType The type of the message.
|
||||
@@ -460,9 +487,9 @@ do -- SETTINGS
|
||||
function SETTINGS:SetSystemMenu( MenuGroup, RootMenu )
|
||||
|
||||
local MenuText = "System Settings"
|
||||
|
||||
|
||||
local MenuTime = timer.getTime()
|
||||
|
||||
|
||||
local SettingsMenu = MENU_GROUP:New( MenuGroup, MenuText, RootMenu ):SetTime( MenuTime )
|
||||
|
||||
-------
|
||||
@@ -472,9 +499,9 @@ do -- SETTINGS
|
||||
local text="A2G Coordinate System XXX"
|
||||
if self.MenuShort then
|
||||
text="A2G Coordinates"
|
||||
end
|
||||
end
|
||||
local A2GCoordinateMenu = MENU_GROUP:New( MenuGroup, text, SettingsMenu ):SetTime( MenuTime )
|
||||
|
||||
|
||||
-- Set LL DMS
|
||||
if not self:IsA2G_LL_DMS() then
|
||||
local text="Lat/Lon Degree Min Sec (LL DMS)"
|
||||
@@ -483,16 +510,16 @@ do -- SETTINGS
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, text, A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "LL DMS" ):SetTime( MenuTime )
|
||||
end
|
||||
|
||||
|
||||
-- Set LL DDM
|
||||
if not self:IsA2G_LL_DDM() then
|
||||
local text="Lat/Lon Degree Dec Min (LL DDM)"
|
||||
if self.MenuShort then
|
||||
text="LL DDM"
|
||||
end
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "Lat/Lon Degree Dec Min (LL DDM)", A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "LL DDM" ):SetTime( MenuTime )
|
||||
end
|
||||
|
||||
|
||||
-- Set LL DMS accuracy.
|
||||
if self:IsA2G_LL_DDM() then
|
||||
local text1="LL DDM Accuracy 1"
|
||||
@@ -500,30 +527,30 @@ do -- SETTINGS
|
||||
local text3="LL DDM Accuracy 3"
|
||||
if self.MenuShort then
|
||||
text1="LL DDM"
|
||||
end
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "LL DDM Accuracy 1", A2GCoordinateMenu, self.MenuLL_DDM_Accuracy, self, MenuGroup, RootMenu, 1 ):SetTime( MenuTime )
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "LL DDM Accuracy 2", A2GCoordinateMenu, self.MenuLL_DDM_Accuracy, self, MenuGroup, RootMenu, 2 ):SetTime( MenuTime )
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "LL DDM Accuracy 3", A2GCoordinateMenu, self.MenuLL_DDM_Accuracy, self, MenuGroup, RootMenu, 3 ):SetTime( MenuTime )
|
||||
end
|
||||
|
||||
|
||||
-- Set BR.
|
||||
if not self:IsA2G_BR() then
|
||||
local text="Bearing, Range (BR)"
|
||||
if self.MenuShort then
|
||||
text="BR"
|
||||
end
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, text , A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "BR" ):SetTime( MenuTime )
|
||||
end
|
||||
|
||||
|
||||
-- Set MGRS.
|
||||
if not self:IsA2G_MGRS() then
|
||||
local text="Military Grid (MGRS)"
|
||||
if self.MenuShort then
|
||||
text="MGRS"
|
||||
end
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, text, A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "MGRS" ):SetTime( MenuTime )
|
||||
end
|
||||
|
||||
|
||||
-- Set MGRS accuracy.
|
||||
if self:IsA2G_MGRS() then
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "MGRS Accuracy 1", A2GCoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 1 ):SetTime( MenuTime )
|
||||
@@ -532,22 +559,22 @@ do -- SETTINGS
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "MGRS Accuracy 4", A2GCoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 4 ):SetTime( MenuTime )
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "MGRS Accuracy 5", A2GCoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 5 ):SetTime( MenuTime )
|
||||
end
|
||||
|
||||
|
||||
-------
|
||||
-- A2A Coordinate System
|
||||
-------
|
||||
|
||||
|
||||
local text="A2A Coordinate System"
|
||||
if self.MenuShort then
|
||||
text="A2A Coordinates"
|
||||
end
|
||||
end
|
||||
local A2ACoordinateMenu = MENU_GROUP:New( MenuGroup, text, SettingsMenu ):SetTime( MenuTime )
|
||||
|
||||
if not self:IsA2A_LL_DMS() then
|
||||
local text="Lat/Lon Degree Min Sec (LL DMS)"
|
||||
if self.MenuShort then
|
||||
text="LL DMS"
|
||||
end
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, text, A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "LL DMS" ):SetTime( MenuTime )
|
||||
end
|
||||
|
||||
@@ -555,7 +582,7 @@ do -- SETTINGS
|
||||
local text="Lat/Lon Degree Dec Min (LL DDM)"
|
||||
if self.MenuShort then
|
||||
text="LL DDM"
|
||||
end
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, text, A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "LL DDM" ):SetTime( MenuTime )
|
||||
end
|
||||
|
||||
@@ -563,7 +590,7 @@ do -- SETTINGS
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "LL DDM Accuracy 1", A2ACoordinateMenu, self.MenuLL_DDM_Accuracy, self, MenuGroup, RootMenu, 1 ):SetTime( MenuTime )
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "LL DDM Accuracy 2", A2ACoordinateMenu, self.MenuLL_DDM_Accuracy, self, MenuGroup, RootMenu, 2 ):SetTime( MenuTime )
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "LL DDM Accuracy 3", A2ACoordinateMenu, self.MenuLL_DDM_Accuracy, self, MenuGroup, RootMenu, 3 ):SetTime( MenuTime )
|
||||
end
|
||||
end
|
||||
|
||||
if not self:IsA2A_BULLS() then
|
||||
local text="Bullseye (BULLS)"
|
||||
@@ -572,20 +599,20 @@ do -- SETTINGS
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, text, A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "BULLS" ):SetTime( MenuTime )
|
||||
end
|
||||
|
||||
|
||||
if not self:IsA2A_BRAA() then
|
||||
local text="Bearing Range Altitude Aspect (BRAA)"
|
||||
if self.MenuShort then
|
||||
text="BRAA"
|
||||
end
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, text, A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "BRAA" ):SetTime( MenuTime )
|
||||
end
|
||||
|
||||
|
||||
if not self:IsA2A_MGRS() then
|
||||
local text="Military Grid (MGRS)"
|
||||
if self.MenuShort then
|
||||
text="MGRS"
|
||||
end
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, text, A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "MGRS" ):SetTime( MenuTime )
|
||||
end
|
||||
|
||||
@@ -596,33 +623,33 @@ do -- SETTINGS
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "MGRS Accuracy 4", A2ACoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 4 ):SetTime( MenuTime )
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "MGRS Accuracy 5", A2ACoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 5 ):SetTime( MenuTime )
|
||||
end
|
||||
|
||||
|
||||
local text="Measures and Weights System"
|
||||
if self.MenuShort then
|
||||
text="Unit System"
|
||||
end
|
||||
local MetricsMenu = MENU_GROUP:New( MenuGroup, text, SettingsMenu ):SetTime( MenuTime )
|
||||
|
||||
|
||||
if self:IsMetric() then
|
||||
local text="Imperial (Miles,Feet)"
|
||||
if self.MenuShort then
|
||||
text="Imperial"
|
||||
end
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, text, MetricsMenu, self.MenuMWSystem, self, MenuGroup, RootMenu, false ):SetTime( MenuTime )
|
||||
end
|
||||
|
||||
|
||||
if self:IsImperial() then
|
||||
local text="Metric (Kilometers,Meters)"
|
||||
if self.MenuShort then
|
||||
text="Metric"
|
||||
end
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, text, MetricsMenu, self.MenuMWSystem, self, MenuGroup, RootMenu, true ):SetTime( MenuTime )
|
||||
end
|
||||
end
|
||||
|
||||
local text="Messages and Reports"
|
||||
if self.MenuShort then
|
||||
text="Messages & Reports"
|
||||
end
|
||||
end
|
||||
local MessagesMenu = MENU_GROUP:New( MenuGroup, text, SettingsMenu ):SetTime( MenuTime )
|
||||
|
||||
local UpdateMessagesMenu = MENU_GROUP:New( MenuGroup, "Update Messages", MessagesMenu ):SetTime( MenuTime )
|
||||
@@ -661,10 +688,10 @@ do -- SETTINGS
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "1 minute", DetailedReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.DetailedReportsMenu, 60 ):SetTime( MenuTime )
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "2 minutes", DetailedReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.DetailedReportsMenu, 120 ):SetTime( MenuTime )
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "3 minutes", DetailedReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.DetailedReportsMenu, 180 ):SetTime( MenuTime )
|
||||
|
||||
|
||||
|
||||
SettingsMenu:Remove( MenuTime )
|
||||
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -697,24 +724,24 @@ do -- SETTINGS
|
||||
function SETTINGS:SetPlayerMenu( PlayerUnit )
|
||||
|
||||
if _SETTINGS.ShowPlayerMenu == true then
|
||||
|
||||
|
||||
local PlayerGroup = PlayerUnit:GetGroup()
|
||||
local PlayerName = PlayerUnit:GetPlayerName()
|
||||
local PlayerNames = PlayerGroup:GetPlayerNames()
|
||||
|
||||
|
||||
local PlayerMenu = MENU_GROUP:New( PlayerGroup, 'Settings "' .. PlayerName .. '"' )
|
||||
|
||||
|
||||
self.PlayerMenu = PlayerMenu
|
||||
|
||||
|
||||
self:I(string.format("FF Setting menu for player %s", tostring(PlayerName)))
|
||||
|
||||
|
||||
local submenu = MENU_GROUP:New( PlayerGroup, "LL Accuracy", PlayerMenu )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "0 Decimal Places", submenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 0 )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "1 Decimal Places", submenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 1 )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "2 Decimal Places", submenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 2 )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "3 Decimal Places", submenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 3 )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "4 Decimal Places", submenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 4 )
|
||||
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "4 Decimal Places", submenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 4 )
|
||||
|
||||
local submenu = MENU_GROUP:New( PlayerGroup, "MGRS Accuracy", PlayerMenu )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "Accuracy 0", submenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 0 )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "Accuracy 1", submenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 1 )
|
||||
@@ -722,7 +749,7 @@ do -- SETTINGS
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "Accuracy 3", submenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 3 )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "Accuracy 4", submenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 4 )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "Accuracy 5", submenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 5 )
|
||||
|
||||
|
||||
------
|
||||
-- A2G Coordinate System
|
||||
------
|
||||
@@ -730,118 +757,118 @@ do -- SETTINGS
|
||||
local text="A2G Coordinate System"
|
||||
if self.MenuShort then
|
||||
text="A2G Coordinates"
|
||||
end
|
||||
end
|
||||
local A2GCoordinateMenu = MENU_GROUP:New( PlayerGroup, text, PlayerMenu )
|
||||
|
||||
|
||||
if not self:IsA2G_LL_DMS() or self.MenuStatic then
|
||||
local text="Lat/Lon Degree Min Sec (LL DMS)"
|
||||
if self.MenuShort then
|
||||
text="LL DMS"
|
||||
end
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, text, A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DMS" )
|
||||
end
|
||||
|
||||
|
||||
if not self:IsA2G_LL_DDM() or self.MenuStatic then
|
||||
local text="Lat/Lon Degree Dec Min (LL DDM)"
|
||||
if self.MenuShort then
|
||||
text="LL DDM"
|
||||
end
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, text, A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DDM" )
|
||||
end
|
||||
|
||||
|
||||
if not self:IsA2G_BR() or self.MenuStatic then
|
||||
local text="Bearing, Range (BR)"
|
||||
if self.MenuShort then
|
||||
text="BR"
|
||||
end
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, text, A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "BR" )
|
||||
end
|
||||
|
||||
|
||||
if not self:IsA2G_MGRS() or self.MenuStatic then
|
||||
local text="Military Grid (MGRS)"
|
||||
if self.MenuShort then
|
||||
text="MGRS"
|
||||
end
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, text, A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "MGRS" )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
------
|
||||
-- A2A Coordinates Menu
|
||||
------
|
||||
|
||||
|
||||
local text="A2A Coordinate System"
|
||||
if self.MenuShort then
|
||||
text="A2A Coordinates"
|
||||
end
|
||||
end
|
||||
local A2ACoordinateMenu = MENU_GROUP:New( PlayerGroup, text, PlayerMenu )
|
||||
|
||||
|
||||
|
||||
|
||||
if not self:IsA2A_LL_DMS() or self.MenuStatic then
|
||||
local text="Lat/Lon Degree Min Sec (LL DMS)"
|
||||
if self.MenuShort then
|
||||
text="LL DMS"
|
||||
end
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, text, A2ACoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DMS" )
|
||||
end
|
||||
|
||||
|
||||
if not self:IsA2A_LL_DDM() or self.MenuStatic then
|
||||
local text="Lat/Lon Degree Dec Min (LL DDM)"
|
||||
if self.MenuShort then
|
||||
text="LL DDM"
|
||||
end
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, text, A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DDM" )
|
||||
end
|
||||
|
||||
|
||||
if not self:IsA2A_BULLS() or self.MenuStatic then
|
||||
local text="Bullseye (BULLS)"
|
||||
if self.MenuShort then
|
||||
text="BULLS"
|
||||
end
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, text, A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "BULLS" )
|
||||
end
|
||||
|
||||
|
||||
if not self:IsA2A_BRAA() or self.MenuStatic then
|
||||
local text="Bearing Range Altitude Aspect (BRAA)"
|
||||
if self.MenuShort then
|
||||
text="BRAA"
|
||||
end
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, text, A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "BRAA" )
|
||||
end
|
||||
|
||||
|
||||
if not self:IsA2A_MGRS() or self.MenuStatic then
|
||||
local text="Military Grid (MGRS)"
|
||||
if self.MenuShort then
|
||||
text="MGRS"
|
||||
end
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, text, A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "MGRS" )
|
||||
end
|
||||
|
||||
|
||||
---
|
||||
-- Unit system
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
local text="Measures and Weights System"
|
||||
if self.MenuShort then
|
||||
text="Unit System"
|
||||
end
|
||||
end
|
||||
local MetricsMenu = MENU_GROUP:New( PlayerGroup, text, PlayerMenu )
|
||||
|
||||
|
||||
if self:IsMetric() or self.MenuStatic then
|
||||
local text="Imperial (Miles,Feet)"
|
||||
if self.MenuShort then
|
||||
text="Imperial"
|
||||
end
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, text, MetricsMenu, self.MenuGroupMWSystem, self, PlayerUnit, PlayerGroup, PlayerName, false )
|
||||
end
|
||||
|
||||
|
||||
if self:IsImperial() or self.MenuStatic then
|
||||
local text="Metric (Kilometers,Meters)"
|
||||
if self.MenuShort then
|
||||
text="Metric"
|
||||
end
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, text, MetricsMenu, self.MenuGroupMWSystem, self, PlayerUnit, PlayerGroup, PlayerName, true )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
---
|
||||
-- Messages and Reports
|
||||
---
|
||||
@@ -849,9 +876,9 @@ do -- SETTINGS
|
||||
local text="Messages and Reports"
|
||||
if self.MenuShort then
|
||||
text="Messages & Reports"
|
||||
end
|
||||
end
|
||||
local MessagesMenu = MENU_GROUP:New( PlayerGroup, text, PlayerMenu )
|
||||
|
||||
|
||||
local UpdateMessagesMenu = MENU_GROUP:New( PlayerGroup, "Update Messages", MessagesMenu )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "Off", UpdateMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Update, 0 )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "5 seconds", UpdateMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Update, 5 )
|
||||
@@ -859,7 +886,7 @@ do -- SETTINGS
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "15 seconds", UpdateMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Update, 15 )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "30 seconds", UpdateMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Update, 30 )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "1 minute", UpdateMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Update, 60 )
|
||||
|
||||
|
||||
local InformationMessagesMenu = MENU_GROUP:New( PlayerGroup, "Information Messages", MessagesMenu )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "5 seconds", InformationMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Information, 5 )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "10 seconds", InformationMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Information, 10 )
|
||||
@@ -867,30 +894,30 @@ do -- SETTINGS
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "30 seconds", InformationMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Information, 30 )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "1 minute", InformationMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Information, 60 )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "2 minutes", InformationMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Information, 120 )
|
||||
|
||||
|
||||
local BriefingReportsMenu = MENU_GROUP:New( PlayerGroup, "Briefing Reports", MessagesMenu )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "15 seconds", BriefingReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Briefing, 15 )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "30 seconds", BriefingReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Briefing, 30 )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "1 minute", BriefingReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Briefing, 60 )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "2 minutes", BriefingReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Briefing, 120 )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "3 minutes", BriefingReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Briefing, 180 )
|
||||
|
||||
|
||||
local OverviewReportsMenu = MENU_GROUP:New( PlayerGroup, "Overview Reports", MessagesMenu )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "15 seconds", OverviewReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Overview, 15 )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "30 seconds", OverviewReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Overview, 30 )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "1 minute", OverviewReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Overview, 60 )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "2 minutes", OverviewReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Overview, 120 )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "3 minutes", OverviewReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Overview, 180 )
|
||||
|
||||
|
||||
local DetailedReportsMenu = MENU_GROUP:New( PlayerGroup, "Detailed Reports", MessagesMenu )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "15 seconds", DetailedReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.DetailedReportsMenu, 15 )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "30 seconds", DetailedReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.DetailedReportsMenu, 30 )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "1 minute", DetailedReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.DetailedReportsMenu, 60 )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "2 minutes", DetailedReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.DetailedReportsMenu, 120 )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "3 minutes", DetailedReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.DetailedReportsMenu, 180 )
|
||||
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -904,7 +931,7 @@ do -- SETTINGS
|
||||
self.PlayerMenu:Remove()
|
||||
self.PlayerMenu = nil
|
||||
end
|
||||
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -961,7 +988,7 @@ do -- SETTINGS
|
||||
self:SetPlayerMenu(PlayerUnit)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- @param #SETTINGS self
|
||||
function SETTINGS:MenuGroupA2ASystem( PlayerUnit, PlayerGroup, PlayerName, A2ASystem )
|
||||
self.A2ASystem = A2ASystem
|
||||
@@ -971,7 +998,7 @@ do -- SETTINGS
|
||||
self:SetPlayerMenu(PlayerUnit)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- @param #SETTINGS self
|
||||
function SETTINGS:MenuGroupLL_DDM_AccuracySystem( PlayerUnit, PlayerGroup, PlayerName, LL_Accuracy )
|
||||
self.LL_Accuracy = LL_Accuracy
|
||||
@@ -981,7 +1008,7 @@ do -- SETTINGS
|
||||
self:SetPlayerMenu(PlayerUnit)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- @param #SETTINGS self
|
||||
function SETTINGS:MenuGroupMGRS_AccuracySystem( PlayerUnit, PlayerGroup, PlayerName, MGRS_Accuracy )
|
||||
self.MGRS_Accuracy = MGRS_Accuracy
|
||||
@@ -1007,9 +1034,48 @@ do -- SETTINGS
|
||||
self:SetMessageTime( MessageType, MessageTime )
|
||||
MESSAGE:New( string.format( "Settings: Default message time set for %s to %d.", MessageType, MessageTime ), 5 ):ToGroup( PlayerGroup )
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
--- Configures the era of the mission to be WWII.
|
||||
-- @param #SETTINGS self
|
||||
-- @return #SETTINGS self
|
||||
function SETTINGS:SetEraWWII()
|
||||
|
||||
self.Era = SETTINGS.__Enum.Era.WWII
|
||||
|
||||
end
|
||||
|
||||
--- Configures the era of the mission to be Korea.
|
||||
-- @param #SETTINGS self
|
||||
-- @return #SETTINGS self
|
||||
function SETTINGS:SetEraKorea()
|
||||
|
||||
self.Era = SETTINGS.__Enum.Era.Korea
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- Configures the era of the mission to be Cold war.
|
||||
-- @param #SETTINGS self
|
||||
-- @return #SETTINGS self
|
||||
function SETTINGS:SetEraCold()
|
||||
|
||||
self.Era = SETTINGS.__Enum.Era.Cold
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- Configures the era of the mission to be Modern war.
|
||||
-- @param #SETTINGS self
|
||||
-- @return #SETTINGS self
|
||||
function SETTINGS:SetEraModern()
|
||||
|
||||
self.Era = SETTINGS.__Enum.Era.Modern
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
@@ -120,7 +120,7 @@ ZONE_BASE = {
|
||||
-- @param #string ZoneName Name of the zone.
|
||||
-- @return #ZONE_BASE self
|
||||
function ZONE_BASE:New( ZoneName )
|
||||
local self = BASE:Inherit( self, BASE:New() )
|
||||
local self = BASE:Inherit( self, FSM:New() )
|
||||
self:F( ZoneName )
|
||||
|
||||
self.ZoneName = ZoneName
|
||||
@@ -1393,7 +1393,7 @@ end
|
||||
function ZONE_POLYGON_BASE:Flush()
|
||||
self:F2()
|
||||
|
||||
self:E( { Polygon = self.ZoneName, Coordinates = self._.Polygon } )
|
||||
self:F( { Polygon = self.ZoneName, Coordinates = self._.Polygon } )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user