4 | rp-radio
5 |
6 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Fraser
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/config.lua:
--------------------------------------------------------------------------------
1 | radioConfig = {
2 | Controls = {
3 | Activator = { -- Open/Close Radio
4 | Name = "INPUT_REPLAY_START_STOP_RECORDING_SECONDARY", -- Control name
5 | Key = 289, -- F2
6 | },
7 | Secondary = {
8 | Name = "INPUT_SPRINT",
9 | Key = 21, -- Left Shift
10 | Enabled = true, -- Require secondary to be pressed to open radio with Activator
11 | },
12 | Toggle = { -- Toggle radio on/off
13 | Name = "INPUT_CONTEXT", -- Control name
14 | Key = 51, -- E
15 | },
16 | Increase = { -- Increase Frequency
17 | Name = "INPUT_CELLPHONE_RIGHT", -- Control name
18 | Key = 175, -- Right Arrow
19 | Pressed = false,
20 | },
21 | Decrease = { -- Decrease Frequency
22 | Name = "INPUT_CELLPHONE_LEFT", -- Control name
23 | Key = 174, -- Left Arrow
24 | Pressed = false,
25 | },
26 | Input = { -- Choose Frequency
27 | Name = "INPUT_FRONTEND_ACCEPT", -- Control name
28 | Key = 201, -- Enter
29 | Pressed = false,
30 | },
31 | Broadcast = {
32 | Name = "INPUT_VEH_PUSHBIKE_SPRINT", -- Control name
33 | Key = 137, -- Caps Lock
34 | },
35 | ToggleClicks = { -- Toggle radio click sounds
36 | Name = "INPUT_SELECT_WEAPON", -- Control name
37 | Key = 37, -- Tab
38 | }
39 | },
40 | Frequency = {
41 | Private = { -- List of private frequencies
42 | [1] = true, -- Make 1 a private frequency
43 | }, -- List of private frequencies
44 | Current = 1, -- Don't touch
45 | CurrentIndex = 1, -- Don't touch
46 | Min = 1, -- Minimum frequency
47 | Max = 1000, -- Max number of frequencies
48 | List = {}, -- Frequency list, Don't touch
49 | Access = {}, -- List of freqencies a player has access to
50 | },
51 | AllowRadioWhenClosed = false -- Allows the radio to be used when not open (uses police radio animation)
52 | }
53 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Deprecated you should use [pma-radio](https://github.com/AvarianKnight/pma-radio/) instead.
2 |
3 | # rp-radio
4 | All credits go to Frazzle for making this, this is just an adapted version for pma-voice.
5 |
6 | #### Note
7 | By default the radio is disabled (its meant to be used as an in-game item) to give players the radio by default in the client.lua at the top change `Radio.Has` to `true`, if you would like to make it an item look at the replies on the FiveM forum post, there is a tutorial for adding it as an ESX item.
8 |
9 | The export that is used to give/take a players radio is `exports["rp-radio"]:SetRadio(true/false)` or the event `Radio.Set`
10 |
11 | ### Exports
12 | Getters
13 |
14 | | Export | Description | Return type |
15 | | ---------------- | --------------------------------------------------- | ----------- |
16 | | IsRadioOpen | Check if player is holding radio | bool |
17 | | IsRadioOn | Check if radio is switched on | bool |
18 | | IsRadioAvailable | Check if player has a radio | bool |
19 | | IsRadioEnabled | Check if radio is enabled | bool |
20 | | CanRadioBeUsed | Check if radio can be used | bool |
21 |
22 | Setters
23 |
24 | | Export | Description | Parameter(s) |
25 | | ------------------------------- | ----------------------------------------------------------- | ------------- |
26 | | SetRadioEnabled | Set if the radio is enabled or not | bool |
27 | | SetRadio | Set if player has a radio or not | bool |
28 | | SetAllowRadioWhenClosed | Allow player to broadcast when closed | bool |
29 | | AddPrivateFrequency | Make a frequency private | int |
30 | | RemovePrivateFrequency | Make a private frequency public | int |
31 | | GivePlayerAccessToFrequency | Give a player access to use a private frequency | int |
32 | | RemovePlayerAccessToFrequency | Remove a players access to use a private frequency | int |
33 | | GivePlayerAccessToFrequencies | Give a player access to use multiple private frequencies | int, int, ... |
34 | | RemovePlayerAccessToFrequencies | Remove a players access to use multiple private frequencies | int, int, ... |
35 |
36 | ### Commands
37 |
38 | | Command | Description |
39 | | ---------- | ------------------------ |
40 | | /radio | Open/close the radio |
41 | | /frequency | Choose radio frequency |
42 |
43 | ### Events
44 |
45 | | Event | Description | Paramters(s) |
46 | | ------------ | -------------------------------- | ---------------------- |
47 | | Radio.Toggle | Opens/close the radio | none |
48 | | Radio.Set | Set if player has a radio or not | bool |
49 |
50 | ### Preview
51 |
52 | - [MP4](https://imgur.com/bAT0mls)
53 |
--------------------------------------------------------------------------------
/client.lua:
--------------------------------------------------------------------------------
1 | local Radio = {
2 | Has = true,
3 | Open = false,
4 | On = false,
5 | Enabled = true,
6 | Handle = nil,
7 | Prop = GetHashKey('prop_cs_hand_radio'), -- only ran once and doesn't break my syntax viewer
8 | Bone = 28422,
9 | Offset = vector3(0.0, 0.0, 0.0),
10 | Rotation = vector3(0.0, 0.0, 0.0),
11 | Dictionary = {
12 | "cellphone@",
13 | "cellphone@in_car@ds",
14 | "cellphone@str",
15 | "random@arrests",
16 | },
17 | Animation = {
18 | "cellphone_text_in",
19 | "cellphone_text_out",
20 | "cellphone_call_listen_a",
21 | "generic_radio_chatter",
22 | },
23 | Clicks = true, -- Radio clicks
24 | }
25 | Radio.Labels = {
26 | { "FRZL_RADIO_HELP", "~s~" .. (radioConfig.Controls.Secondary.Enabled and "~" .. radioConfig.Controls.Secondary.Name .. "~ + ~" .. radioConfig.Controls.Activator.Name .. "~" or "~" .. radioConfig.Controls.Activator.Name .. "~") .. " to hide.~n~~" .. radioConfig.Controls.Toggle.Name .. "~ to turn radio ~g~on~s~.~n~~" .. radioConfig.Controls.Decrease.Name .. "~ or ~" .. radioConfig.Controls.Increase.Name .. "~ to switch frequency~n~~" .. radioConfig.Controls.Input.Name .. "~ to choose frequency~n~~" .. radioConfig.Controls.ToggleClicks.Name .. "~ to ~a~ mic clicks~n~Frequency: ~1~ MHz" },
27 | { "FRZL_RADIO_HELP2", "~s~" .. (radioConfig.Controls.Secondary.Enabled and "~" .. radioConfig.Controls.Secondary.Name .. "~ + ~" .. radioConfig.Controls.Activator.Name .. "~" or "~" .. radioConfig.Controls.Activator.Name .. "~") .. " to hide.~n~~" .. radioConfig.Controls.Toggle.Name .. "~ to turn radio ~r~off~s~.~n~~" .. radioConfig.Controls.Broadcast.Name .. "~ to broadcast.~n~Frequency: ~1~ MHz" },
28 | { "FRZL_RADIO_INPUT", "Enter Frequency" },
29 | }
30 | local unarmed = GetHashKey('weapon_unarmed')
31 | Radio.Commands = {
32 | {
33 | Enabled = true, -- Add a command to be able to open/close the radio
34 | Name = "radio", -- Command name
35 | Help = "Toggle hand radio", -- Command help shown in chatbox when typing the command
36 | Params = {},
37 | Handler = function(src, args, raw)
38 | local playerPed = PlayerPedId()
39 | local isFalling = IsPedFalling(playerPed)
40 | local isDead = IsEntityDead(playerPed)
41 |
42 | if not isFalling and Radio.Enabled and Radio.Has and not isDead then
43 | Radio:Toggle(not Radio.Open)
44 | elseif (Radio.Open or Radio.On) and ((not Radio.Enabled) or (not Radio.Has) or isDead) then
45 | Radio:Toggle(false)
46 | Radio.On = false
47 | Radio:Remove()
48 | exports["pma-voice"]:setVoiceProperty("radioEnabled", false)
49 | elseif Radio.Open and isFalling then
50 | Radio:Toggle(false)
51 | end
52 | end,
53 | },
54 | {
55 | Enabled = true, -- Add a command to choose radio frequency
56 | Name = "frequency", -- Command name
57 | Help = "Change radio frequency", -- Command help shown in chatbox when typing the command
58 | Params = {
59 | {name = "number", "Enter frequency"}
60 | },
61 | Handler = function(src, args, raw)
62 | if Radio.Has then
63 | if args[1] then
64 | local newFrequency = tonumber(args[1])
65 | if newFrequency then
66 | local minFrequency = radioConfig.Frequency.List[1]
67 | if newFrequency >= minFrequency and newFrequency <= radioConfig.Frequency.List[#radioConfig.Frequency.List] and newFrequency == math.floor(newFrequency) then
68 | if not radioConfig.Frequency.Private[newFrequency] or radioConfig.Frequency.Access[newFrequency] then
69 | local idx = nil
70 |
71 | for i = 1, #radioConfig.Frequency.List do
72 | if radioConfig.Frequency.List[i] == newFrequency then
73 | idx = i
74 | break
75 | end
76 | end
77 |
78 | if idx ~= nil then
79 | if Radio.Enabled then
80 | Radio:Remove()
81 | end
82 |
83 | radioConfig.Frequency.CurrentIndex = idx
84 | radioConfig.Frequency.Current = newFrequency
85 |
86 | if Radio.On then
87 | Radio:Add(radioConfig.Frequency.Current)
88 | end
89 | end
90 | end
91 | end
92 | end
93 | end
94 | end
95 | end,
96 | },
97 | }
98 |
99 | -- Setup each radio command if enabled
100 | for i = 1, #Radio.Commands do
101 | if Radio.Commands[i].Enabled then
102 | RegisterCommand(Radio.Commands[i].Name, Radio.Commands[i].Handler, false)
103 | TriggerEvent("chat:addSuggestion", "/" .. Radio.Commands[i].Name, Radio.Commands[i].Help, Radio.Commands[i].Params)
104 | end
105 | end
106 |
107 | -- Create/Destroy handheld radio object
108 | function Radio:Toggle(toggle)
109 | local playerPed = PlayerPedId()
110 | local count = 0
111 |
112 | if not self.Has or IsEntityDead(playerPed) then
113 | self.Open = false
114 |
115 | DetachEntity(self.Handle, true, false)
116 | DeleteEntity(self.Handle)
117 |
118 | return
119 | end
120 |
121 | if self.Open == toggle then
122 | return
123 | end
124 |
125 | self.Open = toggle
126 |
127 | if self.On and not radioConfig.AllowRadioWhenClosed then
128 | exports["pma-voice"]:setVoiceProperty("radioEnabled", toggle)
129 | end
130 |
131 | local dictionaryType = 1 + (IsPedInAnyVehicle(playerPed, false) and 1 or 0)
132 | local animationType = 1 + (self.Open and 0 or 1)
133 | local dictionary = self.Dictionary[dictionaryType]
134 | local animation = self.Animation[animationType]
135 |
136 | RequestAnimDict(dictionary)
137 |
138 | while not HasAnimDictLoaded(dictionary) do
139 | Citizen.Wait(150)
140 | end
141 |
142 | if self.Open then
143 | RequestModel(self.Prop)
144 |
145 | while not HasModelLoaded(self.Prop) do
146 | Citizen.Wait(150)
147 | end
148 |
149 | self.Handle = CreateObject(self.Prop, 0.0, 0.0, 0.0, true, true, false)
150 |
151 | local bone = GetPedBoneIndex(playerPed, self.Bone)
152 |
153 | SetCurrentPedWeapon(playerPed, unarmed, true)
154 | AttachEntityToEntity(self.Handle, playerPed, bone, self.Offset.x, self.Offset.y, self.Offset.z, self.Rotation.x, self.Rotation.y, self.Rotation.z, true, false, false, false, 2, true)
155 |
156 | SetModelAsNoLongerNeeded(self.Handle)
157 |
158 | TaskPlayAnim(playerPed, dictionary, animation, 4.0, -1, -1, 50, 0, false, false, false)
159 | else
160 | TaskPlayAnim(playerPed, dictionary, animation, 4.0, -1, -1, 50, 0, false, false, false)
161 |
162 | Citizen.Wait(700)
163 |
164 | StopAnimTask(playerPed, dictionary, animation, 1.0)
165 |
166 | NetworkRequestControlOfEntity(self.Handle)
167 |
168 | while not NetworkHasControlOfEntity(self.Handle) and count < 5000 do
169 | Citizen.Wait(0)
170 | count = count + 1
171 | end
172 |
173 | DetachEntity(self.Handle, true, false)
174 | DeleteEntity(self.Handle)
175 | end
176 | end
177 |
178 | -- Add player to radio channel
179 | function Radio:Add(id)
180 | exports["pma-voice"]:setRadioChannel(id)
181 | end
182 |
183 | -- Remove player from radio channel
184 | function Radio:Remove()
185 | exports["pma-voice"]:setRadioChannel(0)
186 | end
187 |
188 | -- Increase radio frequency
189 | function Radio:Decrease()
190 | if self.On then
191 | if radioConfig.Frequency.CurrentIndex - 1 < 1 and radioConfig.Frequency.List[radioConfig.Frequency.CurrentIndex] == radioConfig.Frequency.Current then
192 | self:Remove(radioConfig.Frequency.Current)
193 | radioConfig.Frequency.CurrentIndex = #radioConfig.Frequency.List
194 | radioConfig.Frequency.Current = radioConfig.Frequency.List[radioConfig.Frequency.CurrentIndex]
195 | self:Add(radioConfig.Frequency.Current)
196 | elseif radioConfig.Frequency.CurrentIndex - 1 < 1 and radioConfig.Frequency.List[radioConfig.Frequency.CurrentIndex] ~= radioConfig.Frequency.Current then
197 | self:Remove(radioConfig.Frequency.Current)
198 | radioConfig.Frequency.Current = radioConfig.Frequency.List[radioConfig.Frequency.CurrentIndex]
199 | self:Add(radioConfig.Frequency.Current)
200 | else
201 | self:Remove(radioConfig.Frequency.Current)
202 | radioConfig.Frequency.CurrentIndex = radioConfig.Frequency.CurrentIndex - 1
203 | radioConfig.Frequency.Current = radioConfig.Frequency.List[radioConfig.Frequency.CurrentIndex]
204 | self:Add(radioConfig.Frequency.Current)
205 | end
206 | else
207 | if radioConfig.Frequency.CurrentIndex - 1 < 1 and radioConfig.Frequency.List[radioConfig.Frequency.CurrentIndex] == radioConfig.Frequency.Current then
208 | radioConfig.Frequency.CurrentIndex = #radioConfig.Frequency.List
209 | radioConfig.Frequency.Current = radioConfig.Frequency.List[radioConfig.Frequency.CurrentIndex]
210 | elseif radioConfig.Frequency.CurrentIndex - 1 < 1 and radioConfig.Frequency.List[radioConfig.Frequency.CurrentIndex] ~= radioConfig.Frequency.Current then
211 | radioConfig.Frequency.Current = radioConfig.Frequency.List[radioConfig.Frequency.CurrentIndex]
212 | else
213 | radioConfig.Frequency.CurrentIndex = radioConfig.Frequency.CurrentIndex - 1
214 |
215 | if radioConfig.Frequency.List[radioConfig.Frequency.CurrentIndex] == radioConfig.Frequency.Current then
216 | radioConfig.Frequency.CurrentIndex = radioConfig.Frequency.CurrentIndex - 1
217 | end
218 |
219 | radioConfig.Frequency.Current = radioConfig.Frequency.List[radioConfig.Frequency.CurrentIndex]
220 | end
221 | end
222 | end
223 |
224 | -- Decrease radio frequency
225 | function Radio:Increase()
226 | if self.On then
227 | if radioConfig.Frequency.CurrentIndex + 1 > #radioConfig.Frequency.List then
228 | self:Remove(radioConfig.Frequency.Current)
229 | radioConfig.Frequency.CurrentIndex = 1
230 | radioConfig.Frequency.Current = radioConfig.Frequency.List[radioConfig.Frequency.CurrentIndex]
231 | self:Add(radioConfig.Frequency.Current)
232 | else
233 | self:Remove(radioConfig.Frequency.Current)
234 | radioConfig.Frequency.CurrentIndex = radioConfig.Frequency.CurrentIndex + 1
235 | radioConfig.Frequency.Current = radioConfig.Frequency.List[radioConfig.Frequency.CurrentIndex]
236 | self:Add(radioConfig.Frequency.Current)
237 | end
238 | else
239 | if #radioConfig.Frequency.List == radioConfig.Frequency.CurrentIndex + 1 then
240 | if radioConfig.Frequency.List[radioConfig.Frequency.CurrentIndex + 1] == radioConfig.Frequency.Current then
241 | radioConfig.Frequency.CurrentIndex = radioConfig.Frequency.CurrentIndex + 1
242 | end
243 | end
244 |
245 | if radioConfig.Frequency.CurrentIndex + 1 > #radioConfig.Frequency.List then
246 | radioConfig.Frequency.CurrentIndex = 1
247 | radioConfig.Frequency.Current = radioConfig.Frequency.List[radioConfig.Frequency.CurrentIndex]
248 | else
249 | radioConfig.Frequency.CurrentIndex = radioConfig.Frequency.CurrentIndex + 1
250 | radioConfig.Frequency.Current = radioConfig.Frequency.List[radioConfig.Frequency.CurrentIndex]
251 | end
252 | end
253 | end
254 |
255 | -- Generate list of available frequencies
256 | function GenerateFrequencyList()
257 | radioConfig.Frequency.List = {}
258 |
259 | for i = radioConfig.Frequency.Min, radioConfig.Frequency.Max do
260 | if not radioConfig.Frequency.Private[i] or radioConfig.Frequency.Access[i] then
261 | radioConfig.Frequency.List[#radioConfig.Frequency.List + 1] = i
262 | end
263 | end
264 | end
265 |
266 | -- Check if radio is open
267 | function IsRadioOpen()
268 | return Radio.Open
269 | end
270 |
271 | -- Check if radio is switched on
272 | function IsRadioOn()
273 | return Radio.On
274 | end
275 |
276 | -- Check if player has radio
277 | function IsRadioAvailable()
278 | return Radio.Has
279 | end
280 |
281 | -- Check if radio is enabled or not
282 | function IsRadioEnabled()
283 | return not Radio.Enabled
284 | end
285 |
286 | -- Check if radio can be used
287 | function CanRadioBeUsed()
288 | return Radio.Has and Radio.On and Radio.Enabled
289 | end
290 |
291 | -- Set if the radio is enabled or not
292 | function SetRadioEnabled(value)
293 | if type(value) == "string" then
294 | value = value == "true"
295 | elseif type(value) == "number" then
296 | value = value == 1
297 | end
298 |
299 | Radio.Enabled = value and true or false
300 | end
301 |
302 | -- Set if player has a radio or not
303 | function SetRadio(value)
304 | if type(value) == "string" then
305 | value = value == "true"
306 | elseif type(value) == "number" then
307 | value = value == 1
308 | end
309 |
310 | Radio.Has = value and true or false
311 | end
312 |
313 | -- Set if player has access to use the radio when closed
314 | function SetAllowRadioWhenClosed(value)
315 | radioConfig.AllowRadioWhenClosed = value
316 |
317 | if Radio.On and not Radio.Open and radioConfig.AllowRadioWhenClosed then
318 | exports["pma-voice"]:setVoiceProperty("radioEnabled", true)
319 | end
320 | end
321 |
322 | -- Add new frequency
323 | function AddPrivateFrequency(value)
324 | local frequency = tonumber(value)
325 |
326 | if frequency ~= nil then
327 | if not radioConfig.Frequency.Private[frequency] then -- Only add new frequencies
328 | radioConfig.Frequency.Private[frequency] = true
329 |
330 | GenerateFrequencyList()
331 | end
332 | end
333 | end
334 |
335 | -- Remove private frequency
336 | function RemovePrivateFrequency(value)
337 | local frequency = tonumber(value)
338 |
339 | if frequency ~= nil then
340 | if radioConfig.Frequency.Private[frequency] then -- Only remove existing frequencies
341 | radioConfig.Frequency.Private[frequency] = nil
342 |
343 | GenerateFrequencyList()
344 | end
345 | end
346 | end
347 |
348 | -- Give access to a frequency
349 | function GivePlayerAccessToFrequency(value)
350 | local frequency = tonumber(value)
351 |
352 | if frequency ~= nil then
353 | if radioConfig.Frequency.Private[frequency] then -- Check if frequency exists
354 | if not radioConfig.Frequency.Access[frequency] then -- Only add new frequencies
355 | radioConfig.Frequency.Access[frequency] = true
356 |
357 | GenerateFrequencyList()
358 | end
359 | end
360 | end
361 | end
362 |
363 | -- Remove access to a frequency
364 | function RemovePlayerAccessToFrequency(value)
365 | local frequency = tonumber(value)
366 |
367 | if frequency ~= nil then
368 | if radioConfig.Frequency.Access[frequency] then -- Check if player has access to frequency
369 | radioConfig.Frequency.Access[frequency] = nil
370 |
371 | GenerateFrequencyList()
372 | end
373 | end
374 | end
375 |
376 | -- Give access to multiple frequencies
377 | function GivePlayerAccessToFrequencies(...)
378 | local frequencies = { ... }
379 | local newFrequencies = {}
380 |
381 | for i = 1, #frequencies do
382 | local frequency = tonumber(frequencies[i])
383 |
384 | if frequency ~= nil then
385 | if radioConfig.Frequency.Private[frequency] then -- Check if frequency exists
386 | if not radioConfig.Frequency.Access[frequency] then -- Only add new frequencies
387 | newFrequencies[#newFrequencies + 1] = frequency
388 | end
389 | end
390 | end
391 | end
392 |
393 | if #newFrequencies > 0 then
394 | for i = 1, #newFrequencies do
395 | radioConfig.Frequency.Access[newFrequencies[i]] = true
396 | end
397 |
398 | GenerateFrequencyList()
399 | end
400 | end
401 |
402 | -- Remove access to multiple frequencies
403 | function RemovePlayerAccessToFrequencies(...)
404 | local frequencies = { ... }
405 | local removedFrequencies = {}
406 |
407 | for i = 1, #frequencies do
408 | local frequency = tonumber(frequencies[i])
409 |
410 | if frequency ~= nil then
411 | if radioConfig.Frequency.Access[frequency] then -- Check if player has access to frequency
412 | removedFrequencies[#removedFrequencies + 1] = frequency
413 | end
414 | end
415 | end
416 |
417 | if #removedFrequencies > 0 then
418 | for i = 1, #removedFrequencies do
419 | radioConfig.Frequency.Access[removedFrequencies[i]] = nil
420 | end
421 |
422 | GenerateFrequencyList()
423 | end
424 | end
425 |
426 | -- Define exports
427 | exports("IsRadioOpen", IsRadioOpen)
428 | exports("IsRadioOn", IsRadioOn)
429 | exports("IsRadioAvailable", IsRadioAvailable)
430 | exports("IsRadioEnabled", IsRadioEnabled)
431 | exports("CanRadioBeUsed", CanRadioBeUsed)
432 | exports("SetRadioEnabled", SetRadioEnabled)
433 | exports("SetRadio", SetRadio)
434 | exports("SetAllowRadioWhenClosed", SetAllowRadioWhenClosed)
435 | exports("AddPrivateFrequency", AddPrivateFrequency)
436 | exports("RemovePrivateFrequency", RemovePrivateFrequency)
437 | exports("GivePlayerAccessToFrequency", GivePlayerAccessToFrequency)
438 | exports("RemovePlayerAccessToFrequency", RemovePlayerAccessToFrequency)
439 | exports("GivePlayerAccessToFrequencies", GivePlayerAccessToFrequencies)
440 | exports("RemovePlayerAccessToFrequencies", RemovePlayerAccessToFrequencies)
441 |
442 | local isBroadcasting = false
443 |
444 | AddEventHandler('pma-voice:radioActive', function(broadCasting)
445 | isBroadcasting = broadCasting
446 | end)
447 |
448 | Citizen.CreateThread(function()
449 | -- Add Labels
450 | for i = 1, #Radio.Labels do
451 | AddTextEntry(Radio.Labels[i][1], Radio.Labels[i][2])
452 | end
453 |
454 | GenerateFrequencyList()
455 |
456 | while true do
457 | Citizen.Wait(0)
458 | -- Init local vars
459 | local playerPed = PlayerPedId()
460 | local isActivatorPressed = IsControlJustPressed(0, radioConfig.Controls.Activator.Key)
461 | local isSecondaryPressed = (radioConfig.Controls.Secondary.Enabled == false and true or IsControlPressed(0, radioConfig.Controls.Secondary.Key))
462 | local isFalling = IsPedFalling(playerPed)
463 | local isDead = IsEntityDead(playerPed)
464 | local minFrequency = radioConfig.Frequency.List[1]
465 | local broadcastType = 3 + (radioConfig.AllowRadioWhenClosed and 1 or 0) + ((Radio.Open and radioConfig.AllowRadioWhenClosed) and -1 or 0)
466 | local broadcastDictionary = Radio.Dictionary[broadcastType]
467 | local broadcastAnimation = Radio.Animation[broadcastType]
468 | local isPlayingBroadcastAnim = IsEntityPlayingAnim(playerPed, broadcastDictionary, broadcastAnimation, 3)
469 |
470 | -- Open radio settings
471 | if isActivatorPressed and isSecondaryPressed and not isFalling and Radio.Enabled and Radio.Has and not isDead then
472 | Radio:Toggle(not Radio.Open)
473 | elseif (Radio.Open or Radio.On) and ((not Radio.Enabled) or (not Radio.Has) or isDead) then
474 | Radio:Remove()
475 | exports["pma-voice"]:setVoiceProperty("radioEnabled", false)
476 | Radio:Toggle(false)
477 | Radio.On = false
478 | elseif Radio.Open and isFalling then
479 | Radio:Toggle(false)
480 | end
481 |
482 | -- Remove player from private frequency that they don't have access to
483 | if not radioConfig.Frequency.Access[radioConfig.Frequency.Current] and radioConfig.Frequency.Private[radioConfig.Frequency.Current] then
484 | if Radio.On then
485 | Radio:Remove()
486 | end
487 |
488 | radioConfig.Frequency.CurrentIndex = 1
489 | radioConfig.Frequency.Current = minFrequency
490 |
491 | if Radio.On then
492 | Radio:Add(radioConfig.Frequency.Current)
493 | end
494 | end
495 |
496 | -- Check if player is holding radio
497 | if Radio.Open then
498 | local dictionaryType = 1 + (IsPedInAnyVehicle(playerPed, false) and 1 or 0)
499 | local openDictionary = Radio.Dictionary[dictionaryType]
500 | local openAnimation = Radio.Animation[1]
501 | local isPlayingOpenAnim = IsEntityPlayingAnim(playerPed, openDictionary, openAnimation, 3)
502 | local hasWeapon, currentWeapon = GetCurrentPedWeapon(playerPed, 1)
503 |
504 | -- Remove weapon in hand as we are using the radio
505 | if currentWeapon ~= unarmed then
506 | SetCurrentPedWeapon(playerPed, unarmed, true)
507 | end
508 |
509 | -- Display help text
510 | BeginTextCommandDisplayHelp(Radio.Labels[Radio.On and 2 or 1][1])
511 |
512 | if not Radio.On then
513 | AddTextComponentSubstringPlayerName(Radio.Clicks and "~r~disable~w~" or "~g~enable~w~")
514 | end
515 |
516 | AddTextComponentInteger(radioConfig.Frequency.Current)
517 | EndTextCommandDisplayHelp(false, false, false, -1)
518 |
519 | -- Play animation if player is broadcasting to radio
520 | if Radio.On then
521 | if isBroadcasting and not isPlayingBroadcastAnim then
522 | RequestAnimDict(broadcastDictionary)
523 |
524 | while not HasAnimDictLoaded(broadcastDictionary) do
525 | Citizen.Wait(150)
526 | end
527 |
528 | TaskPlayAnim(playerPed, broadcastDictionary, broadcastAnimation, 8.0, -8, -1, 49, 0, 0, 0, 0)
529 | elseif not isBroadcasting and isPlayingBroadcastAnim then
530 | StopAnimTask(playerPed, broadcastDictionary, broadcastAnimation, -4.0)
531 | end
532 | end
533 |
534 | -- Play default animation if not broadcasting
535 | if not isBroadcasting and not isPlayingOpenAnim then
536 | RequestAnimDict(openDictionary)
537 |
538 | while not HasAnimDictLoaded(openDictionary) do
539 | Citizen.Wait(150)
540 | end
541 |
542 | TaskPlayAnim(playerPed, openDictionary, openAnimation, 4.0, -1, -1, 50, 0, false, false, false)
543 | end
544 |
545 | -- Turn radio on/off
546 | if IsControlJustPressed(0, radioConfig.Controls.Toggle.Key) then
547 | Radio.On = not Radio.On
548 |
549 | exports["pma-voice"]:setVoiceProperty("radioEnabled", Radio.On)
550 |
551 | if Radio.On then
552 | SendNUIMessage({ sound = "audio_on", volume = 0.3})
553 | Radio:Add(radioConfig.Frequency.Current)
554 | else
555 | SendNUIMessage({ sound = "audio_off", volume = 0.5})
556 | Radio:Remove()
557 | end
558 | end
559 |
560 | -- Change radio frequency
561 | if not Radio.On then
562 | DisableControlAction(0, radioConfig.Controls.ToggleClicks.Key, false)
563 |
564 | if not radioConfig.Controls.Decrease.Pressed then
565 | if IsControlJustPressed(0, radioConfig.Controls.Decrease.Key) then
566 | radioConfig.Controls.Decrease.Pressed = true
567 | Citizen.CreateThread(function()
568 | while IsControlPressed(0, radioConfig.Controls.Decrease.Key) do
569 | Radio:Decrease()
570 | Citizen.Wait(125)
571 | end
572 |
573 | radioConfig.Controls.Decrease.Pressed = false
574 | end)
575 | end
576 | end
577 |
578 | if not radioConfig.Controls.Increase.Pressed then
579 | if IsControlJustPressed(0, radioConfig.Controls.Increase.Key) then
580 | radioConfig.Controls.Increase.Pressed = true
581 | Citizen.CreateThread(function()
582 | while IsControlPressed(0, radioConfig.Controls.Increase.Key) do
583 | Radio:Increase()
584 | Citizen.Wait(125)
585 | end
586 |
587 | radioConfig.Controls.Increase.Pressed = false
588 | end)
589 | end
590 | end
591 |
592 | if not radioConfig.Controls.Input.Pressed then
593 | if IsControlJustPressed(0, radioConfig.Controls.Input.Key) then
594 | radioConfig.Controls.Input.Pressed = true
595 | Citizen.CreateThread(function()
596 | DisplayOnscreenKeyboard(1, Radio.Labels[3][1], "", radioConfig.Frequency.Current, "", "", "", 3)
597 |
598 | while UpdateOnscreenKeyboard() ~= 1 and UpdateOnscreenKeyboard() ~= 2 do
599 | Citizen.Wait(150)
600 | end
601 |
602 | local input = nil
603 |
604 | if UpdateOnscreenKeyboard() ~= 2 then
605 | input = GetOnscreenKeyboardResult()
606 | end
607 |
608 | Citizen.Wait(500)
609 |
610 | input = tonumber(input)
611 |
612 | if input ~= nil then
613 | if input >= minFrequency and input <= radioConfig.Frequency.List[#radioConfig.Frequency.List] and input == math.floor(input) then
614 | if not radioConfig.Frequency.Private[input] or radioConfig.Frequency.Access[input] then
615 | local idx = nil
616 |
617 | for i = 1, #radioConfig.Frequency.List do
618 | if radioConfig.Frequency.List[i] == input then
619 | idx = i
620 | break
621 | end
622 | end
623 |
624 | if idx ~= nil then
625 | radioConfig.Frequency.CurrentIndex = idx
626 | radioConfig.Frequency.Current = input
627 | end
628 | end
629 | end
630 | end
631 |
632 | radioConfig.Controls.Input.Pressed = false
633 | end)
634 | end
635 | end
636 |
637 | -- Turn radio mic clicks on/off
638 | if IsDisabledControlJustPressed(0, radioConfig.Controls.ToggleClicks.Key) then
639 | Radio.Clicks = not Radio.Clicks
640 |
641 | SendNUIMessage({ sound = "audio_off", volume = 0.5})
642 |
643 | exports["pma-voice"]:setVoiceProperty("micClicks", Radio.Clicks)
644 | end
645 | end
646 | else
647 | -- Play emergency services radio animation
648 | if radioConfig.AllowRadioWhenClosed then
649 | if Radio.Has and Radio.On and isBroadcasting and not isPlayingBroadcastAnim then
650 | RequestAnimDict(broadcastDictionary)
651 |
652 | while not HasAnimDictLoaded(broadcastDictionary) do
653 | Citizen.Wait(150)
654 | end
655 |
656 | TaskPlayAnim(playerPed, broadcastDictionary, broadcastAnimation, 8.0, 0.0, -1, 49, 0, 0, 0, 0)
657 | elseif not isBroadcasting and isPlayingBroadcastAnim then
658 | StopAnimTask(playerPed, broadcastDictionary, broadcastAnimation, -4.0)
659 | end
660 | end
661 | end
662 | end
663 | end)
664 |
665 | AddEventHandler("onClientResourceStart", function(resName)
666 | if GetCurrentResourceName() ~= resName and "pma-voice" ~= resName then
667 | return
668 | end
669 |
670 | exports["pma-voice"]:setVoiceProperty("radioEnabled", false) -- Disable radio control
671 |
672 | if Radio.Open then
673 | Radio:Toggle(false)
674 | end
675 |
676 | Radio.On = false
677 | end)
678 |
679 | RegisterNetEvent("Radio.Toggle")
680 | AddEventHandler("Radio.Toggle", function()
681 | local playerPed = PlayerPedId()
682 | local isFalling = IsPedFalling(playerPed)
683 | local isDead = IsEntityDead(playerPed)
684 |
685 | if not isFalling and not isDead and Radio.Enabled and Radio.Has then
686 | Radio:Toggle(not Radio.Open)
687 | end
688 | end)
689 |
690 | RegisterNetEvent("Radio.Set")
691 | AddEventHandler("Radio.Set", function(value)
692 | if type(value) == "string" then
693 | value = value == "true"
694 | elseif type(value) == "number" then
695 | value = value == 1
696 | end
697 |
698 | Radio.Has = value and true or false
699 | end)
700 |
--------------------------------------------------------------------------------