Merge branch 'FF/Develop' into FF/Fox2

This commit is contained in:
Frank
2019-09-13 19:43:17 +02:00
43 changed files with 2059 additions and 1079 deletions
+38 -16
View File
@@ -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
+167 -136
View File
@@ -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
+47 -1
View File
@@ -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.
+13 -3
View File
@@ -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." )
+1 -1
View File
@@ -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
-466
View File
@@ -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
+483
View File
@@ -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
+5 -3
View File
@@ -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
+321 -2
View File
@@ -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
+247 -181
View File
@@ -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
+2 -2
View File
@@ -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