@@ -31,16 +31,19 @@ function getPlayerSpeakerData(playerElement)
3131 return playerSpeakerData
3232end
3333
34- function clearPlayerSpeaker (playerOrSpeaker )
34+ function clearPlayerSpeaker (playerOrSpeaker , forceDestroy )
3535 for playerElement , speakerData in pairs (playerSpeakers ) do
3636 local speakerBox = speakerData .speakerBox
3737 local matchingElement = (playerElement == playerOrSpeaker ) or (speakerBox == playerOrSpeaker )
3838
3939 if (matchingElement ) then
40- local boxElement = isElement (speakerBox )
4140
42- if (boxElement ) then
43- destroyElement (speakerBox )
41+ if (forceDestroy ) then
42+ local boxElement = isElement (speakerBox )
43+
44+ if (boxElement ) then
45+ destroyElement (speakerBox )
46+ end
4447 end
4548
4649 playerSpeakers [playerElement ] = nil
@@ -52,6 +55,25 @@ function clearPlayerSpeaker(playerOrSpeaker)
5255 return false
5356end
5457
58+ function isObjectSpeaker (objectElement )
59+ local validElement = isElement (objectElement )
60+
61+ if (not validElement ) then
62+ return false
63+ end
64+
65+ for playerElement , speakerData in pairs (playerSpeakers ) do
66+ local speakerBox = speakerData .speakerBox
67+ local matchingElement = (speakerBox == objectElement )
68+
69+ if (matchingElement ) then
70+ return true
71+ end
72+ end
73+
74+ return false
75+ end
76+
5577function onServerCreateSpeaker (streamURL )
5678 if (not client ) then
5779 return false
@@ -69,16 +91,7 @@ function onServerCreateSpeaker(streamURL)
6991 return false
7092 end
7193
72- local playerSpeakerData = getPlayerSpeakerData (client )
73-
74- if (playerSpeakerData ) then
75- local speakerBox = playerSpeakerData .speakerBox
76- local speakerElement = isElement (speakerBox )
77-
78- if (speakerElement ) then
79- destroyElement (speakerBox )
80- end
81- end
94+ clearPlayerSpeaker (client , true )
8295
8396 local playerPosX , playerPosY , playerPosZ = getElementPosition (client )
8497 local playerInterior = getElementInterior (client )
@@ -148,18 +161,7 @@ function onServerDestroySpeaker()
148161 return false
149162 end
150163
151- local playerSpeakerData = getPlayerSpeakerData (client )
152-
153- if (not playerSpeakerData ) then
154- return false
155- end
156-
157- local speakerBox = playerSpeakerData .speakerBox
158- local speakerElement = isElement (speakerBox )
159-
160- if (speakerElement ) then
161- destroyElement (speakerBox )
162- end
164+ clearPlayerSpeaker (client , true )
163165end
164166addEvent (" onServerDestroySpeaker" , true )
165167addEventHandler (" onServerDestroySpeaker" , root , onServerDestroySpeaker )
@@ -175,11 +177,102 @@ function syncSpeakers(startedResource)
175177end
176178addEventHandler (" onPlayerResourceStart" , root , syncSpeakers )
177179
178- function clearSpeakersOnDestroyQuit ()
179- clearPlayerSpeaker (source )
180+ function clearSpeakerOnPlayerQuit ()
181+ clearPlayerSpeaker (source , true )
182+ end
183+ addEventHandler (" onPlayerQuit" , root , clearSpeakerOnPlayerQuit )
184+
185+ function clearSpeakerOnElementDestroy ()
186+ clearPlayerSpeaker (source , false )
187+ end
188+ addEventHandler (" onElementDestroy" , resourceRoot , clearSpeakerOnElementDestroy )
189+
190+ function destroySpeakerAdminCommand (playerElement , _ , targetPlayer )
191+ local hasPlayerRightToDestroySpeaker = hasObjectPermissionTo (playerElement , RADIO_DESTROY_SPEAKER_ACCESS_RIGHT , false )
192+
193+ if (not hasPlayerRightToDestroySpeaker ) then
194+ outputChatBox (" #ff8800[Speakers]: #ffffffYou have no access to #ff8800/" .. RADIO_DESTROY_SPEAKER_COMMAND , playerElement , 255 , 255 , 255 , true )
195+
196+ return false
197+ end
198+
199+ if (not targetPlayer ) then
200+ outputChatBox (" #ff8800[Speakers]: #ffffffSyntax: #ff8800/" .. RADIO_DESTROY_SPEAKER_COMMAND .. " <playerName>" , playerElement , 255 , 255 , 255 , true )
201+
202+ return false
203+ end
204+
205+ local playerFromName = getPlayerFromPartialName (targetPlayer )
206+
207+ if (not playerFromName ) then
208+ outputChatBox (" #ff8800[Speakers]: #ffffffPlayer #ff8800" .. targetPlayer .. " #ffffffnot found." , playerElement , 255 , 255 , 255 , true )
209+
210+ return false
211+ end
212+
213+ local speakerFound = clearPlayerSpeaker (playerFromName , true )
214+ local speakerDestroyed = (speakerFound and " Successfully destroyed #ff8800" .. targetPlayer .. " #ffffff speaker." or " Player #ff8800" .. targetPlayer .. " #ffffff has no speaker." )
215+ local speakerDestroyedMessage = " #ff8800[Speakers]: #ffffff" .. speakerDestroyed
216+
217+ outputChatBox (speakerDestroyedMessage , playerElement , 255 , 255 , 255 , true )
218+ end
219+ addCommandHandler (RADIO_DESTROY_SPEAKER_COMMAND , destroySpeakerAdminCommand )
220+
221+ function destroySpeakersInRangeAdminCommand (playerElement , _ , searchRange )
222+ local hasPlayerRightToDestroySpeaker = hasObjectPermissionTo (playerElement , RADIO_DESTROY_SPEAKERS_IN_RANGE_ACCESS_RIGHT , false )
223+
224+ if (not hasPlayerRightToDestroySpeaker ) then
225+ outputChatBox (" #ff8800[Speakers]: #ffffffYou have no access to #ff8800/" .. RADIO_DESTROY_SPEAKERS_IN_RANGE_COMMAND , playerElement , 255 , 255 , 255 , true )
226+
227+ return false
228+ end
229+
230+ local speakerSearchRange = tonumber (searchRange )
231+ local validSearchRange = (speakerSearchRange and speakerSearchRange > 0 )
232+
233+ if (not speakerSearchRange or not validSearchRange ) then
234+ outputChatBox (" #ff8800[Speakers]: #ffffffSyntax: #ff8800/" .. RADIO_DESTROY_SPEAKERS_IN_RANGE_COMMAND .. " <searchRange>" , playerElement , 255 , 255 , 255 , true )
235+
236+ return false
237+ end
238+
239+ local objectsTable = getElementsByType (" object" , resourceRoot )
240+ local playerInterior = getElementInterior (playerElement )
241+ local playerDimension = getElementDimension (playerElement )
242+ local playerX , playerY , playerZ = getElementPosition (playerElement )
243+ local totalDestroyedSpeakers = 0
244+
245+ for objectID = 1 , # objectsTable do
246+ local objectElement = objectsTable [objectID ]
247+ local objectSpeaker = isObjectSpeaker (objectElement )
248+
249+ if (objectSpeaker ) then
250+ local speakerInterior = getElementInterior (objectElement )
251+ local speakerDimension = getElementDimension (objectElement )
252+ local matchingInterior = (speakerInterior == playerInterior )
253+ local matchingDimension = (speakerDimension == playerDimension )
254+
255+ if (matchingInterior and matchingDimension ) then
256+ local speakerX , speakerY , speakerZ = getElementPosition (objectElement )
257+ local distanceToSpeaker = getDistanceBetweenPoints3D (playerX , playerY , playerZ , speakerX , speakerY , speakerZ )
258+ local speakerInDistance = (distanceToSpeaker <= speakerSearchRange )
259+
260+ if (speakerInDistance ) then
261+ local speakerDestroyed = clearPlayerSpeaker (objectElement , true )
262+
263+ if (speakerDestroyed ) then
264+ local newCountOfDestroyedSpeakers = (totalDestroyedSpeakers + 1 )
265+
266+ totalDestroyedSpeakers = newCountOfDestroyedSpeakers
267+ end
268+ end
269+ end
270+ end
271+ end
272+
273+ outputChatBox (" #ff8800[Speakers]: #ffffffDestroyed #ff8800" .. totalDestroyedSpeakers .. " #ffffff total speakers in range of #ff8800" .. speakerSearchRange , playerElement , 255 , 255 , 255 , true )
180274end
181- addEventHandler (" onPlayerQuit" , root , clearSpeakersOnDestroyQuit )
182- addEventHandler (" onElementDestroy" , resourceRoot , clearSpeakersOnDestroyQuit )
275+ addCommandHandler (RADIO_DESTROY_SPEAKERS_IN_RANGE_COMMAND , destroySpeakersInRangeAdminCommand )
183276
184277function destroyAttachedRadioOnVehicleExplodeOrDestroy ()
185278 local validElement = isElement (source )
@@ -203,9 +296,9 @@ function destroyAttachedRadioOnVehicleExplodeOrDestroy()
203296 local attachedElementObject = (attachedElementType == " object" )
204297
205298 if (attachedElementObject ) then
206- local boxFound = clearPlayerSpeaker (attachedElement )
299+ local speakerFound = clearPlayerSpeaker (attachedElement , true )
207300
208- if (boxFound ) then
301+ if (speakerFound ) then
209302 break
210303 end
211304 end
0 commit comments