New Website Sale - 15% OFF everything

๐Ÿ› ๏ธ 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:

Lua
setr voice_enableRadioAnim 0

2. pma-voice Export

Add this to the bottom of pma-voice/client/module/radio.lua:

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.

Lua
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), optional string (denial message)
  • Usage: Add new entries to create job-specific radio channels

Example - Adding a new reserved channel for mechanics:

Lua
{ jobs = { "mechanic" }, channels = { 920, 920.01, 920.02 } },

Antenna Disable System

Configuration for the antenna hacking/disabling feature.

Lua
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 false to allow disabling without an item
    • Default: "dh_antenna_disabler"

Antenna Debug Mode

Shows antenna coverage radius on the map for testing purposes.

Lua
Shared.AntennaDebug = false -- set to true to see antenna radius on map
  • AntennaDebug: Set to true to 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.

Lua
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:

Lua
{
    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.

Lua
Shared.RadioItem = "radio" -- item name for radio, false to disable
  • RadioItem: Item name in your inventory system
  • Default: "radio"
  • Disable: Set to false to allow radio access without an item requirement

Client Configuration (configs/client.lua)

Radio Animations

Defines multiple animation options for holding and using the radio.

Lua
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 false for 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.

Lua
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

Lua
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

Lua
-- ESX Example
['radio'] = {
    label = 'Radio',
    weight = 1,
    stack = false,
    close = true,
    description = 'A portable radio communication device'
}

Antenna Disabler Item

Lua
-- 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:

Lua
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:

Lua
{ 
    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:

Lua
Shared.RadioItem = false  -- Disable item requirement

Advanced Configuration

Frequency Range

The radio supports frequencies from 0.00 to 9999.99 MHz.


Signal Strength System

Signal strength is calculated based on:

  1. Distance from nearest antenna
  2. Antenna radius configuration
  3. 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.RadioItem is set)
  • Check F8 console for Lua errors
  • Check if resource is started: /ensure devhub_radio

No signal everywhere:

  • Enable Shared.AntennaDebug = true to 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 /job or 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_disabler item
  • Check if Shared.DisableSettings.enabled is true
  • Ensure minigame scripts are loaded
  • Look for errors during antenna interaction