diff --git a/Embedded/Moose_Embedded.lua b/Embedded/Moose_Embedded.lua index 7d283599e..302dd40da 100644 --- a/Embedded/Moose_Embedded.lua +++ b/Embedded/Moose_Embedded.lua @@ -4282,10 +4282,10 @@ end --- Gets the current Point of the GROUP in VEC3 format. -- @return #Vec3 Current Vec3 position of the group. -function GROUP:GetPositionVec3() +function GROUP:GetPointVec3() self:F( self.GroupName ) - local GroupPoint = self:GetUnit(1):GetPositionVec3() + local GroupPoint = self:GetUnit(1):GetPointVec3() self:T( GroupPoint ) return GroupPoint end @@ -4934,7 +4934,7 @@ end function GROUP:TaskRouteToVec3( Point, Speed ) self:F( { Point, Speed } ) - local GroupPoint = self:GetUnit( 1 ):GetPositionVec3() + local GroupPoint = self:GetUnit( 1 ):GetPointVec3() local PointFrom = {} PointFrom.x = GroupPoint.x @@ -5636,7 +5636,7 @@ function UNIT:GetPointVec2() end -function UNIT:GetPositionVec3() +function UNIT:GetPointVec3() self:F( self.UnitName ) local UnitPos = self.DCSUnit:getPosition().p @@ -5648,8 +5648,8 @@ end function UNIT:OtherUnitInRadius( AwaitUnit, Radius ) self:F( { self.UnitName, AwaitUnit.UnitName, Radius } ) - local UnitPos = self:GetPositionVec3() - local AwaitUnitPos = AwaitUnit:GetPositionVec3() + local UnitPos = self:GetPointVec3() + local AwaitUnitPos = AwaitUnit:GetPointVec3() if (((UnitPos.x - AwaitUnitPos.x)^2 + (UnitPos.z - AwaitUnitPos.z)^2)^0.5 <= Radius) then self:T( "true" ) @@ -5671,77 +5671,77 @@ end -- @param #UNIT self function UNIT:Flare( FlareColor ) self:F() - trigger.action.signalFlare( self:GetPositionVec3(), FlareColor , 0 ) + trigger.action.signalFlare( self:GetPointVec3(), FlareColor , 0 ) end --- Signal a white flare at the position of the UNIT. -- @param #UNIT self function UNIT:FlareWhite() self:F() - trigger.action.signalFlare( self:GetPositionVec3(), trigger.flareColor.White , 0 ) + trigger.action.signalFlare( self:GetPointVec3(), trigger.flareColor.White , 0 ) end --- Signal a yellow flare at the position of the UNIT. -- @param #UNIT self function UNIT:FlareYellow() self:F() - trigger.action.signalFlare( self:GetPositionVec3(), trigger.flareColor.Yellow , 0 ) + trigger.action.signalFlare( self:GetPointVec3(), trigger.flareColor.Yellow , 0 ) end --- Signal a green flare at the position of the UNIT. -- @param #UNIT self function UNIT:FlareGreen() self:F() - trigger.action.signalFlare( self:GetPositionVec3(), trigger.flareColor.Green , 0 ) + trigger.action.signalFlare( self:GetPointVec3(), trigger.flareColor.Green , 0 ) end --- Signal a red flare at the position of the UNIT. -- @param #UNIT self function UNIT:FlareRed() self:F() - trigger.action.signalFlare( self:GetPositionVec3(), trigger.flareColor.Red, 0 ) + trigger.action.signalFlare( self:GetPointVec3(), trigger.flareColor.Red, 0 ) end --- Smoke the UNIT. -- @param #UNIT self function UNIT:Smoke( SmokeColor ) self:F() - trigger.action.smoke( self:GetPositionVec3(), SmokeColor ) + trigger.action.smoke( self:GetPointVec3(), SmokeColor ) end --- Smoke the UNIT Green. -- @param #UNIT self function UNIT:SmokeGreen() self:F() - trigger.action.smoke( self:GetPositionVec3(), trigger.smokeColor.Green ) + trigger.action.smoke( self:GetPointVec3(), trigger.smokeColor.Green ) end --- Smoke the UNIT Red. -- @param #UNIT self function UNIT:SmokeRed() self:F() - trigger.action.smoke( self:GetPositionVec3(), trigger.smokeColor.Red ) + trigger.action.smoke( self:GetPointVec3(), trigger.smokeColor.Red ) end --- Smoke the UNIT White. -- @param #UNIT self function UNIT:SmokeWhite() self:F() - trigger.action.smoke( self:GetPositionVec3(), trigger.smokeColor.White ) + trigger.action.smoke( self:GetPointVec3(), trigger.smokeColor.White ) end --- Smoke the UNIT Orange. -- @param #UNIT self function UNIT:SmokeOrange() self:F() - trigger.action.smoke( self:GetPositionVec3(), trigger.smokeColor.Orange ) + trigger.action.smoke( self:GetPointVec3(), trigger.smokeColor.Orange ) end --- Smoke the UNIT Blue. -- @param #UNIT self function UNIT:SmokeBlue() self:F() - trigger.action.smoke( self:GetPositionVec3(), trigger.smokeColor.Blue ) + trigger.action.smoke( self:GetPointVec3(), trigger.smokeColor.Blue ) end -- Is methods @@ -6176,7 +6176,7 @@ function CLIENT:GetPointVec2() return nil end -function CLIENT:GetPositionVec3() +function CLIENT:GetPointVec3() self:F( self.ClientName ) local DCSUnit = Unit.getByName( self.ClientName ) @@ -6218,7 +6218,7 @@ end --- Returns the position of the CLIENT in @{DCSTypes#Vec3} format. -- @param #CLIENT self -- @return DCSTypes#Vec3 -function CLIENT:ClientPosition() +function CLIENT:GetPositionVec3() self:F() local ClientGroupUnit = self:GetClientGroupDCSUnit() @@ -8260,7 +8260,7 @@ function CARGO_ZONE:Signal() if SignalUnit then self:T( 'Signalling Unit' ) - local SignalVehiclePos = SignalUnit:GetPositionVec3() + local SignalVehiclePos = SignalUnit:GetPointVec3() SignalVehiclePos.y = SignalVehiclePos.y + 2 if self.SignalType.ID == CARGO_ZONE.SIGNAL.TYPE.SMOKE.ID then @@ -8700,7 +8700,7 @@ function CARGO_GROUP:IsNear( Client, LandingZone ) if self.CargoGroupName then local CargoGroup = Group.getByName( self.CargoGroupName ) - if routines.IsPartOfGroupInRadius( CargoGroup, Client:ClientPosition(), 250 ) then + if routines.IsPartOfGroupInRadius( CargoGroup, Client:GetPositionVec3(), 250 ) then Near = true end end @@ -8805,7 +8805,7 @@ function CARGO_GROUP:OnBoarded( Client, LandingZone ) local CargoGroup = Group.getByName( self.CargoGroupName ) if not self.CargoInAir then - if routines.IsPartOfGroupInRadius( CargoGroup, Client:ClientPosition(), 25 ) then + if routines.IsPartOfGroupInRadius( CargoGroup, Client:GetPositionVec3(), 25 ) then CargoGroup:destroy() self:StatusLoaded( Client ) OnBoarded = true @@ -8904,7 +8904,7 @@ function CARGO_PACKAGE:IsNear( Client, LandingZone ) self:T( self.CargoClient.ClientName ) self:T( 'Client Exists.' ) - if routines.IsUnitInRadius( self.CargoClient:GetClientGroupDCSUnit(), Client:ClientPosition(), 150 ) then + if routines.IsUnitInRadius( self.CargoClient:GetClientGroupDCSUnit(), Client:GetPositionVec3(), 150 ) then Near = true end end @@ -9011,7 +9011,7 @@ function CARGO_PACKAGE:OnBoarded( Client, LandingZone ) local OnBoarded = false if self.CargoClient and self.CargoClient:GetDCSGroup() then - if routines.IsUnitInRadius( self.CargoClient:GetClientGroupDCSUnit(), self.CargoClient:ClientPosition(), 10 ) then + if routines.IsUnitInRadius( self.CargoClient:GetClientGroupDCSUnit(), self.CargoClient:GetPositionVec3(), 10 ) then -- Switch Cargo from self.CargoClient to Client ... Each cargo can have only one client. So assigning the new client for the cargo is enough. self:StatusLoaded( Client ) @@ -14670,7 +14670,7 @@ function ESCORT._HoldPosition( MenuParam ) routines.removeFunction( self.FollowScheduler ) local PointFrom = {} - local GroupPoint = EscortGroup:GetUnit(1):GetPositionVec3() + local GroupPoint = EscortGroup:GetUnit(1):GetPointVec3() PointFrom = {} PointFrom.x = GroupPoint.x PointFrom.y = GroupPoint.z @@ -15012,15 +15012,15 @@ function ESCORT:_FollowScheduler( FollowDistance ) local GroupUnit = self.EscortGroup:GetUnit( 1 ) if self.CT1 == 0 and self.GT1 == 0 then - self.CV1 = ClientUnit:GetPositionVec3() + self.CV1 = ClientUnit:GetPointVec3() self.CT1 = timer.getTime() - self.GV1 = GroupUnit:GetPositionVec3() + self.GV1 = GroupUnit:GetPointVec3() self.GT1 = timer.getTime() else local CT1 = self.CT1 local CT2 = timer.getTime() local CV1 = self.CV1 - local CV2 = ClientUnit:GetPositionVec3() + local CV2 = ClientUnit:GetPointVec3() self.CT1 = CT2 self.CV1 = CV2 @@ -15034,7 +15034,7 @@ function ESCORT:_FollowScheduler( FollowDistance ) local GT1 = self.GT1 local GT2 = timer.getTime() local GV1 = self.GV1 - local GV2 = GroupUnit:GetPositionVec3() + local GV2 = GroupUnit:GetPointVec3() self.GT1 = GT2 self.GV1 = GV2 @@ -15140,8 +15140,8 @@ function ESCORT:_ReportTargetsScheduler() -- EscortTargetLastVelocity } ) - local EscortTargetUnitPositionVec3 = EscortTargetUnit:GetPositionVec3() - local EscortPositionVec3 = self.EscortGroup:GetPositionVec3() + local EscortTargetUnitPositionVec3 = EscortTargetUnit:GetPointVec3() + local EscortPositionVec3 = self.EscortGroup:GetPointVec3() local Distance = ( ( EscortTargetUnitPositionVec3.x - EscortPositionVec3.x )^2 + ( EscortTargetUnitPositionVec3.y - EscortPositionVec3.y )^2 + ( EscortTargetUnitPositionVec3.z - EscortPositionVec3.z )^2 @@ -15199,8 +15199,8 @@ function ESCORT:_ReportTargetsScheduler() EscortTargetMessage = EscortTargetMessage .. "Unknown target at " end - local EscortTargetUnitPositionVec3 = ClientEscortTargetData.AttackUnit:GetPositionVec3() - local EscortPositionVec3 = self.EscortGroup:GetPositionVec3() + local EscortTargetUnitPositionVec3 = ClientEscortTargetData.AttackUnit:GetPointVec3() + local EscortPositionVec3 = self.EscortGroup:GetPointVec3() local Distance = ( ( EscortTargetUnitPositionVec3.x - EscortPositionVec3.x )^2 + ( EscortTargetUnitPositionVec3.y - EscortPositionVec3.y )^2 + ( EscortTargetUnitPositionVec3.z - EscortPositionVec3.z )^2 @@ -15267,7 +15267,7 @@ function ESCORT:_ReportTargetsScheduler() local TaskPoints = self:RegisterRoute() for WayPointID, WayPoint in pairs( TaskPoints ) do - local EscortPositionVec3 = self.EscortGroup:GetPositionVec3() + local EscortPositionVec3 = self.EscortGroup:GetPointVec3() local Distance = ( ( WayPoint.x - EscortPositionVec3.x )^2 + ( WayPoint.y - EscortPositionVec3.z )^2 ) ^ 0.5 / 1000 @@ -15771,7 +15771,7 @@ function MISSILETRAINER:_AddRange( Client, TrainerWeapon ) if self.DetailsRangeOnOff then local PositionMissile = TrainerWeapon:getPoint() - local PositionTarget = Client:GetPositionVec3() + local PositionTarget = Client:GetPointVec3() local Range = ( ( PositionMissile.x - PositionTarget.x )^2 + ( PositionMissile.y - PositionTarget.y )^2 + @@ -15791,7 +15791,7 @@ function MISSILETRAINER:_AddBearing( Client, TrainerWeapon ) if self.DetailsBearingOnOff then local PositionMissile = TrainerWeapon:getPoint() - local PositionTarget = Client:GetPositionVec3() + local PositionTarget = Client:GetPointVec3() self:T2( { PositionTarget, PositionMissile }) @@ -15839,7 +15839,7 @@ function MISSILETRAINER:_TrackMissiles() if Client and Client:IsAlive() and TrainerSourceUnit and TrainerSourceUnit:IsAlive() and TrainerWeapon and TrainerWeapon:isExist() and TrainerTargetUnit and TrainerTargetUnit:IsAlive() then local PositionMissile = TrainerWeapon:getPosition().p - local PositionTarget = Client:GetPositionVec3() + local PositionTarget = Client:GetPointVec3() local Distance = ( ( PositionMissile.x - PositionTarget.x )^2 + ( PositionMissile.y - PositionTarget.y )^2 + diff --git a/Moose/Cargo.lua b/Moose/Cargo.lua index eb3152f91..9625e78d8 100644 --- a/Moose/Cargo.lua +++ b/Moose/Cargo.lua @@ -146,7 +146,7 @@ function CARGO_ZONE:Signal() if SignalUnit then self:T( 'Signalling Unit' ) - local SignalVehiclePos = SignalUnit:GetPositionVec3() + local SignalVehiclePos = SignalUnit:GetPointVec3() SignalVehiclePos.y = SignalVehiclePos.y + 2 if self.SignalType.ID == CARGO_ZONE.SIGNAL.TYPE.SMOKE.ID then @@ -586,7 +586,7 @@ function CARGO_GROUP:IsNear( Client, LandingZone ) if self.CargoGroupName then local CargoGroup = Group.getByName( self.CargoGroupName ) - if routines.IsPartOfGroupInRadius( CargoGroup, Client:ClientPosition(), 250 ) then + if routines.IsPartOfGroupInRadius( CargoGroup, Client:GetPositionVec3(), 250 ) then Near = true end end @@ -691,7 +691,7 @@ function CARGO_GROUP:OnBoarded( Client, LandingZone ) local CargoGroup = Group.getByName( self.CargoGroupName ) if not self.CargoInAir then - if routines.IsPartOfGroupInRadius( CargoGroup, Client:ClientPosition(), 25 ) then + if routines.IsPartOfGroupInRadius( CargoGroup, Client:GetPositionVec3(), 25 ) then CargoGroup:destroy() self:StatusLoaded( Client ) OnBoarded = true @@ -790,7 +790,7 @@ function CARGO_PACKAGE:IsNear( Client, LandingZone ) self:T( self.CargoClient.ClientName ) self:T( 'Client Exists.' ) - if routines.IsUnitInRadius( self.CargoClient:GetClientGroupDCSUnit(), Client:ClientPosition(), 150 ) then + if routines.IsUnitInRadius( self.CargoClient:GetClientGroupDCSUnit(), Client:GetPositionVec3(), 150 ) then Near = true end end @@ -897,7 +897,7 @@ function CARGO_PACKAGE:OnBoarded( Client, LandingZone ) local OnBoarded = false if self.CargoClient and self.CargoClient:GetDCSGroup() then - if routines.IsUnitInRadius( self.CargoClient:GetClientGroupDCSUnit(), self.CargoClient:ClientPosition(), 10 ) then + if routines.IsUnitInRadius( self.CargoClient:GetClientGroupDCSUnit(), self.CargoClient:GetPositionVec3(), 10 ) then -- Switch Cargo from self.CargoClient to Client ... Each cargo can have only one client. So assigning the new client for the cargo is enough. self:StatusLoaded( Client ) diff --git a/Moose/Client.lua b/Moose/Client.lua index 238ca7fab..b1d4d2e24 100644 --- a/Moose/Client.lua +++ b/Moose/Client.lua @@ -24,7 +24,7 @@ Include.File( "Message" ) --- The CLIENT class -- @type CLIENT --- @extends Base#BASE +-- @extends Unit#UNIT CLIENT = { ONBOARDSIDE = { NONE = 0, @@ -60,16 +60,25 @@ CLIENT = { -- Mission:AddClient( CLIENT:New( 'RU MI-8MTV2*HOT-Deploy Troops 2' ):Transport() ) -- Mission:AddClient( CLIENT:New( 'RU MI-8MTV2*RAMP-Deploy Troops 4' ):Transport() ) function CLIENT:New( ClientName, ClientBriefing ) - local self = BASE:Inherit( self, BASE:New() ) - self:F( ClientName, ClientBriefing ) + self = _DATABASE:FindClient( ClientName ) + self:F( ClientName, ClientBriefing ) self.ClientName = ClientName - self:AddBriefing( ClientBriefing ) - self.MessageSwitch = true - + self:AddBriefing( ClientBriefing ) + self.MessageSwitch = true + return self end +function CLIENT:Register( ClientName ) + local self = BASE:Inherit( self, UNIT:Register( ClientName ) ) + + self.ClientName = ClientName + + return self +end + + --- Transport defines that the Client is a Transport. Transports show cargo. -- @param #CLIENT self -- @return #CLIENT @@ -138,29 +147,12 @@ function CLIENT:IsMultiSeated() return false end ---- Checks if client is alive and returns true or false. --- @param #CLIENT self --- @returns #boolean Returns true if client is alive. -function CLIENT:IsAlive() - self:F( self.ClientName ) - - local ClientUnit = Unit.getByName( self.ClientName ) - - if ClientUnit and ClientUnit:isExist() then - self:T("true") - return true - end - - self:T( "false" ) - return false -end - --- @param #CLIENT self function CLIENT:_AliveCheckScheduler() self:F( { self.ClientName, self.ClientAlive2 } ) - if self:IsAlive() then + if self:IsAlive() then -- Polymorphic call of UNIT if self.ClientAlive2 == false then self:T("Calling Callback function") self.ClientCallBack( self, unpack( self.ClientParameters ) ) @@ -304,109 +296,6 @@ function CLIENT:GetClientGroupDCSUnit() end end --- TODO what is this??? check. possible double function. -function CLIENT:GetUnit() - self:F() - - return UNIT:New( self:GetClientGroupDCSUnit() ) -end - ---- Returns the position of the CLIENT in @{DCSTypes#Vec2} format.. --- @param #CLIENT self --- @return DCSTypes#Vec2 -function CLIENT:GetPointVec2() - self:F() - - local ClientGroupUnit = self:GetClientGroupDCSUnit() - - if ClientGroupUnit then - if ClientGroupUnit:isExist() then - local PointVec3 = ClientGroupUnit:getPoint() --DCSTypes#Vec3 - local PointVec2 = {} --DCSTypes#Vec2 - PointVec2.x = PointVec3.x - PointVec2.y = PointVec3.z - self:T( { PointVec2 } ) - return PointVec2 - end - end - - return nil -end - -function CLIENT:GetPositionVec3() - self:F( self.ClientName ) - - local DCSUnit = Unit.getByName( self.ClientName ) - local UnitPos = DCSUnit:getPosition().p - - self:T( UnitPos ) - return UnitPos -end - -function CLIENT:GetID() - self:F( self.ClientName ) - - local DCSUnit = Unit.getByName( self.ClientName ) - local UnitID = DCSUnit:getID() - - self:T( UnitID ) - return UnitID -end - -function CLIENT:GetName() - self:F( self.ClientName ) - - self:T( self.ClientName ) - return self.ClientName -end - -function CLIENT:GetTypeName() - self:F( self.ClientName ) - - local DCSUnit = Unit.getByName( self.ClientName ) - local TypeName = DCSUnit:getTypeName() - - self:T( TypeName ) - return TypeName -end - - - ---- Returns the position of the CLIENT in @{DCSTypes#Vec3} format. --- @param #CLIENT self --- @return DCSTypes#Vec3 -function CLIENT:ClientPosition() - self:F() - - local ClientGroupUnit = self:GetClientGroupDCSUnit() - - if ClientGroupUnit then - if ClientGroupUnit:isExist() then - return ClientGroupUnit:getPosition() - end - end - - return nil -end - ---- Returns the altitude of the CLIENT. --- @param #CLIENT self --- @return DCSTypes#Distance -function CLIENT:GetAltitude() - self:F() - - local ClientGroupUnit = self:GetClientGroupDCSUnit() - - if ClientGroupUnit then - if ClientGroupUnit:isExist() then - local PointVec3 = ClientGroupUnit:getPoint() --DCSTypes#Vec3 - return PointVec3.y - end - end - - return nil -end - --- Evaluates if the CLIENT is a transport. -- @param #CLIENT self diff --git a/Moose/Database.lua b/Moose/Database.lua index 3347e34d7..b725d9728 100644 --- a/Moose/Database.lua +++ b/Moose/Database.lua @@ -82,13 +82,9 @@ DATABASE = { ClientsByID = {}, }, DCSUnits = {}, - DCSUnitsAlive = {}, DCSGroups = {}, - DCSGroupsAlive = {}, Units = {}, - UnitsAlive = {}, Groups = {}, - GroupsAlive = {}, NavPoints = {}, Statics = {}, Players = {}, @@ -171,180 +167,38 @@ function DATABASE:FindUnit( UnitName ) return UnitFound end ---- Finds a Unit based on the Unit Name. +--- Adds a Unit based on the Unit Name in the DATABASE. -- @param #DATABASE self --- @param Unit#UNIT UnitToAdd --- @return Unit#UNIT The added Unit. -function DATABASE:AddUnit( UnitToAdd ) +function DATABASE:AddUnit( DCSUnit, DCSUnitName ) - self.Units[UnitToAdd.UnitName] = UnitToAdd - return self.Units[UnitToAdd.UnitName] + self.DCSUnits[DCSUnitName] = DCSUnit + self.Units[DCSUnitName] = UNIT:Register( DCSUnitName ) end - - ---- Builds a set of units of coalitons. --- Possible current coalitions are red, blue and neutral. +--- Deletes a Unit from the DATABASE based on the Unit Name. -- @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 +function DATABASE:DeleteUnit( DCSUnitName ) + + self.DCSUnits[DCSUnitName] = nil end ---- Builds a set of units out of categories. --- Possible current categories are plane, helicopter, ground, ship. +--- Finds a CLIENT based on the ClientName. -- @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 +-- @param #string ClientName +-- @return Client#CLIENT The found CLIENT. +function DATABASE:FindClient( ClientName ) + + local ClientFound = self.Clients[ClientName] + return ClientFound end ---- Builds a set of units of defined unit types. --- Possible current types are those types known within DCS world. +--- Adds a CLIENT based on the ClientName in the DATABASE. -- @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 +function DATABASE:AddClient( ClientName ) + + self.Clients[ClientName] = CLIENT:Register( ClientName ) 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: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. - - self:E( { "Adding Database Datapoints with filters" } ) - for DCSUnitName, DCSUnit in pairs( _DATABASE.DCSUnits ) do - - if self:_IsIncludeDCSUnit( DCSUnit ) then - - self:E( { "Adding Unit:", DCSUnitName } ) - self.DCSUnits[DCSUnitName] = _DATABASE.DCSUnits[DCSUnitName] - self.Units[DCSUnitName] = _DATABASE.Units[DCSUnitName] - - if _DATABASE.DCSUnitsAlive[DCSUnitName] then - self.DCSUnitsAlive[DCSUnitName] = _DATABASE.DCSUnitsAlive[DCSUnitName] - self.UnitsAlive[DCSUnitName] = _DATABASE.UnitsAlive[DCSUnitName] - end - - end - end - - for DCSGroupName, DCSGroup in pairs( _DATABASE.DCSGroups ) do - - --if self:_IsIncludeDCSGroup( DCSGroup ) then - self:E( { "Adding Group:", DCSGroupName } ) - self.DCSGroups[DCSGroupName] = _DATABASE.DCSGroups[DCSGroupName] - self.Groups[DCSGroupName] = _DATABASE.Groups[DCSGroupName] - --end - - if _DATABASE.DCSGroupsAlive[DCSGroupName] then - self.DCSGroupsAlive[DCSGroupName] = _DATABASE.DCSGroupsAlive[DCSGroupName] - self.GroupsAlive[DCSGroupName] = _DATABASE.GroupsAlive[DCSGroupName] - end - end - - for DCSUnitName, Client in pairs( _DATABASE.Clients ) do - self:E( { "Adding Client for Unit:", DCSUnitName } ) - self.Clients[DCSUnitName] = _DATABASE.Clients[DCSUnitName] - 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 - - --- 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 @@ -471,7 +325,7 @@ end -- @return #DATABASE self function DATABASE:_RegisterDatabase() - local CoalitionsData = { AlivePlayersRed = coalition.getGroups( coalition.side.RED ), AlivePlayersBlue = coalition.getGroups( coalition.side.BLUE ) } + local CoalitionsData = { GroupsRed = coalition.getGroups( coalition.side.RED ), GroupsBlue = coalition.getGroups( coalition.side.BLUE ) } for CoalitionId, CoalitionData in pairs( CoalitionsData ) do for DCSGroupId, DCSGroup in pairs( CoalitionData ) do @@ -481,42 +335,28 @@ function DATABASE:_RegisterDatabase() self:E( { "Register Group:", DCSGroup, DCSGroupName } ) self.DCSGroups[DCSGroupName] = DCSGroup self.Groups[DCSGroupName] = GROUP:New( DCSGroup ) - - if self:_IsAliveDCSGroup(DCSGroup) then - self:E( { "Register Alive Group:", DCSGroup, DCSGroupName } ) - self.DCSGroupsAlive[DCSGroupName] = DCSGroup - self.GroupsAlive[DCSGroupName] = self.Groups[DCSGroupName] - end - + for DCSUnitId, DCSUnit in pairs( DCSGroup:getUnits() ) do local DCSUnitName = DCSUnit:getName() self:E( { "Register Unit:", DCSUnit, DCSUnitName } ) - - self.DCSUnits[DCSUnitName] = DCSUnit - self:AddUnit( UNIT:Register( DCSUnit ) ) - --self.Units[DCSUnitName] = UNIT:Register( DCSUnit ) - - if self:_IsAliveDCSUnit(DCSUnit) then - self:E( { "Register Alive Unit:", DCSUnit, DCSUnitName } ) - self.DCSUnitsAlive[DCSUnitName] = DCSUnit - self.UnitsAlive[DCSUnitName] = self.Units[DCSUnitName] - end + self:AddUnit( DCSUnit, DCSUnitName ) end else - self:E( "Group does not exist: " .. DCSGroup ) + self:E( { "Group does not exist: ", DCSGroup } ) end - for ClientName, ClientTemplate in pairs( self.Templates.ClientsByName ) do - self.Clients[ClientName] = CLIENT:New( ClientName ) - end end end + + for ClientName, ClientTemplate in pairs( self.Templates.ClientsByName ) do + self:E( { "Adding Client:", ClientName } ) + self:AddClient( ClientName ) + end return self end - --- Events --- Handles the OnBirth event for the alive units set. @@ -527,11 +367,8 @@ function DATABASE:_EventOnBirth( Event ) if Event.IniDCSUnit then if self:_IsIncludeDCSUnit( Event.IniDCSUnit ) then - self.DCSUnits[Event.IniDCSUnitName] = Event.IniDCSUnit - self.DCSUnitsAlive[Event.IniDCSUnitName] = Event.IniDCSUnit - self:AddUnit( UNIT:Register( Event.IniDCSUnit ) ) - --self.Units[Event.IniDCSUnitName] = UNIT:Register( Event.IniDCSUnit ) - + self:AddUnit( Event.IniDCSUnit, Event.IniDCSUnitName ) + --if not self.DCSGroups[Event.IniDCSGroupName] then -- self.DCSGroups[Event.IniDCSGroupName] = Event.IniDCSGroupName -- self.DCSGroupsAlive[Event.IniDCSGroupName] = Event.IniDCSGroupName @@ -549,9 +386,8 @@ 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 + if self.DCSUnits[Event.IniDCSUnitName] then + self:DeleteUnit( Event.IniDCSUnitName ) end end end @@ -639,10 +475,10 @@ end -- @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:ForEachDCSUnitAlive( IteratorFunction, ... ) +function DATABASE:ForEachDCSUnit( IteratorFunction, ... ) self:F( arg ) - self:ForEach( IteratorFunction, arg, self.DCSUnitsAlive ) + self:ForEach( IteratorFunction, arg, self.DCSUnits ) return self end @@ -850,7 +686,6 @@ function DATABASE:TraceDatabase() self:F() self:T( { "DCSUnits:", self.DCSUnits } ) - self:T( { "DCSUnitsAlive:", self.DCSUnitsAlive } ) end diff --git a/Moose/Escort.lua b/Moose/Escort.lua index e45a3c876..f239d7eca 100644 --- a/Moose/Escort.lua +++ b/Moose/Escort.lua @@ -635,7 +635,7 @@ function ESCORT._HoldPosition( MenuParam ) routines.removeFunction( self.FollowScheduler ) local PointFrom = {} - local GroupPoint = EscortGroup:GetUnit(1):GetPositionVec3() + local GroupPoint = EscortGroup:GetUnit(1):GetPointVec3() PointFrom = {} PointFrom.x = GroupPoint.x PointFrom.y = GroupPoint.z @@ -977,15 +977,15 @@ function ESCORT:_FollowScheduler( FollowDistance ) local GroupUnit = self.EscortGroup:GetUnit( 1 ) if self.CT1 == 0 and self.GT1 == 0 then - self.CV1 = ClientUnit:GetPositionVec3() + self.CV1 = ClientUnit:GetPointVec3() self.CT1 = timer.getTime() - self.GV1 = GroupUnit:GetPositionVec3() + self.GV1 = GroupUnit:GetPointVec3() self.GT1 = timer.getTime() else local CT1 = self.CT1 local CT2 = timer.getTime() local CV1 = self.CV1 - local CV2 = ClientUnit:GetPositionVec3() + local CV2 = ClientUnit:GetPointVec3() self.CT1 = CT2 self.CV1 = CV2 @@ -999,7 +999,7 @@ function ESCORT:_FollowScheduler( FollowDistance ) local GT1 = self.GT1 local GT2 = timer.getTime() local GV1 = self.GV1 - local GV2 = GroupUnit:GetPositionVec3() + local GV2 = GroupUnit:GetPointVec3() self.GT1 = GT2 self.GV1 = GV2 @@ -1082,7 +1082,7 @@ function ESCORT:_ReportTargetsScheduler() self:T( EscortObject ) if EscortObject and EscortObject:isExist() and EscortObject.id_ < 50000000 then - local EscortTargetUnit = UNIT:New( EscortObject ) + local EscortTargetUnit = UNIT:Find( EscortObject ) local EscortTargetUnitName = EscortTargetUnit:GetName() @@ -1105,8 +1105,8 @@ function ESCORT:_ReportTargetsScheduler() -- EscortTargetLastVelocity } ) - local EscortTargetUnitPositionVec3 = EscortTargetUnit:GetPositionVec3() - local EscortPositionVec3 = self.EscortGroup:GetPositionVec3() + local EscortTargetUnitPositionVec3 = EscortTargetUnit:GetPointVec3() + local EscortPositionVec3 = self.EscortGroup:GetPointVec3() local Distance = ( ( EscortTargetUnitPositionVec3.x - EscortPositionVec3.x )^2 + ( EscortTargetUnitPositionVec3.y - EscortPositionVec3.y )^2 + ( EscortTargetUnitPositionVec3.z - EscortPositionVec3.z )^2 @@ -1164,8 +1164,8 @@ function ESCORT:_ReportTargetsScheduler() EscortTargetMessage = EscortTargetMessage .. "Unknown target at " end - local EscortTargetUnitPositionVec3 = ClientEscortTargetData.AttackUnit:GetPositionVec3() - local EscortPositionVec3 = self.EscortGroup:GetPositionVec3() + local EscortTargetUnitPositionVec3 = ClientEscortTargetData.AttackUnit:GetPointVec3() + local EscortPositionVec3 = self.EscortGroup:GetPointVec3() local Distance = ( ( EscortTargetUnitPositionVec3.x - EscortPositionVec3.x )^2 + ( EscortTargetUnitPositionVec3.y - EscortPositionVec3.y )^2 + ( EscortTargetUnitPositionVec3.z - EscortPositionVec3.z )^2 @@ -1232,7 +1232,7 @@ function ESCORT:_ReportTargetsScheduler() local TaskPoints = self:RegisterRoute() for WayPointID, WayPoint in pairs( TaskPoints ) do - local EscortPositionVec3 = self.EscortGroup:GetPositionVec3() + local EscortPositionVec3 = self.EscortGroup:GetPointVec3() local Distance = ( ( WayPoint.x - EscortPositionVec3.x )^2 + ( WayPoint.y - EscortPositionVec3.z )^2 ) ^ 0.5 / 1000 diff --git a/Moose/Group.lua b/Moose/Group.lua index a886d75b3..d532c23df 100644 --- a/Moose/Group.lua +++ b/Moose/Group.lua @@ -282,10 +282,10 @@ end --- Gets the current Point of the GROUP in VEC3 format. -- @return #Vec3 Current Vec3 position of the group. -function GROUP:GetPositionVec3() +function GROUP:GetPointVec3() self:F( self.GroupName ) - local GroupPoint = self:GetUnit(1):GetPositionVec3() + local GroupPoint = self:GetUnit(1):GetPointVec3() self:T( GroupPoint ) return GroupPoint end @@ -311,7 +311,7 @@ end -- @return Unit#UNIT The DCS Unit. function GROUP:GetUnit( UnitNumber ) self:F( { self.GroupName, UnitNumber } ) - return UNIT:New( self.DCSGroup:getUnit( UnitNumber ) ) + return UNIT:Find( self.DCSGroup:getUnit( UnitNumber ) ) end --- Returns the category name of the group. @@ -934,7 +934,7 @@ end function GROUP:TaskRouteToVec3( Point, Speed ) self:F( { Point, Speed } ) - local GroupPoint = self:GetUnit( 1 ):GetPositionVec3() + local GroupPoint = self:GetUnit( 1 ):GetPointVec3() local PointFrom = {} PointFrom.x = GroupPoint.x diff --git a/Moose/MissileTrainer.lua b/Moose/MissileTrainer.lua index 051ad1b10..d7773c502 100644 --- a/Moose/MissileTrainer.lua +++ b/Moose/MissileTrainer.lua @@ -452,8 +452,8 @@ function MISSILETRAINER:_EventShot( Event ) local Client = self.DBClients[TrainerTargetDCSUnitName] if Client then - local TrainerSourceUnit = UNIT:New( TrainerSourceDCSUnit ) - local TrainerTargetUnit = UNIT:New( TrainerTargetDCSUnit ) + local TrainerSourceUnit = UNIT:Find( TrainerSourceDCSUnit ) + local TrainerTargetUnit = UNIT:Find( TrainerTargetDCSUnit ) if self.MessagesOnOff == true and self.AlertsLaunchesOnOff == true then @@ -489,7 +489,7 @@ function MISSILETRAINER:_AddRange( Client, TrainerWeapon ) if self.DetailsRangeOnOff then local PositionMissile = TrainerWeapon:getPoint() - local PositionTarget = Client:GetPositionVec3() + local PositionTarget = Client:GetPointVec3() local Range = ( ( PositionMissile.x - PositionTarget.x )^2 + ( PositionMissile.y - PositionTarget.y )^2 + @@ -509,7 +509,7 @@ function MISSILETRAINER:_AddBearing( Client, TrainerWeapon ) if self.DetailsBearingOnOff then local PositionMissile = TrainerWeapon:getPoint() - local PositionTarget = Client:GetPositionVec3() + local PositionTarget = Client:GetPointVec3() self:T2( { PositionTarget, PositionMissile }) @@ -557,7 +557,7 @@ function MISSILETRAINER:_TrackMissiles() if Client and Client:IsAlive() and TrainerSourceUnit and TrainerSourceUnit:IsAlive() and TrainerWeapon and TrainerWeapon:isExist() and TrainerTargetUnit and TrainerTargetUnit:IsAlive() then local PositionMissile = TrainerWeapon:getPosition().p - local PositionTarget = Client:GetPositionVec3() + local PositionTarget = Client:GetPointVec3() local Distance = ( ( PositionMissile.x - PositionTarget.x )^2 + ( PositionMissile.y - PositionTarget.y )^2 + diff --git a/Moose/Set.lua b/Moose/Set.lua new file mode 100644 index 000000000..e10978d3a --- /dev/null +++ b/Moose/Set.lua @@ -0,0 +1,758 @@ +--- 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() + + -- 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 ) + + + return self +end + +--- Finds a Unit based on the Unit Name. +-- @param #SET self +-- @param #string UnitName +-- @return Unit#UNIT The found Unit. +function SET:FindUnit( UnitName ) + + local UnitFound = self.Units[UnitName] + return UnitFound +end + +--- Finds a Unit based on the Unit Name. +-- @param #SET self +-- @param Unit#UNIT UnitToAdd +-- @return Unit#UNIT The added Unit. +function SET:AddUnit( UnitToAdd ) + + self.Units[UnitToAdd.UnitName] = UnitToAdd + return self.Units[UnitToAdd.UnitName] +end + + + +--- Builds a set of units of coalitons. +-- Possible current coalitions are red, blue and neutral. +-- @param #SET self +-- @param #string Coalitions Can take the following values: "red", "blue", "neutral". +-- @return #SET self +function SET: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 + +--- Builds a set of units out of categories. +-- Possible current categories are plane, helicopter, ground, ship. +-- @param #SET self +-- @param #string Categories Can take the following values: "plane", "helicopter", "ground", "ship". +-- @return #SET self +function SET: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 + +--- Builds a set of units of defined unit types. +-- Possible current types are those types known within DCS world. +-- @param #SET self +-- @param #string Types Can take those type strings known within DCS world. +-- @return #SET self +function SET: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 + +--- Builds a set of units of defined countries. +-- Possible current countries are those known within DCS world. +-- @param #SET self +-- @param #string Countries Can take those country strings known within DCS world. +-- @return #SET self +function SET: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 #SET self +-- @param #string Prefixes The prefix of which the unit name starts with. +-- @return #SET self +function SET: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 #SET self +-- @param #string Prefixes The prefix of which the group name where the unit belongs to starts with. +-- @return #SET self +function SET: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 #SET self +-- @return #SET self +function SET: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. + + self:E( { "Adding Set Datapoints with filters" } ) + for DCSUnitName, DCSUnit in pairs( _DATABASE.DCSUnits ) do + + if self:_IsIncludeDCSUnit( DCSUnit ) then + + self:E( { "Adding Unit:", DCSUnitName } ) + self.DCSUnits[DCSUnitName] = _DATABASE.DCSUnits[DCSUnitName] + self.Units[DCSUnitName] = _DATABASE.Units[DCSUnitName] + + if _DATABASE.DCSUnitsAlive[DCSUnitName] then + self.DCSUnitsAlive[DCSUnitName] = _DATABASE.DCSUnitsAlive[DCSUnitName] + self.UnitsAlive[DCSUnitName] = _DATABASE.UnitsAlive[DCSUnitName] + end + + end + end + + for DCSGroupName, DCSGroup in pairs( _DATABASE.DCSGroups ) do + + --if self:_IsIncludeDCSGroup( DCSGroup ) then + self:E( { "Adding Group:", DCSGroupName } ) + self.DCSGroups[DCSGroupName] = _DATABASE.DCSGroups[DCSGroupName] + self.Groups[DCSGroupName] = _DATABASE.Groups[DCSGroupName] + --end + + if _DATABASE.DCSGroupsAlive[DCSGroupName] then + self.DCSGroupsAlive[DCSGroupName] = _DATABASE.DCSGroupsAlive[DCSGroupName] + self.GroupsAlive[DCSGroupName] = _DATABASE.GroupsAlive[DCSGroupName] + end + end + + for DCSUnitName, Client in pairs( _DATABASE.Clients ) do + self:E( { "Adding Client for Unit:", DCSUnitName } ) + self.Clients[DCSUnitName] = _DATABASE.Clients[DCSUnitName] + end + + else + self:E( "There is a structural error in MOOSE. No _DATABASE has been defined! Cannot build this custom SET." ) + 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 + +--- Private method that registers all datapoints within in the mission. +-- @param #SET self +-- @return #SET self +function SET:_RegisterDatabase() + + local CoalitionsData = { AlivePlayersRed = coalition.getGroups( coalition.side.RED ), AlivePlayersBlue = coalition.getGroups( coalition.side.BLUE ) } + for CoalitionId, CoalitionData in pairs( CoalitionsData ) do + for DCSGroupId, DCSGroup in pairs( CoalitionData ) do + + if DCSGroup:isExist() then + local DCSGroupName = DCSGroup:getName() + + self:E( { "Register Group:", DCSGroup, DCSGroupName } ) + self.DCSGroups[DCSGroupName] = DCSGroup + self.Groups[DCSGroupName] = GROUP:New( DCSGroup ) + + if self:_IsAliveDCSGroup(DCSGroup) then + self:E( { "Register Alive Group:", DCSGroup, DCSGroupName } ) + self.DCSGroupsAlive[DCSGroupName] = DCSGroup + self.GroupsAlive[DCSGroupName] = self.Groups[DCSGroupName] + end + + for DCSUnitId, DCSUnit in pairs( DCSGroup:getUnits() ) do + + local DCSUnitName = DCSUnit:getName() + self:E( { "Register Unit:", DCSUnit, DCSUnitName } ) + + self.DCSUnits[DCSUnitName] = DCSUnit + self:AddUnit( UNIT:Find( DCSUnit ) ) + --self.Units[DCSUnitName] = UNIT:Register( DCSUnit ) + + if self:_IsAliveDCSUnit(DCSUnit) then + self:E( { "Register Alive Unit:", DCSUnit, DCSUnitName } ) + self.DCSUnitsAlive[DCSUnitName] = DCSUnit + self.UnitsAlive[DCSUnitName] = self.Units[DCSUnitName] + end + end + else + self:E( "Group does not exist: " .. DCSGroup ) + end + + for ClientName, ClientTemplate in pairs( self.Templates.ClientsByName ) do + self.Clients[ClientName] = CLIENT:Find( ClientName ) + end + end + end + + return self +end + + +--- Events + +--- Handles the OnBirth event for the alive units set. +-- @param #SET self +-- @param Event#EVENTDATA Event +function SET:_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 + self:AddUnit( UNIT:Register( Event.IniDCSUnit ) ) + --self.Units[Event.IniDCSUnitName] = UNIT:Register( Event.IniDCSUnit ) + + --if not self.DCSGroups[Event.IniDCSGroupName] then + -- self.DCSGroups[Event.IniDCSGroupName] = Event.IniDCSGroupName + -- self.DCSGroupsAlive[Event.IniDCSGroupName] = Event.IniDCSGroupName + -- self.Groups[Event.IniDCSGroupName] = GROUP:New( Event.IniDCSGroup ) + --end + 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 + if self.DCSUnitsAlive[Event.IniDCSUnitName] then + self.DCSUnits[Event.IniDCSUnitName] = nil + self.DCSUnitsAlive[Event.IniDCSUnitName] = nil + 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:_IsIncludeDCSUnit( 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:_IsIncludeDCSUnit( 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 + + +function SET: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 + + self:_RegisterDatabase() + self:_RegisterPlayers() + + return self +end + + +--- +-- @param #SET self +-- @param DCSUnit#Unit DCSUnit +-- @return #SET self +function SET:_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 #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 + + diff --git a/Moose/Unit.lua b/Moose/Unit.lua index ee7c24357..16e585f5e 100644 --- a/Moose/Unit.lua +++ b/Moose/Unit.lua @@ -49,61 +49,40 @@ UNIT = { -- @field Orange -- @field Blue - ---- Finds the Unit from the _DATABASE. --- @param #UNIT self --- @param DCSUnit#Unit DCSUnit --- @return Unit#UNIT -function UNIT:New( DCSUnit ) - - if DCSUnit then - local UnitName = DCSUnit:getName() - if _DATABASE then - local UnitFound = _DATABASE:FindUnit( UnitName ) - if UnitFound then - return UnitFound - end - end - end - - self.UnitName = nil - return nil -end - --- Create a new UNIT from DCSUnit. -- @param #UNIT self -- @param DCSUnit#Unit DCSUnit -- @param Database#DATABASE Database -- @return Unit#UNIT -function UNIT:Register( DCSUnit ) +function UNIT:Register( UnitName ) - if DCSUnit then - local self = BASE:Inherit( self, BASE:New() ) - self:F( DCSUnit ) - self.UnitName = DCSUnit:getName() - return self - end - - self.UnitName = nil - return nil + local self = BASE:Inherit( self, BASE:New() ) + self:F( UnitName ) + self.UnitName = UnitName + return self end ---- Create a new UNIT from a Unit Name. + +--- Finds a UNIT from the _DATABASE using a DCSUnit object. +-- @param #UNIT self +-- @param DCSUnit#Unit DCSUnit +-- @return Unit#UNIT +function UNIT:Find( DCSUnit ) + + local UnitName = DCSUnit:getName() + local UnitFound = _DATABASE:FindUnit( UnitName ) + return UnitFound +end + +--- Find a UNIT in the _DATABASE using the name of the UNIT. -- @param #UNIT self -- @param #string Unit Name -- @return Unit#UNIT -function UNIT:NewFromName( UnitName ) - local self = BASE:Inherit( self, BASE:New() ) - self:F( UnitName ) - - local DCSUnit = Unit.getByName( UnitName ) - if DCSUnit then - self.UnitName = DCSUnit:getName() - return self - end - - self.UnitName = nil -- Sanitize - return nil +function UNIT:FindByName( UnitName ) +-- self:F( UnitName ) + + local FoundUnit = _DATABASE:FindUnit( UnitName ) + return FoundUnit end function UNIT:GetDCSUnit() @@ -182,7 +161,7 @@ function UNIT:IsAlive() return UnitIsAlive end - return nil + return false end --- Returns if the unit is activated. @@ -443,32 +422,46 @@ function UNIT:GetPointVec2() local DCSUnit = self:GetDCSUnit() if DCSUnit then - local UnitPos = DCSUnit:getPosition().p + local UnitPointVec3 = DCSUnit:getPosition().p - local UnitPoint = {} - UnitPoint.x = UnitPos.x - UnitPoint.y = UnitPos.z + local UnitPointVec2 = {} + UnitPointVec2.x = UnitPointVec3.x + UnitPointVec2.y = UnitPointVec3.z - self:T( UnitPoint ) - return UnitPoint + self:T( UnitPointVec2 ) + return UnitPointVec2 end return nil end +function UNIT:GetPointVec3() + self:F( self.UnitName ) + + local DCSUnit = self:GetDCSUnit() + + if DCSUnit then + local UnitPointVec3 = DCSUnit:getPosition().p + self:T( UnitPointVec3 ) + return UnitPointVec3 + end + + return nil +end + function UNIT:GetPositionVec3() self:F( self.UnitName ) local DCSUnit = self:GetDCSUnit() if DCSUnit then - local UnitPos = DCSUnit:getPosition().p - self:T( UnitPos ) - return UnitPos + local UnitPosition = DCSUnit:getPosition() + self:T( UnitPosition ) + return UnitPosition end - - return nil + + return nil end --- Returns the unit's velocity vector. @@ -505,26 +498,27 @@ function UNIT:InAir() return nil end -function UNIT:GetPositionVec3() - self:F( self.UnitName ) +--- Returns the altitude of the UNIT. +-- @param #UNIT self +-- @return DCSTypes#Distance +function UNIT:GetAltitude() + self:F() local DCSUnit = self:GetDCSUnit() if DCSUnit then - local UnitPos = DCSUnit:getPosition().p - self:T( UnitPos ) - return UnitPos + local UnitPointVec3 = DCSUnit:getPoint() --DCSTypes#Vec3 + return UnitPointVec3.y end return nil -end - +end function UNIT:OtherUnitInRadius( AwaitUnit, Radius ) self:F( { self.UnitName, AwaitUnit.UnitName, Radius } ) - local UnitPos = self:GetPositionVec3() - local AwaitUnitPos = AwaitUnit:GetPositionVec3() + local UnitPos = self:GetPointVec3() + local AwaitUnitPos = AwaitUnit:GetPointVec3() if (((UnitPos.x - AwaitUnitPos.x)^2 + (UnitPos.z - AwaitUnitPos.z)^2)^0.5 <= Radius) then self:T( "true" ) @@ -556,77 +550,77 @@ end -- @param #UNIT self function UNIT:Flare( FlareColor ) self:F() - trigger.action.signalFlare( self:GetPositionVec3(), FlareColor , 0 ) + trigger.action.signalFlare( self:GetPointVec3(), FlareColor , 0 ) end --- Signal a white flare at the position of the UNIT. -- @param #UNIT self function UNIT:FlareWhite() self:F() - trigger.action.signalFlare( self:GetPositionVec3(), trigger.flareColor.White , 0 ) + trigger.action.signalFlare( self:GetPointVec3(), trigger.flareColor.White , 0 ) end --- Signal a yellow flare at the position of the UNIT. -- @param #UNIT self function UNIT:FlareYellow() self:F() - trigger.action.signalFlare( self:GetPositionVec3(), trigger.flareColor.Yellow , 0 ) + trigger.action.signalFlare( self:GetPointVec3(), trigger.flareColor.Yellow , 0 ) end --- Signal a green flare at the position of the UNIT. -- @param #UNIT self function UNIT:FlareGreen() self:F() - trigger.action.signalFlare( self:GetPositionVec3(), trigger.flareColor.Green , 0 ) + trigger.action.signalFlare( self:GetPointVec3(), trigger.flareColor.Green , 0 ) end --- Signal a red flare at the position of the UNIT. -- @param #UNIT self function UNIT:FlareRed() self:F() - trigger.action.signalFlare( self:GetPositionVec3(), trigger.flareColor.Red, 0 ) + trigger.action.signalFlare( self:GetPointVec3(), trigger.flareColor.Red, 0 ) end --- Smoke the UNIT. -- @param #UNIT self function UNIT:Smoke( SmokeColor ) self:F() - trigger.action.smoke( self:GetPositionVec3(), SmokeColor ) + trigger.action.smoke( self:GetPointVec3(), SmokeColor ) end --- Smoke the UNIT Green. -- @param #UNIT self function UNIT:SmokeGreen() self:F() - trigger.action.smoke( self:GetPositionVec3(), trigger.smokeColor.Green ) + trigger.action.smoke( self:GetPointVec3(), trigger.smokeColor.Green ) end --- Smoke the UNIT Red. -- @param #UNIT self function UNIT:SmokeRed() self:F() - trigger.action.smoke( self:GetPositionVec3(), trigger.smokeColor.Red ) + trigger.action.smoke( self:GetPointVec3(), trigger.smokeColor.Red ) end --- Smoke the UNIT White. -- @param #UNIT self function UNIT:SmokeWhite() self:F() - trigger.action.smoke( self:GetPositionVec3(), trigger.smokeColor.White ) + trigger.action.smoke( self:GetPointVec3(), trigger.smokeColor.White ) end --- Smoke the UNIT Orange. -- @param #UNIT self function UNIT:SmokeOrange() self:F() - trigger.action.smoke( self:GetPositionVec3(), trigger.smokeColor.Orange ) + trigger.action.smoke( self:GetPointVec3(), trigger.smokeColor.Orange ) end --- Smoke the UNIT Blue. -- @param #UNIT self function UNIT:SmokeBlue() self:F() - trigger.action.smoke( self:GetPositionVec3(), trigger.smokeColor.Blue ) + trigger.action.smoke( self:GetPointVec3(), trigger.smokeColor.Blue ) end -- Is methods diff --git a/Presentations/DCS World - MOOSE - Development - Part 3 - The DATABASE - UNIT - CLIENT - GROUP - ZONE, .pptx b/Presentations/DCS World - MOOSE - Development - Part 3 - The DATABASE - UNIT - CLIENT - GROUP - ZONE, .pptx new file mode 100644 index 000000000..002c7ac64 Binary files /dev/null and b/Presentations/DCS World - MOOSE - Development - Part 3 - The DATABASE - UNIT - CLIENT - GROUP - ZONE, .pptx differ diff --git a/Test Missions/Moose_Test_TASK_Pickup_and_Deploy/MOOSE_Test_TASK_Pickup_and_Deploy.miz b/Test Missions/Moose_Test_TASK_Pickup_and_Deploy/MOOSE_Test_TASK_Pickup_and_Deploy.miz index 28934e59b..2c514f752 100644 Binary files a/Test Missions/Moose_Test_TASK_Pickup_and_Deploy/MOOSE_Test_TASK_Pickup_and_Deploy.miz and b/Test Missions/Moose_Test_TASK_Pickup_and_Deploy/MOOSE_Test_TASK_Pickup_and_Deploy.miz differ