๐ ๏ธ Configuration
โ ๏ธ REQUIRED STEPS BEFORE USE
1. pma-voice Configuration in server.cfg
Make sure that voice_enableRadioAnim in server.cfg is set to 0. If it doesn't exist, add to server.cfg:
setr voice_enableRadioAnim 02. pma-voice Export
Add this to the bottom of pma-voice/client/module/radio.lua:
exports("getRadioData", function()
return radioData
end)Shared Configuration (configs/shared.lua)
Reserved Channels System
Controls which radio frequencies are restricted to specific jobs or custom conditions.
Shared.ReservedChannels = {
{ jobs = { "police", "sheriff", "state" }, channels = { 909, 909.01, 909.02, 911 } },
{ jobs = { "police", "sheriff", "state", "ambulance" }, channels = { 912 } },
{ jobs = { "mechanic1" }, channels = { 913 } },
{ jobs = { "mechanic2" }, channels = { 914 } },
{ channels = { 915 }, handler = function(source, channel)
local crimeJob = "xd"
if crimeJob == "vagos" then
return true
else
return false, "Access only for Vagos members"
end
end
},
}- jobs: Array of job names that have access to the specified channels
- channels: Array of frequency numbers that are reserved
- handler: Optional custom function for advanced access control
- Parameters:
source(player ID),channel(frequency number) - Returns:
boolean(access granted), optionalstring(denial message)
- Parameters:
- Usage: Add new entries to create job-specific radio channels
Example - Adding a new reserved channel for mechanics:
{ jobs = { "mechanic" }, channels = { 920, 920.01, 920.02 } },Antenna Disable System
Configuration for the antenna hacking/disabling feature.
Shared.DisableSettings = {
enabled = true,
time = 60000 * 20, -- time in ms that antenna is disabled
item = "dh_antenna_disabler", -- item required to disable antenna or you can set to false to do not require item
}- enabled: Enable/disable the antenna disabling feature
- time: Duration in milliseconds that antenna remains disabled (default: 20 minutes)
- item: Item name required to disable antenna
- Set to
falseto allow disabling without an item - Default:
"dh_antenna_disabler"
- Set to
Antenna Debug Mode
Shows antenna coverage radius on the map for testing purposes.
Shared.AntennaDebug = false -- set to true to see antenna radius on map- AntennaDebug: Set to
trueto visualize antenna coverage areas on the map - Usage: Enable during setup to verify antenna placement and coverage
Antenna Locations
Defines all radio antenna locations across the map and their signal coverage.
Shared.AntennaLocations = {
{prop = "reh_prop_reh_tablet_01a", coords = vector3(-1267.271, -2442.962, 14.603), rotation = vec3(118.426, -87.740, 122.140), radius = 1500.0},
{prop = "reh_prop_reh_tablet_01a", coords = vector3(1369.801, -2325.915, 61.777), rotation = vec3(118.426, -87.740, 122.140), radius = 1650.0},
-- ... more locations
}- prop: Prop model name for the antenna object
- coords: vector3 coordinates (x, y, z) for antenna placement
- rotation: vec3 rotation values (pitch, roll, yaw)
- radius: Signal coverage radius in game units
- Default Locations: 12 antennas strategically placed across the map
- Coverage Areas:
- Los Santos: 1300-1650 unit radius
- Sandy Shores: 1350-2000 unit radius
- Paleto Bay: 1200-3000 unit radius
Adding a New Antenna:
{
prop = "reh_prop_reh_tablet_01a",
coords = vector3(x, y, z),
rotation = vec3(pitch, roll, yaw),
radius = 1500.0
},Radio Item Name
Defines the inventory item name for the radio.
Shared.RadioItem = "radio" -- item name for radio, false to disable- RadioItem: Item name in your inventory system
- Default:
"radio" - Disable: Set to
falseto allow radio access without an item requirement
Client Configuration (configs/client.lua)
Radio Animations
Defines multiple animation options for holding and using the radio.
Config.Animations = {
{ -- Animation 1: Holding Radio (RPEmotes style)
dict = "anim@male@holding_radio",
anim = "holding_radio_clip",
flags = 49,
propModel = "prop_cs_hand_radio",
bone = 28422,
offsets = { x = 0.09, y = 0.03, z = 0.0, xRot = -70.0, yRot = 10.0, zRot = 290.0 },
},
{ -- Animation 2: Reading (Phone style)
dict = "cellphone@",
anim = "cellphone_text_read_base",
flags = 49,
propModel = "prop_cs_hand_radio",
bone = 28422,
offsets = { x = 0.0, y = 0.0, z = 0.0, xRot = 0.0, yRot = 0.0, zRot = 0.0 },
},
{ -- Animation 3: Generic Radio Chatter
dict = "random@arrests",
anim = "generic_radio_chatter",
flags = 49,
propModel = false,
bone = 28422,
offsets = { x = 0.0, y = 0.0, z = 0.0, xRot = 0.0, yRot = 0.0, zRot = 0.0 },
},
{ -- Animation 4: Listening
dict = "cellphone@",
anim = "cellphone_call_listen_base",
flags = 49,
propModel = "prop_cs_hand_radio",
bone = 28422,
offsets = { x = 0.0, y = 0.0, z = 0.0, xRot = 0.0, yRot = 0.0, zRot = 0.0 },
},
}- dict: Animation dictionary name
- anim: Specific animation name within the dictionary
- flags: Animation flags (49 = upperbody + loop)
- propModel: Radio prop model (set to
falsefor no prop) - bone: Bone ID for prop attachment (28422 = right hand)
- offsets: Position and rotation offsets for the prop
- x, y, z: Position offset
- xRot, yRot, zRot: Rotation offset in degrees
- Players can switch between animations in-game settings
Aiming Animation
Special animation used when player is aiming with a weapon while using radio.
Config.AimingAnim = {
dict = "arrest",
anim = "radio_chatter",
flags = 49,
propModel = false,
bone = 28422,
offsets = { x = 0.0, y = 0.0, z = 0.0, xRot = 0.0, yRot = 0.0, zRot = 0.0 },
}- Same structure as regular animations
- No prop model by default for compatibility with weapon aiming
- Automatically activates when player aims while radio is open
Translation Configuration (configs/translation.lua)
Customize all user-facing text in the resource. Full multi-language support.
Tuning Minigame Translations
Shared.Lang = {
['tuning_signal_tuning'] = "SIGNAL TUNING",
['tuning_description'] = "STABILIZE THE DISTORTED FREQUENCY SIGNAL",
['tuning_instructions'] = "Match your signal to the ghost reference line...",
-- ... more tuning translations
}Items Configuration (items/items.lua)
Add these items to your inventory system:
Radio Item
-- ESX Example
['radio'] = {
label = 'Radio',
weight = 1,
stack = false,
close = true,
description = 'A portable radio communication device'
}Antenna Disabler Item
-- ESX Example
['dh_antenna_disabler'] = {
label = 'Antenna Disabler',
weight = 1,
stack = true,
close = true,
description = 'Device to temporarily disable radio antennas'
}Item Images:
items/dh_antenna_disabler.png- Provided in the resource- Add to your inventory images folder
Customization Examples
Creating Job-Specific Channels
Add multiple job groups with shared access:
Shared.ReservedChannels = {
-- Emergency Services (Police + EMS)
{ jobs = { "police", "sheriff", "ambulance" }, channels = { 911, 911.01, 911.02 } },
-- Police Only
{ jobs = { "police", "sheriff", "state" }, channels = { 909, 909.1, 909.2 } },
-- Medical Only
{ jobs = { "ambulance", "doctor" }, channels = { 912 } },
-- Mechanics
{ jobs = { "mechanic" }, channels = { 913, 913.1 } },
-- Government
{ jobs = { "government", "mayor" }, channels = { 920 } },
}Custom Access Handler Example
Create advanced access control based on custom logic:
{
channels = { 915, 916, 917 },
handler = function(source, channel)
local xPlayer = ESX.GetPlayerFromId(source)
-- Check gang affiliation
local gang = xPlayer.getGang() -- Your gang system
if gang == "vagos" and channel == 915 then
return true
elseif gang == "ballas" and channel == 916 then
return true
elseif gang == "families" and channel == 917 then
return true
else
return false, "This channel is restricted to gang members"
end
end
},Making Radio Accessible Without Item
Allow all players to use radio without needing the item:
Shared.RadioItem = false -- Disable item requirementAdvanced Configuration
Frequency Range
The radio supports frequencies from 0.00 to 9999.99 MHz.
Signal Strength System
Signal strength is calculated based on:
- Distance from nearest antenna
- Antenna radius configuration
- Whether antenna is disabled
Signal Levels:
- 5 bars: Within optimal range (< 50% of radius)
- 3-4 bars: Medium range (50-75% of radius)
- 1-2 bars: Weak signal (75-100% of radius)
- 0 bars: No signal (outside radius or antenna disabled)
UI Customization
Players can customize their radio interface:
- Wallpaper: None or Custom
- Background Opacity: Adjustable transparency
- Radio Volume: Individual volume control
- Button Click Volume: UI sound control
- HUD Display: Toggle on/off
- Radio Scale: Size adjustment
- HUD Scale: HUD size adjustment
- Position: Drag and reposition UI elements
- Animation: Choose from available animations
Troubleshooting
Radio not opening:
- Verify player has the radio item (if
Shared.RadioItemis set) - Check F8 console for Lua errors
- Check if resource is started:
/ensure devhub_radio
No signal everywhere:
- Enable
Shared.AntennaDebug = trueto visualize coverage - Verify antenna coordinates are valid
- Ensure antenna props are spawning correctly
Reserved channels not working:
- Verify job names match your framework's job names exactly
- Check player's job with
/jobor similar command - Review server console for access denial messages
- Test custom handler functions with debug prints
Antenna hacking not working:
- Verify player has
dh_antenna_disableritem - Check if
Shared.DisableSettings.enabledistrue - Ensure minigame scripts are loaded
- Look for errors during antenna interaction