Module Database
+ Module DATABASE
-Administers the Initial Sets of the Mission Templates as defined within the Mission Editor.
- -Administers the Spawning of new Groups within the DCSRTE and administers these new Groups within the DATABASE object(s).
Global(s)
| DATABASE | - | - -
| _Database | -- |
Type DATABASE
- | DATABASE.ActivePlayers | +DATABASE.AlivePlayers | @@ -109,6 +100,90 @@ | DATABASE.ClientsByName | + | +
| DATABASE.DCSGroups | ++ + | +|||
| DATABASE.DCSGroupsAlive | ++ + | +|||
| DATABASE.DCSUnits | ++ + | +|||
| DATABASE.DCSUnitsAlive | ++ + | +|||
| DATABASE.Filter | ++ + | +|||
| DATABASE:FilterCategories(Categories) | +
+ Builds a set of units out of categories. + |
+ |||
| DATABASE:FilterCoalitions(Coalitions) | +
+ Builds a set of units of coalitons. + |
+ |||
| DATABASE:FilterCountries(Countries) | +
+ Builds a set of units of defined countries. + |
+ |||
| DATABASE:FilterGroupPrefixes(Prefixes) | +
+ Builds a set of units of defined group prefixes. + |
+ |||
| DATABASE.FilterMeta | ++ + | +|||
| DATABASE:FilterStart() | +
+ Starts the filtering. + |
+ |||
| DATABASE:FilterTypes(Types) | +
+ Builds a set of units of defined unit types. + |
+ |||
| DATABASE:FilterUnitPrefixes(Prefixes) | +
+ Builds a set of units of defined unit prefixes. + |
+ |||
| DATABASE:ForEachAliveUnit(IteratorFunction, ...) | +
+ Interate the DATABASE and call an interator function for each alive unit, providing the Unit and optional parameters. |
|||
| DATABASE:New() |
- Creates a new DATABASE Object to administer the Groups defined and alive within the DCSRTE. +Creates a new DATABASE object, building a set of units belonging to a coalitions, categories, countries, types or with defined prefix names. |
|||
| DATABASE.Players | + | +|||
| DATABASE:ScanEnvironment() | ++ | |||
| DATABASE.Statics | + | +|||
| DATABASE:TraceDatabase() | +
+ Traces the current database contents in the log ... |
|||
| DATABASE.Units | + | +|||
| DATABASE:_EventOnBirth(Event) | +
+ Handles the OnBirth event for the alive units set. + |
+ |||
| DATABASE:_EventOnDeadOrCrash(Event) | +
+ Handles the OnDead or OnCrash event for alive units set. + |
+ |||
| DATABASE:_IsAliveDCSUnit(DCSUnit) | ++ + | +|||
| DATABASE:_IsIncludeDCSUnit(DCSUnit) | ++ | |||
| EVENT | - | -|||
| _EVENTDISPATCHER | -
- Declare the event dispatcher based on the EVENT class |
-
-
- - - #EVENT - -_EVENTDISPATCHER - - -
-
-
-
Declare the event dispatcher based on the EVENT class
-
Type Event
diff --git a/Documentation/GOHOMETASK.html b/Documentation/GOHOMETASK.html
index b1ebecdcd..dc2a4b028 100644
--- a/Documentation/GOHOMETASK.html
+++ b/Documentation/GOHOMETASK.html
@@ -21,6 +21,7 @@
Some additional notes that need to be remembered:
-
-
Templates are actually groups defined within the mission editor, with the flag "Late Activation" set. As such, these groups are never used within the mission, but are used by the #SPAWN module.
- It is important to defined BEFORE you spawn new groups, a proper initialization of the SPAWN instance is done with the options you want to use.
- When designing a mission, NEVER name groups using a "#" within the name of the group Spawn Template(s), or the SPAWN module logic won't work anymore.
- SPAWN object construction methods:
-Create a new SPAWN object with the SPAWN.New or the SPAWN.NewWithAlias methods:
- SPAWN.New: Creates a new SPAWN object taking the name of the group that functions as the Template.
+ - Templates are actually groups defined within the mission editor, with the flag "Late Activation" set. As such, these groups are never used within the mission, but are used by the #SPAWN module. +
- It is important to defined BEFORE you spawn new groups, a proper initialization of the SPAWN instance is done with the options you want to use. +
- When designing a mission, NEVER name groups using a "#" within the name of the group Spawn Template(s), or the SPAWN module logic won't work anymore. +
SPAWN construction methods:
+Create a new SPAWN object with the SPAWN.New or the SPAWN.NewWithAlias methods:
+ +-
+
- SPAWN.New: Creates a new SPAWN object taking the name of the group that functions as the Template.
It is important to understand how the SPAWN class works internally. The SPAWN object created will contain internally a list of groups that will be spawned and that are already spawned. The initialization functions will modify this list of groups so that when a group gets spawned, ALL information is already prepared when spawning. This is done for performance reasons. So in principle, the group list will contain all parameters and configurations after initialization, and when groups get actually spawned, this spawning can be done quickly and efficient.
--
-
SPAWN object initialization methods:
-A spawn object will behave differently based on the usage of initialization methods:
- SPAWN.Limit: Limits the amount of groups that can be alive at the same time and that can be dynamically spawned.
- SPAWN.RandomizeRoute: Randomize the routes of spawned groups.
- SPAWN.RandomizeTemplate: Randomize the group templates so that when a new group is spawned, a random group template is selected from one of the templates defined.
- SPAWN.Uncontrolled: Spawn plane groups uncontrolled.
- SPAWN.Array: Make groups visible before they are actually activated, and order these groups like a batallion in an array.
- SPAWN.Repeat: Re-spawn groups when they land at the home base. Similar functions are SPAWN.RepeatOnLanding and SPAWN.RepeatOnEngineShutDown.
- SPAWN object spawning methods:
-Groups can be spawned at different times and methods:
- SPAWN.Spawn: Spawn one new group based on the last spawned index.
- SPAWN.ReSpawn: Re-spawn a group based on a given index.
- SPAWN.SpawnScheduled: Spawn groups at scheduled but randomized intervals. You can use SPAWN.SpawnScheduleStart and SPAWN.SpawnScheduleStop to start and stop the schedule respectively.
- SPAWN.SpawnFromUnit: Spawn a new group taking the position of a UNIT.
- SPAWN.SpawnInZone: Spawn a new group in a ZONE.
-
SPAWN initialization methods:
+A spawn object will behave differently based on the usage of initialization methods:
+ +-
+
- SPAWN.Limit: Limits the amount of groups that can be alive at the same time and that can be dynamically spawned. +
- SPAWN.RandomizeRoute: Randomize the routes of spawned groups. +
- SPAWN.RandomizeTemplate: Randomize the group templates so that when a new group is spawned, a random group template is selected from one of the templates defined. +
- SPAWN.Uncontrolled: Spawn plane groups uncontrolled. +
- SPAWN.Array: Make groups visible before they are actually activated, and order these groups like a batallion in an array. +
- SPAWN.Repeat: Re-spawn groups when they land at the home base. Similar functions are SPAWN.RepeatOnLanding and SPAWN.RepeatOnEngineShutDown. +
SPAWN spawning methods:
+Groups can be spawned at different times and methods:
+ +-
+
- SPAWN.Spawn: Spawn one new group based on the last spawned index. +
- SPAWN.ReSpawn: Re-spawn a group based on a given index. +
- SPAWN.SpawnScheduled: Spawn groups at scheduled but randomized intervals. You can use SPAWN.SpawnScheduleStart and SPAWN.SpawnScheduleStop to start and stop the schedule respectively. +
- SPAWN.SpawnFromUnit: Spawn a new group taking the position of a UNIT. +
- SPAWN.SpawnInZone: Spawn a new group in a ZONE. +
Note that SPAWN.Spawn and SPAWN.ReSpawn return a GROUP#GROUP.New object, that contains a reference to the DCSGroup object. You can use the GROUP object to do further actions with the DCSGroup.
--
-
- SPAWN object cleaning:
-
- Sometimes, it will occur during a mission run-time, that ground or especially air objects get damaged, and will while being damged stop their activities, while remaining alive. - In such cases, the SPAWN object will just sit there and wait until that group gets destroyed, but most of the time it won't, - and it may occur that no new groups are or can be spawned as limits are reached. - To prevent this, a SPAWN.CleanUp initialization method has been defined that will silently monitor the status of each spawned group. - Once a group has a velocity = 0, and has been waiting for a defined interval, that group will be cleaned or removed from run-time. - There is a catch however :-) If a damaged group has returned to an airbase within the coalition, that group will not be considered as "lost"... - In such a case, when the inactive group is cleaned, a new group will Re-spawned automatically. - This models AI that has succesfully returned to their airbase, to restart their combat activities. - Check the SPAWN.CleanUp for further info.
-
SPAWN object cleaning:
+Sometimes, it will occur during a mission run-time, that ground or especially air objects get damaged, and will while being damged stop their activities, while remaining alive. +In such cases, the SPAWN object will just sit there and wait until that group gets destroyed, but most of the time it won't, +and it may occur that no new groups are or can be spawned as limits are reached. +To prevent this, a SPAWN.CleanUp initialization method has been defined that will silently monitor the status of each spawned group. +Once a group has a velocity = 0, and has been waiting for a defined interval, that group will be cleaned or removed from run-time. +There is a catch however :-) If a damaged group has returned to an airbase within the coalition, that group will not be considered as "lost"... +In such a case, when the inactive group is cleaned, a new group will Re-spawned automatically. +This models AI that has succesfully returned to their airbase, to restart their combat activities. +Check the SPAWN.CleanUp for further info.
Global(s)
@@ -2052,7 +2058,7 @@ Nothing found -TODO Need to delete this... _Database does this now ...
+TODO Need to delete this... _DATABASE does this now ...
Parameter
-
diff --git a/Documentation/StaticObject.html b/Documentation/StaticObject.html
index 9f6847026..aa4f9fe4e 100644
--- a/Documentation/StaticObject.html
+++ b/Documentation/StaticObject.html
@@ -21,6 +21,7 @@
- CARGO
- CleanUp
- Client +
- DATABASE
- DCSAirbase
- DCSCoalitionObject
- DCSCommand @@ -37,7 +38,6 @@
- DESTROYGROUPSTASK
- DESTROYRADARSTASK
- DESTROYUNITTYPESTASK -
- Database
- Escort
- Event
- GOHOMETASK diff --git a/Documentation/TASK.html b/Documentation/TASK.html index bc244726c..a8215456d 100644 --- a/Documentation/TASK.html +++ b/Documentation/TASK.html @@ -21,6 +21,7 @@
- CARGO
- CleanUp
- Client +
- DATABASE
- DCSAirbase
- DCSCoalitionObject
- DCSCommand @@ -37,7 +38,6 @@
- DESTROYGROUPSTASK
- DESTROYRADARSTASK
- DESTROYUNITTYPESTASK -
- Database
- Escort
- Event
- GOHOMETASK diff --git a/Documentation/Unit.html b/Documentation/Unit.html index 985e6a1e7..ed1a6112c 100644 --- a/Documentation/Unit.html +++ b/Documentation/Unit.html @@ -21,6 +21,7 @@
- CARGO
- CleanUp
- Client +
- DATABASE
- DCSAirbase
- DCSCoalitionObject
- DCSCommand @@ -37,7 +38,6 @@
- DESTROYGROUPSTASK
- DESTROYRADARSTASK
- DESTROYUNITTYPESTASK -
- Database
- Escort
- Event
- GOHOMETASK diff --git a/Documentation/Zone.html b/Documentation/Zone.html index 1b9c3cb4b..15939e2e1 100644 --- a/Documentation/Zone.html +++ b/Documentation/Zone.html @@ -21,6 +21,7 @@
- CARGO
- CleanUp
- Client +
- DATABASE
- DCSAirbase
- DCSCoalitionObject
- DCSCommand @@ -37,7 +38,6 @@
- DESTROYGROUPSTASK
- DESTROYRADARSTASK
- DESTROYUNITTYPESTASK -
- Database
- Escort
- Event
- GOHOMETASK diff --git a/Documentation/env.html b/Documentation/env.html index 959ef7350..ddd05da06 100644 --- a/Documentation/env.html +++ b/Documentation/env.html @@ -21,6 +21,7 @@
- CARGO
- CleanUp
- Client +
- DATABASE
- DCSAirbase
- DCSCoalitionObject
- DCSCommand @@ -37,7 +38,6 @@
- DESTROYGROUPSTASK
- DESTROYRADARSTASK
- DESTROYUNITTYPESTASK -
- Database
- Escort
- Event
- GOHOMETASK diff --git a/Documentation/index.html b/Documentation/index.html index 50958b731..d6bdc643a 100644 --- a/Documentation/index.html +++ b/Documentation/index.html @@ -21,6 +21,7 @@
- CARGO
- CleanUp
- Client +
- DATABASE
- DCSAirbase
- DCSCoalitionObject
- DCSCommand @@ -37,7 +38,6 @@
- DESTROYGROUPSTASK
- DESTROYRADARSTASK
- DESTROYUNITTYPESTASK -
- Database
- Escort
- Event
- GOHOMETASK @@ -87,6 +87,12 @@
- CARGO
- CleanUp
- Client +
- DATABASE
- DCSAirbase
- DCSCoalitionObject
- DCSCommand @@ -37,7 +38,6 @@
- DESTROYGROUPSTASK
- DESTROYRADARSTASK
- DESTROYUNITTYPESTASK -
- Database
- Escort
- Event
- GOHOMETASK diff --git a/Documentation/routines.html b/Documentation/routines.html index d33caf801..0318b5608 100644 --- a/Documentation/routines.html +++ b/Documentation/routines.html @@ -21,6 +21,7 @@
- CARGO
- CleanUp
- Client +
- DATABASE
- DCSAirbase
- DCSCoalitionObject
- DCSCommand @@ -37,7 +38,6 @@
- DESTROYGROUPSTASK
- DESTROYRADARSTASK
- DESTROYUNITTYPESTASK -
- Database
- Escort
- Event
- GOHOMETASK diff --git a/Embedded/Moose_Embedded.lua b/Embedded/Moose_Embedded.lua index df0080676..91d90b24f 100644 --- a/Embedded/Moose_Embedded.lua +++ b/Embedded/Moose_Embedded.lua @@ -1697,7 +1697,7 @@ function routines.getGroupRoute(groupIdent, task) -- same as getGroupPoints bu -- refactor to search by groupId and allow groupId and groupName as inputs local gpId = groupIdent if type(groupIdent) == 'string' and not tonumber(groupIdent) then - gpId = _Database.Groups[groupIdent].groupId + gpId = _DATABASE.Groups[groupIdent].groupId end for coa_name, coa_data in pairs(env.mission.coalition) do @@ -1747,6 +1747,7 @@ function routines.getGroupRoute(groupIdent, task) -- same as getGroupPoints bu end --if coa_name == 'red' or coa_name == 'blue' and type(coa_data) == 'table' then end --for coa_name, coa_data in pairs(mission.coalition) do end + routines.ground.patrolRoute = function(vars) @@ -3504,11 +3505,6 @@ function EVENT:onEvent( Event ) end end - - ---- Declare the event dispatcher based on the EVENT class -_EVENTDISPATCHER = EVENT:New() -- #EVENT - --- A GROUP class abstraction of a DCSGroup class. -- The GROUP class will take an abstraction of the DCSGroup class, providing more methods that can be done with a GROUP. -- @module Group @@ -4510,7 +4506,7 @@ end function GROUP:GetTaskMission() self:F( self.GroupName ) - return routines.utils.deepCopy( _Database.Groups[self.GroupName].Template ) + return routines.utils.deepCopy( _DATABASE.Groups[self.GroupName].Template ) end --- Return the mission route of the group. @@ -4519,7 +4515,7 @@ end function GROUP:GetTaskRoute() self:F( self.GroupName ) - return routines.utils.deepCopy( _Database.Groups[self.GroupName].Template.route.points ) + return routines.utils.deepCopy( _DATABASE.Groups[self.GroupName].Template.route.points ) end --- Return the route of a group by using the @{Database#DATABASE} class. @@ -4543,7 +4539,7 @@ function GROUP:CopyRoute( Begin, End, Randomize, Radius ) self:T( { GroupName } ) - local Template = _Database.Groups[GroupName].Template + local Template = _DATABASE.Groups[GroupName].Template if Template then if not Begin then @@ -5257,14 +5253,40 @@ Include.File( "Event" ) -- @extends Base#BASE DATABASE = { ClassName = "DATABASE", + DCSUnits = {}, + DCSUnitsAlive = {}, Units = {}, Groups = {}, + DCSGroups = {}, + DCSGroupsAlive = {}, NavPoints = {}, Statics = {}, Players = {}, - ActivePlayers = {}, + AlivePlayers = {}, ClientsByName = {}, ClientsByID = {}, + 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 = @@ -5283,8 +5305,9 @@ local _DATABASECategory = } ---- Creates a new DATABASE Object to administer the Groups defined and alive within the DCSRTE. --- @return DATABASE +--- 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 +-- @return #DATABASE -- @usage -- -- Define a new DATABASE Object. This DBObject will contain a reference to all Group and Unit Templates defined within the ME and the DCSRTE. -- DBObject = DATABASE:New() @@ -5292,6 +5315,234 @@ function DATABASE:New() -- 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 ) + + return self +end + +--- Builds a set of units of coalitons. +-- Possible current coalitions are red, blue and neutral. +-- @param #DATABASE self +-- @param #string Coalitions Can take the following values: "red", "blue", "neutral". +-- @return #DATABASE self +function DATABASE:FilterCoalition( Coalitions ) + if not self.Filter.Coalitions then + self.Filter.Coalitions = {} + end + if type( Coalitions ) ~= "table" then + Coalitions = { Coalitions } + end + for CoalitionID, Coalition in pairs( Coalitions ) do + self.Filter.Coalitions[Coalition] = Coalition + end + return self +end + +--- Builds a set of units out of categories. +-- Possible current categories are plane, helicopter, ground, ship. +-- @param #DATABASE self +-- @param #string Categories Can take the following values: "plane", "helicopter", "ground", "ship". +-- @return #DATABASE self +function DATABASE:FilterCategory( Categories ) + if not self.Filter.Categories then + self.Filter.Categories = {} + end + if type( Categories ) ~= "table" then + Categories = { Categories } + end + for CategoryID, Category in pairs( Categories ) do + self.Filter.Categories[Category] = Category + end + return self +end + +--- Builds a set of units of defined unit types. +-- Possible current types are those types known within DCS world. +-- @param #DATABASE self +-- @param #string Types Can take those type strings known within DCS world. +-- @return #DATABASE self +function DATABASE:FilterType( Types ) + if not self.Filter.Types then + self.Filter.Types = {} + end + if type( Types ) ~= "table" then + Types = { Types } + end + for TypeID, Type in pairs( Types ) do + self.Filter.Types[Type] = Type + end + return self +end + +--- Builds a set of units of defined countries. +-- Possible current countries are those known within DCS world. +-- @param #DATABASE self +-- @param #string Countries Can take those country strings known within DCS world. +-- @return #DATABASE self +function DATABASE:FilterCountries( Countries ) + if not self.Filter.Countries then + self.Filter.Countries = {} + end + if type( Countries ) ~= "table" then + Countries = { Countries } + end + for CountryID, Country in pairs( Countries ) do + self.Filter.Countries[Country] = Country + end + return self +end + +--- Builds a set of units of defined unit prefixes. +-- All the units starting with the given prefixes will be included within the set. +-- @param #DATABASE self +-- @param #string Prefixes The prefix of which the unit name starts with. +-- @return #DATABASE self +function DATABASE:FilterUnitPrefix( Prefixes ) + if not self.Filter.UnitPrefixes then + self.Filter.UnitPrefixes = {} + end + if type( Prefixes ) ~= "table" then + Prefixes = { Prefixes } + end + for PrefixID, Prefix in pairs( Prefixes ) do + self.Filter.UnitPrefixes[Prefix] = Prefix + end + return self +end + +--- Builds a set of units of defined group prefixes. +-- All the units starting with the given group prefixes will be included within the set. +-- @param #DATABASE self +-- @param #string Prefixes The prefix of which the group name where the unit belongs to starts with. +-- @return #DATABASE self +function DATABASE:FilterGroupPrefix( Prefixes ) + if not self.Filter.GroupPrefixes then + self.Filter.GroupPrefixes = {} + end + if type( Prefixes ) ~= "table" then + Prefixes = { Prefixes } + end + for PrefixID, Prefix in pairs( Prefixes ) do + self.Filter.GroupPrefixes[Prefix] = Prefix + end + return self +end + +--- Starts the filtering. +-- @param #DATABASE self +-- @return #DATABASE self +function DATABASE:FilterStart() + + if _DATABASE then + -- OK, we have a _DATABASE + -- Now use the different filters to build the set. + -- We first take ALL of the Units of the _DATABASE. + for UnitRegistrationID, UnitRegistration in pairs( _DATABASE.Units ) do + self:T( UnitRegistration ) + local DCSUnit = Unit.getByName( UnitRegistration.UnitName ) + if self:IsIncludeDCSUnit( DCSUnit ) then + self.DCSUnits[DCSUnit:getName()] = DCSUnit + end + if self:IsAliveDCSUnit( DCSUnit ) then + self.DCSUnitsAlive[DCSUnit:getName()] = DCSUnit + end + end + else + self:E( "There is a structural error in MOOSE. No _DATABASE has been defined! Cannot build this custom DATABASE." ) + end + + return self +end + +--- +-- @param #DATABASE self +-- @param DCSUnit#Unit DCSUnit +-- @return #DATABASE self +function DATABASE:IsIncludeDCSUnit( DCSUnit ) + self:F( DCSUnit ) + local DCSUnitInclude = true + + if self.Filter.Coalitions then + local DCSUnitCoalition = false + for CoalitionID, CoalitionName in pairs( self.Filter.Coalitions ) do + self:T( { "Coalition:", DCSUnit:getCoalition(), self.FilterMeta.Coalitions[CoalitionName], CoalitionName } ) + if self.FilterMeta.Coalitions[CoalitionName] and self.FilterMeta.Coalitions[CoalitionName] == DCSUnit:getCoalition() then + DCSUnitCoalition = true + end + end + DCSUnitInclude = DCSUnitInclude and DCSUnitCoalition + end + + if self.Filter.Categories then + local DCSUnitCategory = false + for CategoryID, CategoryName in pairs( self.Filter.Categories ) do + self:T( { "Category:", DCSUnit:getDesc().category, self.FilterMeta.Categories[CategoryName], CategoryName } ) + if self.FilterMeta.Categories[CategoryName] and self.FilterMeta.Categories[CategoryName] == DCSUnit:getDesc().category then + DCSUnitCategory = true + end + end + DCSUnitInclude = DCSUnitInclude and DCSUnitCategory + end + + if self.Filter.Types then + local DCSUnitType = false + for TypeID, TypeName in pairs( self.Filter.Types ) do + self:T( { "Type:", DCSUnit:getTypeName(), TypeName } ) + if TypeName == DCSUnit:getTypeName() then + DCSUnitType = true + end + end + DCSUnitInclude = DCSUnitInclude and DCSUnitType + end + + if self.Filter.Countries then + local DCSUnitCountry = false + for CountryID, CountryName in pairs( self.Filter.Countries ) do + self:T( { "Country:", DCSUnit:getCountry(), CountryName } ) + if country.id[CountryName] == DCSUnit:getCountry() then + DCSUnitCountry = true + end + end + DCSUnitInclude = DCSUnitInclude and DCSUnitCountry + end + + if self.Filter.UnitPrefixes then + local DCSUnitPrefix = false + for UnitPrefixId, UnitPrefix in pairs( self.Filter.UnitPrefixes ) do + self:T( { "Unit Prefix:", string.find( DCSUnit:getName(), UnitPrefix, 1 ), UnitPrefix } ) + if string.find( DCSUnit:getName(), UnitPrefix, 1 ) then + DCSUnitPrefix = true + end + end + DCSUnitInclude = DCSUnitInclude and DCSUnitPrefix + end + + self:T( DCSUnitInclude ) + return DCSUnitInclude +end + +--- +-- @param #DATABASE self +-- @param DCSUnit#Unit DCSUnit +-- @return #DATABASE self +function DATABASE: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 + + +function DATABASE:ScanEnvironment() + self:F() self.Navpoints = {} self.Units = {} @@ -5299,7 +5550,7 @@ function DATABASE:New() for coa_name, coa_data in pairs(env.mission.coalition) do if (coa_name == 'red' or coa_name == 'blue') and type(coa_data) == 'table' then - self.Units[coa_name] = {} + --self.Units[coa_name] = {} ---------------------------------------------- -- build nav points DB @@ -5323,8 +5574,8 @@ function DATABASE:New() for cntry_id, cntry_data in pairs(coa_data.country) do local countryName = string.lower(cntry_data.name) - self.Units[coa_name][countryName] = {} - self.Units[coa_name][countryName]["countryId"] = cntry_data.id + --self.Units[coa_name][countryName] = {} + --self.Units[coa_name][countryName]["countryId"] = cntry_data.id if type(cntry_data) == 'table' then --just making sure @@ -5336,7 +5587,7 @@ function DATABASE:New() if ((type(obj_type_data) == 'table') and obj_type_data.group and (type(obj_type_data.group) == 'table') and (#obj_type_data.group > 0)) then --there's a group! - self.Units[coa_name][countryName][category] = {} + --self.Units[coa_name][countryName][category] = {} for group_num, GroupTemplate in pairs(obj_type_data.group) do @@ -5356,14 +5607,14 @@ function DATABASE:New() return self 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 -- This method is used by the SPAWN class. function DATABASE:Spawn( SpawnTemplate ) + self:F( SpawnTemplate.name ) - self:T( { SpawnTemplate.SpawnCountryID, SpawnTemplate.SpawnCategoryID, SpawnTemplate.name } ) + self:T( { SpawnTemplate.SpawnCountryID, SpawnTemplate.SpawnCategoryID } ) -- Copy the spawn variables of the template in temporary storage, nullify, and restore the spawn variables. local SpawnCoalitionID = SpawnTemplate.SpawnCoalitionID @@ -5438,11 +5689,47 @@ function DATABASE:_RegisterGroup( GroupTemplate ) self.ClientsByName[UnitTemplateName] = UnitTemplate self.ClientsByID[UnitTemplate.unitId] = UnitTemplate end - self:T( { "Unit", self.Units[UnitTemplateName].UnitName } ) + self:E( { "Unit", self.Units[UnitTemplateName].UnitName } ) end end -_Database = DATABASE:New() -- Database#DATABASE +--- Handles the OnBirth event for the alive units set. +-- @param #DATABASE self +-- @param Event#EVENTDATA Event +function DATABASE:_EventOnBirth( Event ) + self:F( { Event } ) + + if Event.IniDCSUnit then + if self:IsIncludeDCSUnit( Event.IniDCSUnit ) then + self.DCSUnits[Event.IniDCSUnitName] = Event.IniDCSUnit + self.DCSUnitsAlive[Event.IniDCSUnitName] = Event.IniDCSUnit + end + end +end + +--- Handles the OnDead or OnCrash event for alive units set. +-- @param #DATABASE self +-- @param Event#EVENTDATA Event +function DATABASE:_EventOnDeadOrCrash( Event ) + self:F( { Event } ) + + if Event.IniDCSUnit then + if self.DCSUnitsAlive[Event.IniDCSUnitName] then + self.DCSUnits[Event.IniDCSUnitName] = nil + self.DCSUnitsAlive[Event.IniDCSUnitName] = nil + end + end +end + +--- Traces the current database contents in the log ... (for debug reasons). +-- @param #DATABASE self +-- @return #DATABASE self +function DATABASE:TraceDatabase() + self:F() + + self:T( { "DCSUnits:", self.DCSUnits } ) + self:T( { "DCSUnitsAlive:", self.DCSUnitsAlive } ) +end --- Scoring system for MOOSE. @@ -7467,12 +7754,12 @@ function CLIENT:GetDCSGroup() -- Now we need to resolve the bugs in DCS 1.5 ... -- Consult the database for the units of the Client Group. (ClientGroup:getUnits() returns nil) self:T3( "Bug 1.5 logic" ) - local ClientUnits = _Database.Groups[self.ClientName].Units + local ClientUnits = _DATABASE.Groups[self.ClientName].Units self:T3( { ClientUnits[1].name, env.getValueDictByKey(ClientUnits[1].name) } ) for ClientUnitID, ClientUnitData in pairs( ClientUnits ) do self:T3( { tonumber(UnitData:getID()), ClientUnitData.unitId } ) if tonumber(UnitData:getID()) == ClientUnitData.unitId then - local ClientGroupTemplate = _Database.Groups[self.ClientName].Template + local ClientGroupTemplate = _DATABASE.Groups[self.ClientName].Template self.ClientID = ClientGroupTemplate.groupId self.ClientGroupUnit = UnitData self:T3( self.ClientName .. " : group found in bug 1.5 resolvement logic!" ) @@ -10411,7 +10698,7 @@ function MISSIONSCHEDULER.Scheduler() if Mission.GoalFunction ~= nil then Mission.GoalFunction( Mission, Client ) end - _Database:_AddMissionTaskScore( Client:GetClientGroupDCSUnit(), Mission.Name, 25 ) + _DATABASE:_AddMissionTaskScore( Client:GetClientGroupDCSUnit(), Mission.Name, 25 ) -- if not Mission:IsCompleted() then -- end @@ -10872,7 +11159,7 @@ function CLEANUP:_CleanUpScheduler() local CleanUpUnitName = UnitData.CleanUpUnitName if CleanUpUnit then self:T( { "CleanUp Scheduler", "Checking:", CleanUpUnitName } ) - if _Database:GetStatusGroup( CleanUpGroupName ) ~= "ReSpawn" then + if _DATABASE:GetStatusGroup( CleanUpGroupName ) ~= "ReSpawn" then local CleanUpUnitVec3 = CleanUpUnit:getPoint() --self:T( CleanUpUnitVec3 ) local CleanUpUnitVec2 = {} @@ -11315,7 +11602,7 @@ function SPAWN:Array( SpawnAngle, SpawnWidth, SpawnDeltaX, SpawnDeltaY ) _EVENTDISPATCHER:OnEngineShutDownForTemplate( self.SpawnGroups[SpawnGroupID].SpawnTemplate, self._OnEngineShutDown, self ) end - self.SpawnGroups[SpawnGroupID].Group = _Database:Spawn( self.SpawnGroups[SpawnGroupID].SpawnTemplate ) + self.SpawnGroups[SpawnGroupID].Group = _DATABASE:Spawn( self.SpawnGroups[SpawnGroupID].SpawnTemplate ) SpawnX = SpawnXIndex * SpawnDeltaX SpawnY = SpawnYIndex * SpawnDeltaY @@ -11387,7 +11674,7 @@ function SPAWN:SpawnWithIndex( SpawnIndex ) _EVENTDISPATCHER:OnEngineShutDownForTemplate( self.SpawnGroups[self.SpawnIndex].SpawnTemplate, self._OnEngineShutDown, self ) end - self.SpawnGroups[self.SpawnIndex].Group = _Database:Spawn( self.SpawnGroups[self.SpawnIndex].SpawnTemplate ) + self.SpawnGroups[self.SpawnIndex].Group = _DATABASE:Spawn( self.SpawnGroups[self.SpawnIndex].SpawnTemplate ) -- If there is a SpawnFunction hook defined, call it. if self.SpawnFunctionHook then @@ -11395,7 +11682,7 @@ function SPAWN:SpawnWithIndex( SpawnIndex ) end -- TODO: Need to fix this by putting an "R" in the name of the group when the group repeats. --if self.SpawnRepeat then - -- _Database:SetStatusGroup( SpawnTemplate.name, "ReSpawn" ) + -- _DATABASE:SetStatusGroup( SpawnTemplate.name, "ReSpawn" ) --end end @@ -11896,7 +12183,7 @@ function SPAWN:_GetTemplate( SpawnTemplatePrefix ) local SpawnTemplate = nil - SpawnTemplate = routines.utils.deepCopy( _Database.Groups[SpawnTemplatePrefix].Template ) + SpawnTemplate = routines.utils.deepCopy( _DATABASE.Groups[SpawnTemplatePrefix].Template ) if SpawnTemplate == nil then error( 'No Template returned for SpawnTemplatePrefix = ' .. SpawnTemplatePrefix ) @@ -12053,7 +12340,7 @@ function SPAWN:_GetSpawnIndex( SpawnIndex ) end --- TODO Need to delete this... _Database does this now ... +-- TODO Need to delete this... _DATABASE does this now ... function SPAWN:_OnBirth( event ) if timer.getTime0() < timer.getAbsTime() then -- dont need to add units spawned in at the start of the mission if mist is loaded in init line @@ -12071,7 +12358,7 @@ function SPAWN:_OnBirth( event ) end --- Obscolete --- @todo Need to delete this... _Database does this now ... +-- @todo Need to delete this... _DATABASE does this now ... function SPAWN:_OnDeadOrCrash( event ) self:F( self.SpawnTemplatePrefix, event ) @@ -12398,7 +12685,7 @@ function SEAD:EventShot( Event ) local _targetMimgroup = Unit.getGroup(Weapon.getTarget(SEADWeapon)) local _targetMimgroupName = _targetMimgroup:getName() local _targetMimcont= _targetMimgroup:getController() - local _targetskill = _Database.Units[_targetMimname].Template.skill + local _targetskill = _DATABASE.Units[_targetMimname].Template.skill self:T( self.SEADGroupPrefixes ) self:T( _targetMimgroupName ) local SEADGroupFound = false diff --git a/Loaders/MOOSE-Template.miz b/Loaders/MOOSE-Template.miz index 108e949f1..0590654ec 100644 Binary files a/Loaders/MOOSE-Template.miz and b/Loaders/MOOSE-Template.miz differ diff --git a/Loaders/Moose_Load_Dynamic.lua b/Loaders/Moose_Load_Dynamic.lua index 7fb711e0e..aa7f1fd9d 100644 --- a/Loaders/Moose_Load_Dynamic.lua +++ b/Loaders/Moose_Load_Dynamic.lua @@ -38,6 +38,6 @@ env.info( "Include.MissionPath = " .. Include.MissionPath) Include.Files = {} -Include.File( "Database" ) +Include.File( "Moose" ) env.info("Loaded MOOSE Include Engine") \ No newline at end of file diff --git a/Loaders/Moose_Load_Embedded.lua b/Loaders/Moose_Load_Embedded.lua index 350bb9c92..3aa464d98 100644 --- a/Loaders/Moose_Load_Embedded.lua +++ b/Loaders/Moose_Load_Embedded.lua @@ -20,4 +20,6 @@ env.info( "Include.MissionPath = " .. Include.MissionPath) Include.Files = {} +Include.File( "Moose" ) + env.info("Loaded MOOSE Include Engine") diff --git a/Moose/CleanUp.lua b/Moose/CleanUp.lua index 1e0c902c5..5b564ca58 100644 --- a/Moose/CleanUp.lua +++ b/Moose/CleanUp.lua @@ -264,7 +264,7 @@ function CLEANUP:_CleanUpScheduler() local CleanUpUnitName = UnitData.CleanUpUnitName if CleanUpUnit then self:T( { "CleanUp Scheduler", "Checking:", CleanUpUnitName } ) - if _Database:GetStatusGroup( CleanUpGroupName ) ~= "ReSpawn" then + if _DATABASE:GetStatusGroup( CleanUpGroupName ) ~= "ReSpawn" then local CleanUpUnitVec3 = CleanUpUnit:getPoint() --self:T( CleanUpUnitVec3 ) local CleanUpUnitVec2 = {} diff --git a/Moose/Client.lua b/Moose/Client.lua index 5cb17fba3..bc444e5c5 100644 --- a/Moose/Client.lua +++ b/Moose/Client.lua @@ -196,12 +196,12 @@ function CLIENT:GetDCSGroup() -- Now we need to resolve the bugs in DCS 1.5 ... -- Consult the database for the units of the Client Group. (ClientGroup:getUnits() returns nil) self:T3( "Bug 1.5 logic" ) - local ClientUnits = _Database.Groups[self.ClientName].Units + local ClientUnits = _DATABASE.Groups[self.ClientName].Units self:T3( { ClientUnits[1].name, env.getValueDictByKey(ClientUnits[1].name) } ) for ClientUnitID, ClientUnitData in pairs( ClientUnits ) do self:T3( { tonumber(UnitData:getID()), ClientUnitData.unitId } ) if tonumber(UnitData:getID()) == ClientUnitData.unitId then - local ClientGroupTemplate = _Database.Groups[self.ClientName].Template + local ClientGroupTemplate = _DATABASE.Groups[self.ClientName].Template self.ClientID = ClientGroupTemplate.groupId self.ClientGroupUnit = UnitData self:T3( self.ClientName .. " : group found in bug 1.5 resolvement logic!" ) diff --git a/Moose/Database.lua b/Moose/Database.lua index b9ba85c1b..109566d2f 100644 --- a/Moose/Database.lua +++ b/Moose/Database.lua @@ -1,6 +1,5 @@ ---- Administers the Initial Sets of the Mission Templates as defined within the Mission Editor. --- Administers the Spawning of new Groups within the DCSRTE and administers these new Groups within the DATABASE object(s). --- @module Database +--- +-- @module DATABASE -- @author FlightControl Include.File( "Routines" ) @@ -9,19 +8,100 @@ Include.File( "Menu" ) Include.File( "Group" ) Include.File( "Event" ) ---- The DATABASE class +--- +-- Administers the Initial Sets of the Mission Templates as defined within the Mission Editor. +-- Mission designers can use the DATABASE 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 ... +-- +-- DATABASE construction methods: +-- ================================= +-- Create a new DATABASE object with the @{#DATABASE.New} method: +-- +-- * @{#DATABASE.New}: Creates a new DATABASE object. +-- +-- +-- DATABASE filter criteria: +-- ========================= +-- You can set filter criteria to define the set of units within the database. +-- Filter criteria are defined by: +-- +-- * @{#DATABASE.FilterCoalitions}: Builds the DATABASE with the units belonging to the coalition(s). +-- * @{#DATABASE.FilterCategories}: Builds the DATABASE with the units belonging to the category(ies). +-- * @{#DATABASE.FilterTypes}: Builds the DATABASE with the units belonging to the unit type(s). +-- * @{#DATABASE.FilterCountries}: Builds the DATABASE with the units belonging to the country(ies). +-- * @{#DATABASE.FilterUnitPrefixes}: Builds the DATABASE with the units starting with the same prefix string(s). +-- +-- Once the filter criteria have been set for the DATABASE, you can start filtering using: +-- +-- * @{#DATABASE.FilterStart}: Starts the filtering of the units within the database. +-- +-- Planned filter criteria within development are (so these are not yet available): +-- +-- * @{#DATABASE.FilterGroupPrefixes}: Builds the DATABASE with the groups of the units starting with the same prefix string(s). +-- * @{#DATABASE.FilterZones}: Builds the DATABASE with the units within a @{Zone#ZONE}. +-- +-- +-- DATABASE iterators: +-- =================== +-- Once the filters have been defined and the DATABASE has been built, you can iterate the database with the available iterator methods. +-- The iterator methods will walk the DATABASE set, and call for each element within the set a function that you provide. +-- The following iterator methods are currently available within the DATABASE: +-- +-- * @{#DATABASE.ForEachAliveUnit}: Calls a function for each alive unit it finds within the DATABASE. +-- +-- Planned iterators methods in development are (so these are not yet available): +-- +-- * @{#DATABASE.ForEachUnit}: Calls a function for each unit contained within the DATABASE. +-- * @{#DATABASE.ForEachGroup}: Calls a function for each group contained within the DATABASE. +-- * @{#DATABASE.ForEachUnitInZone}: Calls a function for each unit within a certain zone contained within the DATABASE. +-- -- @type DATABASE -- @extends Base#BASE DATABASE = { ClassName = "DATABASE", + DCSUnits = {}, + DCSUnitsAlive = {}, Units = {}, Groups = {}, + DCSGroups = {}, + DCSGroupsAlive = {}, NavPoints = {}, Statics = {}, Players = {}, - ActivePlayers = {}, + AlivePlayers = {}, ClientsByName = {}, ClientsByID = {}, + 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 = @@ -40,8 +120,9 @@ local _DATABASECategory = } ---- Creates a new DATABASE Object to administer the Groups defined and alive within the DCSRTE. --- @return DATABASE +--- 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 +-- @return #DATABASE -- @usage -- -- Define a new DATABASE Object. This DBObject will contain a reference to all Group and Unit Templates defined within the ME and the DCSRTE. -- DBObject = DATABASE:New() @@ -49,67 +130,145 @@ function DATABASE:New() -- 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 ) + + return self +end - self.Navpoints = {} - self.Units = {} - --Build routines.db.units and self.Navpoints - for coa_name, coa_data in pairs(env.mission.coalition) do +--- Builds a set of units of coalitons. +-- Possible current coalitions are red, blue and neutral. +-- @param #DATABASE self +-- @param #string Coalitions Can take the following values: "red", "blue", "neutral". +-- @return #DATABASE self +function DATABASE:FilterCoalitions( Coalitions ) + if not self.Filter.Coalitions then + self.Filter.Coalitions = {} + end + if type( Coalitions ) ~= "table" then + Coalitions = { Coalitions } + end + for CoalitionID, Coalition in pairs( Coalitions ) do + self.Filter.Coalitions[Coalition] = Coalition + end + return self +end - if (coa_name == 'red' or coa_name == 'blue') and type(coa_data) == 'table' then - self.Units[coa_name] = {} +--- Builds a set of units out of categories. +-- Possible current categories are plane, helicopter, ground, ship. +-- @param #DATABASE self +-- @param #string Categories Can take the following values: "plane", "helicopter", "ground", "ship". +-- @return #DATABASE self +function DATABASE:FilterCategories( Categories ) + if not self.Filter.Categories then + self.Filter.Categories = {} + end + if type( Categories ) ~= "table" then + Categories = { Categories } + end + for CategoryID, Category in pairs( Categories ) do + self.Filter.Categories[Category] = Category + end + return self +end - ---------------------------------------------- - -- build nav points DB - self.Navpoints[coa_name] = {} - if coa_data.nav_points then --navpoints - for nav_ind, nav_data in pairs(coa_data.nav_points) do +--- Builds a set of units of defined unit types. +-- Possible current types are those types known within DCS world. +-- @param #DATABASE self +-- @param #string Types Can take those type strings known within DCS world. +-- @return #DATABASE self +function DATABASE:FilterTypes( Types ) + if not self.Filter.Types then + self.Filter.Types = {} + end + if type( Types ) ~= "table" then + Types = { Types } + end + for TypeID, Type in pairs( Types ) do + self.Filter.Types[Type] = Type + end + return self +end - if type(nav_data) == 'table' then - self.Navpoints[coa_name][nav_ind] = routines.utils.deepCopy(nav_data) +--- Builds a set of units of defined countries. +-- Possible current countries are those known within DCS world. +-- @param #DATABASE self +-- @param #string Countries Can take those country strings known within DCS world. +-- @return #DATABASE self +function DATABASE:FilterCountries( Countries ) + if not self.Filter.Countries then + self.Filter.Countries = {} + end + if type( Countries ) ~= "table" then + Countries = { Countries } + end + for CountryID, Country in pairs( Countries ) do + self.Filter.Countries[Country] = Country + end + return self +end - self.Navpoints[coa_name][nav_ind]['name'] = nav_data.callsignStr -- name is a little bit more self-explanatory. - self.Navpoints[coa_name][nav_ind]['point'] = {} -- point is used by SSE, support it. - self.Navpoints[coa_name][nav_ind]['point']['x'] = nav_data.x - self.Navpoints[coa_name][nav_ind]['point']['y'] = 0 - self.Navpoints[coa_name][nav_ind]['point']['z'] = nav_data.y - end +--- Builds a set of units of defined unit prefixes. +-- All the units starting with the given prefixes will be included within the set. +-- @param #DATABASE self +-- @param #string Prefixes The prefix of which the unit name starts with. +-- @return #DATABASE self +function DATABASE:FilterUnitPrefixes( Prefixes ) + if not self.Filter.UnitPrefixes then + self.Filter.UnitPrefixes = {} + end + if type( Prefixes ) ~= "table" then + Prefixes = { Prefixes } + end + for PrefixID, Prefix in pairs( Prefixes ) do + self.Filter.UnitPrefixes[Prefix] = Prefix + end + return self +end + +--- Builds a set of units of defined group prefixes. +-- All the units starting with the given group prefixes will be included within the set. +-- @param #DATABASE self +-- @param #string Prefixes The prefix of which the group name where the unit belongs to starts with. +-- @return #DATABASE self +function DATABASE:FilterGroupPrefixes( Prefixes ) + if not self.Filter.GroupPrefixes then + self.Filter.GroupPrefixes = {} + end + if type( Prefixes ) ~= "table" then + Prefixes = { Prefixes } + end + for PrefixID, Prefix in pairs( Prefixes ) do + self.Filter.GroupPrefixes[Prefix] = Prefix + end + return self +end + +--- Starts the filtering. +-- @param #DATABASE self +-- @return #DATABASE self +function DATABASE:FilterStart() + + if _DATABASE then + -- OK, we have a _DATABASE + -- Now use the different filters to build the set. + -- We first take ALL of the Units of the _DATABASE. + for UnitRegistrationID, UnitRegistration in pairs( _DATABASE.Units ) do + self:T( UnitRegistration ) + local DCSUnit = Unit.getByName( UnitRegistration.UnitName ) + if self:_IsIncludeDCSUnit( DCSUnit ) then + self.DCSUnits[DCSUnit:getName()] = DCSUnit end + if self:_IsAliveDCSUnit( DCSUnit ) then + self.DCSUnitsAlive[DCSUnit:getName()] = DCSUnit end - ------------------------------------------------- - if coa_data.country then --there is a country table - for cntry_id, cntry_data in pairs(coa_data.country) do - - local countryName = string.lower(cntry_data.name) - self.Units[coa_name][countryName] = {} - self.Units[coa_name][countryName]["countryId"] = cntry_data.id - - if type(cntry_data) == 'table' then --just making sure - - for obj_type_name, obj_type_data in pairs(cntry_data) do - - if obj_type_name == "helicopter" or obj_type_name == "ship" or obj_type_name == "plane" or obj_type_name == "vehicle" or obj_type_name == "static" then --should be an unncessary check - - local category = obj_type_name - - if ((type(obj_type_data) == 'table') and obj_type_data.group and (type(obj_type_data.group) == 'table') and (#obj_type_data.group > 0)) then --there's a group! - - self.Units[coa_name][countryName][category] = {} - - for group_num, GroupTemplate in pairs(obj_type_data.group) do - - if GroupTemplate and GroupTemplate.units and type(GroupTemplate.units) == 'table' then --making sure again- this is a valid group - self:_RegisterGroup( GroupTemplate ) - end --if GroupTemplate and GroupTemplate.units then - end --for group_num, GroupTemplate in pairs(obj_type_data.group) do - end --if ((type(obj_type_data) == 'table') and obj_type_data.group and (type(obj_type_data.group) == 'table') and (#obj_type_data.group > 0)) then - end --if obj_type_name == "helicopter" or obj_type_name == "ship" or obj_type_name == "plane" or obj_type_name == "vehicle" or obj_type_name == "static" then - end --for obj_type_name, obj_type_data in pairs(cntry_data) do - end --if type(cntry_data) == 'table' then - end --for cntry_id, cntry_data in pairs(coa_data.country) do - end --if coa_data.country then --there is a country table - end --if coa_name == 'red' or coa_name == 'blue' and type(coa_data) == 'table' then - end --for coa_name, coa_data in pairs(mission.coalition) do - + end + else + self:E( "There is a structural error in MOOSE. No _DATABASE has been defined! Cannot build this custom DATABASE." ) + end + return self end @@ -119,8 +278,9 @@ end -- SpawnCountryID, SpawnCategoryID -- This method is used by the SPAWN class. function DATABASE:Spawn( SpawnTemplate ) + self:F( SpawnTemplate.name ) - self:T( { SpawnTemplate.SpawnCountryID, SpawnTemplate.SpawnCategoryID, SpawnTemplate.name } ) + self:T( { SpawnTemplate.SpawnCountryID, SpawnTemplate.SpawnCategoryID } ) -- Copy the spawn variables of the template in temporary storage, nullify, and restore the spawn variables. local SpawnCoalitionID = SpawnTemplate.SpawnCoalitionID @@ -195,10 +355,237 @@ function DATABASE:_RegisterGroup( GroupTemplate ) self.ClientsByName[UnitTemplateName] = UnitTemplate self.ClientsByID[UnitTemplate.unitId] = UnitTemplate end - self:T( { "Unit", self.Units[UnitTemplateName].UnitName } ) + self:E( { "Unit", self.Units[UnitTemplateName].UnitName } ) end end -_Database = DATABASE:New() -- Database#DATABASE +--- Handles the OnBirth event for the alive units set. +-- @param #DATABASE self +-- @param Event#EVENTDATA Event +function DATABASE:_EventOnBirth( Event ) + self:F( { Event } ) + + if Event.IniDCSUnit then + if self:_IsIncludeDCSUnit( Event.IniDCSUnit ) then + self.DCSUnits[Event.IniDCSUnitName] = Event.IniDCSUnit + self.DCSUnitsAlive[Event.IniDCSUnitName] = Event.IniDCSUnit + end + end +end + +--- Handles the OnDead or OnCrash event for alive units set. +-- @param #DATABASE self +-- @param Event#EVENTDATA Event +function DATABASE:_EventOnDeadOrCrash( Event ) + self:F( { Event } ) + + if Event.IniDCSUnit then + if self.DCSUnitsAlive[Event.IniDCSUnitName] then + self.DCSUnits[Event.IniDCSUnitName] = nil + self.DCSUnitsAlive[Event.IniDCSUnitName] = nil + end + end +end + +--- Interate the DATABASE and call an interator function for each **alive** unit, providing the Unit and optional parameters. +-- @param #DATABASE self +-- @param #function IteratorFunction The function that will be called when there is an alive unit in the database. The function needs to accept a UNIT parameter. +-- @return #DATABASE self +function DATABASE:ForEachAliveUnit( IteratorFunction, ... ) + self:F( arg ) + + local function CoRoutine() + local Count = 0 + for DCSUnitID, DCSUnit in pairs( self.DCSUnitsAlive ) do + self:T2( DCSUnit ) + IteratorFunction( DCSUnit, 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 + timer.scheduleFunction( Schedule, {}, timer.getTime() + 0.001 ) + end + end + + timer.scheduleFunction( Schedule, {}, timer.getTime() + 1 ) + + return self +end + +function DATABASE:ScanEnvironment() + self:F() + + self.Navpoints = {} + self.Units = {} + --Build routines.db.units and self.Navpoints + for coa_name, coa_data in pairs(env.mission.coalition) do + + if (coa_name == 'red' or coa_name == 'blue') and type(coa_data) == 'table' then + --self.Units[coa_name] = {} + + ---------------------------------------------- + -- build nav points DB + self.Navpoints[coa_name] = {} + if coa_data.nav_points then --navpoints + for nav_ind, nav_data in pairs(coa_data.nav_points) do + + if type(nav_data) == 'table' then + self.Navpoints[coa_name][nav_ind] = routines.utils.deepCopy(nav_data) + + self.Navpoints[coa_name][nav_ind]['name'] = nav_data.callsignStr -- name is a little bit more self-explanatory. + self.Navpoints[coa_name][nav_ind]['point'] = {} -- point is used by SSE, support it. + self.Navpoints[coa_name][nav_ind]['point']['x'] = nav_data.x + self.Navpoints[coa_name][nav_ind]['point']['y'] = 0 + self.Navpoints[coa_name][nav_ind]['point']['z'] = nav_data.y + end + end + end + ------------------------------------------------- + if coa_data.country then --there is a country table + for cntry_id, cntry_data in pairs(coa_data.country) do + + local countryName = string.lower(cntry_data.name) + --self.Units[coa_name][countryName] = {} + --self.Units[coa_name][countryName]["countryId"] = cntry_data.id + + if type(cntry_data) == 'table' then --just making sure + + for obj_type_name, obj_type_data in pairs(cntry_data) do + + if obj_type_name == "helicopter" or obj_type_name == "ship" or obj_type_name == "plane" or obj_type_name == "vehicle" or obj_type_name == "static" then --should be an unncessary check + + local category = obj_type_name + + if ((type(obj_type_data) == 'table') and obj_type_data.group and (type(obj_type_data.group) == 'table') and (#obj_type_data.group > 0)) then --there's a group! + + --self.Units[coa_name][countryName][category] = {} + + for group_num, GroupTemplate in pairs(obj_type_data.group) do + + if GroupTemplate and GroupTemplate.units and type(GroupTemplate.units) == 'table' then --making sure again- this is a valid group + self:_RegisterGroup( GroupTemplate ) + end --if GroupTemplate and GroupTemplate.units then + end --for group_num, GroupTemplate in pairs(obj_type_data.group) do + end --if ((type(obj_type_data) == 'table') and obj_type_data.group and (type(obj_type_data.group) == 'table') and (#obj_type_data.group > 0)) then + end --if obj_type_name == "helicopter" or obj_type_name == "ship" or obj_type_name == "plane" or obj_type_name == "vehicle" or obj_type_name == "static" then + end --for obj_type_name, obj_type_data in pairs(cntry_data) do + end --if type(cntry_data) == 'table' then + end --for cntry_id, cntry_data in pairs(coa_data.country) do + end --if coa_data.country then --there is a country table + end --if coa_name == 'red' or coa_name == 'blue' and type(coa_data) == 'table' then + end --for coa_name, coa_data in pairs(mission.coalition) do + + return self +end + + +--- +-- @param #DATABASE self +-- @param DCSUnit#Unit DCSUnit +-- @return #DATABASE self +function DATABASE:_IsIncludeDCSUnit( DCSUnit ) + self:F( DCSUnit ) + local DCSUnitInclude = true + + if self.Filter.Coalitions then + local DCSUnitCoalition = false + for CoalitionID, CoalitionName in pairs( self.Filter.Coalitions ) do + self:T( { "Coalition:", DCSUnit:getCoalition(), self.FilterMeta.Coalitions[CoalitionName], CoalitionName } ) + if self.FilterMeta.Coalitions[CoalitionName] and self.FilterMeta.Coalitions[CoalitionName] == DCSUnit:getCoalition() then + DCSUnitCoalition = true + end + end + DCSUnitInclude = DCSUnitInclude and DCSUnitCoalition + end + + if self.Filter.Categories then + local DCSUnitCategory = false + for CategoryID, CategoryName in pairs( self.Filter.Categories ) do + self:T( { "Category:", DCSUnit:getDesc().category, self.FilterMeta.Categories[CategoryName], CategoryName } ) + if self.FilterMeta.Categories[CategoryName] and self.FilterMeta.Categories[CategoryName] == DCSUnit:getDesc().category then + DCSUnitCategory = true + end + end + DCSUnitInclude = DCSUnitInclude and DCSUnitCategory + end + + if self.Filter.Types then + local DCSUnitType = false + for TypeID, TypeName in pairs( self.Filter.Types ) do + self:T( { "Type:", DCSUnit:getTypeName(), TypeName } ) + if TypeName == DCSUnit:getTypeName() then + DCSUnitType = true + end + end + DCSUnitInclude = DCSUnitInclude and DCSUnitType + end + + if self.Filter.Countries then + local DCSUnitCountry = false + for CountryID, CountryName in pairs( self.Filter.Countries ) do + self:T( { "Country:", DCSUnit:getCountry(), CountryName } ) + if country.id[CountryName] == DCSUnit:getCountry() then + DCSUnitCountry = true + end + end + DCSUnitInclude = DCSUnitInclude and DCSUnitCountry + end + + if self.Filter.UnitPrefixes then + local DCSUnitPrefix = false + for UnitPrefixId, UnitPrefix in pairs( self.Filter.UnitPrefixes ) do + self:T( { "Unit Prefix:", string.find( DCSUnit:getName(), UnitPrefix, 1 ), UnitPrefix } ) + if string.find( DCSUnit:getName(), UnitPrefix, 1 ) then + DCSUnitPrefix = true + end + end + DCSUnitInclude = DCSUnitInclude and DCSUnitPrefix + end + + self:T( DCSUnitInclude ) + return DCSUnitInclude +end + +--- +-- @param #DATABASE self +-- @param DCSUnit#Unit DCSUnit +-- @return #DATABASE self +function DATABASE:_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 + + +--- Traces the current database contents in the log ... (for debug reasons). +-- @param #DATABASE self +-- @return #DATABASE self +function DATABASE:TraceDatabase() + self:F() + + self:T( { "DCSUnits:", self.DCSUnits } ) + self:T( { "DCSUnitsAlive:", self.DCSUnitsAlive } ) +end diff --git a/Moose/Event.lua b/Moose/Event.lua index a51ec4a88..a18d4d22b 100644 --- a/Moose/Event.lua +++ b/Moose/Event.lua @@ -482,8 +482,3 @@ function EVENT:onEvent( Event ) end end - - ---- Declare the event dispatcher based on the EVENT class -_EVENTDISPATCHER = EVENT:New() -- #EVENT - diff --git a/Moose/Group.lua b/Moose/Group.lua index 8e4ddc502..c7f9faa4b 100644 --- a/Moose/Group.lua +++ b/Moose/Group.lua @@ -999,7 +999,7 @@ end function GROUP:GetTaskMission() self:F( self.GroupName ) - return routines.utils.deepCopy( _Database.Groups[self.GroupName].Template ) + return routines.utils.deepCopy( _DATABASE.Groups[self.GroupName].Template ) end --- Return the mission route of the group. @@ -1008,7 +1008,7 @@ end function GROUP:GetTaskRoute() self:F( self.GroupName ) - return routines.utils.deepCopy( _Database.Groups[self.GroupName].Template.route.points ) + return routines.utils.deepCopy( _DATABASE.Groups[self.GroupName].Template.route.points ) end --- Return the route of a group by using the @{Database#DATABASE} class. @@ -1032,7 +1032,7 @@ function GROUP:CopyRoute( Begin, End, Randomize, Radius ) self:T( { GroupName } ) - local Template = _Database.Groups[GroupName].Template + local Template = _DATABASE.Groups[GroupName].Template if Template then if not Begin then diff --git a/Moose/Mission.lua b/Moose/Mission.lua index 002fb4286..61b10e7a0 100644 --- a/Moose/Mission.lua +++ b/Moose/Mission.lua @@ -474,7 +474,7 @@ function MISSIONSCHEDULER.Scheduler() if Mission.GoalFunction ~= nil then Mission.GoalFunction( Mission, Client ) end - _Database:_AddMissionTaskScore( Client:GetClientGroupDCSUnit(), Mission.Name, 25 ) + _DATABASE:_AddMissionTaskScore( Client:GetClientGroupDCSUnit(), Mission.Name, 25 ) -- if not Mission:IsCompleted() then -- end diff --git a/Moose/Moose.lua b/Moose/Moose.lua new file mode 100644 index 000000000..b9df585ce --- /dev/null +++ b/Moose/Moose.lua @@ -0,0 +1,15 @@ +--- The main include file for the MOOSE system. + +Include.File( "Routines" ) +Include.File( "Base" ) +Include.File( "Database" ) +Include.File( "Event" ) + +-- The order of the declarations is important here. Don't touch it. + +--- Declare the event dispatcher based on the EVENT class +_EVENTDISPATCHER = EVENT:New() -- #EVENT + +--- Declare the main database object, which is used internally by the MOOSE classes. +_DATABASE = DATABASE:New():ScanEnvironment() -- Database#DATABASE + diff --git a/Moose/Routines.lua b/Moose/Routines.lua index 14f840d55..4f12b2222 100644 --- a/Moose/Routines.lua +++ b/Moose/Routines.lua @@ -449,14 +449,14 @@ end do -- THE MAIN FUNCTION -- Accessed 100 times/sec. routines.main = function() - timer.scheduleFunction(routines.main, {}, timer.getTime() + 0.1) --reschedule first in case of Lua error + timer.scheduleFunction(routines.main, {}, timer.getTime() + 2) --reschedule first in case of Lua error ---------------------------------------------------------------------------------------------------------- --area to add new stuff in routines.do_scheduled_functions() end -- end of routines.main - timer.scheduleFunction(routines.main, {}, timer.getTime() + 0.1) + timer.scheduleFunction(routines.main, {}, timer.getTime() + 2) end @@ -1696,7 +1696,7 @@ function routines.getGroupRoute(groupIdent, task) -- same as getGroupPoints bu -- refactor to search by groupId and allow groupId and groupName as inputs local gpId = groupIdent if type(groupIdent) == 'string' and not tonumber(groupIdent) then - gpId = _Database.Groups[groupIdent].groupId + gpId = _DATABASE.Groups[groupIdent].groupId end for coa_name, coa_data in pairs(env.mission.coalition) do @@ -1746,6 +1746,7 @@ function routines.getGroupRoute(groupIdent, task) -- same as getGroupPoints bu end --if coa_name == 'red' or coa_name == 'blue' and type(coa_data) == 'table' then end --for coa_name, coa_data in pairs(mission.coalition) do end + routines.ground.patrolRoute = function(vars) diff --git a/Moose/Sead.lua b/Moose/Sead.lua index f30459de2..d89c47cf0 100644 --- a/Moose/Sead.lua +++ b/Moose/Sead.lua @@ -67,7 +67,7 @@ function SEAD:EventShot( Event ) local _targetMimgroup = Unit.getGroup(Weapon.getTarget(SEADWeapon)) local _targetMimgroupName = _targetMimgroup:getName() local _targetMimcont= _targetMimgroup:getController() - local _targetskill = _Database.Units[_targetMimname].Template.skill + local _targetskill = _DATABASE.Units[_targetMimname].Template.skill self:T( self.SEADGroupPrefixes ) self:T( _targetMimgroupName ) local SEADGroupFound = false diff --git a/Moose/Spawn.lua b/Moose/Spawn.lua index d89eb821d..be92d9ea0 100644 --- a/Moose/Spawn.lua +++ b/Moose/Spawn.lua @@ -21,8 +21,8 @@ -- * It is important to defined BEFORE you spawn new groups, a proper initialization of the SPAWN instance is done with the options you want to use. -- * When designing a mission, NEVER name groups using a "#" within the name of the group Spawn Template(s), or the SPAWN module logic won't work anymore. -- --- 1. SPAWN object construction methods: --- ------------------------------------- +-- SPAWN construction methods: +-- =========================== -- Create a new SPAWN object with the @{#SPAWN.New} or the @{#SPAWN.NewWithAlias} methods: -- -- * @{#SPAWN.New}: Creates a new SPAWN object taking the name of the group that functions as the Template. @@ -31,8 +31,8 @@ -- The initialization functions will modify this list of groups so that when a group gets spawned, ALL information is already prepared when spawning. This is done for performance reasons. -- So in principle, the group list will contain all parameters and configurations after initialization, and when groups get actually spawned, this spawning can be done quickly and efficient. -- --- 2. SPAWN object initialization methods: --- --------------------------------------- +-- SPAWN initialization methods: +-- ============================= -- A spawn object will behave differently based on the usage of initialization methods: -- -- * @{#SPAWN.Limit}: Limits the amount of groups that can be alive at the same time and that can be dynamically spawned. @@ -42,8 +42,8 @@ -- * @{#SPAWN.Array}: Make groups visible before they are actually activated, and order these groups like a batallion in an array. -- * @{#SPAWN.Repeat}: Re-spawn groups when they land at the home base. Similar functions are @{#SPAWN.RepeatOnLanding} and @{#SPAWN.RepeatOnEngineShutDown}. -- --- 2. SPAWN object spawning methods: --- --------------------------------- +-- SPAWN spawning methods: +-- ======================= -- Groups can be spawned at different times and methods: -- -- * @{#SPAWN.Spawn}: Spawn one new group based on the last spawned index. @@ -55,8 +55,8 @@ -- Note that @{#SPAWN.Spawn} and @{#SPAWN.ReSpawn} return a @{GROUP#GROUP.New} object, that contains a reference to the DCSGroup object. -- You can use the @{GROUP} object to do further actions with the DCSGroup. -- --- 3. SPAWN object cleaning: --- ------------------------- +-- SPAWN object cleaning: +-- ========================= -- Sometimes, it will occur during a mission run-time, that ground or especially air objects get damaged, and will while being damged stop their activities, while remaining alive. -- In such cases, the SPAWN object will just sit there and wait until that group gets destroyed, but most of the time it won't, -- and it may occur that no new groups are or can be spawned as limits are reached. @@ -384,7 +384,7 @@ function SPAWN:Array( SpawnAngle, SpawnWidth, SpawnDeltaX, SpawnDeltaY ) _EVENTDISPATCHER:OnEngineShutDownForTemplate( self.SpawnGroups[SpawnGroupID].SpawnTemplate, self._OnEngineShutDown, self ) end - self.SpawnGroups[SpawnGroupID].Group = _Database:Spawn( self.SpawnGroups[SpawnGroupID].SpawnTemplate ) + self.SpawnGroups[SpawnGroupID].Group = _DATABASE:Spawn( self.SpawnGroups[SpawnGroupID].SpawnTemplate ) SpawnX = SpawnXIndex * SpawnDeltaX SpawnY = SpawnYIndex * SpawnDeltaY @@ -456,7 +456,7 @@ function SPAWN:SpawnWithIndex( SpawnIndex ) _EVENTDISPATCHER:OnEngineShutDownForTemplate( self.SpawnGroups[self.SpawnIndex].SpawnTemplate, self._OnEngineShutDown, self ) end - self.SpawnGroups[self.SpawnIndex].Group = _Database:Spawn( self.SpawnGroups[self.SpawnIndex].SpawnTemplate ) + self.SpawnGroups[self.SpawnIndex].Group = _DATABASE:Spawn( self.SpawnGroups[self.SpawnIndex].SpawnTemplate ) -- If there is a SpawnFunction hook defined, call it. if self.SpawnFunctionHook then @@ -464,7 +464,7 @@ function SPAWN:SpawnWithIndex( SpawnIndex ) end -- TODO: Need to fix this by putting an "R" in the name of the group when the group repeats. --if self.SpawnRepeat then - -- _Database:SetStatusGroup( SpawnTemplate.name, "ReSpawn" ) + -- _DATABASE:SetStatusGroup( SpawnTemplate.name, "ReSpawn" ) --end end @@ -965,7 +965,7 @@ function SPAWN:_GetTemplate( SpawnTemplatePrefix ) local SpawnTemplate = nil - SpawnTemplate = routines.utils.deepCopy( _Database.Groups[SpawnTemplatePrefix].Template ) + SpawnTemplate = routines.utils.deepCopy( _DATABASE.Groups[SpawnTemplatePrefix].Template ) if SpawnTemplate == nil then error( 'No Template returned for SpawnTemplatePrefix = ' .. SpawnTemplatePrefix ) @@ -1122,7 +1122,7 @@ function SPAWN:_GetSpawnIndex( SpawnIndex ) end --- TODO Need to delete this... _Database does this now ... +-- TODO Need to delete this... _DATABASE does this now ... function SPAWN:_OnBirth( event ) if timer.getTime0() < timer.getAbsTime() then -- dont need to add units spawned in at the start of the mission if mist is loaded in init line @@ -1140,7 +1140,7 @@ function SPAWN:_OnBirth( event ) end --- Obscolete --- @todo Need to delete this... _Database does this now ... +-- @todo Need to delete this... _DATABASE does this now ... function SPAWN:_OnDeadOrCrash( event ) self:F( self.SpawnTemplatePrefix, event ) diff --git a/Moose/Zone.lua b/Moose/Zone.lua index eb16cf63a..c1ef13b25 100644 --- a/Moose/Zone.lua +++ b/Moose/Zone.lua @@ -46,9 +46,10 @@ function ZONE:GetRandomPointVec2() local Point = {} local Zone = trigger.misc.getZone( self.ZoneName ) - - Point.x = Zone.point.x + math.random( Zone.radius * -1, Zone.radius ) - Point.y = Zone.point.z + math.random( Zone.radius * -1, Zone.radius ) + + local angle = math.random() * math.pi*2; + Point.x = Zone.point.x + math.cos( angle ) * math.random() * Zone.radius; + Point.y = Zone.point.z + math.sin( angle ) * math.random() * Zone.radius; self:T( { Zone, Point } ) diff --git a/Test Missions/Moose_Test_DATABASE/Moose_Test_DATABASE.lua b/Test Missions/Moose_Test_DATABASE/Moose_Test_DATABASE.lua new file mode 100644 index 000000000..88f76d82a --- /dev/null +++ b/Test Missions/Moose_Test_DATABASE/Moose_Test_DATABASE.lua @@ -0,0 +1,74 @@ +Include.File( 'Database' ) +Include.File( 'Spawn' ) + +DBBluePlanes = DATABASE:New() + :FilterCoalitions( "blue" ) + :FilterCategories( "plane" ) + :FilterStart() + +DBRedVehicles = DATABASE:New() + :FilterCoalitions( "red" ) + :FilterCategories( "ground" ) + :FilterStart() + +DBShips = DATABASE:New() + :FilterCategories( "ship" ) + :FilterStart() + +DBBelgium = DATABASE:New() + :FilterCategories( "helicopter" ) + :FilterCountries( "BELGIUM" ) + :FilterStart() + +DBNorthKorea = DATABASE:New() + :FilterCountries( "NORTH_KOREA" ) + :FilterStart() + +DBKA50Vinson = DATABASE:New() + :FilterTypes( { "Ka-50", "VINSON" } ) + :FilterStart() + +DBBluePlanes:TraceDatabase() +DBRedVehicles:TraceDatabase() +DBShips:TraceDatabase() +DBBelgium:TraceDatabase() +DBNorthKorea:TraceDatabase() +DBKA50Vinson:TraceDatabase() + + +SpawnUS_Plane = SPAWN:New( 'Database Spawn Test USA Plane') +GroupUS_Plane = SpawnUS_Plane:Spawn() + +SpawnUS_Vehicle = SPAWN:New( 'Database Spawn Test USA Vehicle') +GroupUS_Vehicle = SpawnUS_Vehicle:Spawn() + +SpawnUS_Ship = SPAWN:New( 'Database Spawn Test USA Ship') +GroupUS_Ship = SpawnUS_Ship:Spawn() + +SpawnRU_Vehicle = SPAWN:New( 'Database Spawn Test RUSSIA Vehicle') +GroupRU_Vehicle = SpawnRU_Vehicle:Spawn() + +SpawnRU_Ship = SPAWN:New( 'Database Spawn Test RUSSIA Ship') +GroupRU_Ship = SpawnRU_Ship:Spawn() + +SpawnUS_AttackVehicle = SPAWN:New( 'Database Spawn Test USA Attack Vehicle' ) +SpawnRU_AttackVehicle = SPAWN:New( 'Database Spawn Test RUSSIA Attack Vehicle' ) + +for i = 1, 10 do + GroupRU_AttackVehicle = SpawnRU_AttackVehicle:SpawnInZone( ZONE:New("Spawn Zone RU"), true) + GroupUS_AttackVehicle = SpawnUS_AttackVehicle:SpawnInZone( ZONE:New("Spawn Zone US"), true) +end + + +--DBBlue:TraceDatabase() +routines.scheduleFunction( DBBluePlanes.TraceDatabase, { DBBluePlanes }, 1 ) +routines.scheduleFunction( DBRedVehicles.TraceDatabase, { DBRedVehicles }, 1 ) +routines.scheduleFunction( DBShips.TraceDatabase, { DBShips }, 1 ) +routines.scheduleFunction( DBBelgium.TraceDatabase, { DBBelgium }, 1 ) +routines.scheduleFunction( DBNorthKorea.TraceDatabase, { DBNorthKorea }, 1 ) +routines.scheduleFunction( DBKA50Vinson.TraceDatabase, { DBKA50Vinson }, 1 ) + +DBRedVehicles + :ForEachAliveUnit( function( DCSUnit ) + DBRedVehicles:T( DCSUnit:getName() ) + end ) diff --git a/Test Missions/Moose_Test_DATABASE/Moose_Test_DATABASE.miz b/Test Missions/Moose_Test_DATABASE/Moose_Test_DATABASE.miz new file mode 100644 index 000000000..8942d4325 Binary files /dev/null and b/Test Missions/Moose_Test_DATABASE/Moose_Test_DATABASE.miz differ
The CLIENT models client units in multi player missions.
+Set TASK to destroy certain unit types.
-Administers the Initial Sets of the Mission Templates as defined within the Mission Editor.