From 971f5e9ca491aceae2f517e686032a38aeeee740 Mon Sep 17 00:00:00 2001 From: Sven Van de Velde Date: Thu, 12 May 2016 14:53:28 +0200 Subject: [PATCH] Updates --- Moose/Client.lua | 42 ++++- Moose/Database.lua | 21 +-- Moose/MissileTrainer.lua | 158 +++++++++++------- Moose/Unit.lua | 13 +- .../Moose_Test_MISSILETRAINER.miz | Bin 114890 -> 115947 bytes 5 files changed, 154 insertions(+), 80 deletions(-) diff --git a/Moose/Client.lua b/Moose/Client.lua index be60463fb..9489d8019 100644 --- a/Moose/Client.lua +++ b/Moose/Client.lua @@ -12,7 +12,7 @@ Include.File( "Message" ) --- The CLIENT class -- @type CLIENT --- @extends Unit#UNIT +-- @extends Base#BASE CLIENT = { ONBOARDSIDE = { NONE = 0, @@ -48,7 +48,7 @@ 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, UNIT:New( Unit.getByName( ClientName ) ) ) + local self = BASE:Inherit( self, BASE:New() ) self:F( ClientName, ClientBriefing ) self.ClientName = ClientName @@ -319,6 +319,44 @@ function CLIENT:GetPointVec2() 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 diff --git a/Moose/Database.lua b/Moose/Database.lua index 7b1f216df..bca8306b1 100644 --- a/Moose/Database.lua +++ b/Moose/Database.lua @@ -413,6 +413,7 @@ function DATABASE:_RegisterGroup( GroupTemplate ) self.Templates.Units[UnitTemplateName].GroupName = GroupTemplateName self.Templates.Units[UnitTemplateName].GroupTemplate = GroupTemplate self.Templates.Units[UnitTemplateName].GroupId = GroupTemplate.groupId + self:E( {"skill",UnitTemplate.skill}) if UnitTemplate.skill and (UnitTemplate.skill == "Client" or UnitTemplate.skill == "Player") then self.Templates.ClientsByName[UnitTemplateName] = UnitTemplate self.Templates.ClientsByID[UnitTemplate.unitId] = UnitTemplate @@ -477,11 +478,10 @@ function DATABASE:_RegisterDatabase() self.DCSUnitsAlive[DCSUnitName] = DCSUnit self.UnitsAlive[DCSUnitName] = self.Units[DCSUnitName] end - - if self.Templates.ClientsByName[DCSUnitName] then - self.Clients[DCSUnitName] = CLIENT:New( DCSUnitName ) - end - + end + + for ClientName, ClientTemplate in pairs( self.Templates.ClientsByName ) do + self.Clients[ClientName] = CLIENT:New( ClientName ) end end end @@ -504,11 +504,12 @@ function DATABASE:_EventOnBirth( Event ) self.DCSUnitsAlive[Event.IniDCSUnitName] = Event.IniDCSUnit self.Units[Event.IniDCSUnitName] = UNIT:New( 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 + --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 diff --git a/Moose/MissileTrainer.lua b/Moose/MissileTrainer.lua index eaed63155..e3b19f8b6 100644 --- a/Moose/MissileTrainer.lua +++ b/Moose/MissileTrainer.lua @@ -36,34 +36,39 @@ function MISSILETRAINER:New( Distance ) self.DBUnits = self.DB.Units for ClientID, Client in pairs( self.DBClients ) do - Client:Message( "Welcome to the Missile Trainer", 10, "ID", "TEST" ) - - Client.MainMenu = MENU_CLIENT:New( Client, "Missile Trainer", nil ) - - Client.MenuMessages = MENU_CLIENT:New( Client, "Messages", Client.MainMenu ) - Client.MenuOn = MENU_CLIENT_COMMAND:New( Client, "Messages On", Client.MenuMessages, self._MenuMessages, { MenuSelf = self, MessagesOnOff = true } ) - Client.MenuOff = MENU_CLIENT_COMMAND:New( Client, "Messages Off", Client.MenuMessages, self._MenuMessages, { MenuSelf = self, MessagesOnOff = false } ) - - Client.MenuTracking = MENU_CLIENT:New( Client, "Tracking", Client.MainMenu ) - Client.MenuTrackingToAll = MENU_CLIENT_COMMAND:New( Client, "To All", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingToAll = true } ) - Client.MenuTrackingToTarget = MENU_CLIENT_COMMAND:New( Client, "To Target", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingToAll = false } ) - Client.MenuTrackOn = MENU_CLIENT_COMMAND:New( Client, "Tracking On", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, Tracking = true } ) - Client.MenuTrackOff = MENU_CLIENT_COMMAND:New( Client, "Tracking Off", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, Tracking = false } ) - - Client.MenuAlerts = MENU_CLIENT:New( Client, "Alerts", Client.MainMenu ) - Client.MenuAlertsToAll = MENU_CLIENT_COMMAND:New( Client, "To All", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsToAll = true } ) - Client.MenuAlertsToTarget = MENU_CLIENT_COMMAND:New( Client, "To Target", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsToAll = false } ) - Client.MenuHitsOn = MENU_CLIENT_COMMAND:New( Client, "Hits On", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsHits = true } ) - Client.MenuHitsOff = MENU_CLIENT_COMMAND:New( Client, "Hits Off", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsHits = false } ) - Client.MenuLaunchesOn = MENU_CLIENT_COMMAND:New( Client, "Launches On", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsLaunches = true } ) - Client.MenuLaunchesOff = MENU_CLIENT_COMMAND:New( Client, "Launches Off", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsLaunches = false } ) - - Client.MenuDetails = MENU_CLIENT:New( Client, "Details", Client.MainMenu ) - Client.MenuDetailsDistanceOn = MENU_CLIENT_COMMAND:New( Client, "Range On", Client.MenuDetails, self._MenuMessages, { MenuSelf = self, DetailsRange = true } ) - Client.MenuDetailsDistanceOff = MENU_CLIENT_COMMAND:New( Client, "Range Off", Client.MenuDetails, self._MenuMessages, { MenuSelf = self, DetailsRange = false } ) - Client.MenuDetailsBearingOn = MENU_CLIENT_COMMAND:New( Client, "Bearing On", Client.MenuDetails, self._MenuMessages, { MenuSelf = self, DetailsBearing = true } ) - Client.MenuDetailsBearingOff = MENU_CLIENT_COMMAND:New( Client, "Bearing Off", Client.MenuDetails, self._MenuMessages, { MenuSelf = self, DetailsBearing = false } ) - + + local function _Alive( Client ) + + Client:Message( "Welcome to the Missile Trainer", 10, "ID", "TEST" ) + + Client.MainMenu = MENU_CLIENT:New( Client, "Missile Trainer", nil ) + + Client.MenuMessages = MENU_CLIENT:New( Client, "Messages", Client.MainMenu ) + Client.MenuOn = MENU_CLIENT_COMMAND:New( Client, "Messages On", Client.MenuMessages, self._MenuMessages, { MenuSelf = self, MessagesOnOff = true } ) + Client.MenuOff = MENU_CLIENT_COMMAND:New( Client, "Messages Off", Client.MenuMessages, self._MenuMessages, { MenuSelf = self, MessagesOnOff = false } ) + + Client.MenuTracking = MENU_CLIENT:New( Client, "Tracking", Client.MainMenu ) + Client.MenuTrackingToAll = MENU_CLIENT_COMMAND:New( Client, "To All", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingToAll = true } ) + Client.MenuTrackingToTarget = MENU_CLIENT_COMMAND:New( Client, "To Target", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingToAll = false } ) + Client.MenuTrackOn = MENU_CLIENT_COMMAND:New( Client, "Tracking On", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, Tracking = true } ) + Client.MenuTrackOff = MENU_CLIENT_COMMAND:New( Client, "Tracking Off", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, Tracking = false } ) + + Client.MenuAlerts = MENU_CLIENT:New( Client, "Alerts", Client.MainMenu ) + Client.MenuAlertsToAll = MENU_CLIENT_COMMAND:New( Client, "To All", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsToAll = true } ) + Client.MenuAlertsToTarget = MENU_CLIENT_COMMAND:New( Client, "To Target", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsToAll = false } ) + Client.MenuHitsOn = MENU_CLIENT_COMMAND:New( Client, "Hits On", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsHits = true } ) + Client.MenuHitsOff = MENU_CLIENT_COMMAND:New( Client, "Hits Off", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsHits = false } ) + Client.MenuLaunchesOn = MENU_CLIENT_COMMAND:New( Client, "Launches On", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsLaunches = true } ) + Client.MenuLaunchesOff = MENU_CLIENT_COMMAND:New( Client, "Launches Off", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsLaunches = false } ) + + Client.MenuDetails = MENU_CLIENT:New( Client, "Details", Client.MainMenu ) + Client.MenuDetailsDistanceOn = MENU_CLIENT_COMMAND:New( Client, "Range On", Client.MenuDetails, self._MenuMessages, { MenuSelf = self, DetailsRange = true } ) + Client.MenuDetailsDistanceOff = MENU_CLIENT_COMMAND:New( Client, "Range Off", Client.MenuDetails, self._MenuMessages, { MenuSelf = self, DetailsRange = false } ) + Client.MenuDetailsBearingOn = MENU_CLIENT_COMMAND:New( Client, "Bearing On", Client.MenuDetails, self._MenuMessages, { MenuSelf = self, DetailsBearing = true } ) + Client.MenuDetailsBearingOff = MENU_CLIENT_COMMAND:New( Client, "Bearing Off", Client.MenuDetails, self._MenuMessages, { MenuSelf = self, DetailsBearing = false } ) + end + + Client:Alive( _Alive ) end -- self.DB:ForEachClient( @@ -145,10 +150,9 @@ function MISSILETRAINER:_EventShot( Event ) local TrainerTargetDCSUnit = TrainerWeapon:getTarget() -- Identify target local TrainerTargetDCSUnitName = Unit.getName( TrainerTargetDCSUnit ) - local TrainerTargetDCSGroup = TrainerTargetDCSUnit:getGroup() - local TrainerTargetDCSGroupName = TrainerTargetDCSGroup:getName() local TrainerTargetSkill = _DATABASE.Templates.Units[TrainerTargetDCSUnitName].Template.skill + self:T(TrainerTargetDCSUnitName ) local Client = self.DBClients[TrainerTargetDCSUnitName] if Client then @@ -271,46 +275,70 @@ function MISSILETRAINER:_TrackMissiles() local TrainerWeapon = MissileData.TrainerWeapon local TrainerTargetUnit = MissileData.TrainerTargetUnit - local PositionMissile = TrainerWeapon:getPosition().p - local PositionTarget = Client:GetPositionVec3() + if 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 Distance = ( ( PositionMissile.x - PositionTarget.x )^2 + + ( PositionMissile.y - PositionTarget.y )^2 + + ( PositionMissile.z - PositionTarget.z )^2 + ) ^ 0.5 + + if Distance <= self.Distance then + -- Hit alert + TrainerWeapon:destroy() + if self.MessagesOnOff and self.AlertsHits then - local Distance = ( ( PositionMissile.x - PositionTarget.x )^2 + - ( PositionMissile.y - PositionTarget.y )^2 + - ( PositionMissile.z - PositionTarget.z )^2 - ) ^ 0.5 - - if Distance <= self.Distance then - -- Hit alert - TrainerWeapon:destroy() - if self.MessagesOnOff and self.AlertsHits then - - self:T( "Destroyed" ) - - local Message = MESSAGE:New( - string.format( "%s launched by %s destroyed", - TrainerWeapon:getTypeName(), - TrainerSourceUnit:GetTypeName() - ),"Tracking", 2, "ID" ) - - if self.AlertsToAll then - Message:ToAll() - else - Message:ToClient( Client ) + self:T( "killed" ) + + local Message = MESSAGE:New( + string.format( "%s launched by %s killed '%s'", + TrainerWeapon:getTypeName(), + TrainerSourceUnit:GetTypeName(), + TrainerSourceUnit:GetPlayerName() + ),"Tracking", 15, "ID" ) + + if self.AlertsToAll then + Message:ToAll() + else + Message:ToClient( Client ) + end + + MissileData = nil + table.remove( TrackingData.MissileData, MissileDataID ) + self:T(TrackingData.MissileData) + end + else + local TrackingTo = string.format( " -> %s launched by %s", + TrainerWeapon:getTypeName(), + TrainerSourceUnit:GetName() + ) + + if ClientDataID == TrackingDataID then + ClientData.MessageToClient = ClientData.MessageToClient .. TrackingTo .. self:AddRange( ClientData.Client, TrainerWeapon ) .. self:AddBearing( ClientData.Client, TrainerWeapon ) .. "\n" + else + ClientData.MessageToAll = ClientData.MessageToAll .. TrackingTo .. self:AddRange( TrackingData.Client, TrainerWeapon ) .. self:AddBearing( TrackingData.Client, TrainerWeapon ) .. "\n" end - - MissileData = nil - table.remove( TrackingData.MissileData, MissileDataID ) end else - local TrackingTo = string.format( " -> %s launched by %s", - TrainerWeapon:getTypeName(), - TrainerSourceUnit:GetName() - ) + if not ( TrainerWeapon and TrainerWeapon:isExist() ) then + if self.MessagesOnOff and self.AlertsLaunches then + -- Weapon does not exist anymore. Delete from Table + local Message = MESSAGE:New( + string.format( "%s launched by %s is self destructed!", + TrainerWeapon:getTypeName(), + TrainerSourceUnit:GetTypeName() + ),"Tracking", 5, "ID" ) - if ClientDataID == TrackingDataID then - ClientData.MessageToClient = ClientData.MessageToClient .. TrackingTo .. self:AddRange( ClientData.Client, TrainerWeapon ) .. self:AddBearing( ClientData.Client, TrainerWeapon ) .. "\n" - else - ClientData.MessageToAll = ClientData.MessageToAll .. TrackingTo .. self:AddRange( TrackingData.Client, TrainerWeapon ) .. self:AddBearing( TrackingData.Client, TrainerWeapon ) .. "\n" + if self.AlertsToAll then + Message:ToAll() + else + Message:ToClient( Client ) + end + end + MissileData = nil + table.remove( TrackingData.MissileData, MissileDataID ) + self:T(TrackingData.MissileData) end end end diff --git a/Moose/Unit.lua b/Moose/Unit.lua index a6091a77c..4cea12dbb 100644 --- a/Moose/Unit.lua +++ b/Moose/Unit.lua @@ -56,11 +56,13 @@ UNIT = { -- @return Unit#UNIT function UNIT:New( DCSUnit ) local self = BASE:Inherit( self, BASE:New() ) - self:F( DCSUnit:getName() ) + self:F( DCSUnit ) self.DCSUnit = DCSUnit - self.UnitName = DCSUnit:getName() - self.UnitID = DCSUnit:getID() + if DCSUnit then + self.UnitName = DCSUnit:getName() + self.UnitID = DCSUnit:getID() + end return self end @@ -91,6 +93,11 @@ function UNIT:GetName() return self.UnitName end +function UNIT:GetPlayerName() + self:F( self.UnitName ) + + return self.DCSUnit:getPlayerName() +end function UNIT:GetTypeName() self:F( self.UnitName ) diff --git a/Test Missions/Moose_Test_MISSILETRAINER/Moose_Test_MISSILETRAINER.miz b/Test Missions/Moose_Test_MISSILETRAINER/Moose_Test_MISSILETRAINER.miz index aa99ee89791f756cfd0943a160c18a849a8f0294..1bba5cd294ac83b9ebe4d696729315f8d9012721 100644 GIT binary patch delta 7890 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 delta 6798 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