mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-08-15 10:47:21 +00:00
431 lines
12 KiB
Lua
431 lines
12 KiB
Lua
--- Manage sets of units and groups.
|
|
--
|
|
-- @{#Set} class
|
|
-- ==================
|
|
-- Mission designers can use the SET class to build sets of units belonging to certain:
|
|
--
|
|
-- * Coalitions
|
|
-- * Categories
|
|
-- * Countries
|
|
-- * Unit types
|
|
-- * Starting with certain prefix strings.
|
|
--
|
|
-- This list will grow over time. Planned developments are to include filters and iterators.
|
|
-- Additional filters will be added around @{Zone#ZONEs}, Radiuses, Active players, ...
|
|
-- More iterators will be implemented in the near future ...
|
|
--
|
|
-- Administers the Initial Sets of the Mission Templates as defined within the Mission Editor.
|
|
--
|
|
-- SET construction methods:
|
|
-- =================================
|
|
-- Create a new SET object with the @{#SET.New} method:
|
|
--
|
|
-- * @{#SET.New}: Creates a new SET object.
|
|
--
|
|
--
|
|
-- SET filter criteria:
|
|
-- =========================
|
|
-- You can set filter criteria to define the set of units within the SET.
|
|
-- Filter criteria are defined by:
|
|
--
|
|
-- * @{#SET.FilterCoalitions}: Builds the SET with the units belonging to the coalition(s).
|
|
-- * @{#SET.FilterCategories}: Builds the SET with the units belonging to the category(ies).
|
|
-- * @{#SET.FilterTypes}: Builds the SET with the units belonging to the unit type(s).
|
|
-- * @{#SET.FilterCountries}: Builds the SET with the units belonging to the country(ies).
|
|
-- * @{#SET.FilterUnitPrefixes}: Builds the SET with the units starting with the same prefix string(s).
|
|
--
|
|
-- Once the filter criteria have been set for the SET, you can start filtering using:
|
|
--
|
|
-- * @{#SET.FilterStart}: Starts the filtering of the units within the SET.
|
|
--
|
|
-- Planned filter criteria within development are (so these are not yet available):
|
|
--
|
|
-- * @{#SET.FilterGroupPrefixes}: Builds the SET with the groups of the units starting with the same prefix string(s).
|
|
-- * @{#SET.FilterZones}: Builds the SET with the units within a @{Zone#ZONE}.
|
|
--
|
|
--
|
|
-- SET iterators:
|
|
-- ===================
|
|
-- Once the filters have been defined and the SET has been built, you can iterate the SET with the available iterator methods.
|
|
-- The iterator methods will walk the SET set, and call for each element within the set a function that you provide.
|
|
-- The following iterator methods are currently available within the SET:
|
|
--
|
|
-- * @{#SET.ForEachAliveUnit}: Calls a function for each alive unit it finds within the SET.
|
|
--
|
|
-- Planned iterators methods in development are (so these are not yet available):
|
|
--
|
|
-- * @{#SET.ForEachUnit}: Calls a function for each unit contained within the SET.
|
|
-- * @{#SET.ForEachGroup}: Calls a function for each group contained within the SET.
|
|
-- * @{#SET.ForEachUnitInZone}: Calls a function for each unit within a certain zone contained within the SET.
|
|
--
|
|
-- ====
|
|
-- @module Set
|
|
-- @author FlightControl
|
|
|
|
Include.File( "Routines" )
|
|
Include.File( "Base" )
|
|
Include.File( "Menu" )
|
|
Include.File( "Group" )
|
|
Include.File( "Unit" )
|
|
Include.File( "Event" )
|
|
Include.File( "Client" )
|
|
|
|
--- SET class
|
|
-- @type SET
|
|
-- @extends Base#BASE
|
|
SET = {
|
|
ClassName = "SET",
|
|
Templates = {
|
|
Units = {},
|
|
Groups = {},
|
|
ClientsByName = {},
|
|
ClientsByID = {},
|
|
},
|
|
DCSUnits = {},
|
|
DCSUnitsAlive = {},
|
|
DCSGroups = {},
|
|
DCSGroupsAlive = {},
|
|
Units = {},
|
|
UnitsAlive = {},
|
|
Groups = {},
|
|
GroupsAlive = {},
|
|
NavPoints = {},
|
|
Statics = {},
|
|
Players = {},
|
|
PlayersAlive = {},
|
|
Clients = {},
|
|
ClientsAlive = {},
|
|
Filter = {
|
|
Coalitions = nil,
|
|
Categories = nil,
|
|
Types = nil,
|
|
Countries = nil,
|
|
UnitPrefixes = nil,
|
|
GroupPrefixes = nil,
|
|
},
|
|
FilterMeta = {
|
|
Coalitions = {
|
|
red = coalition.side.RED,
|
|
blue = coalition.side.BLUE,
|
|
neutral = coalition.side.NEUTRAL,
|
|
},
|
|
Categories = {
|
|
plane = Unit.Category.AIRPLANE,
|
|
helicopter = Unit.Category.HELICOPTER,
|
|
ground = Unit.Category.GROUND_UNIT,
|
|
ship = Unit.Category.SHIP,
|
|
structure = Unit.Category.STRUCTURE,
|
|
},
|
|
},
|
|
}
|
|
|
|
local _DATABASECoalition =
|
|
{
|
|
[1] = "Red",
|
|
[2] = "Blue",
|
|
}
|
|
|
|
local _DATABASECategory =
|
|
{
|
|
[Unit.Category.AIRPLANE] = "Plane",
|
|
[Unit.Category.HELICOPTER] = "Helicopter",
|
|
[Unit.Category.GROUND_UNIT] = "Vehicle",
|
|
[Unit.Category.SHIP] = "Ship",
|
|
[Unit.Category.STRUCTURE] = "Structure",
|
|
}
|
|
|
|
|
|
--- Creates a new SET object, building a set of units belonging to a coalitions, categories, countries, types or with defined prefix names.
|
|
-- @param #SET self
|
|
-- @return #SET
|
|
-- @usage
|
|
-- -- Define a new SET Object. This DBObject will contain a reference to all Group and Unit Templates defined within the ME and the DCSRTE.
|
|
-- DBObject = SET:New()
|
|
function SET:New( Database )
|
|
|
|
-- Inherits from BASE
|
|
local self = BASE:Inherit( self, BASE:New() )
|
|
|
|
_EVENTDISPATCHER:OnBirth( self._EventOnBirth, self )
|
|
_EVENTDISPATCHER:OnDead( self._EventOnDeadOrCrash, self )
|
|
_EVENTDISPATCHER:OnCrash( self._EventOnDeadOrCrash, self )
|
|
|
|
|
|
-- Add SET with registered clients and already alive players
|
|
|
|
-- Follow alive players and clients
|
|
_EVENTDISPATCHER:OnPlayerEnterUnit( self._EventOnPlayerEnterUnit, self )
|
|
_EVENTDISPATCHER:OnPlayerLeaveUnit( self._EventOnPlayerLeaveUnit, self )
|
|
|
|
self.Collection = Database
|
|
|
|
self:_RegisterSet()
|
|
self:_RegisterPlayers()
|
|
|
|
return self
|
|
end
|
|
|
|
--- Finds an Object based on the Object Name.
|
|
-- @param #SET self
|
|
-- @param #string ObjectName
|
|
-- @return #table The Object found.
|
|
function SET:_Find( ObjectName )
|
|
|
|
local ObjectFound = self.Set[ObjectName]
|
|
return ObjectFound
|
|
end
|
|
|
|
--- Adds a Object based on the Object Name.
|
|
-- @param #SET self
|
|
-- @param #string ObjectName
|
|
-- @param #table Object
|
|
-- @return #table The added Object.
|
|
function SET:_Add( ObjectName, Object )
|
|
|
|
self.Set[ObjectName] = Object
|
|
end
|
|
|
|
--- Starts the filtering for the defined collection.
|
|
-- @param #SET self
|
|
-- @return #SET self
|
|
function SET:_FilterStart()
|
|
|
|
for ObjectName, Object in pairs( self.Collection ) do
|
|
|
|
if self:IsIncludeObject( Object ) then
|
|
self:E( { "Adding Object:", ObjectName } )
|
|
self:_Add( ObjectName, Object )
|
|
end
|
|
end
|
|
|
|
return self
|
|
end
|
|
|
|
|
|
|
|
--- Private method that registers all alive players in the mission.
|
|
-- @param #SET self
|
|
-- @return #SET self
|
|
function SET:_RegisterPlayers()
|
|
|
|
local CoalitionsData = { AlivePlayersRed = coalition.getPlayers( coalition.side.RED ), AlivePlayersBlue = coalition.getPlayers( coalition.side.BLUE ) }
|
|
for CoalitionId, CoalitionData in pairs( CoalitionsData ) do
|
|
for UnitId, UnitData in pairs( CoalitionData ) do
|
|
self:T3( { "UnitData:", UnitData } )
|
|
if UnitData and UnitData:isExist() then
|
|
local UnitName = UnitData:getName()
|
|
if not self.PlayersAlive[UnitName] then
|
|
self:E( { "Add player for unit:", UnitName, UnitData:getPlayerName() } )
|
|
self.PlayersAlive[UnitName] = UnitData:getPlayerName()
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
return self
|
|
end
|
|
|
|
--- Events
|
|
|
|
--- Handles the OnBirth event for the Set.
|
|
-- @param #SET self
|
|
-- @param Event#EVENTDATA Event
|
|
function SET:_EventOnBirth( Event )
|
|
self:F( { Event } )
|
|
|
|
if Event.IniDCSUnit then
|
|
local ObjectName, Object = self:AddInDatabase( Event )
|
|
if self:IsIncludeObject( Object ) then
|
|
self:_Add( ObjectName, Object )
|
|
--self:_EventOnPlayerEnterUnit( Event )
|
|
end
|
|
end
|
|
end
|
|
|
|
--- Handles the OnDead or OnCrash event for alive units set.
|
|
-- @param #SET self
|
|
-- @param Event#EVENTDATA Event
|
|
function SET:_EventOnDeadOrCrash( Event )
|
|
self:F( { Event } )
|
|
|
|
if Event.IniDCSUnit then
|
|
local ObjectName, Object = self:FindInDatabase( Event )
|
|
if ObjectName and Object then
|
|
self:_Delete( ObjectName )
|
|
end
|
|
end
|
|
end
|
|
|
|
----- Handles the OnPlayerEnterUnit event to fill the active players table (with the unit filter applied).
|
|
---- @param #SET self
|
|
---- @param Event#EVENTDATA Event
|
|
--function SET:_EventOnPlayerEnterUnit( Event )
|
|
-- self:F( { Event } )
|
|
--
|
|
-- if Event.IniDCSUnit then
|
|
-- if self:IsIncludeObject( Event.IniDCSUnit ) then
|
|
-- if not self.PlayersAlive[Event.IniDCSUnitName] then
|
|
-- self:E( { "Add player for unit:", Event.IniDCSUnitName, Event.IniDCSUnit:getPlayerName() } )
|
|
-- self.PlayersAlive[Event.IniDCSUnitName] = Event.IniDCSUnit:getPlayerName()
|
|
-- self.ClientsAlive[Event.IniDCSUnitName] = _DATABASE.Clients[ Event.IniDCSUnitName ]
|
|
-- end
|
|
-- end
|
|
-- end
|
|
--end
|
|
--
|
|
----- Handles the OnPlayerLeaveUnit event to clean the active players table.
|
|
---- @param #SET self
|
|
---- @param Event#EVENTDATA Event
|
|
--function SET:_EventOnPlayerLeaveUnit( Event )
|
|
-- self:F( { Event } )
|
|
--
|
|
-- if Event.IniDCSUnit then
|
|
-- if self:IsIncludeObject( Event.IniDCSUnit ) then
|
|
-- if self.PlayersAlive[Event.IniDCSUnitName] then
|
|
-- self:E( { "Cleaning player for unit:", Event.IniDCSUnitName, Event.IniDCSUnit:getPlayerName() } )
|
|
-- self.PlayersAlive[Event.IniDCSUnitName] = nil
|
|
-- self.ClientsAlive[Event.IniDCSUnitName] = nil
|
|
-- end
|
|
-- end
|
|
-- end
|
|
--end
|
|
|
|
--- Iterators
|
|
|
|
--- Interate the SET and call an interator function for the given set, providing the Object for each element within the set and optional parameters.
|
|
-- @param #SET self
|
|
-- @param #function IteratorFunction The function that will be called when there is an alive player in the SET.
|
|
-- @return #SET self
|
|
function SET:ForEach( IteratorFunction, arg, Set )
|
|
self:F( arg )
|
|
|
|
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 % 10 == 0 then
|
|
coroutine.yield( false )
|
|
end
|
|
end
|
|
return true
|
|
end
|
|
|
|
local co = coroutine.create( CoRoutine )
|
|
|
|
local function Schedule()
|
|
|
|
local status, res = coroutine.resume( co )
|
|
self:T( { status, res } )
|
|
|
|
if status == false then
|
|
error( res )
|
|
end
|
|
if res == false then
|
|
return true -- resume next time the loop
|
|
end
|
|
|
|
return false
|
|
end
|
|
|
|
local Scheduler = SCHEDULER:New( self, Schedule, {}, 0.001, 0.001, 0 )
|
|
|
|
return self
|
|
end
|
|
|
|
|
|
--- Interate the SET and call an interator function for each **alive** unit, providing the Unit and optional parameters.
|
|
-- @param #SET self
|
|
-- @param #function IteratorFunction The function that will be called when there is an alive unit in the SET. The function needs to accept a UNIT parameter.
|
|
-- @return #SET self
|
|
function SET:ForEachDCSUnitAlive( IteratorFunction, ... )
|
|
self:F( arg )
|
|
|
|
self:ForEach( IteratorFunction, arg, self.DCSUnitsAlive )
|
|
|
|
return self
|
|
end
|
|
|
|
--- Interate the SET and call an interator function for each **alive** player, providing the Unit of the player and optional parameters.
|
|
-- @param #SET self
|
|
-- @param #function IteratorFunction The function that will be called when there is an alive player in the SET. The function needs to accept a UNIT parameter.
|
|
-- @return #SET self
|
|
function SET:ForEachPlayer( IteratorFunction, ... )
|
|
self:F( arg )
|
|
|
|
self:ForEach( IteratorFunction, arg, self.PlayersAlive )
|
|
|
|
return self
|
|
end
|
|
|
|
|
|
--- Interate the SET and call an interator function for each client, providing the Client to the function and optional parameters.
|
|
-- @param #SET self
|
|
-- @param #function IteratorFunction The function that will be called when there is an alive player in the SET. The function needs to accept a CLIENT parameter.
|
|
-- @return #SET self
|
|
function SET:ForEachClient( IteratorFunction, ... )
|
|
self:F( arg )
|
|
|
|
self:ForEach( IteratorFunction, arg, self.Clients )
|
|
|
|
return self
|
|
end
|
|
|
|
|
|
--- Decides whether to include the Object
|
|
-- @param #SET self
|
|
-- @param #table Object
|
|
-- @return #SET self
|
|
function SET:IsIncludeObject( Object )
|
|
self:F( Object )
|
|
|
|
return true
|
|
end
|
|
|
|
|
|
---
|
|
-- @param #SET self
|
|
-- @param DCSUnit#Unit DCSUnit
|
|
-- @return #SET self
|
|
function SET:_IsAliveDCSUnit( DCSUnit )
|
|
self:F( DCSUnit )
|
|
local DCSUnitAlive = false
|
|
if DCSUnit and DCSUnit:isExist() and DCSUnit:isActive() then
|
|
if self.DCSUnits[DCSUnit:getName()] then
|
|
DCSUnitAlive = true
|
|
end
|
|
end
|
|
self:T( DCSUnitAlive )
|
|
return DCSUnitAlive
|
|
end
|
|
|
|
---
|
|
-- @param #SET self
|
|
-- @param DCSGroup#Group DCSGroup
|
|
-- @return #SET self
|
|
function SET:_IsAliveDCSGroup( DCSGroup )
|
|
self:F( DCSGroup )
|
|
local DCSGroupAlive = false
|
|
if DCSGroup and DCSGroup:isExist() then
|
|
if self.DCSGroups[DCSGroup:getName()] then
|
|
DCSGroupAlive = true
|
|
end
|
|
end
|
|
self:T( DCSGroupAlive )
|
|
return DCSGroupAlive
|
|
end
|
|
|
|
|
|
--- Traces the current SET contents in the log ... (for debug reasons).
|
|
-- @param #SET self
|
|
-- @return #SET self
|
|
function SET:TraceDatabase()
|
|
self:F()
|
|
|
|
self:T( { "DCSUnits:", self.DCSUnits } )
|
|
self:T( { "DCSUnitsAlive:", self.DCSUnitsAlive } )
|
|
end
|
|
|
|
|