Emergency radio V2

Cosmos In-Game emergency radio

Upgrade your server’s roleplay and tactical coordination with cs-speak, a professional and fully customizableradio/communication script. Designed as a sleek, interactive tablet, it delivers an unparalleled user experience and advanced features that go beyond standard voice systems.


Key Features & Unmatched Customization

cs-speak gives your players total control over their communication environment, ensuring an organized and immersive experience:

  • Interactive Tablet UI: A modern, clean, and user-friendly tablet interface for immersive gameplay.

  • Total Layout Control:

    • Customizable Columns: Deactivate channel categories you don’t need! Keep your screen clutter-free and focused on what matters.
    • Minimizable Channels: Minimize specific channels to save screen space without disconnecting, maintaining a tidy UI.
  • Advanced Audio Management:

    • Mute & Deafen Functionality: Control your microphone and speaker output with clear on-screen indicators visible to both you and other users.
    • Status Toggling: Switch your presence between Available (:green_circle:) and Busy (:red_circle:). This status is clearly displayed on your user cell for improved team coordination.
  • Tactical Communication Tools:

    • Cross-Channel Whispers: Enjoy the popular β€œwhisper” functionality, allowing private, tactical communication between different channels, similar to TeamSpeak 3 (TS3).
    • User Drag-and-Drop (Permissions Required): With configured permissions, authorized users can drag and drop other users between channels, making squad management and quick meetings effortless.

Seamless Framework Compatibility

cs-speak is built for maximum compatibility, ensuring a smooth fit regardless of your server’s setup:

  • :white_check_mark: Major Framework Support: Fully compatible with QBOX, ESX, and QBCORE.
  • :white_check_mark: Standalone Ready: Running a custom or non-framework server? cs-speak works perfectly in Standalonemode with no external framework dependencies required!

Buy here!

Tebex Link: ESCROWED

Tebex Link: NO-ESCROWED

Config file preview

Config = {}

-- ═══════════════════════════════════════════════════════════════
--  FRAMEWORK CONFIGURATION
-- ═══════════════════════════════════════════════════════════════
-- Options: "qbcore", "qbox", "esx", "standalone"
-- In "standalone" mode, everyone can use drag & drop if enabled
Config.Framework = "qbcore"

-- ═══════════════════════════════════════════════════════════════
--  DRAG & DROP CONFIGURATION FOR MOVING USERS BETWEEN CHANNELS
-- ═══════════════════════════════════════════════════════════════
Config.DragAndDrop = {
    -- Enable/disable the drag and drop system completely
    Enabled = true,
    
    -- If TRUE: Everyone can move users between channels
    -- If FALSE: Only users with specific permissions can move
    AllowEveryone = false,
    
    -- PERMISSIONS BY JOB AND SPECIFIC GRADES (only used if AllowEveryone = false)
    -- Format: ["job_name"] = {grade1, grade2, grade3, ...}
    -- Player MUST have the job AND be in one of the listed grades
    -- If you want ALL grades to have permission, use: {0,1,2,3,4,5,6,7,8,9,10}
    Permissions = {
        -- POLICE (Sergeants and above: grades 3, 4, 5)
        ["police"] = {3, 4, 5},
        ["sheriff"] = {3, 4, 5},
        
        -- EMERGENCY SERVICES (Doctors and chiefs: grades 2, 3, 4)
        ["ambulance"] = {2, 3, 4},
        ["fire"] = {2, 3, 4},
        
        -- ADD MORE JOBS HERE:
        -- ["job_name"] = {grade1, grade2, grade3},
        -- 
        -- Examples:
        -- ["mechanic"] = {4, 5},           -- Only grades 4 and 5
        -- ["government"] = {0,1,2,3,4,5},  -- All grades
    }
}

-- ═══════════════════════════════════════════════════════════════
--  RADIO CHANNELS
-- ═══════════════════════════════════════════════════════════════
Config.Channels = {
    ["dirsapd"] = {
        [1] = {
            ["label"] = "COMMAND",
            ["id"] = "msapd_mando"
        },
        [2] = {
            ["label"] = "STATION",
            ["id"] = "msapd_comisaria"
        },
        [3] = {
            ["label"] = "AWAITING ASSIGNMENT",
            ["id"] = "msapd_awaiting"
        },
        [4] = {
            ["label"] = "TAC 01",
            ["id"] = "msapd_tac01"
        },
        [5] = {
            ["label"] = "TAC 02",
            ["id"] = "msapd_tac02"
        },
        [6] = {
            ["label"] = "TAC 03",
            ["id"] = "msapd_tac03"
        },
        [7] = {
            ["label"] = "TAC 04",
            ["id"] = "msapd_tac04"
        },
        [8] = {
            ["label"] = "SERGEANTS OFFICE",
            ["id"] = "msapd_sargentos"    
        },
        [9] = {
            ["label"] = "DETECTIVES OFFICE",
            ["id"] = "msapd_detectives"
        },
        [10] = {
            ["label"] = "IAA OFFICE",
            ["id"] = "msapd_ofiaa"
        },
        [11] = {
            ["label"] = "INVESTIGATION OFFICE",
            ["id"] = "msapd_ofinv"
        },
        [12] = {
            ["label"] = "SWAT OFFICE",
            ["id"] = "msapd_ofswat"
        },
        [13] = {
            ["label"] = "ASD OFFICE",
            ["id"] = "msapd_asd"
        },
        [14] = {
            ["label"] = "RTD OFFICE",
            ["id"] = "msapd_rtd"
        }
    },
    ["sapd"] = {
        [1] = {
            ["label"] = "10 ADAM 10",
            ["id"] = "sapd_10adam10"
        },
        [2] = {
            ["label"] = "10 ADAM 20",
            ["id"] = "sapd_10adam20"
        },
        [3] = {
            ["label"] = "10 ADAM 30",
            ["id"] = "sapd_10adam30"
        },
        [4] = {
            ["label"] = "10 ADAM 40",
            ["id"] = "sapd_10adam40"
        },
        [5] = {
            ["label"] = "10 ADAM 50",
            ["id"] = "sapd_10adam50"
        },
        [6] = {
            ["label"] = "10 ADAM 60",
            ["id"] = "sapd_10adam60"  
        },
        [7] = {
            ["label"] = "10 ADAM 70",
            ["id"] = "sapd_10adam70"
        },
        [8] = {
            ["label"] = "10 ADAM 80",
            ["id"] = "sapd_10adam80"
        },
        [9] = {
            ["label"] = "10 ADAM 90",
            ["id"] = "sapd_10adam90"
        },
        [10] = {
            ["label"] = "10 MARY 10",
            ["id"] = "sapd_10mary10"
        },
        [11] = {
            ["label"] = "10 MARY 20",
            ["id"] = "sapd_10mary20"
        },
        [12] = {
            ["label"] = "10 MARY 30",
            ["id"] = "sapd_10mary30"
        },
        [13] = {
            ["label"] = "DAVID 10",
            ["id"] = "msapd_david10"
        },
        [14] = {
            ["label"] = "DAVID 20",
            ["id"] = "msapd_david20"
        },
        [15] = {
            ["label"] = "DAVID 30",
            ["id"] = "msapd_david30"
        },
        [16] = {
            ["label"] = "KING 10",
            ["id"] = "sapd_king10"
        },
        [17] = {
            ["label"] = "PEGASUS 10",
            ["id"] = "sapd_pegaso10"
        },
        [18] = {
            ["label"] = "ROBERT",
            ["id"] = "sapd_robert"
        },
        [19] = {
            ["label"] = "BRADFORD",
            ["id"] = "sapd_bradford"
        },
        [20] = {
            ["label"] = "LINCOLN 10",
            ["id"] = "sapd_linconn"
        }
    },
    ["dirsaed"] = {
        [1] = {
            ["label"] = "COMMAND",
            ["id"] = "msafd_mandoem"
        },
        [2] = {
            ["label"] = "COMMISSIONER & CHIEF",
            ["id"] = "msafd_comisionado"
        },
        [3] = {
            ["label"] = "DAVIS STATION",
            ["id"] = "msafd_davisstation"
        },
        [4] = {
            ["label"] = "PALETO BAY STATION",
            ["id"] = "msafd_paletobay"
        },
        [5] = {
            ["label"] = "ALPHA 10",
            ["id"] = "msafd_alpha10"
        },
        [6] = {
            ["label"] = "ALPHA 20",
            ["id"] = "msafd_alpha20"
        },
        [7] = {
            ["label"] = "ALPHA 30",
            ["id"] = "msafd_alpha30"
        },
        [8] = {
            ["label"] = "ALPHA 40",
            ["id"] = "msafd_alpha40"
        },
        [9] = {
            ["label"] = "ALPHA 50",
            ["id"] = "msafd_alpha50"
        },
        [10] = {
            ["label"] = "MIKE 1",
            ["id"] = "msafd_mike1"
        },
        [11] = {
            ["label"] = "MIKE 2",
            ["id"] = "msafd_mike2"
        },
        [12] = {
            ["label"] = "MIKE 3",
            ["id"] = "msafd_mike3"
        },
        [13] = {
            ["label"] = "BRAVO 10",
            ["id"] = "msafd_bravo10"
        },
        [14] = {
            ["label"] = "BRAVO 20",
            ["id"] = "msafd_bravo20"
        },
        [15] = {
            ["label"] = "BRAVO 30",
            ["id"] = "msafd_bravo30"
        },
        [16] = {
            ["label"] = "CHARLIE 10",
            ["id"] = "msafd_charlie10"
        },
        [17] = {
            ["label"] = "CHARLIE 20",
            ["id"] = "msafd_charlie20"
        },
        [18] = {
            ["label"] = "FOXTROT 10",
            ["id"] = "msafd_foxtrot10"
        },
        [19] = {
            ["label"] = "FALCON 10",
            ["id"] = "msafd_halcon10"
        },
        [20] = {
            ["label"] = "PELICAN 10",
            ["id"] = "msafd_pelicano10"
        }
    },
    ["saed"] = {
        [1] = {
            ["label"] = "LOS SANTOS MC",
            ["id"] = "saed_lsmedical"
        },
        [2] = {
            ["label"] = "SANDY SHORES MC",
            ["id"] = "saed_ssmedical"
        },
        [3] = {
            ["label"] = "BETA 10",
            ["id"] = "saed_beta10"
        },
        [4] = {
            ["label"] = "BETA 20",
            ["id"] = "saed_beta20"
        },
        [5] = {
            ["label"] = "BETA 30",
            ["id"] = "saed_beta30"
        },
        [6] = {
            ["label"] = "BETA 40",
            ["id"] = "saed_beta40"
        },
        [7] = {
            ["label"] = "TAC MI-1",
            ["id"] = "saed_tacmi1"
        },
        [8] = {
            ["label"] = "TAC MI-2",
            ["id"] = "saed_tacmi2"
        },
        [9] = {
            ["label"] = "TAC MI-3",
            ["id"] = "saed_tacmi3"
        },
        [10] = {
            ["label"] = "BRAVO 10",
            ["id"] = "saed_bravo10"
        },
        [11] = {
            ["label"] = "BRAVO 20",
            ["id"] = "saed_bravo20"
        },
        [12] = {
            ["label"] = "BRAVO 30",
            ["id"] = "saed_bravo30"
        },
        [13] = {
            ["label"] = "TAU 10",
            ["id"] = "saed_tau10"
        },
        [14] = {
            ["label"] = "SIGMA 10",
            ["id"] = "saed_sigma10"
        },
    }
}

Config.Whispers = {

    ["common-commands"] = {
        ["keybind"] = {
            ["name"] = "[Whisper] [PD/ED] freq. Mandos",
            ["defaultkey"] = ""
        },
        ["channels"] = {
            "msapd_mando",
            "msafd_mandoem",
            "saed_lsmedical",
            "saed_ssmedical"
        }
    },

    --[[ SAPD ]]--

    ["sapd-commands"] = {
        ["keybind"] = {
            ["name"] = "[Whisper] [SAPD] freq. Tac-Mando",
            ["defaultkey"] = ""
        },
        ["channels"] = {
            "msapd_mando",
            "msapd_tac01",
            "msapd_tac02",
            "msapd_tac03",
            "msapd_tac04"
        }
    },

    ["sapd-comi"] = {
        ["keybind"] = {
            ["name"] = "[Whisper] [SAPD] comi. <-> Mando",
            ["defaultkey"] = ""
        },
        ["channels"] = {
            "msapd_mando",
            "msapd_comisaria"
        }
    },

    ["sapd-all"] = {
        ["keybind"] = {
            ["name"] = "[Whisper] [SAPD] freq. all SAPD",
            ["defaultkey"] = ""
        },
        ["channels"] = { }
    },

    ["sapd-awaiting"] = {
        ["keybind"] = {
            ["name"] = "[Whisper] [SAPD] Mando -> asig.",
            ["defaultkey"] = ""
        },
        ["channels"] = {
            "msapd_awaiting",
            "msapd_mando"
        }
    },

    --[[ SAED ]]--

    ["saed-all"] = { 
        ["keybind"] = {
            ["name"] = "[Whisper] [SAED] freq. all SAED",
            ["defaultkey"] = ""
        },
        ["channels"] = { }
    },

    ["saed-depmando"] = { 
        ["keybind"] = {
            ["name"] = "[Whisper] [SAED] dep. <-> mando",
            ["defaultkey"] = ""
        },
        ["channels"] = { 
            "msafd_mandoem",
            "msafd_davisstation",
            "msafd_paletobay",
            "saed_lsmedical",
            "saed_ssmedical"
        }
    },

    ["safd-stations"] = { 
        ["keybind"] = {
            ["name"] = "[Whisper] [SAED] freq. all SAFD",
            ["defaultkey"] = ""
        },
        ["channels"] = { }
    },

    ["sams-stations"] = { 
        ["keybind"] = {
            ["name"] = "[Whisper] [SAED] freq. all SAMS",
            ["defaultkey"] = ""
        },
        ["channels"] = { }
    }
}

CreateThread(function()
    for i = 1, #Config.Channels["dirsapd"] do
        if not string.find(Config.Channels["dirsapd"][i].id, "_tac0") and not string.find(Config.Channels["dirsapd"][i].id, "msapd_comisaria") then
            table.insert(Config.Whispers["sapd-all"]["channels"], Config.Channels["dirsapd"][i].id)
        end
    end

    for i = 1, #Config.Channels["sapd"] do
        table.insert(Config.Whispers["sapd-all"]["channels"], Config.Channels["sapd"][i].id)
    end

    for i = 1, #Config.Channels["dirsaed"] do
        table.insert(Config.Whispers["saed-all"]["channels"], Config.Channels["dirsaed"][i].id)
        table.insert(Config.Whispers["safd-stations"]["channels"], Config.Channels["dirsaed"][i].id) -- Todos los canales del SAFD
    end

    for i = 1, #Config.Channels["saed"] do
        table.insert(Config.Whispers["saed-all"]["channels"], Config.Channels["saed"][i].id)
        table.insert(Config.Whispers["sams-stations"]["channels"], Config.Channels["saed"][i].id) -- Todos los canales del SAMS
    end

    for key, value in pairs(Config.Whispers) do
        if type(value) == "table" and value["channels"] then
            local new_channels = {}

            for _, channel in ipairs(value["channels"]) do
                new_channels[channel] = true
            end

            value["channels"] = new_channels
        end
    end
end)

exports("GetRadioChannels", function()
    return Config.Channels
end)

GetAssignationById = function(id)
    for directory, data in pairs(Config.Channels) do
        for i = 1, #data do
            if data[i].id == id then
                return data[i].label
            end
        end
    end

    return false
end

exports("GetAssignationById", GetAssignationById)
Code is accessible Yes (no-escrowed version)
Subscription-based No
Lines (approximately) +1100
Requirements pma-voice (included)
Support Yes

Is there any plans for a preview?

Specifically on Cross-Channel Whispers, Intersted to see how it works as PMA (Natively) doesn’t support multi channel radios at the same time

Looks so cool, is there a testserver? or atleast a video?

SIncerely
Beans

It’s possible! PMA works by using arrays of net IDs as the listened-to players. If we add the net IDs from the other channel to the target array, we’re merging the targets of both channels. That’s how whispers are created. You can also create new whispers in the config file.

DEFAULT WHISPERS CONFIG FILE:

Config.Whispers = {

    ["common-commands"] = {
        ["keybind"] = {
            ["name"] = "[Whisper] [PD/ED] freq. Mandos",
            ["defaultkey"] = ""
        },
        ["channels"] = {
            "msapd_mando",
            "msafd_mandoem",
            "saed_lsmedical",
            "saed_ssmedical"
        }
    },

    --[[ SAPD ]]--

    ["sapd-commands"] = {
        ["keybind"] = {
            ["name"] = "[Whisper] [SAPD] freq. Tac-Mando",
            ["defaultkey"] = ""
        },
        ["channels"] = {
            "msapd_mando",
            "msapd_tac01",
            "msapd_tac02",
            "msapd_tac03",
            "msapd_tac04"
        }
    },

    ["sapd-comi"] = {
        ["keybind"] = {
            ["name"] = "[Whisper] [SAPD] comi. <-> Mando",
            ["defaultkey"] = ""
        },
        ["channels"] = {
            "msapd_mando",
            "msapd_comisaria"
        }
    },

    ["sapd-all"] = {
        ["keybind"] = {
            ["name"] = "[Whisper] [SAPD] freq. all SAPD",
            ["defaultkey"] = ""
        },
        ["channels"] = { }
    },

    ["sapd-awaiting"] = {
        ["keybind"] = {
            ["name"] = "[Whisper] [SAPD] Mando -> asig.",
            ["defaultkey"] = ""
        },
        ["channels"] = {
            "msapd_awaiting",
            "msapd_mando"
        }
    },

    --[[ SAED ]]--

    ["saed-all"] = { 
        ["keybind"] = {
            ["name"] = "[Whisper] [SAED] freq. all SAED",
            ["defaultkey"] = ""
        },
        ["channels"] = { }
    },

    ["saed-depmando"] = { 
        ["keybind"] = {
            ["name"] = "[Whisper] [SAED] dep. <-> mando",
            ["defaultkey"] = ""
        },
        ["channels"] = { 
            "msafd_mandoem",
            "msafd_davisstation",
            "msafd_paletobay",
            "saed_lsmedical",
            "saed_ssmedical"
        }
    },

    ["safd-stations"] = { 
        ["keybind"] = {
            ["name"] = "[Whisper] [SAED] freq. all SAFD",
            ["defaultkey"] = ""
        },
        ["channels"] = { }
    },

    ["sams-stations"] = { 
        ["keybind"] = {
            ["name"] = "[Whisper] [SAED] freq. all SAMS",
            ["defaultkey"] = ""
        },
        ["channels"] = { }
    }
}

I got this preview before the update was even finished. I’ll post a full preview with all the new features in this post soon :sweat_smile:

Hey, that doesnt really show the features tbf, im missing the whole point with the whisper system and how you managed it in PMA lol

I think this still doesn’t really explain it, What i think everyone is looking for is can you hear and reply to both channels

For example, Can i connect to both channel 1 and 2 at the same time. Hearing any transmissions on either 1 or 2 and then also having a keybind to broadcast on channel 1 or channel 2 indipendently

The channel hearing option isn’t implemented by default; you can configure it using whispers. This means that if someone speaks to you, you can reply by sending a general message to all frequencies in that category (if you keep the default settings, but you can change them as well), or you can create a two-way whisper. For example, if you use the X key to communicate from channel A to channel B, those on channel B can communicate with channel A using the same key (X). Regarding the preview, I’m not exactly sure what you want me to show you; it’s a whisper feature where you can speak to channels you’ve configured while on another channel.

But I don’t know what to show you; they’re keybinds that allow you to communicate using all the pre-configured frequencies while on another channel. I have a screenshot of the keybind configuration in the comic. Could you please show an example of whispering in the video?

Ohhh so you can go into channels but also stay in yours?

You can’t literally be on multiple frequencies, but you can communicate with them using keybinds. However, your user will NOT appear as connected to that other frequency, only to your own.

The best script, :100:

1 Like