Merge remote-tracking branch 'origin/master' into develop

# Conflicts:
#	Moose Development/Moose/AI/AI_A2A_Dispatcher.lua
#	Moose Development/Moose/AI/AI_A2G_Dispatcher.lua
#	Moose Development/Moose/AI/AI_CAP.lua
#	Moose Development/Moose/AI/AI_CAS.lua
#	Moose Development/Moose/AI/AI_Patrol.lua
#	Moose Development/Moose/Core/Base.lua
#	Moose Development/Moose/Core/Beacon.lua
#	Moose Development/Moose/Core/Database.lua
#	Moose Development/Moose/Core/Fsm.lua
#	Moose Development/Moose/Core/MarkerOps_Base.lua
#	Moose Development/Moose/Core/Menu.lua
#	Moose Development/Moose/Core/Message.lua
#	Moose Development/Moose/Core/Point.lua
#	Moose Development/Moose/Core/ScheduleDispatcher.lua
#	Moose Development/Moose/Core/Scheduler.lua
#	Moose Development/Moose/Core/Set.lua
#	Moose Development/Moose/Core/Spawn.lua
#	Moose Development/Moose/Core/Zone.lua
#	Moose Development/Moose/DCS.lua
#	Moose Development/Moose/Functional/Detection.lua
#	Moose Development/Moose/Functional/Mantis.lua
#	Moose Development/Moose/Functional/Range.lua
#	Moose Development/Moose/Functional/Scoring.lua
#	Moose Development/Moose/Functional/Sead.lua
#	Moose Development/Moose/Modules.lua
#	Moose Development/Moose/Ops/ATIS.lua
#	Moose Development/Moose/Ops/Airboss.lua
#	Moose Development/Moose/Sound/UserSound.lua
#	Moose Development/Moose/Utilities/Enums.lua
#	Moose Development/Moose/Utilities/FiFo.lua
#	Moose Development/Moose/Utilities/Profiler.lua
#	Moose Development/Moose/Utilities/Routines.lua
#	Moose Development/Moose/Utilities/STTS.lua
#	Moose Development/Moose/Utilities/Utils.lua
#	Moose Development/Moose/Wrapper/Airbase.lua
#	Moose Development/Moose/Wrapper/Controllable.lua
#	Moose Development/Moose/Wrapper/Group.lua
#	Moose Development/Moose/Wrapper/Marker.lua
#	Moose Development/Moose/Wrapper/Positionable.lua
#	Moose Development/Moose/Wrapper/Unit.lua
#	Moose Setup/Moose.files
This commit is contained in:
Applevangelist
2022-09-06 09:53:22 +02:00
parent bf3ee93c23
commit 8cceee49ea
59 changed files with 8939 additions and 9472 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -97,11 +97,11 @@ BEACON.Type={
-- @field #number TACAN_TANKER_Y TACtical Air Navigation system for tankers on Y band.
-- @field #number VOR Very High Frequency Omni-Directional Range
-- @field #number ILS_LOCALIZER ILS localizer
-- @field #number ILS_GLIDESLOPE ILS glideslope.
-- @field #number ILS_GLIDESLOPE ILS glide slope.
-- @field #number PRGM_LOCALIZER PRGM localizer.
-- @field #number PRGM_GLIDESLOPE PRGM glideslope.
-- @field #number PRGM_GLIDESLOPE PRGM glide slope.
-- @field #number BROADCAST_STATION Broadcast station.
-- @field #number VORTAC Radio-based navigational aid for aircraft pilots consisting of a co-located VHF omnidirectional range (VOR) beacon and a tactical air navigation system (TACAN) beacon.
-- @field #number VORTAC Radio-based navigational aid for aircraft pilots consisting of a co-located VHF omni-directional range (VOR) beacon and a tactical air navigation system (TACAN) beacon.
-- @field #number TACAN_AA_MODE_X TACtical Air Navigation for aircraft on X band.
-- @field #number TACAN_AA_MODE_Y TACtical Air Navigation for aircraft on Y band.
-- @field #number VORDME Radio beacon that combines a VHF omnidirectional range (VOR) with a distance measuring equipment (DME).
@@ -211,7 +211,7 @@ function BEACON:ActivateTACAN(Channel, Mode, Message, Bearing, Duration)
-- Start beacon.
self.Positionable:CommandActivateBeacon(Type, System, Frequency, UnitID, Channel, Mode, AA, Message, Bearing)
-- Stop sheduler.
-- Stop scheduler.
if Duration then
self.Positionable:DeactivateBeacon(Duration)
end
@@ -237,7 +237,7 @@ function BEACON:ActivateICLS(Channel, Callsign, Duration)
-- Start beacon.
self.Positionable:CommandActivateICLS(Channel, UnitID, Callsign)
-- Stop sheduler
-- Stop scheduler
if Duration then -- Schedule the stop of the BEACON if asked by the MD
self.Positionable:DeactivateBeacon(Duration)
end
@@ -354,8 +354,8 @@ end
--- Activates a general purpose Radio Beacon
-- This uses the very generic singleton function "trigger.action.radioTransmission()" provided by DCS to broadcast a sound file on a specific frequency.
-- Although any frequency could be used, only 2 DCS Modules can home on radio beacons at the time of writing : the Huey and the Mi-8.
-- They can home in on these specific frequencies :
-- Although any frequency could be used, only a few DCS Modules can home on radio beacons at the time of writing, i.e. the Mi-8, Huey, Gazelle etc.
-- The following e.g. can home in on these specific frequencies :
-- * **Mi8**
-- * R-828 -> 20-60MHz
-- * ARKUD -> 100-150MHz (canal 1 : 114166, canal 2 : 114333, canal 3 : 114583, canal 4 : 121500, canal 5 : 123100, canal 6 : 124100) AM

View File

@@ -31,7 +31,6 @@
-- @module Core.Database
-- @image Core_Database.JPG
--- @type DATABASE
-- @field #string ClassName Name of the class.
-- @field #table Templates Templates: Units, Groups, Statics, ClientsByName, ClientsByID.
@@ -51,7 +50,7 @@
-- * PLAYERS
-- * CARGOS
--
-- On top, for internal MOOSE administration purposes, the DATBASE administers the Unit and Group TEMPLATES as defined within the Mission Editor.
-- On top, for internal MOOSE administration purposes, the DATABASE 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.
@@ -90,22 +89,19 @@ DATABASE = {
FLIGHTCONTROLS = {},
}
local _DATABASECoalition =
{
[1] = "Red",
[2] = "Blue",
[3] = "Neutral",
}
local _DATABASECategory =
{
["plane"] = Unit.Category.AIRPLANE,
["helicopter"] = Unit.Category.HELICOPTER,
["vehicle"] = Unit.Category.GROUND_UNIT,
["ship"] = Unit.Category.SHIP,
["static"] = Unit.Category.STRUCTURE,
}
local _DATABASECoalition = {
[1] = "Red",
[2] = "Blue",
[3] = "Neutral",
}
local _DATABASECategory = {
["plane"] = Unit.Category.AIRPLANE,
["helicopter"] = Unit.Category.HELICOPTER,
["vehicle"] = Unit.Category.GROUND_UNIT,
["ship"] = Unit.Category.SHIP,
["static"] = Unit.Category.STRUCTURE,
}
--- Creates a new DATABASE object, building a set of units belonging to a coalitions, categories, countries, types or with defined prefix names.
-- @param #DATABASE self
@@ -130,7 +126,7 @@ function DATABASE:New()
self:HandleEvent( EVENTS.DeleteCargo )
self:HandleEvent( EVENTS.NewZone )
self:HandleEvent( EVENTS.DeleteZone )
--self:HandleEvent( EVENTS.PlayerEnterUnit, self._EventOnPlayerEnterUnit ) -- This is not working anymore!, handling this through the birth event.
-- 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()
@@ -155,7 +151,6 @@ function DATABASE:FindUnit( UnitName )
return UnitFound
end
--- Adds a Unit based on the Unit Name in the DATABASE.
-- @param #DATABASE self
-- @param #string DCSUnitName Unit name.
@@ -173,7 +168,6 @@ function DATABASE:AddUnit( DCSUnitName )
return self.UNITS[DCSUnitName]
end
--- Deletes a Unit from the DATABASE based on the Unit Name.
-- @param #DATABASE self
function DATABASE:DeleteUnit( DCSUnitName )
@@ -194,7 +188,6 @@ function DATABASE:AddStatic( DCSStaticName )
return nil
end
--- Deletes a Static from the DATABASE based on the Static Name.
-- @param #DATABASE self
function DATABASE:DeleteStatic( DCSStaticName )
@@ -224,7 +217,6 @@ function DATABASE:AddAirbase( AirbaseName )
return self.AIRBASES[AirbaseName]
end
--- Deletes a Airbase from the DATABASE based on the Airbase Name.
-- @param #DATABASE self
-- @param #string AirbaseName The name of the airbase
@@ -233,17 +225,6 @@ function DATABASE:DeleteAirbase( AirbaseName )
self.AIRBASES[AirbaseName] = nil
end
--- Finds an AIRBASE based on the AirbaseName.
-- @param #DATABASE self
-- @param #string AirbaseName
-- @return Wrapper.Airbase#AIRBASE The found AIRBASE.
function DATABASE:FindAirbase( AirbaseName )
local AirbaseFound = self.AIRBASES[AirbaseName]
return AirbaseFound
end
do -- Zones
--- Finds a @{Zone} based on the zone name.
@@ -267,7 +248,6 @@ do -- Zones
end
end
--- Deletes a @{Zone} from the DATABASE based on the zone name.
-- @param #DATABASE self
-- @param #string ZoneName The name of the zone.
@@ -276,13 +256,12 @@ do -- Zones
self.ZONES[ZoneName] = nil
end
--- Private method that registers new ZONE_BASE derived objects within the DATABASE Object.
-- @param #DATABASE self
-- @return #DATABASE self
function DATABASE:_RegisterZones()
for ZoneID, ZoneData in pairs(env.mission.triggers.zones) do
for ZoneID, ZoneData in pairs( env.mission.triggers.zones ) do
local ZoneName = ZoneData.name
-- Color
@@ -374,7 +353,6 @@ do -- Zones
end
end -- zone
do -- Zone_Goal
@@ -400,7 +378,6 @@ do -- Zone_Goal
end
end
--- Deletes a @{Zone} from the DATABASE based on the zone name.
-- @param #DATABASE self
-- @param #string ZoneName The name of the zone.
@@ -422,7 +399,6 @@ do -- 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
@@ -464,38 +440,38 @@ do -- cargo
for CargoGroupName, CargoGroup in pairs( Groups ) do
if self:IsCargo( CargoGroupName ) then
local CargoInfo = CargoGroupName:match("#CARGO(.*)")
local CargoParam = CargoInfo and CargoInfo:match( "%((.*)%)")
local CargoName1 = CargoGroupName:match("(.*)#CARGO%(.*%)")
local CargoName2 = CargoGroupName:match(".*#CARGO%(.*%)(.*)")
local CargoName = CargoName1 .. ( CargoName2 or "" )
local Type = CargoParam and CargoParam:match( "T=([%a%d ]+),?")
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]+),?") )
local CargoInfo = CargoGroupName:match( "#CARGO(.*)" )
local CargoParam = CargoInfo and CargoInfo:match( "%((.*)%)" )
local CargoName1 = CargoGroupName:match( "(.*)#CARGO%(.*%)" )
local CargoName2 = CargoGroupName:match( ".*#CARGO%(.*%)(.*)" )
local CargoName = CargoName1 .. (CargoName2 or "")
local Type = CargoParam and CargoParam:match( "T=([%a%d ]+),?" )
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})
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(.*)")
local CargoParam = CargoInfo and CargoInfo:match( "%((.*)%)")
local CargoName = CargoStaticName:match("(.*)#CARGO")
local Type = CargoParam and CargoParam:match( "T=([%a%d ]+),?")
local Category = CargoParam and CargoParam:match( "C=([%a%d ]+),?")
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]+),?") )
local CargoInfo = CargoStaticName:match( "#CARGO(.*)" )
local CargoParam = CargoInfo and CargoInfo:match( "%((.*)%)" )
local CargoName = CargoStaticName:match( "(.*)#CARGO" )
local Type = CargoParam and CargoParam:match( "T=([%a%d ]+),?" )
local Category = CargoParam and CargoParam:match( "C=([%a%d ]+),?" )
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})
self:I( { "Register CargoSlingload:", Type = Type, Name = Name, LoadRadius = LoadRadius, NearRadius = NearRadius } )
CARGO_SLINGLOAD:New( CargoStatic, Type, Name, LoadRadius, NearRadius )
else
if Category == "CRATE" then
self:I({"Register CargoCrate:",Type=Type,Name=Name,LoadRadius=LoadRadius,NearRadius=NearRadius})
self:I( { "Register CargoCrate:", Type = Type, Name = Name, LoadRadius = LoadRadius, NearRadius = NearRadius } )
CARGO_CRATE:New( CargoStatic, Type, Name, LoadRadius, NearRadius )
end
end
@@ -516,7 +492,6 @@ function DATABASE:FindClient( ClientName )
return ClientFound
end
--- Adds a CLIENT based on the ClientName in the DATABASE.
-- @param #DATABASE self
-- @param #string ClientName Name of the Client unit.
@@ -530,7 +505,6 @@ function DATABASE:AddClient( ClientName )
return self.CLIENTS[ClientName]
end
--- Finds a GROUP based on the GroupName.
-- @param #DATABASE self
-- @param #string GroupName
@@ -541,7 +515,6 @@ function DATABASE:FindGroup( GroupName )
return GroupFound
end
--- Adds a GROUP based on the GroupName in the DATABASE.
-- @param #DATABASE self
function DATABASE:AddGroup( GroupName )
@@ -589,7 +562,6 @@ function DATABASE:GetPlayers()
return self.PLAYERS
end
--- Get the player table from the DATABASE, which contains all UNIT objects.
-- The player table contains all UNIT objects of the player with the key the name of the player (PlayerName).
-- @param #DATABASE self
@@ -602,7 +574,6 @@ function DATABASE:GetPlayerUnits()
return self.PLAYERUNITS
end
--- Get the player table from the DATABASE which have joined in the mission historically.
-- The player table contains all UNIT objects with the key the name of the player (PlayerName).
-- @param #DATABASE self
@@ -615,7 +586,6 @@ function DATABASE:GetPlayersJoined()
return self.PLAYERSJOINED
end
--- Instantiate new Groups within the DCSRTE.
-- This method expects EXACTLY the same structure as a structure within the ME, and needs 2 additional fields defined:
-- SpawnCountryID, SpawnCategoryID
@@ -638,7 +608,7 @@ function DATABASE:Spawn( SpawnTemplate )
SpawnTemplate.CountryID = nil
SpawnTemplate.CategoryID = nil
self:_RegisterGroupTemplate( SpawnTemplate, SpawnCoalitionID, SpawnCategoryID, SpawnCountryID )
self:_RegisterGroupTemplate( SpawnTemplate, SpawnCoalitionID, SpawnCategoryID, SpawnCountryID )
self:T3( SpawnTemplate )
coalition.addGroup( SpawnCountryID, SpawnCategoryID, SpawnTemplate )
@@ -720,7 +690,7 @@ function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionSide, Category
for unit_num, UnitTemplate in pairs( GroupTemplate.units ) do
UnitTemplate.name = env.getValueDictByKey(UnitTemplate.name)
UnitTemplate.name = env.getValueDictByKey( UnitTemplate.name )
self.Templates.Units[UnitTemplate.name] = {}
self.Templates.Units[UnitTemplate.name].UnitName = UnitTemplate.name
@@ -740,17 +710,16 @@ function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionSide, Category
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
-- Debug info.
self:T( { Group = self.Templates.Groups[GroupTemplateName].GroupName,
self:T( { Group = self.Templates.Groups[GroupTemplateName].GroupName,
Coalition = self.Templates.Groups[GroupTemplateName].CoalitionID,
Category = self.Templates.Groups[GroupTemplateName].CategoryID,
Country = self.Templates.Groups[GroupTemplateName].CountryID,
Units = UnitNames
}
)
Category = self.Templates.Groups[GroupTemplateName].CategoryID,
Country = self.Templates.Groups[GroupTemplateName].CountryID,
Units = UnitNames,
} )
end
--- Get group template.
@@ -797,9 +766,8 @@ function DATABASE:_RegisterStaticTemplate( StaticTemplate, CoalitionID, Category
self:T( { 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 )
@@ -815,7 +783,7 @@ function DATABASE:GetStaticGroupTemplate( StaticName )
local StaticTemplate = self.Templates.Statics[StaticName].GroupTemplate
return StaticTemplate, self.Templates.Statics[StaticName].CoalitionID, self.Templates.Statics[StaticName].CategoryID, self.Templates.Statics[StaticName].CountryID
else
self:E("ERROR: Static group template does NOT exist for static "..tostring(StaticName))
self:E( "ERROR: Static group template does NOT exist for static " .. tostring( StaticName ) )
return nil
end
end
@@ -842,7 +810,7 @@ function DATABASE:GetGroupNameFromUnitName( UnitName )
if self.Templates.Units[UnitName] then
return self.Templates.Units[UnitName].GroupName
else
self:E("ERROR: Unit template does not exist for unit "..tostring(UnitName))
self:E( "ERROR: Unit template does not exist for unit " .. tostring( UnitName ) )
return nil
end
end
@@ -916,8 +884,6 @@ function DATABASE:GetCategoryFromAirbase( AirbaseName )
return self.AIRBASES[AirbaseName]:GetCategory()
end
--- Private method that registers all alive players in the mission.
-- @param #DATABASE self
-- @return #DATABASE self
@@ -941,8 +907,7 @@ function DATABASE:_RegisterPlayers()
return self
end
--- Private method that registers all Groups and Units within in the mission.
--- Private method that registers all Groups and Units within the mission.
-- @param #DATABASE self
-- @return #DATABASE self
function DATABASE:_RegisterGroupsAndUnits()
@@ -959,7 +924,7 @@ function DATABASE:_RegisterGroupsAndUnits()
local DCSGroupName = DCSGroup:getName()
-- Add group.
self:I(string.format("Register Group: %s", tostring(DCSGroupName)))
self:I( string.format( "Register Group: %s", tostring( DCSGroupName ) ) )
self:AddGroup( DCSGroupName )
-- Loop over units in group.
@@ -969,12 +934,12 @@ function DATABASE:_RegisterGroupsAndUnits()
local DCSUnitName = DCSUnit:getName()
-- Add unit.
self:I(string.format("Register Unit: %s", tostring(DCSUnitName)))
self:I( string.format( "Register Unit: %s", tostring( DCSUnitName ) ) )
self:AddUnit( DCSUnitName )
end
else
self:E({"Group does not exist: ", DCSGroup})
self:E( { "Group does not exist: ", DCSGroup } )
end
end
@@ -983,7 +948,7 @@ function DATABASE:_RegisterGroupsAndUnits()
return self
end
--- Private method that registers all Units of skill Client or Player within in the mission.
--- Private method that registers all Units of skill Client or Player within the mission.
-- @param #DATABASE self
-- @return #DATABASE self
function DATABASE:_RegisterClients()
@@ -1001,7 +966,7 @@ end
-- @param #DATABASE self
function DATABASE:_RegisterStatics()
local CoalitionsData={GroupsRed=coalition.getStaticObjects(coalition.side.RED), GroupsBlue=coalition.getStaticObjects(coalition.side.BLUE), GroupsNeutral=coalition.getStaticObjects(coalition.side.NEUTRAL)}
local CoalitionsData = { GroupsRed = coalition.getStaticObjects( coalition.side.RED ), GroupsBlue = coalition.getStaticObjects( coalition.side.BLUE ), GroupsNeutral = coalition.getStaticObjects( coalition.side.NEUTRAL ) }
for CoalitionId, CoalitionData in pairs( CoalitionsData ) do
for DCSStaticId, DCSStatic in pairs( CoalitionData ) do
@@ -1009,10 +974,10 @@ function DATABASE:_RegisterStatics()
if DCSStatic:isExist() then
local DCSStaticName = DCSStatic:getName()
self:I(string.format("Register Static: %s", tostring(DCSStaticName)))
self:I( string.format( "Register Static: %s", tostring( DCSStaticName ) ) )
self:AddStatic( DCSStaticName )
else
self:E( { "Static does not exist: ", DCSStatic } )
self:E( { "Static does not exist: ", DCSStatic } )
end
end
end
@@ -1031,7 +996,7 @@ function DATABASE:_RegisterAirbases()
local DCSAirbaseName = DCSAirbase:getName()
-- This gave the incorrect value to be inserted into the airdromeID for DCS 2.5.6. Is fixed now.
local airbaseID=DCSAirbase:getID()
local airbaseID = DCSAirbase:getID()
-- Add and register airbase.
local airbase=self:AddAirbase( DCSAirbaseName )
@@ -1043,7 +1008,7 @@ function DATABASE:_RegisterAirbases()
local text=string.format("Register %s: %s (UID=%d), Runways=%d, Parking=%d [", AIRBASE.CategoryName[airbase.category], tostring(DCSAirbaseName), airbaseUID, #airbase.runways, airbase.NparkingTotal)
for _,terminalType in pairs(AIRBASE.TerminalType) do
if airbase.NparkingTerminal and airbase.NparkingTerminal[terminalType] then
text=text..string.format("%d=%d ", terminalType, airbase.NparkingTerminal[terminalType])
text = text .. string.format( "%d=%d ", terminalType, airbase.NparkingTerminal[terminalType] )
end
end
text=text.."]"
@@ -1054,7 +1019,6 @@ function DATABASE:_RegisterAirbases()
return self
end
--- Events
--- Handles the OnBirth event for the alive units set.
@@ -1077,10 +1041,10 @@ function DATABASE:_EventOnBirth( Event )
self:AddGroup( Event.IniDCSGroupName )
-- Add airbase if it was spawned later in the mission.
local DCSAirbase = Airbase.getByName(Event.IniDCSUnitName)
local DCSAirbase = Airbase.getByName( Event.IniDCSUnitName )
if DCSAirbase then
self:I(string.format("Adding airbase %s", tostring(Event.IniDCSUnitName)))
self:AddAirbase(Event.IniDCSUnitName)
self:I( string.format( "Adding airbase %s", tostring( Event.IniDCSUnitName ) ) )
self:AddAirbase( Event.IniDCSUnitName )
end
end
@@ -1108,7 +1072,7 @@ function DATABASE:_EventOnBirth( Event )
-- Add client in case it does not exist already.
if not client then
client=self:AddClient(Event.IniDCSUnitName)
client = self:AddClient( Event.IniDCSUnitName )
end
-- Add player.
@@ -1132,8 +1096,8 @@ function DATABASE:_EventOnBirth( Event )
end
end
end
--- Handles the OnDead or OnCrash event for alive units set.
-- @param #DATABASE self
@@ -1180,7 +1144,7 @@ function DATABASE:_EventOnDeadOrCrash( Event )
-- Delete unit.
if self.UNITS[Event.IniDCSUnitName] then
self:DeleteUnit(Event.IniDCSUnitName)
self:DeleteUnit( Event.IniDCSUnitName )
end
-- Remove client players.
@@ -1194,9 +1158,9 @@ function DATABASE:_EventOnDeadOrCrash( Event )
end
-- Add airbase if it was spawned later in the mission.
local airbase=self.AIRBASES[Event.IniDCSUnitName] --Wrapper.Airbase#AIRBASE
local airbase = self.AIRBASES[Event.IniDCSUnitName] -- Wrapper.Airbase#AIRBASE
if airbase and (airbase:IsHelipad() or airbase:IsShip()) then
self:DeleteAirbase(Event.IniDCSUnitName)
self:DeleteAirbase( Event.IniDCSUnitName )
end
end
@@ -1205,7 +1169,6 @@ function DATABASE:_EventOnDeadOrCrash( Event )
self:AccountDestroys( Event )
end
--- Handles the OnPlayerEnterUnit event to fill the active players table (with the unit filter applied).
-- @param #DATABASE self
-- @param Core.Event#EVENTDATA Event
@@ -1237,13 +1200,12 @@ function DATABASE:_EventOnPlayerEnterUnit( Event )
Settings:SetPlayerMenu( Event.IniUnit )
else
self:E("ERROR: getPlayerName() returned nil for event PlayerEnterUnit")
self:E( "ERROR: getPlayerName() returned nil for event PlayerEnterUnit" )
end
end
end
end
--- Handles the OnPlayerLeaveUnit event to clean the active players table.
-- @param #DATABASE self
-- @param Core.Event#EVENTDATA Event
@@ -1270,9 +1232,9 @@ function DATABASE:_EventOnPlayerLeaveUnit( Event )
self:DeletePlayer(Event.IniUnit, PlayerName)
-- Client stuff.
local client=self.CLIENTS[Event.IniDCSUnitName] --Wrapper.Client#CLIENT
local client = self.CLIENTS[Event.IniDCSUnitName] -- Wrapper.Client#CLIENT
if client then
client:RemovePlayer(PlayerName)
client:RemovePlayer( PlayerName )
end
end
@@ -1292,22 +1254,22 @@ function DATABASE:ForEach( IteratorFunction, FinalizeFunction, arg, Set )
local function CoRoutine()
local Count = 0
for ObjectID, Object in pairs( Set ) do
self:T2( Object )
IteratorFunction( Object, unpack( arg ) )
Count = Count + 1
-- if Count % 100 == 0 then
-- coroutine.yield( false )
-- end
self:T2( Object )
IteratorFunction( Object, unpack( arg ) )
Count = Count + 1
-- if Count % 100 == 0 then
-- coroutine.yield( false )
-- end
end
return true
end
-- local co = coroutine.create( CoRoutine )
-- local co = coroutine.create( CoRoutine )
local co = CoRoutine
local function Schedule()
-- local status, res = coroutine.resume( co )
-- local status, res = coroutine.resume( co )
local status, res = co()
self:T3( { status, res } )
@@ -1323,18 +1285,17 @@ 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
--- Iterate the DATABASE and call an iterator function for each **alive** STATIC, providing the STATIC and optional parameters.
-- @param #DATABASE self
-- @param #function IteratorFunction The function that will be called for each object in the database. The function needs to accept a STATIC parameter.
-- @return #DATABASE self
function DATABASE:ForEachStatic( IteratorFunction, FinalizeFunction, ... ) --R2.1
function DATABASE:ForEachStatic( IteratorFunction, FinalizeFunction, ... ) -- R2.1
self:F2( arg )
self:ForEach( IteratorFunction, FinalizeFunction, arg, self.STATICS )
@@ -1342,7 +1303,6 @@ function DATABASE:ForEachStatic( IteratorFunction, FinalizeFunction, ... ) --R2
return self
end
--- Iterate the DATABASE and call an iterator function for each **alive** UNIT, providing the UNIT and optional parameters.
-- @param #DATABASE self
-- @param #function IteratorFunction The function that will be called for each object in the database. The function needs to accept a UNIT parameter.
@@ -1355,7 +1315,6 @@ function DATABASE:ForEachUnit( IteratorFunction, FinalizeFunction, ... )
return self
end
--- Iterate the DATABASE and call an iterator function for each **alive** GROUP, providing the GROUP and optional parameters.
-- @param #DATABASE self
-- @param #function IteratorFunction The function that will be called for each object in the database. The function needs to accept a GROUP parameter.
@@ -1368,7 +1327,6 @@ function DATABASE:ForEachGroup( IteratorFunction, FinalizeFunction, ... )
return self
end
--- Iterate the DATABASE and call an iterator function for each **ALIVE** player, providing the player name and optional parameters.
-- @param #DATABASE self
-- @param #function IteratorFunction The function that will be called for each object in the database. The function needs to accept the player name.
@@ -1381,7 +1339,6 @@ function DATABASE:ForEachPlayer( IteratorFunction, FinalizeFunction, ... )
return self
end
--- Iterate the DATABASE and call an iterator function for each player who has joined the mission, providing the Unit of the player and optional parameters.
-- @param #DATABASE self
-- @param #function IteratorFunction The function that will be called for each object in the database. The function needs to accept a UNIT parameter.
@@ -1406,7 +1363,6 @@ function DATABASE:ForEachPlayerUnit( IteratorFunction, FinalizeFunction, ... )
return self
end
--- Iterate the DATABASE and call an iterator function for each CLIENT, providing the CLIENT to the function and optional parameters.
-- @param #DATABASE self
-- @param #function IteratorFunction The function that will be called object in the database. The function needs to accept a CLIENT parameter.
@@ -1431,7 +1387,6 @@ function DATABASE:ForEachCargo( IteratorFunction, ... )
return self
end
--- Handles the OnEventNewCargo event.
-- @param #DATABASE self
-- @param Core.Event#EVENTDATA EventData
@@ -1443,7 +1398,6 @@ function DATABASE:OnEventNewCargo( EventData )
end
end
--- Handles the OnEventDeleteCargo.
-- @param #DATABASE self
-- @param Core.Event#EVENTDATA EventData
@@ -1455,7 +1409,6 @@ function DATABASE:OnEventDeleteCargo( EventData )
end
end
--- Handles the OnEventNewZone event.
-- @param #DATABASE self
-- @param Core.Event#EVENTDATA EventData
@@ -1467,7 +1420,6 @@ function DATABASE:OnEventNewZone( EventData )
end
end
--- Handles the OnEventDeleteZone.
-- @param #DATABASE self
-- @param Core.Event#EVENTDATA EventData
@@ -1479,8 +1431,6 @@ function DATABASE:OnEventDeleteZone( EventData )
end
end
--- Gets the player settings
-- @param #DATABASE self
-- @param #string PlayerName
@@ -1490,7 +1440,6 @@ function DATABASE:GetPlayerSettings( PlayerName )
return self.PLAYERSETTINGS[PlayerName]
end
--- Sets the player settings
-- @param #DATABASE self
-- @param #string PlayerName
@@ -1532,9 +1481,9 @@ end
function DATABASE:FindOpsGroup(groupname)
-- Get group and group name.
if type(groupname)=="string" then
if type( groupname ) == "string" then
else
groupname=groupname:GetName()
groupname = groupname:GetName()
end
--env.info("Getting OPSGROUP "..tostring(groupname))
@@ -1571,16 +1520,16 @@ end
--- Add a flight control to the data base.
-- @param #DATABASE self
-- @param Ops.FlightControl#FLIGHTCONTROL flightcontrol
function DATABASE:AddFlightControl(flightcontrol)
function DATABASE:AddFlightControl( flightcontrol )
self:F2( { flightcontrol } )
self.FLIGHTCONTROLS[flightcontrol.airbasename]=flightcontrol
self.FLIGHTCONTROLS[flightcontrol.airbasename] = flightcontrol
end
--- Get a flight control object from the data base.
-- @param #DATABASE self
-- @param #string airbasename Name of the associated airbase.
-- @return Ops.FlightControl#FLIGHTCONTROL The FLIGHTCONTROL object.s
function DATABASE:GetFlightControl(airbasename)
function DATABASE:GetFlightControl( airbasename )
return self.FLIGHTCONTROLS[airbasename]
end
@@ -1672,90 +1621,91 @@ function DATABASE:_RegisterTemplates()
return self
end
--- Account the Hits of the Players.
-- @param #DATABASE self
-- @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" )
--- Account the Hits of the Players.
-- @param #DATABASE self
-- @param Core.Event#EVENTDATA Event
function DATABASE:AccountHits( Event )
self:F( { Event } )
-- What is he hitting?
if Event.TgtCategory then
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
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.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
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.
end
Hit.Players[Event.WeaponPlayerName] = true
else -- A scenery object was hit.
end
end
end
end
--- Account the destroys.
-- @param #DATABASE self
-- @param Core.Event#EVENTDATA Event
function DATABASE:AccountDestroys( Event )
self:F( { Event } )
--- 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 = ""
local TargetGroupName = ""
local TargetPlayerName = ""
local TargetCoalition = nil
local TargetCategory = nil
local TargetType = nil
local TargetUnitCoalition = nil
local TargetUnitCategory = nil
local TargetUnitType = nil
local TargetUnit = nil
local TargetGroup = nil
local TargetUnitName = ""
local TargetGroupName = ""
local TargetPlayerName = ""
local TargetCoalition = nil
local TargetCategory = nil
local TargetType = nil
local TargetUnitCoalition = nil
local TargetUnitCategory = nil
local TargetUnitType = nil
if Event.IniDCSUnit then
if Event.IniDCSUnit then
TargetUnit = Event.IniUnit
TargetUnitName = Event.IniDCSUnitName
TargetGroup = Event.IniDCSGroup
TargetGroupName = Event.IniDCSGroupName
TargetPlayerName = Event.IniPlayerName
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
TargetCoalition = Event.IniCoalition
-- TargetCategory = TargetUnit:getCategory()
-- TargetCategory = TargetUnit:getDesc().category -- Workaround
TargetCategory = Event.IniCategory
TargetType = Event.IniTypeName
TargetUnitType = TargetType
TargetUnitType = TargetType
self:T( { TargetUnitName, TargetGroupName, TargetPlayerName, TargetCoalition, TargetCategory, TargetType } )
end
local Destroyed = false
-- What is the player destroying?
if self.HITS[Event.IniUnitName] then -- Was there a hit for this unit for this player before registered???
self.DESTROYS[Event.IniUnitName] = self.DESTROYS[Event.IniUnitName] or {}
self.DESTROYS[Event.IniUnitName] = true
end
self:T( { TargetUnitName, TargetGroupName, TargetPlayerName, TargetCoalition, TargetCategory, TargetType } )
end
local Destroyed = false
-- What is the player destroying?
if self.HITS[Event.IniUnitName] then -- Was there a hit for this unit for this player before registered???
self.DESTROYS[Event.IniUnitName] = self.DESTROYS[Event.IniUnitName] or {}
self.DESTROYS[Event.IniUnitName] = true
end
end

View File

@@ -14,7 +14,7 @@
-- ![Objects](..\Presentations\EVENT\Dia2.JPG)
--
-- Within a running mission, various DCS events occur. Units are dynamically created, crash, die, shoot stuff, get hit etc.
-- This module provides a mechanism to dispatch those events occuring within your running mission, to the different objects orchestrating your mission.
-- This module provides a mechanism to dispatch those events occurring within your running mission, to the different objects orchestrating your mission.
--
-- ![Objects](..\Presentations\EVENT\Dia3.JPG)
--
@@ -32,11 +32,11 @@
--
-- ![Objects](..\Presentations\EVENT\Dia5.JPG)
--
-- There are 5 levels of kind of objects that the _EVENTDISPATCHER services:
-- There are 5 types/levels of objects that the _EVENTDISPATCHER services:
--
-- * _DATABASE object: The core of the MOOSE objects. Any object that is created, deleted or updated, is done in this database.
-- * SET_ derived classes: Subsets of the _DATABASE object. These subsets are updated by the _EVENTDISPATCHER as the second priority.
-- * UNIT objects: UNIT objects can subscribe to DCS events. Each DCS event will be directly published to teh subscribed UNIT object.
-- * SET_ derived classes: These are subsets of the _DATABASE object. These subsets are updated by the _EVENTDISPATCHER as the second priority.
-- * UNIT objects: UNIT objects can subscribe to DCS events. Each DCS event will be directly published to the subscribed UNIT object.
-- * GROUP objects: GROUP objects can subscribe to DCS events. Each DCS event will be directly published to the subscribed GROUP object.
-- * Any other object: Various other objects can subscribe to DCS events. Each DCS event triggered will be published to each subscribed object.
--

File diff suppressed because it is too large Load Diff

View File

@@ -1,89 +1,87 @@
--- **Core** - Models the process to achieve goal(s).
--
-- ===
--
--
-- ## Features:
--
--
-- * Define the goal.
-- * Monitor the goal achievement.
-- * Manage goal contribution by players.
--
--
-- ===
--
--
-- Classes that implement a goal achievement, will derive from GOAL to implement the ways how the achievements can be realized.
--
--
-- ===
--
--
-- ### Author: **FlightControl**
-- ### Contributions: **funkyfranky**
--
--
-- ===
--
--
-- @module Core.Goal
-- @image Core_Goal.JPG
do -- Goal
--- @type GOAL
-- @extends Core.Fsm#FSM
--- Models processes that have an objective with a defined achievement. Derived classes implement the ways how the achievements can be realized.
--
--
-- # 1. GOAL constructor
--
--
-- * @{#GOAL.New}(): Creates a new GOAL object.
--
--
-- # 2. GOAL is a finite state machine (FSM).
--
--
-- ## 2.1. GOAL States
--
--
-- * **Pending**: The goal object is in progress.
-- * **Achieved**: The goal objective is Achieved.
--
--
-- ## 2.2. GOAL Events
--
--
-- * **Achieved**: Set the goal objective to Achieved.
--
--
-- # 3. Player contributions.
--
--
-- Goals are most of the time achieved by players. These player achievements can be registered as part of the goal achievement.
-- Use @{#GOAL.AddPlayerContribution}() to add a player contribution to the goal.
-- The player contributions are based on a points system, an internal counter per player.
-- So once the goal has been achieved, the player contributions can be queried using @{#GOAL.GetPlayerContributions}(),
-- So once the goal has been achieved, the player contributions can be queried using @{#GOAL.GetPlayerContributions}(),
-- that retrieves all contributions done by the players. For one player, the contribution can be queried using @{#GOAL.GetPlayerContribution}().
-- The total amount of player contributions can be queried using @{#GOAL.GetTotalContributions}().
--
--
-- # 4. Goal achievement.
--
--
-- Once the goal is achieved, the mission designer will need to trigger the goal achievement using the **Achieved** event.
-- The underlying 2 examples will achieve the goals for the `Goal` object:
--
--
-- Goal:Achieved() -- Achieve the goal immediately.
-- Goal:__Achieved( 30 ) -- Achieve the goal within 30 seconds.
--
--
-- # 5. Check goal achievement.
--
--
-- The method @{#GOAL.IsAchieved}() will return true if the goal is achieved (the trigger **Achieved** was executed).
-- You can use this method to check asynchronously if a goal has been achieved, for example using a scheduler.
--
--
-- @field #GOAL
GOAL = {
ClassName = "GOAL",
}
--- @field #table GOAL.Players
GOAL.Players = {}
--- @field #number GOAL.TotalContributions
GOAL.TotalContributions = 0
--- GOAL Constructor.
-- @param #GOAL self
-- @return #GOAL
function GOAL:New()
local self = BASE:Inherit( self, FSM:New() ) -- #GOAL
self:F( {} )
@@ -104,11 +102,10 @@ do -- Goal
-- @param #string From
-- @param #string Event
-- @param #string To
self:SetStartState( "Pending" )
self:AddTransition( "*", "Achieved", "Achieved" )
self:AddTransition( "*", "Achieved", "Achieved" )
--- Achieved Handler OnBefore for GOAL
-- @function [parent=#GOAL] OnBeforeAchieved
-- @param #GOAL self
@@ -116,47 +113,44 @@ do -- Goal
-- @param #string Event
-- @param #string To
-- @return #boolean
--- Achieved Handler OnAfter for GOAL
-- @function [parent=#GOAL] OnAfterAchieved
-- @param #GOAL self
-- @param #string From
-- @param #string Event
-- @param #string To
--- Achieved Trigger for GOAL
-- @function [parent=#GOAL] Achieved
-- @param #GOAL self
--- Achieved Asynchronous Trigger for GOAL
-- @function [parent=#GOAL] __Achieved
-- @param #GOAL self
-- @param #number Delay
self:SetEventPriority( 5 )
return self
end
--- Add a new contribution by a player.
-- @param #GOAL self
-- @param #string PlayerName The name of the player.
function GOAL:AddPlayerContribution( PlayerName )
self:F({PlayerName})
self:F( { PlayerName } )
self.Players[PlayerName] = self.Players[PlayerName] or 0
self.Players[PlayerName] = self.Players[PlayerName] + 1
self.TotalContributions = self.TotalContributions + 1
end
--- @param #GOAL self
-- @param #number Player contribution.
function GOAL:GetPlayerContribution( PlayerName )
return self.Players[PlayerName] or 0
return self.Players[PlayerName] or 0
end
--- Get the players who contributed to achieve the goal.
-- The result is a list of players, sorted by the name of the players.
-- @param #GOAL self
@@ -165,7 +159,6 @@ do -- Goal
return self.Players or {}
end
--- Gets the total contributions that happened to achieve the goal.
-- The result is a number.
-- @param #GOAL self
@@ -173,9 +166,7 @@ do -- Goal
function GOAL:GetTotalContributions()
return self.TotalContributions or 0
end
--- Validates if the goal is achieved.
-- @param #GOAL self
-- @return #boolean true if the goal is achieved.
@@ -183,4 +174,4 @@ do -- Goal
return self:Is( "Achieved" )
end
end
end

View File

@@ -277,7 +277,6 @@ do -- MENU_BASE
end
end
do -- MENU_COMMAND_BASE
--- @type MENU_COMMAND_BASE
-- @field #function MenuCallHandler

View File

@@ -1,9 +1,9 @@
--- **Core** - Informs the players using messages during a simulation.
--
--
-- ===
--
--
-- ## Features:
--
--
-- * A more advanced messaging system using the DCS message system.
-- * Time messages.
-- * Send messages based on a message type, which has a pre-defined duration that can be tweaked in SETTINGS.
@@ -13,7 +13,7 @@
-- * Send messages to a specific unit or client.
--
-- ===
--
--
-- @module Core.Message
-- @image Core_Message.JPG
@@ -24,14 +24,14 @@
--- Message System to display Messages to Clients, Coalitions or All.
-- Messages are shown on the display panel for an amount of seconds, and will then disappear.
-- Messages can contain a category which is indicating the category of the message.
--
--
-- ## MESSAGE construction
--
--
-- Messages are created with @{#MESSAGE.New}. Note that when the MESSAGE object is created, no message is sent yet.
-- To send messages, you need to use the To functions.
--
--
-- ## Send messages to an audience
--
--
-- Messages are sent:
--
-- * To a @{Client} using @{#MESSAGE.ToClient}().
@@ -41,26 +41,26 @@
-- * To the red coalition using @{#MESSAGE.ToRed}().
-- * To the blue coalition using @{#MESSAGE.ToBlue}().
-- * To all Players using @{#MESSAGE.ToAll}().
--
--
-- ## Send conditionally to an audience
--
--
-- Messages can be sent conditionally to an audience (when a condition is true):
--
--
-- * To all players using @{#MESSAGE.ToAllIf}().
-- * To a coalition using @{#MESSAGE.ToCoalitionIf}().
--
--
-- ===
--
--
-- ### Author: **FlightControl**
-- ### Contributions:
--
-- ### Contributions:
--
-- ===
--
--
-- @field #MESSAGE
MESSAGE = {
ClassName = "MESSAGE",
MessageCategory = 0,
MessageID = 0,
ClassName = "MESSAGE",
MessageCategory = 0,
MessageID = 0,
}
--- Message Types
@@ -70,10 +70,9 @@ MESSAGE.Type = {
Information = "Information",
Briefing = "Briefing Report",
Overview = "Overview Report",
Detailed = "Detailed Report"
Detailed = "Detailed Report",
}
--- Creates a new MESSAGE object. Note that these MESSAGE objects are not yet displayed on the display panel. You must use the functions @{ToClient} or @{ToCoalition} or @{ToAll} to send these Messages to the respective recipients.
-- @param self
-- @param #string MessageText is the text of the Message.
@@ -82,52 +81,52 @@ MESSAGE.Type = {
-- @param #boolean ClearScreen (optional) Clear all previous messages if true.
-- @return #MESSAGE
-- @usage
-- -- Create a series of new Messages.
-- -- MessageAll is meant to be sent to all players, for 25 seconds, and is classified as "Score".
-- -- MessageRED is meant to be sent to the RED players only, for 10 seconds, and is classified as "End of Mission", with ID "Win".
-- -- MessageClient1 is meant to be sent to a Client, for 25 seconds, and is classified as "Score", with ID "Score".
-- -- MessageClient1 is meant to be sent to a Client, for 25 seconds, and is classified as "Score", with ID "Score".
-- MessageAll = MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", 25, "End of Mission" )
-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", 25, "Penalty" )
-- MessageClient1 = MESSAGE:New( "Congratulations, you've just hit a target", 25, "Score" )
-- MessageClient2 = MESSAGE:New( "Congratulations, you've just killed a target", 25, "Score")
--
-- -- Create a series of new Messages.
-- -- MessageAll is meant to be sent to all players, for 25 seconds, and is classified as "Score".
-- -- MessageRED is meant to be sent to the RED players only, for 10 seconds, and is classified as "End of Mission", with ID "Win".
-- -- MessageClient1 is meant to be sent to a Client, for 25 seconds, and is classified as "Score", with ID "Score".
-- -- MessageClient1 is meant to be sent to a Client, for 25 seconds, and is classified as "Score", with ID "Score".
-- MessageAll = MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", 25, "End of Mission" )
-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", 25, "Penalty" )
-- MessageClient1 = MESSAGE:New( "Congratulations, you've just hit a target", 25, "Score" )
-- MessageClient2 = MESSAGE:New( "Congratulations, you've just killed a target", 25, "Score")
--
function MESSAGE:New( MessageText, MessageDuration, MessageCategory, ClearScreen )
local self = BASE:Inherit( self, BASE:New() )
self:F( { MessageText, MessageDuration, MessageCategory } )
local self = BASE:Inherit( self, BASE:New() )
self:F( { MessageText, MessageDuration, MessageCategory } )
self.MessageType = nil
-- When no MessageCategory is given, we don't show it as a title...
if MessageCategory and MessageCategory ~= "" then
if MessageCategory:sub(-1) ~= "\n" then
if MessageCategory and MessageCategory ~= "" then
if MessageCategory:sub( -1 ) ~= "\n" then
self.MessageCategory = MessageCategory .. ": "
else
self.MessageCategory = MessageCategory:sub( 1, -2 ) .. ":\n"
self.MessageCategory = MessageCategory:sub( 1, -2 ) .. ":\n"
end
else
self.MessageCategory = ""
end
self.ClearScreen=false
if ClearScreen~=nil then
self.ClearScreen=ClearScreen
self.ClearScreen = false
if ClearScreen ~= nil then
self.ClearScreen = ClearScreen
end
self.MessageDuration = MessageDuration or 5
self.MessageTime = timer.getTime()
self.MessageText = MessageText:gsub("^\n","",1):gsub("\n$","",1)
self.MessageSent = false
self.MessageGroup = false
self.MessageCoalition = false
self.MessageDuration = MessageDuration or 5
self.MessageTime = timer.getTime()
self.MessageText = MessageText:gsub( "^\n", "", 1 ):gsub( "\n$", "", 1 )
return self
self.MessageSent = false
self.MessageGroup = false
self.MessageCoalition = false
return self
end
--- Creates a new MESSAGE object of a certain type.
-- Note that these MESSAGE objects are not yet displayed on the display panel.
--- Creates a new MESSAGE object of a certain type.
-- Note that these MESSAGE objects are not yet displayed on the display panel.
-- You must use the functions @{ToClient} or @{ToCoalition} or @{ToAll} to send these Messages to the respective recipients.
-- The message display times are automatically defined based on the timing settings in the @{Settings} menu.
-- @param self
@@ -136,65 +135,65 @@ end
-- @param #boolean ClearScreen (optional) Clear all previous messages.
-- @return #MESSAGE
-- @usage
--
-- MessageAll = MESSAGE:NewType( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", MESSAGE.Type.Information )
-- MessageRED = MESSAGE:NewType( "To the RED Players: You receive a penalty because you've killed one of your own units", MESSAGE.Type.Information )
-- MessageClient1 = MESSAGE:NewType( "Congratulations, you've just hit a target", MESSAGE.Type.Update )
-- MessageClient2 = MESSAGE:NewType( "Congratulations, you've just killed a target", MESSAGE.Type.Update )
--
function MESSAGE:NewType( MessageText, MessageType, ClearScreen )
local self = BASE:Inherit( self, BASE:New() )
self:F( { MessageText } )
self.MessageType = MessageType
self.ClearScreen=false
if ClearScreen~=nil then
self.ClearScreen=ClearScreen
self.ClearScreen = false
if ClearScreen ~= nil then
self.ClearScreen = ClearScreen
end
self.MessageTime = timer.getTime()
self.MessageText = MessageText:gsub("^\n","",1):gsub("\n$","",1)
self.MessageText = MessageText:gsub( "^\n", "", 1 ):gsub( "\n$", "", 1 )
return self
end
--- Clears all previous messages from the screen before the new message is displayed. Not that this must come before all functions starting with ToX(), e.g. ToAll(), ToGroup() etc.
--- Clears all previous messages from the screen before the new message is displayed. Not that this must come before all functions starting with ToX(), e.g. ToAll(), ToGroup() etc.
-- @param #MESSAGE self
-- @return #MESSAGE
function MESSAGE:Clear()
self:F()
self.ClearScreen=true
self.ClearScreen = true
return self
end
--- Sends a MESSAGE to a Client Group. Note that the Group needs to be defined within the ME with the skillset "Client" or "Player".
-- @param #MESSAGE self
-- @param Wrapper.Client#CLIENT Client is the Group of the Client.
-- @param Core.Settings#SETTINGS Settings Settings used to display the message.
-- @return #MESSAGE
-- @usage
-- -- Send the 2 messages created with the @{New} method to the Client Group.
-- -- Note that the Message of MessageClient2 is overwriting the Message of MessageClient1.
-- ClientGroup = Group.getByName( "ClientGroup" )
--
-- MessageClient1 = MESSAGE:New( "Congratulations, you've just hit a target", "Score", 25, "Score" ):ToClient( ClientGroup )
-- MessageClient2 = MESSAGE:New( "Congratulations, you've just killed a target", "Score", 25, "Score" ):ToClient( ClientGroup )
-- or
-- MESSAGE:New( "Congratulations, you've just hit a target", "Score", 25, "Score" ):ToClient( ClientGroup )
-- MESSAGE:New( "Congratulations, you've just killed a target", "Score", 25, "Score" ):ToClient( ClientGroup )
-- or
-- MessageClient1 = MESSAGE:New( "Congratulations, you've just hit a target", "Score", 25, "Score" )
-- MessageClient2 = MESSAGE:New( "Congratulations, you've just killed a target", "Score", 25, "Score" )
-- MessageClient1:ToClient( ClientGroup )
-- MessageClient2:ToClient( ClientGroup )
-- -- Send the 2 messages created with the @{New} method to the Client Group.
-- -- Note that the Message of MessageClient2 is overwriting the Message of MessageClient1.
-- ClientGroup = Group.getByName( "ClientGroup" )
--
-- MessageClient1 = MESSAGE:New( "Congratulations, you've just hit a target", "Score", 25, "Score" ):ToClient( ClientGroup )
-- MessageClient2 = MESSAGE:New( "Congratulations, you've just killed a target", "Score", 25, "Score" ):ToClient( ClientGroup )
-- or
-- MESSAGE:New( "Congratulations, you've just hit a target", "Score", 25, "Score" ):ToClient( ClientGroup )
-- MESSAGE:New( "Congratulations, you've just killed a target", "Score", 25, "Score" ):ToClient( ClientGroup )
-- or
-- MessageClient1 = MESSAGE:New( "Congratulations, you've just hit a target", "Score", 25, "Score" )
-- MessageClient2 = MESSAGE:New( "Congratulations, you've just killed a target", "Score", 25, "Score" )
-- MessageClient1:ToClient( ClientGroup )
-- MessageClient2:ToClient( ClientGroup )
--
function MESSAGE:ToClient( Client, Settings )
self:F( Client )
self:F( Client )
if Client and Client:GetClientGroupID() then
if Client and Client:GetClientGroupID() then
if self.MessageType then
local Settings = Settings or ( Client and _DATABASE:GetPlayerSettings( Client:GetPlayerName() ) ) or _SETTINGS -- Core.Settings#SETTINGS
@@ -215,7 +214,7 @@ function MESSAGE:ToClient( Client, Settings )
return self
end
--- Sends a MESSAGE to a Group.
--- Sends a MESSAGE to a Group.
-- @param #MESSAGE self
-- @param Wrapper.Group#GROUP Group to which the message is displayed.
-- @return #MESSAGE Message object.
@@ -223,16 +222,40 @@ function MESSAGE:ToGroup( Group, Settings )
self:F( Group.GroupName )
if Group then
if self.MessageType then
local Settings = Settings or (Group and _DATABASE:GetPlayerSettings( Group:GetPlayerName() )) or _SETTINGS -- Core.Settings#SETTINGS
self.MessageDuration = Settings:GetMessageTime( self.MessageType )
self.MessageCategory = "" -- self.MessageType .. ": "
end
if self.MessageDuration ~= 0 then
self:T( self.MessageCategory .. self.MessageText:gsub( "\n$", "" ):gsub( "\n$", "" ) .. " / " .. self.MessageDuration )
trigger.action.outTextForGroup( Group:GetID(), self.MessageCategory .. self.MessageText:gsub( "\n$", "" ):gsub( "\n$", "" ), self.MessageDuration, self.ClearScreen )
end
end
return self
end
--- Sends a MESSAGE to a Unit.
-- @param #MESSAGE self
-- @param Wrapper.Unit#UNIT Unit to which the message is displayed.
-- @return #MESSAGE Message object.
function MESSAGE:ToUnit( Unit, Settings )
self:F( Unit.IdentifiableName )
if Unit then
if self.MessageType then
local Settings = Settings or ( Group and _DATABASE:GetPlayerSettings( Group:GetPlayerName() ) ) or _SETTINGS -- Core.Settings#SETTINGS
local Settings = Settings or ( Unit and _DATABASE:GetPlayerSettings( Unit:GetPlayerName() ) ) or _SETTINGS -- Core.Settings#SETTINGS
self.MessageDuration = Settings:GetMessageTime( self.MessageType )
self.MessageCategory = "" -- self.MessageType .. ": "
end
if self.MessageDuration ~= 0 then
self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration )
trigger.action.outTextForGroup( Group:GetID(), self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration, self.ClearScreen )
trigger.action.outTextForUnit( Unit:GetID(), self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration, self.ClearScreen )
end
end
@@ -264,58 +287,64 @@ function MESSAGE:ToUnit( Unit, Settings )
end
--- Sends a MESSAGE to the Blue coalition.
-- @param #MESSAGE self
-- @return #MESSAGE
-- @usage
-- -- Send a message created with the @{New} method to the BLUE coalition.
-- MessageBLUE = MESSAGE:New( "To the BLUE Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToBlue()
-- or
-- MESSAGE:New( "To the BLUE Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToBlue()
-- or
-- MessageBLUE = MESSAGE:New( "To the BLUE Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" )
-- MessageBLUE:ToBlue()
function MESSAGE:ToBlue()
self:F()
self:ToCoalition( coalition.side.BLUE )
return self
end
--- Sends a MESSAGE to the Red Coalition.
-- @param #MESSAGE self
-- @return #MESSAGE
-- @usage
-- -- Send a message created with the @{New} method to the RED coalition.
-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToRed()
-- or
-- MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToRed()
-- or
-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" )
-- MessageRED:ToRed()
function MESSAGE:ToRed( )
self:F()
--
-- -- Send a message created with the @{New} method to the BLUE coalition.
-- MessageBLUE = MESSAGE:New( "To the BLUE Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToBlue()
-- or
-- MESSAGE:New( "To the BLUE Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToBlue()
-- or
-- MessageBLUE = MESSAGE:New( "To the BLUE Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" )
-- MessageBLUE:ToBlue()
--
function MESSAGE:ToBlue()
self:F()
self:ToCoalition( coalition.side.RED )
return self
self:ToCoalition( coalition.side.BLUE )
return self
end
--- Sends a MESSAGE to a Coalition.
--- Sends a MESSAGE to the Red Coalition.
-- @param #MESSAGE self
-- @return #MESSAGE
-- @usage
--
-- -- Send a message created with the @{New} method to the RED coalition.
-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToRed()
-- or
-- MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToRed()
-- or
-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" )
-- MessageRED:ToRed()
--
function MESSAGE:ToRed()
self:F()
self:ToCoalition( coalition.side.RED )
return self
end
--- Sends a MESSAGE to a Coalition.
-- @param #MESSAGE self
-- @param #DCS.coalition.side CoalitionSide @{#DCS.coalition.side} to which the message is displayed.
-- @param Core.Settings#SETTINGS Settings (Optional) Settings for message display.
-- @return #MESSAGE Message object.
-- @usage
-- -- Send a message created with the @{New} method to the RED coalition.
-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToCoalition( coalition.side.RED )
-- or
-- MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToCoalition( coalition.side.RED )
-- or
-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" )
-- MessageRED:ToCoalition( coalition.side.RED )
--
-- -- Send a message created with the @{New} method to the RED coalition.
-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToCoalition( coalition.side.RED )
-- or
-- MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToCoalition( coalition.side.RED )
-- or
-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" )
-- MessageRED:ToCoalition( coalition.side.RED )
--
function MESSAGE:ToCoalition( CoalitionSide, Settings )
self:F( CoalitionSide )
self:F( CoalitionSide )
if self.MessageType then
local Settings = Settings or _SETTINGS -- Core.Settings#SETTINGS
@@ -323,20 +352,20 @@ function MESSAGE:ToCoalition( CoalitionSide, Settings )
self.MessageCategory = "" -- self.MessageType .. ": "
end
if CoalitionSide then
if CoalitionSide then
if self.MessageDuration ~= 0 then
self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration )
trigger.action.outTextForCoalition( CoalitionSide, self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration, self.ClearScreen )
self:T( self.MessageCategory .. self.MessageText:gsub( "\n$", "" ):gsub( "\n$", "" ) .. " / " .. self.MessageDuration )
trigger.action.outTextForCoalition( CoalitionSide, self.MessageText:gsub( "\n$", "" ):gsub( "\n$", "" ), self.MessageDuration, self.ClearScreen )
end
end
return self
end
return self
end
--- Sends a MESSAGE to a Coalition if the given Condition is true.
--- Sends a MESSAGE to a Coalition if the given Condition is true.
-- @param #MESSAGE self
-- @param CoalitionSide needs to be filled out by the defined structure of the standard scripting engine @{coalition.side}.
-- @param #boolean Condition Sends the message only if the condition is true.
-- @param #boolean Condition Sends the message only if the condition is true.
-- @return #MESSAGE self
function MESSAGE:ToCoalitionIf( CoalitionSide, Condition )
self:F( CoalitionSide )
@@ -344,7 +373,7 @@ function MESSAGE:ToCoalitionIf( CoalitionSide, Condition )
if Condition and Condition == true then
self:ToCoalition( CoalitionSide )
end
return self
end
@@ -353,14 +382,16 @@ end
-- @param Core.Settings#Settings Settings (Optional) Settings for message display.
-- @return #MESSAGE
-- @usage
-- -- Send a message created to all players.
-- MessageAll = MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25, "Win" ):ToAll()
-- or
-- MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25, "Win" ):ToAll()
-- or
-- MessageAll = MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25, "Win" )
-- MessageAll:ToAll()
function MESSAGE:ToAll(Settings)
--
-- -- Send a message created to all players.
-- MessageAll = MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25, "Win" ):ToAll()
-- or
-- MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25, "Win" ):ToAll()
-- or
-- MessageAll = MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25, "Win" )
-- MessageAll:ToAll()
--
function MESSAGE:ToAll( Settings )
self:F()
if self.MessageType then
@@ -370,14 +401,13 @@ function MESSAGE:ToAll(Settings)
end
if self.MessageDuration ~= 0 then
self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration )
trigger.action.outText( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration, self.ClearScreen )
self:T( self.MessageCategory .. self.MessageText:gsub( "\n$", "" ):gsub( "\n$", "" ) .. " / " .. self.MessageDuration )
trigger.action.outText( self.MessageCategory .. self.MessageText:gsub( "\n$", "" ):gsub( "\n$", "" ), self.MessageDuration, self.ClearScreen )
end
return self
end
--- Sends a MESSAGE to all players if the given Condition is true.
-- @param #MESSAGE self
-- @return #MESSAGE
@@ -387,5 +417,5 @@ function MESSAGE:ToAllIf( Condition )
self:ToAll()
end
return self
return self
end

View File

@@ -1,13 +1,13 @@
--- **Core** - Provides a handy means to create messages and reports.
--
-- ===
--
--
-- ## Features:
--
--
-- * Create text blocks that are formatted.
-- * Create automatic indents.
-- * Variate the delimiters between reporting lines.
--
--
-- ===
--
-- ### Authors: FlightControl : Design & Programming
@@ -15,7 +15,6 @@
-- @module Core.Report
-- @image Core_Report.JPG
--- @type REPORT
-- @extends Core.Base#BASE
@@ -36,7 +35,7 @@ function REPORT:New( Title )
self.Report = {}
self:SetTitle( Title or "" )
self:SetTitle( Title or "" )
self:SetIndent( 3 )
return self
@@ -45,28 +44,26 @@ end
--- Has the REPORT Text?
-- @param #REPORT self
-- @return #boolean
function REPORT:HasText() --R2.1
function REPORT:HasText() -- R2.1
return #self.Report > 0
end
--- Set indent of a REPORT.
-- @param #REPORT self
-- @param #number Indent
-- @return #REPORT
function REPORT:SetIndent( Indent ) --R2.1
function REPORT:SetIndent( Indent ) -- R2.1
self.Indent = Indent
return self
end
--- Add a new line to a REPORT.
-- @param #REPORT self
-- @param #string Text
-- @return #REPORT
function REPORT:Add( Text )
self.Report[#self.Report+1] = Text
self.Report[#self.Report + 1] = Text
return self
end
@@ -76,17 +73,17 @@ end
-- @param #string Separator (optional) The start of each report line can begin with an optional separator character. This can be a "-", or "#", or "*". You're free to choose what you find the best.
-- @return #REPORT
function REPORT:AddIndent( Text, Separator )
self.Report[#self.Report+1] = ( ( Separator and Separator .. string.rep( " ", self.Indent - 1 ) ) or string.rep(" ", self.Indent ) ) .. Text:gsub("\n","\n"..string.rep( " ", self.Indent ) )
self.Report[#self.Report + 1] = ((Separator and Separator .. string.rep( " ", self.Indent - 1 )) or string.rep( " ", self.Indent )) .. Text:gsub( "\n", "\n" .. string.rep( " ", self.Indent ) )
return self
end
--- Produces the text of the report, taking into account an optional delimeter, which is \n by default.
--- Produces the text of the report, taking into account an optional delimiter, which is \n by default.
-- @param #REPORT self
-- @param #string Delimiter (optional) A delimiter text.
-- @return #string The report text.
function REPORT:Text( Delimiter )
Delimiter = Delimiter or "\n"
local ReportText = ( self.Title ~= "" and self.Title .. Delimiter or self.Title ) .. table.concat( self.Report, Delimiter ) or ""
local ReportText = (self.Title ~= "" and self.Title .. Delimiter or self.Title) .. table.concat( self.Report, Delimiter ) or ""
return ReportText
end
@@ -95,7 +92,7 @@ end
-- @param #string Title The title of the report.
-- @return #REPORT
function REPORT:SetTitle( Title )
self.Title = Title
self.Title = Title
return self
end

View File

@@ -1,36 +1,36 @@
--- **Core** -- SCHEDULEDISPATCHER dispatches the different schedules.
--
--
-- ===
--
--
-- Takes care of the creation and dispatching of scheduled functions for SCHEDULER objects.
--
--
-- This class is tricky and needs some thorough explanation.
-- SCHEDULE classes are used to schedule functions for objects, or as persistent objects.
-- The SCHEDULEDISPATCHER class ensures that:
--
--
-- - Scheduled functions are planned according the SCHEDULER object parameters.
-- - Scheduled functions are repeated when requested, according the SCHEDULER object parameters.
-- - Scheduled functions are automatically removed when the schedule is finished, according the SCHEDULER object parameters.
--
--
-- The SCHEDULEDISPATCHER class will manage SCHEDULER object in memory during garbage collection:
--
--
-- - When a SCHEDULER object is not attached to another object (that is, it's first :Schedule() parameter is nil), then the SCHEDULER object is _persistent_ within memory.
-- - When a SCHEDULER object *is* attached to another object, then the SCHEDULER object is _not persistent_ within memory after a garbage collection!
--
-- The none persistency of SCHEDULERS attached to objects is required to allow SCHEDULER objects to be garbage collectged, when the parent object is also desroyed or nillified and garbage collected.
-- Even when there are pending timer scheduled functions to be executed for the SCHEDULER object,
--
-- The non-persistency of SCHEDULERS attached to objects is required to allow SCHEDULER objects to be garbage collected when the parent object is destroyed, or set to nil and garbage collected.
-- Even when there are pending timer scheduled functions to be executed for the SCHEDULER object,
-- these will not be executed anymore when the SCHEDULER object has been destroyed.
--
--
-- The SCHEDULEDISPATCHER allows multiple scheduled functions to be planned and executed for one SCHEDULER object.
-- The SCHEDULER object therefore keeps a table of "CallID's", which are returned after each planning of a new scheduled function by the SCHEDULEDISPATCHER.
-- The SCHEDULER object plans new scheduled functions through the @{Core.Scheduler#SCHEDULER.Schedule}() method.
-- The SCHEDULER object plans new scheduled functions through the @{Core.Scheduler#SCHEDULER.Schedule}() method.
-- The Schedule() method returns the CallID that is the reference ID for each planned schedule.
--
--
-- ===
--
--
-- ### Contributions: -
-- ### Authors: FlightControl : Design & Programming
--
--
-- @module Core.ScheduleDispatcher
-- @image Core_Schedule_Dispatcher.JPG
@@ -38,7 +38,7 @@
-- @type SCHEDULEDISPATCHER
-- @field #string ClassName Name of the class.
-- @field #number CallID Call ID counter.
-- @field #table PersistentSchedulers Persistant schedulers.
-- @field #table PersistentSchedulers Persistent schedulers.
-- @field #table ObjectSchedulers Schedulers that only exist as long as the master object exists.
-- @field #table Schedule Meta table setmetatable( {}, { __mode = "k" } ).
-- @extends Core.Base#BASE
@@ -46,11 +46,11 @@
--- The SCHEDULEDISPATCHER structure
-- @type SCHEDULEDISPATCHER
SCHEDULEDISPATCHER = {
ClassName = "SCHEDULEDISPATCHER",
CallID = 0,
PersistentSchedulers = {},
ObjectSchedulers = {},
Schedule = nil,
ClassName = "SCHEDULEDISPATCHER",
CallID = 0,
PersistentSchedulers = {},
ObjectSchedulers = {},
Schedule = nil,
}
--- Player data table holding all important parameters of each player.
@@ -58,7 +58,7 @@ SCHEDULEDISPATCHER = {
-- @field #function Function The schedule function to be called.
-- @field #table Arguments Schedule function arguments.
-- @field #number Start Start time in seconds.
-- @field #number Repeat Repeat time intervall in seconds.
-- @field #number Repeat Repeat time interval in seconds.
-- @field #number Randomize Randomization factor [0,1].
-- @field #number Stop Stop time in seconds.
-- @field #number StartTime Time in seconds when the scheduler is created.
@@ -77,7 +77,7 @@ end
--- Add a Schedule to the ScheduleDispatcher.
-- The development of this method was really tidy.
-- It is constructed as such that a garbage collection is executed on the weak tables, when the Scheduler is nillified.
-- It is constructed as such that a garbage collection is executed on the weak tables, when the Scheduler is set to nil.
-- Nothing of this code should be modified without testing it thoroughly.
-- @param #SCHEDULEDISPATCHER self
-- @param Core.Scheduler#SCHEDULER Scheduler Scheduler object.
@@ -85,7 +85,7 @@ end
-- @param #table ScheduleArguments Table of arguments passed to the ScheduleFunction.
-- @param #number Start Start time in seconds.
-- @param #number Repeat Repeat interval in seconds.
-- @param #number Randomize Radomization factor [0,1].
-- @param #number Randomize Randomization factor [0,1].
-- @param #number Stop Stop time in seconds.
-- @param #number TraceLevel Trace level [0,3].
-- @param Core.Fsm#FSM Fsm Finite state model.
@@ -95,32 +95,32 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
-- Increase counter.
self.CallID = self.CallID + 1
-- Create ID.
local CallID = self.CallID .. "#" .. ( Scheduler.MasterObject and Scheduler.MasterObject.GetClassNameAndID and Scheduler.MasterObject:GetClassNameAndID() or "" ) or ""
self:T2(string.format("Adding schedule #%d CallID=%s", self.CallID, CallID))
local CallID = self.CallID .. "#" .. (Scheduler.MasterObject and Scheduler.MasterObject.GetClassNameAndID and Scheduler.MasterObject:GetClassNameAndID() or "") or ""
self:T2( string.format( "Adding schedule #%d CallID=%s", self.CallID, CallID ) )
-- Initialize PersistentSchedulers
self.PersistentSchedulers = self.PersistentSchedulers or {}
-- Initialize the ObjectSchedulers array, which is a weakly coupled table.
-- If the object used as the key is nil, then the garbage collector will remove the item from the Functions array.
self.ObjectSchedulers = self.ObjectSchedulers or setmetatable( {}, { __mode = "v" } )
self.ObjectSchedulers = self.ObjectSchedulers or setmetatable( {}, { __mode = "v" } )
if Scheduler.MasterObject then
--env.info("FF Object Scheduler")
self.ObjectSchedulers[CallID] = Scheduler
self:F3( { CallID = CallID, ObjectScheduler = tostring(self.ObjectSchedulers[CallID]), MasterObject = tostring(Scheduler.MasterObject) } )
self:F3( { CallID = CallID, ObjectScheduler = tostring( self.ObjectSchedulers[CallID] ), MasterObject = tostring( Scheduler.MasterObject ) } )
else
--env.info("FF Persistent Scheduler")
self.PersistentSchedulers[CallID] = Scheduler
self:F3( { CallID = CallID, PersistentScheduler = self.PersistentSchedulers[CallID] } )
end
self.Schedule = self.Schedule or setmetatable( {}, { __mode = "k" } )
self.Schedule[Scheduler] = self.Schedule[Scheduler] or {}
self.Schedule[Scheduler][CallID] = {} --#SCHEDULEDISPATCHER.ScheduleData
self.Schedule[Scheduler][CallID] = {} -- #SCHEDULEDISPATCHER.ScheduleData
self.Schedule[Scheduler][CallID].Function = ScheduleFunction
self.Schedule[Scheduler][CallID].Arguments = ScheduleArguments
self.Schedule[Scheduler][CallID].StartTime = timer.getTime() + ( Start or 0 )
@@ -128,8 +128,7 @@ 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.
@@ -151,10 +150,10 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
-- 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.
-- So this little piece of code does its magic wonderfully, performance overhead is negligible, as scheduled calls don't happen that often.
local Info = {}
if debug then
TraceLevel = TraceLevel or 2
Info = debug.getinfo( TraceLevel, "nlS" )
@@ -168,7 +167,7 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
--- Function passed to the DCS timer.scheduleFunction()
self.Schedule[Scheduler][CallID].CallHandler = function( Params )
local CallID = Params.CallID
local Info = Params.Info or {}
local Source = Info.source or "?"
@@ -182,27 +181,27 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
end
return errmsg
end
-- Get object or persistant scheduler object.
local Scheduler = self.ObjectSchedulers[CallID] --Core.Scheduler#SCHEDULER
-- Get object or persistent scheduler object.
local Scheduler = self.ObjectSchedulers[CallID] -- Core.Scheduler#SCHEDULER
if not Scheduler then
Scheduler = self.PersistentSchedulers[CallID]
end
--self:T3( { Scheduler = Scheduler } )
-- self:T3( { Scheduler = Scheduler } )
if Scheduler then
local MasterObject = tostring(Scheduler.MasterObject)
-- Schedule object.
local Schedule = self.Schedule[Scheduler][CallID] --#SCHEDULEDISPATCHER.ScheduleData
--self:T3( { Schedule = Schedule } )
local MasterObject = tostring( Scheduler.MasterObject )
local SchedulerObject = Scheduler.MasterObject --Scheduler.SchedulerObject Now is this the Maste or Scheduler object?
-- Schedule object.
local Schedule = self.Schedule[Scheduler][CallID] -- #SCHEDULEDISPATCHER.ScheduleData
-- self:T3( { Schedule = Schedule } )
local SchedulerObject = Scheduler.MasterObject -- Scheduler.SchedulerObject Now is this the Master or Scheduler object?
local ShowTrace = Scheduler.ShowTrace
local ScheduleFunction = Schedule.Function
local ScheduleArguments = Schedule.Arguments or {}
local Start = Schedule.Start
@@ -210,12 +209,11 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
local Randomize = Schedule.Randomize or 0
local Stop = Schedule.Stop or 0
local ScheduleID = Schedule.ScheduleID
local Prefix = ( Repeat == 0 ) and "--->" or "+++>"
local Prefix = (Repeat == 0) and "--->" or "+++>"
local Status, Result
--self:E( { SchedulerObject = SchedulerObject } )
-- self:E( { SchedulerObject = SchedulerObject } )
if SchedulerObject then
local function Timer()
if ShowTrace then
@@ -230,40 +228,39 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
if ShowTrace then
self:T( Prefix .. Name .. ":" .. Line .. " (" .. Source .. ")" )
end
return ScheduleFunction( unpack( ScheduleArguments ) )
return ScheduleFunction( unpack( ScheduleArguments ) )
end
Status, Result = xpcall( Timer, ErrorHandler )
end
local CurrentTime = timer.getTime()
local StartTime = Schedule.StartTime
-- Debug info.
self:F3( { CallID=CallID, ScheduleID=ScheduleID, Master = MasterObject, CurrentTime = CurrentTime, StartTime = StartTime, Start = Start, Repeat = Repeat, Randomize = Randomize, Stop = Stop } )
if Status and (( Result == nil ) or ( Result and Result ~= false ) ) then
if Repeat ~= 0 and ( ( Stop == 0 ) or ( Stop ~= 0 and CurrentTime <= StartTime + Stop ) ) then
local ScheduleTime = CurrentTime + Repeat + math.random(- ( Randomize * Repeat / 2 ), ( Randomize * Repeat / 2 )) + 0.0001 -- Accuracy
--self:T3( { Repeat = CallID, CurrentTime, ScheduleTime, ScheduleArguments } )
self:F3( { CallID = CallID, ScheduleID = ScheduleID, Master = MasterObject, CurrentTime = CurrentTime, StartTime = StartTime, Start = Start, Repeat = Repeat, Randomize = Randomize, Stop = Stop } )
if Status and ((Result == nil) or (Result and Result ~= false)) then
if Repeat ~= 0 and ((Stop == 0) or (Stop ~= 0 and CurrentTime <= StartTime + Stop)) then
local ScheduleTime = CurrentTime + Repeat + math.random( -(Randomize * Repeat / 2), (Randomize * Repeat / 2) ) + 0.0001 -- Accuracy
-- self:T3( { Repeat = CallID, CurrentTime, ScheduleTime, ScheduleArguments } )
return ScheduleTime -- returns the next time the function needs to be called.
else
self:Stop( Scheduler, CallID )
end
else
self:Stop( Scheduler, CallID )
end
else
self:I( "<<<>" .. Name .. ":" .. Line .. " (" .. Source .. ")" )
end
return nil
end
self:Start( Scheduler, CallID, Info )
return CallID
end
@@ -287,33 +284,33 @@ end
-- @param #string Info (Optional) Debug info.
function SCHEDULEDISPATCHER:Start( Scheduler, CallID, Info )
self:F2( { Start = CallID, Scheduler = Scheduler } )
if CallID then
local Schedule = self.Schedule[Scheduler][CallID] --#SCHEDULEDISPATCHER.ScheduleData
local Schedule = self.Schedule[Scheduler][CallID] -- #SCHEDULEDISPATCHER.ScheduleData
-- Only start when there is no ScheduleID defined!
-- This prevents to "Start" the scheduler twice with the same CallID...
if not Schedule.ScheduleID then
-- Current time in seconds.
local Tnow=timer.getTime()
Schedule.StartTime = Tnow -- Set the StartTime field to indicate when the scheduler started.
local Tnow = timer.getTime()
Schedule.StartTime = Tnow -- Set the StartTime field to indicate when the scheduler started.
-- Start DCS schedule function https://wiki.hoggitworld.com/view/DCS_func_scheduleFunction
Schedule.ScheduleID = timer.scheduleFunction(Schedule.CallHandler, { CallID = CallID, Info = Info }, Tnow + Schedule.Start)
self:T(string.format("Starting scheduledispatcher Call ID=%s ==> Schedule ID=%s", tostring(CallID), tostring(Schedule.ScheduleID)))
Schedule.ScheduleID = timer.scheduleFunction( Schedule.CallHandler, { CallID = CallID, Info = Info }, Tnow + Schedule.Start )
self:T( string.format( "Starting SCHEDULEDISPATCHER Call ID=%s ==> Schedule ID=%s", tostring( CallID ), tostring( Schedule.ScheduleID ) ) )
end
else
-- Recursive.
for CallID, Schedule in pairs( self.Schedule[Scheduler] or {} ) do
self:Start( Scheduler, CallID, Info ) -- Recursive
end
end
end
@@ -325,29 +322,29 @@ function SCHEDULEDISPATCHER:Stop( Scheduler, CallID )
self:F2( { Stop = CallID, Scheduler = Scheduler } )
if CallID then
local Schedule = self.Schedule[Scheduler][CallID] --#SCHEDULEDISPATCHER.ScheduleData
local Schedule = self.Schedule[Scheduler][CallID] -- #SCHEDULEDISPATCHER.ScheduleData
-- Only stop when there is a ScheduleID defined for the CallID. So, when the scheduler was stopped before, do nothing.
if Schedule.ScheduleID then
self:T(string.format("scheduledispatcher stopping scheduler CallID=%s, ScheduleID=%s", tostring(CallID), tostring(Schedule.ScheduleID)))
self:T( string.format( "SCHEDULEDISPATCHER stopping scheduler CallID=%s, ScheduleID=%s", tostring( CallID ), tostring( Schedule.ScheduleID ) ) )
-- Remove schedule function https://wiki.hoggitworld.com/view/DCS_func_removeFunction
timer.removeFunction(Schedule.ScheduleID)
timer.removeFunction( Schedule.ScheduleID )
Schedule.ScheduleID = nil
else
self:T(string.format("Error no ScheduleID for CallID=%s", tostring(CallID)))
self:T( string.format( "Error no ScheduleID for CallID=%s", tostring( CallID ) ) )
end
else
for CallID, Schedule in pairs( self.Schedule[Scheduler] or {} ) do
self:Stop( Scheduler, CallID ) -- Recursive
end
end
end
@@ -362,7 +359,7 @@ function SCHEDULEDISPATCHER:Clear( Scheduler )
end
end
--- Shopw tracing info.
--- Show tracing info.
-- @param #SCHEDULEDISPATCHER self
-- @param Core.Scheduler#SCHEDULER Scheduler Scheduler object.
function SCHEDULEDISPATCHER:ShowTrace( Scheduler )

View File

@@ -3,15 +3,15 @@
-- ===
--
-- ## Features:
--
--
-- * Schedule functions over time,
-- * optionally in an optional specified time interval,
-- * optionally **repeating** with a specified time repeat interval,
-- * optionally **randomizing** with a specified time interval randomization factor,
-- * optionally **stop** the repeating after a specified time interval.
-- * optionally in an optional specified time interval,
-- * optionally **repeating** with a specified time repeat interval,
-- * optionally **randomizing** with a specified time interval randomization factor,
-- * optionally **stop** the repeating after a specified time interval.
--
-- ===
--
--
-- # Demo Missions
--
-- ### [SCHEDULER Demo Missions source code](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/SCH%20-%20Scheduler)
@@ -19,23 +19,23 @@
-- ### [SCHEDULER Demo Missions, only for beta testers](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/SCH%20-%20Scheduler)
--
-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases)
--
-- ===
--
-- # YouTube Channel
--
-- ### [SCHEDULER YouTube Channel (none)]()
--
--
-- ===
--
-- ### Contributions:
--
-- # YouTube Channel
--
-- ### [SCHEDULER YouTube Channel (none)]()
--
-- ===
--
-- ### Contributions:
--
-- * FlightControl : Concept & Testing
--
-- ### Authors:
--
--
-- ### Authors:
--
-- * FlightControl : Design & Programming
--
--
-- ===
--
-- @module Core.Scheduler
@@ -48,62 +48,61 @@
-- @field #boolean ShowTrace Trace info if true.
-- @extends Core.Base#BASE
--- Creates and handles schedules over time, which allow to execute code at specific time intervals with randomization.
--
--
-- A SCHEDULER can manage **multiple** (repeating) schedules. Each planned or executing schedule has a unique **ScheduleID**.
-- The ScheduleID is returned when the method @{#SCHEDULER.Schedule}() is called.
-- It is recommended to store the ScheduleID in a variable, as it is used in the methods @{SCHEDULER.Start}() and @{SCHEDULER.Stop}(),
-- which can start and stop specific repeating schedules respectively within a SCHEDULER object.
--
-- ## SCHEDULER constructor
--
--
-- The SCHEDULER class is quite easy to use, but note that the New constructor has variable parameters:
--
--
-- The @{#SCHEDULER.New}() method returns 2 variables:
--
--
-- 1. The SCHEDULER object reference.
-- 2. The first schedule planned in the SCHEDULER object.
--
--
-- To clarify the different appliances, lets have a look at the following examples:
--
--
-- ### Construct a SCHEDULER object without a persistent schedule.
--
--
-- * @{#SCHEDULER.New}( nil ): Setup a new SCHEDULER object, which is persistently executed after garbage collection.
--
--
-- MasterObject = SCHEDULER:New()
-- SchedulerID = MasterObject:Schedule( nil, ScheduleFunction, {} )
--
--
-- The above example creates a new MasterObject, but does not schedule anything.
-- A separate schedule is created by using the MasterObject using the method :Schedule..., which returns a ScheduleID
--
--
-- ### Construct a SCHEDULER object without a volatile schedule, but volatile to the Object existence...
--
-- * @{#SCHEDULER.New}( Object ): Setup a new SCHEDULER object, which is linked to the Object. When the Object is nillified or destroyed, the SCHEDULER object will also be destroyed and stopped after garbage collection.
--
--
-- * @{#SCHEDULER.New}( Object ): Setup a new SCHEDULER object, which is linked to the Object. When the Object is set to nil or destroyed, the SCHEDULER object will also be destroyed and stopped after garbage collection.
--
-- ZoneObject = ZONE:New( "ZoneName" )
-- MasterObject = SCHEDULER:New( ZoneObject )
-- SchedulerID = MasterObject:Schedule( ZoneObject, ScheduleFunction, {} )
-- ...
-- ZoneObject = nil
-- garbagecollect()
--
--
-- The above example creates a new MasterObject, but does not schedule anything, and is bound to the existence of ZoneObject, which is a ZONE.
-- A separate schedule is created by using the MasterObject using the method :Schedule()..., which returns a ScheduleID
-- Later in the logic, the ZoneObject is put to nil, and garbage is collected.
-- As a result, the MasterObject will cancel any planned schedule.
--
--
-- ### Construct a SCHEDULER object with a persistent schedule.
--
--
-- * @{#SCHEDULER.New}( nil, Function, FunctionArguments, Start, ... ): Setup a new persistent SCHEDULER object, and start a new schedule for the Function with the defined FunctionArguments according the Start and sequent parameters.
--
--
-- MasterObject, SchedulerID = SCHEDULER:New( nil, ScheduleFunction, {} )
--
--
-- The above example creates a new MasterObject, and does schedule the first schedule as part of the call.
-- Note that 2 variables are returned here: MasterObject, ScheduleID...
--
--
-- ### Construct a SCHEDULER object without a schedule, but volatile to the Object existence...
--
--
-- * @{#SCHEDULER.New}( Object, Function, FunctionArguments, Start, ... ): Setup a new SCHEDULER object, linked to Object, and start a new schedule for the Function with the defined FunctionArguments according the Start and sequent parameters.
--
-- ZoneObject = ZONE:New( "ZoneName" )
@@ -112,13 +111,13 @@
-- ...
-- ZoneObject = nil
-- garbagecollect()
--
--
-- The above example creates a new MasterObject, and schedules a method call (ScheduleFunction),
-- and is bound to the existence of ZoneObject, which is a ZONE object (ZoneObject).
-- Both a MasterObject and a SchedulerID variable are returned.
-- Later in the logic, the ZoneObject is put to nil, and garbage is collected.
-- As a result, the MasterObject will cancel the planned schedule.
--
--
-- ## SCHEDULER timer stopping and (re-)starting.
--
-- The SCHEDULER can be stopped and restarted with the following methods:
@@ -133,70 +132,70 @@
-- MasterObject:Stop( SchedulerID )
-- ...
-- MasterObject:Start( SchedulerID )
--
--
-- The above example creates a new MasterObject, and does schedule the first schedule as part of the call.
-- Note that 2 variables are returned here: MasterObject, ScheduleID...
-- Later in the logic, the repeating schedule with SchedulerID is stopped.
-- A bit later, the repeating schedule with SchedulerId is (re)-started.
--
-- Note that 2 variables are returned here: MasterObject, ScheduleID...
-- Later in the logic, the repeating schedule with SchedulerID is stopped.
-- A bit later, the repeating schedule with SchedulerId is (re)-started.
--
-- ## Create a new schedule
--
-- With the method @{#SCHEDULER.Schedule}() a new time event can be scheduled.
--
-- With the method @{#SCHEDULER.Schedule}() a new time event can be scheduled.
-- This method is used by the :New() constructor when a new schedule is planned.
--
--
-- Consider the following code fragment of the SCHEDULER object creation.
--
--
-- ZoneObject = ZONE:New( "ZoneName" )
-- MasterObject = SCHEDULER:New( ZoneObject )
--
-- Several parameters can be specified that influence the behaviour of a Schedule.
--
--
-- Several parameters can be specified that influence the behavior of a Schedule.
--
-- ### A single schedule, immediately executed
--
--
-- SchedulerID = MasterObject:Schedule( ZoneObject, ScheduleFunction, {} )
--
-- The above example schedules a new ScheduleFunction call to be executed asynchronously, within milleseconds ...
--
--
-- The above example schedules a new ScheduleFunction call to be executed asynchronously, within milliseconds ...
--
-- ### A single schedule, planned over time
--
--
-- SchedulerID = MasterObject:Schedule( ZoneObject, ScheduleFunction, {}, 10 )
--
--
-- The above example schedules a new ScheduleFunction call to be executed asynchronously, within 10 seconds ...
--
--
-- ### A schedule with a repeating time interval, planned over time
--
--
-- SchedulerID = MasterObject:Schedule( ZoneObject, ScheduleFunction, {}, 10, 60 )
--
-- The above example schedules a new ScheduleFunction call to be executed asynchronously, within 10 seconds,
--
-- The above example schedules a new ScheduleFunction call to be executed asynchronously, within 10 seconds,
-- and repeating 60 every seconds ...
--
--
-- ### A schedule with a repeating time interval, planned over time, with time interval randomization
--
--
-- SchedulerID = MasterObject:Schedule( ZoneObject, ScheduleFunction, {}, 10, 60, 0.5 )
--
-- The above example schedules a new ScheduleFunction call to be executed asynchronously, within 10 seconds,
--
-- The above example schedules a new ScheduleFunction call to be executed asynchronously, within 10 seconds,
-- and repeating 60 seconds, with a 50% time interval randomization ...
-- So the repeating time interval will be randomized using the **0.5**,
-- and will calculate between **60 - ( 60 * 0.5 )** and **60 + ( 60 * 0.5 )** for each repeat,
-- So the repeating time interval will be randomized using the **0.5**,
-- and will calculate between **60 - ( 60 * 0.5 )** and **60 + ( 60 * 0.5 )** for each repeat,
-- which is in this example between **30** and **90** seconds.
--
--
-- ### A schedule with a repeating time interval, planned over time, with time interval randomization, and stop after a time interval
--
--
-- SchedulerID = MasterObject:Schedule( ZoneObject, ScheduleFunction, {}, 10, 60, 0.5, 300 )
--
-- The above example schedules a new ScheduleFunction call to be executed asynchronously, within 10 seconds,
--
-- The above example schedules a new ScheduleFunction call to be executed asynchronously, within 10 seconds,
-- The schedule will repeat every 60 seconds.
-- So the repeating time interval will be randomized using the **0.5**,
-- and will calculate between **60 - ( 60 * 0.5 )** and **60 + ( 60 * 0.5 )** for each repeat,
-- So the repeating time interval will be randomized using the **0.5**,
-- and will calculate between **60 - ( 60 * 0.5 )** and **60 + ( 60 * 0.5 )** for each repeat,
-- which is in this example between **30** and **90** seconds.
-- The schedule will stop after **300** seconds.
--
--
-- @field #SCHEDULER
SCHEDULER = {
ClassName = "SCHEDULER",
Schedules = {},
MasterObject = nil,
ShowTrace = nil,
ClassName = "SCHEDULER",
Schedules = {},
MasterObject = nil,
ShowTrace = nil,
}
--- SCHEDULER constructor.
@@ -211,15 +210,15 @@ SCHEDULER = {
-- @return #SCHEDULER self.
-- @return #table The ScheduleID of the planned schedule.
function SCHEDULER:New( MasterObject, SchedulerFunction, SchedulerArguments, Start, Repeat, RandomizeFactor, Stop )
local self = BASE:Inherit( self, BASE:New() ) -- #SCHEDULER
self:F2( { Start, Repeat, RandomizeFactor, Stop } )
local ScheduleID = nil
self.MasterObject = MasterObject
self.ShowTrace = false
if SchedulerFunction then
ScheduleID = self:Schedule( MasterObject, SchedulerFunction, SchedulerArguments, Start, Repeat, RandomizeFactor, Stop, 3 )
end
@@ -235,7 +234,7 @@ end
-- @param #number Start Specifies the amount of seconds that will be waited before the scheduling is started, and the event function is called.
-- @param #number Repeat Specifies the time interval in seconds when the scheduler will call the event function.
-- @param #number RandomizeFactor Specifies a randomization factor between 0 and 1 to randomize the Repeat.
-- @param #number Stop Time interval in seconds after which the scheduler will be stoppe.
-- @param #number Stop Time interval in seconds after which the scheduler will be stopped.
-- @param #number TraceLevel Trace level [0,3]. Default 3.
-- @param Core.Fsm#FSM Fsm Finite state model.
-- @return #string The Schedule ID of the planned schedule.
@@ -245,28 +244,27 @@ function SCHEDULER:Schedule( MasterObject, SchedulerFunction, SchedulerArguments
-- Debug info.
local ObjectName = "-"
if MasterObject and MasterObject.ClassName and MasterObject.ClassID then
if MasterObject and MasterObject.ClassName and MasterObject.ClassID then
ObjectName = MasterObject.ClassName .. MasterObject.ClassID
end
self:F3( { "Schedule :", ObjectName, tostring( MasterObject ), Start, Repeat, RandomizeFactor, Stop } )
self:F3( { "Schedule :", ObjectName, tostring( MasterObject ), Start, Repeat, RandomizeFactor, Stop } )
-- Set master object.
self.MasterObject = MasterObject
-- Add schedule.
local ScheduleID = _SCHEDULEDISPATCHER:AddSchedule(
self,
SchedulerFunction,
SchedulerArguments,
Start,
Repeat,
RandomizeFactor,
Stop,
TraceLevel or 3,
Fsm
)
self.Schedules[#self.Schedules+1] = ScheduleID
local ScheduleID = _SCHEDULEDISPATCHER:AddSchedule( self,
SchedulerFunction,
SchedulerArguments,
Start,
Repeat,
RandomizeFactor,
Stop,
TraceLevel or 3,
Fsm
)
self.Schedules[#self.Schedules + 1] = ScheduleID
return ScheduleID
end
@@ -276,7 +274,7 @@ end
-- @param #string ScheduleID (Optional) The Schedule ID of the planned (repeating) schedule.
function SCHEDULER:Start( ScheduleID )
self:F3( { ScheduleID } )
self:T(string.format("Starting scheduler ID=%s", tostring(ScheduleID)))
self:T( string.format( "Starting scheduler ID=%s", tostring( ScheduleID ) ) )
_SCHEDULEDISPATCHER:Start( self, ScheduleID )
end
@@ -285,7 +283,7 @@ end
-- @param #string ScheduleID (Optional) The ScheduleID of the planned (repeating) schedule.
function SCHEDULER:Stop( ScheduleID )
self:F3( { ScheduleID } )
self:T(string.format("Stopping scheduler ID=%s", tostring(ScheduleID)))
self:T( string.format( "Stopping scheduler ID=%s", tostring( ScheduleID ) ) )
_SCHEDULEDISPATCHER:Stop( self, ScheduleID )
end
@@ -294,15 +292,15 @@ end
-- @param #string ScheduleID (optional) The ScheduleID of the planned (repeating) schedule.
function SCHEDULER:Remove( ScheduleID )
self:F3( { ScheduleID } )
self:T(string.format("Removing scheduler ID=%s", tostring(ScheduleID)))
self:T( string.format( "Removing scheduler ID=%s", tostring( ScheduleID ) ) )
_SCHEDULEDISPATCHER:RemoveSchedule( self, ScheduleID )
end
--- Clears all pending schedules.
-- @param #SCHEDULER self
function SCHEDULER:Clear()
self:F3( )
self:T(string.format("Clearing scheduler"))
self:F3()
self:T( string.format( "Clearing scheduler" ) )
_SCHEDULEDISPATCHER:Clear( self )
end

File diff suppressed because it is too large Load Diff

View File

@@ -29,15 +29,14 @@
-- @module Core.Settings
-- @image Core_Settings.JPG
--- @type SETTINGS
-- @extends Core.Base#BASE
--- Takes care of various settings that influence the behaviour of certain functionalities and classes within the MOOSE framework.
--- Takes care of various settings that influence the behavior 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.
-- The SETTINGS class takes care of various settings that influence the behavior of certain functionalities and classes within the MOOSE framework.
-- SETTINGS can work on 2 levels:
--
-- - **Default settings**: A running mission has **Default settings**.
@@ -59,7 +58,7 @@
--
-- 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.
-- Note that the **Default settings** will only be used when a player has not chosen its own settings.
--
-- ## 2.2) Player settings menu
--
@@ -69,7 +68,7 @@
--
-- ## 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**.
-- Of course, it may be required 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.
@@ -94,8 +93,8 @@
--
-- - 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.
-- - A2G LL DMS: Latitude Longitude [Degrees Minutes Seconds](https://en.wikipedia.org/wiki/Geographic_coordinate_conversion). The accuracy can also be adapted.
-- - A2G LL DDM: Latitude Longitude [Decimal Degrees Minutes](https://en.wikipedia.org/wiki/Decimal_degrees). The accuracy can also be adapted.
--
-- ### 3.1.2) A2G coordinates setting **menu**
--
@@ -183,7 +182,7 @@
-- 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.
-- The Settings Menu will provide for each Message Type a selection of proposed durations from which can be chosen.
-- 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!
--
@@ -196,7 +195,7 @@
--
-- ## 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.
-- The threat level metric is scaled according the era of the battle. A target that is AAA, will pose a much greater 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.
@@ -213,8 +212,8 @@
SETTINGS = {
ClassName = "SETTINGS",
ShowPlayerMenu = true,
MenuShort = false,
MenuStatic = false,
MenuShort = false,
MenuStatic = false,
}
SETTINGS.__Enum = {}
@@ -231,7 +230,6 @@ SETTINGS.__Enum.Era = {
Modern = 4,
}
do -- SETTINGS
--- SETTINGS constructor.
@@ -269,14 +267,14 @@ do -- SETTINGS
-- Short text are better suited for, e.g., VR.
-- @param #SETTINGS self
-- @param #boolean onoff If *true* use short menu texts. If *false* long ones (default).
function SETTINGS:SetMenutextShort(onoff)
function SETTINGS:SetMenutextShort( onoff )
_SETTINGS.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)
function SETTINGS:SetMenuStatic( onoff )
_SETTINGS.MenuStatic = onoff
end
@@ -304,7 +302,7 @@ do -- SETTINGS
-- @param #SETTINGS self
-- @return #boolean true if metric.
function SETTINGS:IsMetric()
return ( self.Metric ~= nil and self.Metric == true ) or ( self.Metric == nil and _SETTINGS:IsMetric() )
return (self.Metric ~= nil and self.Metric == true) or (self.Metric == nil and _SETTINGS:IsMetric())
end
--- Sets the SETTINGS imperial.
@@ -317,7 +315,7 @@ do -- SETTINGS
-- @param #SETTINGS self
-- @return #boolean true if imperial.
function SETTINGS:IsImperial()
return ( self.Metric ~= nil and self.Metric == false ) or ( self.Metric == nil and _SETTINGS:IsMetric() )
return (self.Metric ~= nil and self.Metric == false) or (self.Metric == nil and _SETTINGS:IsMetric())
end
--- Sets the SETTINGS LL accuracy.
@@ -359,13 +357,12 @@ do -- SETTINGS
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.
-- @return #number
function SETTINGS:GetMessageTime( MessageType )
return ( self.MessageTypeTimings and self.MessageTypeTimings[MessageType] ) or _SETTINGS:GetMessageTime( MessageType )
return (self.MessageTypeTimings and self.MessageTypeTimings[MessageType]) or _SETTINGS:GetMessageTime( MessageType )
end
--- Sets A2G LL DMS
@@ -386,14 +383,14 @@ do -- SETTINGS
-- @param #SETTINGS self
-- @return #boolean true if LL DMS
function SETTINGS:IsA2G_LL_DMS()
return ( self.A2GSystem and self.A2GSystem == "LL DMS" ) or ( not self.A2GSystem and _SETTINGS:IsA2G_LL_DMS() )
return (self.A2GSystem and self.A2GSystem == "LL DMS") or (not self.A2GSystem and _SETTINGS:IsA2G_LL_DMS())
end
--- Is LL DDM
-- @param #SETTINGS self
-- @return #boolean true if LL DDM
function SETTINGS:IsA2G_LL_DDM()
return ( self.A2GSystem and self.A2GSystem == "LL DDM" ) or ( not self.A2GSystem and _SETTINGS:IsA2G_LL_DDM() )
return (self.A2GSystem and self.A2GSystem == "LL DDM") or (not self.A2GSystem and _SETTINGS:IsA2G_LL_DDM())
end
--- Sets A2G MGRS
@@ -407,7 +404,7 @@ do -- SETTINGS
-- @param #SETTINGS self
-- @return #boolean true if MGRS
function SETTINGS:IsA2G_MGRS()
return ( self.A2GSystem and self.A2GSystem == "MGRS" ) or ( not self.A2GSystem and _SETTINGS:IsA2G_MGRS() )
return (self.A2GSystem and self.A2GSystem == "MGRS") or (not self.A2GSystem and _SETTINGS:IsA2G_MGRS())
end
--- Sets A2G BRA
@@ -421,7 +418,7 @@ do -- SETTINGS
-- @param #SETTINGS self
-- @return #boolean true if BRA
function SETTINGS:IsA2G_BR()
return ( self.A2GSystem and self.A2GSystem == "BR" ) or ( not self.A2GSystem and _SETTINGS:IsA2G_BR() )
return (self.A2GSystem and self.A2GSystem == "BR") or (not self.A2GSystem and _SETTINGS:IsA2G_BR())
end
--- Sets A2A BRA
@@ -435,7 +432,7 @@ do -- SETTINGS
-- @param #SETTINGS self
-- @return #boolean true if BRA
function SETTINGS:IsA2A_BRAA()
return ( self.A2ASystem and self.A2ASystem == "BRAA" ) or ( not self.A2ASystem and _SETTINGS:IsA2A_BRAA() )
return (self.A2ASystem and self.A2ASystem == "BRAA") or (not self.A2ASystem and _SETTINGS:IsA2A_BRAA())
end
--- Sets A2A BULLS
@@ -449,7 +446,7 @@ do -- SETTINGS
-- @param #SETTINGS self
-- @return #boolean true if BULLS
function SETTINGS:IsA2A_BULLS()
return ( self.A2ASystem and self.A2ASystem == "BULLS" ) or ( not self.A2ASystem and _SETTINGS:IsA2A_BULLS() )
return (self.A2ASystem and self.A2ASystem == "BULLS") or (not self.A2ASystem and _SETTINGS:IsA2A_BULLS())
end
--- Sets A2A LL DMS
@@ -470,14 +467,14 @@ do -- SETTINGS
-- @param #SETTINGS self
-- @return #boolean true if LL DMS
function SETTINGS:IsA2A_LL_DMS()
return ( self.A2ASystem and self.A2ASystem == "LL DMS" ) or ( not self.A2ASystem and _SETTINGS:IsA2A_LL_DMS() )
return (self.A2ASystem and self.A2ASystem == "LL DMS") or (not self.A2ASystem and _SETTINGS:IsA2A_LL_DMS())
end
--- Is LL DDM
-- @param #SETTINGS self
-- @return #boolean true if LL DDM
function SETTINGS:IsA2A_LL_DDM()
return ( self.A2ASystem and self.A2ASystem == "LL DDM" ) or ( not self.A2ASystem and _SETTINGS:IsA2A_LL_DDM() )
return (self.A2ASystem and self.A2ASystem == "LL DDM") or (not self.A2ASystem and _SETTINGS:IsA2A_LL_DDM())
end
--- Sets A2A MGRS
@@ -491,7 +488,7 @@ do -- SETTINGS
-- @param #SETTINGS self
-- @return #boolean true if MGRS
function SETTINGS:IsA2A_MGRS()
return ( self.A2ASystem and self.A2ASystem == "MGRS" ) or ( not self.A2ASystem and _SETTINGS:IsA2A_MGRS() )
return (self.A2ASystem and self.A2ASystem == "MGRS") or (not self.A2ASystem and _SETTINGS:IsA2A_MGRS())
end
--- @param #SETTINGS self
@@ -510,37 +507,37 @@ do -- SETTINGS
-- A2G Coordinate System
-------
local text="A2G Coordinate System"
local text = "A2G Coordinate System"
if _SETTINGS.MenuShort then
text="A2G Coordinates"
text = "A2G Coordinates"
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)"
local text = "Lat/Lon Degree Min Sec (LL DMS)"
if _SETTINGS.MenuShort then
text="LL DMS"
text = "LL DMS"
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)"
local text = "Lat/Lon Degree Dec Min (LL DDM)"
if _SETTINGS.MenuShort then
text="LL DDM"
text = "LL DDM"
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"
local text2="LL DDM Accuracy 2"
local text3="LL DDM Accuracy 3"
local text1 = "LL DDM Accuracy 1"
local text2 = "LL DDM Accuracy 2"
local text3 = "LL DDM Accuracy 3"
if _SETTINGS.MenuShort then
text1="LL DDM"
text1 = "LL DDM"
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 )
@@ -549,18 +546,18 @@ do -- SETTINGS
-- Set BR.
if not self:IsA2G_BR() then
local text="Bearing, Range (BR)"
local text = "Bearing, Range (BR)"
if _SETTINGS.MenuShort then
text="BR"
text = "BR"
end
MENU_GROUP_COMMAND:New( MenuGroup, text , A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "BR" ):SetTime( MenuTime )
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)"
local text = "Military Grid (MGRS)"
if _SETTINGS.MenuShort then
text="MGRS"
text = "MGRS"
end
MENU_GROUP_COMMAND:New( MenuGroup, text, A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "MGRS" ):SetTime( MenuTime )
end
@@ -578,24 +575,24 @@ do -- SETTINGS
-- A2A Coordinate System
-------
local text="A2A Coordinate System"
local text = "A2A Coordinate System"
if _SETTINGS.MenuShort then
text="A2A Coordinates"
text = "A2A Coordinates"
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)"
local text = "Lat/Lon Degree Min Sec (LL DMS)"
if _SETTINGS.MenuShort then
text="LL DMS"
text = "LL DMS"
end
MENU_GROUP_COMMAND:New( MenuGroup, text, A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "LL DMS" ):SetTime( MenuTime )
end
if not self:IsA2A_LL_DDM() then
local text="Lat/Lon Degree Dec Min (LL DDM)"
local text = "Lat/Lon Degree Dec Min (LL DDM)"
if _SETTINGS.MenuShort then
text="LL DDM"
text = "LL DDM"
end
MENU_GROUP_COMMAND:New( MenuGroup, text, A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "LL DDM" ):SetTime( MenuTime )
end
@@ -608,25 +605,25 @@ do -- SETTINGS
end
if not self:IsA2A_BULLS() then
local text="Bullseye (BULLS)"
local text = "Bullseye (BULLS)"
if _SETTINGS.MenuShort then
text="Bulls"
text = "Bulls"
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)"
local text = "Bearing Range Altitude Aspect (BRAA)"
if _SETTINGS.MenuShort then
text="BRAA"
text = "BRAA"
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)"
local text = "Military Grid (MGRS)"
if _SETTINGS.MenuShort then
text="MGRS"
text = "MGRS"
end
MENU_GROUP_COMMAND:New( MenuGroup, text, A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "MGRS" ):SetTime( MenuTime )
end
@@ -639,31 +636,31 @@ do -- SETTINGS
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"
local text = "Measures and Weights System"
if _SETTINGS.MenuShort then
text="Unit System"
text = "Unit System"
end
local MetricsMenu = MENU_GROUP:New( MenuGroup, text, SettingsMenu ):SetTime( MenuTime )
if self:IsMetric() then
local text="Imperial (Miles,Feet)"
local text = "Imperial (Miles,Feet)"
if _SETTINGS.MenuShort then
text="Imperial"
text = "Imperial"
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)"
local text = "Metric (Kilometers,Meters)"
if _SETTINGS.MenuShort then
text="Metric"
text = "Metric"
end
MENU_GROUP_COMMAND:New( MenuGroup, text, MetricsMenu, self.MenuMWSystem, self, MenuGroup, RootMenu, true ):SetTime( MenuTime )
end
local text="Messages and Reports"
local text = "Messages and Reports"
if _SETTINGS.MenuShort then
text="Messages & Reports"
text = "Messages & Reports"
end
local MessagesMenu = MENU_GROUP:New( MenuGroup, text, SettingsMenu ):SetTime( MenuTime )
@@ -704,7 +701,6 @@ do -- SETTINGS
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
@@ -748,11 +744,11 @@ do -- SETTINGS
self.PlayerMenu = PlayerMenu
self:I(string.format("Setting menu for player %s", tostring(PlayerName)))
self:I( string.format( "Setting menu for player %s", tostring( PlayerName ) ) )
local submenu = MENU_GROUP:New( PlayerGroup, "LL Accuracy", PlayerMenu )
MENU_GROUP_COMMAND:New( PlayerGroup, "LL 0 Decimals", submenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 0 )
MENU_GROUP_COMMAND:New( PlayerGroup, "LL 1 Decimal", submenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 1 )
MENU_GROUP_COMMAND:New( PlayerGroup, "LL 1 Decimal", submenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 1 )
MENU_GROUP_COMMAND:New( PlayerGroup, "LL 2 Decimals", submenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 2 )
MENU_GROUP_COMMAND:New( PlayerGroup, "LL 3 Decimals", submenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 3 )
MENU_GROUP_COMMAND:New( PlayerGroup, "LL 4 Decimals", submenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 4 )
@@ -769,40 +765,40 @@ do -- SETTINGS
-- A2G Coordinate System
------
local text="A2G Coordinate System"
local text = "A2G Coordinate System"
if _SETTINGS.MenuShort then
text="A2G Coordinates"
text = "A2G Coordinates"
end
local A2GCoordinateMenu = MENU_GROUP:New( PlayerGroup, text, PlayerMenu )
if not self:IsA2G_LL_DMS() or _SETTINGS.MenuStatic then
local text="Lat/Lon Degree Min Sec (LL DMS)"
local text = "Lat/Lon Degree Min Sec (LL DMS)"
if _SETTINGS.MenuShort then
text="A2G LL DMS"
text = "A2G LL DMS"
end
MENU_GROUP_COMMAND:New( PlayerGroup, text, A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DMS" )
end
if not self:IsA2G_LL_DDM() or _SETTINGS.MenuStatic then
local text="Lat/Lon Degree Dec Min (LL DDM)"
local text = "Lat/Lon Degree Dec Min (LL DDM)"
if _SETTINGS.MenuShort then
text="A2G LL DDM"
text = "A2G LL DDM"
end
MENU_GROUP_COMMAND:New( PlayerGroup, text, A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DDM" )
end
if not self:IsA2G_BR() or _SETTINGS.MenuStatic then
local text="Bearing, Range (BR)"
local text = "Bearing, Range (BR)"
if _SETTINGS.MenuShort then
text="A2G BR"
text = "A2G BR"
end
MENU_GROUP_COMMAND:New( PlayerGroup, text, A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "BR" )
end
if not self:IsA2G_MGRS() or _SETTINGS.MenuStatic then
local text="Military Grid (MGRS)"
local text = "Military Grid (MGRS)"
if _SETTINGS.MenuShort then
text="A2G MGRS"
text = "A2G MGRS"
end
MENU_GROUP_COMMAND:New( PlayerGroup, text, A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "MGRS" )
end
@@ -811,49 +807,48 @@ do -- SETTINGS
-- A2A Coordinates Menu
------
local text="A2A Coordinate System"
local text = "A2A Coordinate System"
if _SETTINGS.MenuShort then
text="A2A Coordinates"
text = "A2A Coordinates"
end
local A2ACoordinateMenu = MENU_GROUP:New( PlayerGroup, text, PlayerMenu )
if not self:IsA2A_LL_DMS() or _SETTINGS.MenuStatic then
local text="Lat/Lon Degree Min Sec (LL DMS)"
local text = "Lat/Lon Degree Min Sec (LL DMS)"
if _SETTINGS.MenuShort then
text="A2A LL DMS"
text = "A2A LL DMS"
end
MENU_GROUP_COMMAND:New( PlayerGroup, text, A2ACoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DMS" )
end
if not self:IsA2A_LL_DDM() or _SETTINGS.MenuStatic then
local text="Lat/Lon Degree Dec Min (LL DDM)"
local text = "Lat/Lon Degree Dec Min (LL DDM)"
if _SETTINGS.MenuShort then
text="A2A LL DDM"
text = "A2A LL DDM"
end
MENU_GROUP_COMMAND:New( PlayerGroup, text, A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DDM" )
end
if not self:IsA2A_BULLS() or _SETTINGS.MenuStatic then
local text="Bullseye (BULLS)"
local text = "Bullseye (BULLS)"
if _SETTINGS.MenuShort then
text="A2A BULLS"
text = "A2A BULLS"
end
MENU_GROUP_COMMAND:New( PlayerGroup, text, A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "BULLS" )
end
if not self:IsA2A_BRAA() or _SETTINGS.MenuStatic then
local text="Bearing Range Altitude Aspect (BRAA)"
local text = "Bearing Range Altitude Aspect (BRAA)"
if _SETTINGS.MenuShort then
text="A2A BRAA"
text = "A2A BRAA"
end
MENU_GROUP_COMMAND:New( PlayerGroup, text, A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "BRAA" )
end
if not self:IsA2A_MGRS() or _SETTINGS.MenuStatic then
local text="Military Grid (MGRS)"
local text = "Military Grid (MGRS)"
if _SETTINGS.MenuShort then
text="A2A MGRS"
text = "A2A MGRS"
end
MENU_GROUP_COMMAND:New( PlayerGroup, text, A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "MGRS" )
end
@@ -862,24 +857,24 @@ do -- SETTINGS
-- Unit system
---
local text="Measures and Weights System"
local text = "Measures and Weights System"
if _SETTINGS.MenuShort then
text="Unit System"
text = "Unit System"
end
local MetricsMenu = MENU_GROUP:New( PlayerGroup, text, PlayerMenu )
if self:IsMetric() or _SETTINGS.MenuStatic then
local text="Imperial (Miles,Feet)"
local text = "Imperial (Miles,Feet)"
if _SETTINGS.MenuShort then
text="Imperial"
text = "Imperial"
end
MENU_GROUP_COMMAND:New( PlayerGroup, text, MetricsMenu, self.MenuGroupMWSystem, self, PlayerUnit, PlayerGroup, PlayerName, false )
end
if self:IsImperial() or _SETTINGS.MenuStatic then
local text="Metric (Kilometers,Meters)"
local text = "Metric (Kilometers,Meters)"
if _SETTINGS.MenuShort then
text="Metric"
text = "Metric"
end
MENU_GROUP_COMMAND:New( PlayerGroup, text, MetricsMenu, self.MenuGroupMWSystem, self, PlayerUnit, PlayerGroup, PlayerName, true )
end
@@ -888,9 +883,9 @@ do -- SETTINGS
-- Messages and Reports
---
local text="Messages and Reports"
local text = "Messages and Reports"
if _SETTINGS.MenuShort then
text="Messages & Reports"
text = "Messages & Reports"
end
local MessagesMenu = MENU_GROUP:New( PlayerGroup, text, PlayerMenu )
@@ -950,39 +945,38 @@ do -- SETTINGS
return self
end
--- @param #SETTINGS self
function SETTINGS:A2GMenuSystem( MenuGroup, RootMenu, A2GSystem )
self.A2GSystem = A2GSystem
MESSAGE:New( string.format("Settings: Default A2G coordinate system set to %s for all players!", A2GSystem ), 5 ):ToAll()
MESSAGE:New( string.format( "Settings: Default A2G coordinate system set to %s for all players!", A2GSystem ), 5 ):ToAll()
self:SetSystemMenu( MenuGroup, RootMenu )
end
--- @param #SETTINGS self
function SETTINGS:A2AMenuSystem( MenuGroup, RootMenu, A2ASystem )
self.A2ASystem = A2ASystem
MESSAGE:New( string.format("Settings: Default A2A coordinate system set to %s for all players!", A2ASystem ), 5 ):ToAll()
MESSAGE:New( string.format( "Settings: Default A2A coordinate system set to %s for all players!", A2ASystem ), 5 ):ToAll()
self:SetSystemMenu( MenuGroup, RootMenu )
end
--- @param #SETTINGS self
function SETTINGS:MenuLL_DDM_Accuracy( MenuGroup, RootMenu, LL_Accuracy )
self.LL_Accuracy = LL_Accuracy
MESSAGE:New( string.format("Settings: Default LL accuracy set to %s for all players!", LL_Accuracy ), 5 ):ToAll()
MESSAGE:New( string.format( "Settings: Default LL accuracy set to %s for all players!", LL_Accuracy ), 5 ):ToAll()
self:SetSystemMenu( MenuGroup, RootMenu )
end
--- @param #SETTINGS self
function SETTINGS:MenuMGRS_Accuracy( MenuGroup, RootMenu, MGRS_Accuracy )
self.MGRS_Accuracy = MGRS_Accuracy
MESSAGE:New( string.format("Settings: Default MGRS accuracy set to %s for all players!", MGRS_Accuracy ), 5 ):ToAll()
MESSAGE:New( string.format( "Settings: Default MGRS accuracy set to %s for all players!", MGRS_Accuracy ), 5 ):ToAll()
self:SetSystemMenu( MenuGroup, RootMenu )
end
--- @param #SETTINGS self
function SETTINGS:MenuMWSystem( MenuGroup, RootMenu, MW )
self.Metric = MW
MESSAGE:New( string.format("Settings: Default measurement format set to %s for all players!", MW and "Metric" or "Imperial" ), 5 ):ToAll()
MESSAGE:New( string.format( "Settings: Default measurement format set to %s for all players!", MW and "Metric" or "Imperial" ), 5 ):ToAll()
self:SetSystemMenu( MenuGroup, RootMenu )
end
@@ -995,12 +989,12 @@ do -- SETTINGS
do
--- @param #SETTINGS self
function SETTINGS:MenuGroupA2GSystem( PlayerUnit, PlayerGroup, PlayerName, A2GSystem )
BASE:E( {self, PlayerUnit:GetName(), A2GSystem} )
BASE:E( { self, PlayerUnit:GetName(), A2GSystem } )
self.A2GSystem = A2GSystem
MESSAGE:New( string.format( "Settings: A2G format set to %s for player %s.", A2GSystem, PlayerName ), 5 ):ToGroup( PlayerGroup )
if _SETTINGS.MenuStatic==false then
self:RemovePlayerMenu(PlayerUnit)
self:SetPlayerMenu(PlayerUnit)
if _SETTINGS.MenuStatic == false then
self:RemovePlayerMenu( PlayerUnit )
self:SetPlayerMenu( PlayerUnit )
end
end
@@ -1008,9 +1002,9 @@ do -- SETTINGS
function SETTINGS:MenuGroupA2ASystem( PlayerUnit, PlayerGroup, PlayerName, A2ASystem )
self.A2ASystem = A2ASystem
MESSAGE:New( string.format( "Settings: A2A format set to %s for player %s.", A2ASystem, PlayerName ), 5 ):ToGroup( PlayerGroup )
if _SETTINGS.MenuStatic==false then
self:RemovePlayerMenu(PlayerUnit)
self:SetPlayerMenu(PlayerUnit)
if _SETTINGS.MenuStatic == false then
self:RemovePlayerMenu( PlayerUnit )
self:SetPlayerMenu( PlayerUnit )
end
end
@@ -1018,9 +1012,9 @@ do -- SETTINGS
function SETTINGS:MenuGroupLL_DDM_AccuracySystem( PlayerUnit, PlayerGroup, PlayerName, LL_Accuracy )
self.LL_Accuracy = LL_Accuracy
MESSAGE:New( string.format( "Settings: LL format accuracy set to %d decimal places for player %s.", LL_Accuracy, PlayerName ), 5 ):ToGroup( PlayerGroup )
if _SETTINGS.MenuStatic==false then
self:RemovePlayerMenu(PlayerUnit)
self:SetPlayerMenu(PlayerUnit)
if _SETTINGS.MenuStatic == false then
self:RemovePlayerMenu( PlayerUnit )
self:SetPlayerMenu( PlayerUnit )
end
end
@@ -1028,9 +1022,9 @@ do -- SETTINGS
function SETTINGS:MenuGroupMGRS_AccuracySystem( PlayerUnit, PlayerGroup, PlayerName, MGRS_Accuracy )
self.MGRS_Accuracy = MGRS_Accuracy
MESSAGE:New( string.format( "Settings: MGRS format accuracy set to %d for player %s.", MGRS_Accuracy, PlayerName ), 5 ):ToGroup( PlayerGroup )
if _SETTINGS.MenuStatic==false then
self:RemovePlayerMenu(PlayerUnit)
self:SetPlayerMenu(PlayerUnit)
if _SETTINGS.MenuStatic == false then
self:RemovePlayerMenu( PlayerUnit )
self:SetPlayerMenu( PlayerUnit )
end
end
@@ -1038,9 +1032,9 @@ do -- SETTINGS
function SETTINGS:MenuGroupMWSystem( PlayerUnit, PlayerGroup, PlayerName, MW )
self.Metric = MW
MESSAGE:New( string.format( "Settings: Measurement format set to %s for player %s.", MW and "Metric" or "Imperial", PlayerName ), 5 ):ToGroup( PlayerGroup )
if _SETTINGS.MenuStatic==false then
self:RemovePlayerMenu(PlayerUnit)
self:SetPlayerMenu(PlayerUnit)
if _SETTINGS.MenuStatic == false then
self:RemovePlayerMenu( PlayerUnit )
self:SetPlayerMenu( PlayerUnit )
end
end
@@ -1070,7 +1064,6 @@ do -- SETTINGS
end
--- Configures the era of the mission to be Cold war.
-- @param #SETTINGS self
-- @return #SETTINGS self
@@ -1080,7 +1073,6 @@ do -- SETTINGS
end
--- Configures the era of the mission to be Modern war.
-- @param #SETTINGS self
-- @return #SETTINGS self
@@ -1090,7 +1082,4 @@ do -- SETTINGS
end
end

File diff suppressed because it is too large Load Diff