Skip to content

Player-side API

local radio = exports.meridian:getState()
if radio and radio.connected and radio.talkgroup then
print(("On %s (%d) in zone %s"):format(radio.talkgroup.name, radio.talkgroup.id, radio.zone.name))
end

getState() returns nil until the radio has finished loading (a second or two after joining). After that it always returns the latest state:

Field Meaning
power Switched on
connected Switched on and connected to the radio system
connection "offline", "connecting", "online" or "error"
visible The radio UI is showing
unitId, alias This radio’s unit ID and alias (for example 1-ADAM-12 Smith)
systemName The radio system’s name
zones Every zone the radio may use: { id, name, alias, talkgroups = { { id, name, alias }, ... } }
zone The selected zone { id, name, alias }, or nil
talkgroup The selected talkgroup { id, name, alias }, or nil
transmitting The player is transmitting (the system granted the call)
receiving The call heard right now: { talkgroupId, unitId, alias, emergency }, or nil
emergency This radio has an emergency active
emergencies Every active emergency: { unitId, alias, talkgroupId, acknowledgedBy } (acknowledgedBy is nil until a dispatcher acknowledges it)
inhibited A dispatcher or administrator has disabled this radio
signal { bars = 0-4, siteId }
volume 0–150 (percent)
model "handheld" or "mobile"

These are local client events: they fire only on the player’s own machine, and never reach the server.

Event Arguments
meridian:stateChanged state, previousState (previousState is nil the first time). Fires last, after any of the events below
meridian:powerChanged on
meridian:connectionChanged connected
meridian:talkgroupChanged talkgroup, zone (either can be nil)
meridian:transmitStart talkgroup
meridian:transmitStop none
meridian:receiveStart { talkgroupId, unitId, alias, emergency }
meridian:receiveStop none
meridian:emergencyChanged active (this radio’s own emergency)
meridian:emergenciesChanged the full emergencies list
meridian:signalChanged bars, siteId
meridian:visibilityChanged visible

When the player moves from one call to the next without a gap, receiveStop is followed immediately by receiveStart.

AddEventHandler("meridian:transmitStart", function(talkgroup)
-- your own radio animation, a HUD "TX" light, etc.
end)
AddEventHandler("meridian:emergenciesChanged", function(emergencies)
for _, e in ipairs(emergencies) do
print(("EMERGENCY: %s on talkgroup %d%s"):format(e.alias, e.talkgroupId,
e.acknowledgedBy and (" (acknowledged by " .. e.acknowledgedBy .. ")") or ""))
end
end)

In JavaScript: on("meridian:talkgroupChanged", (talkgroup, zone) => { ... }) and exports.meridian.getState().

Export Effect
setPower(on) Switch the radio on or off
setVisible(visible) Show or hide the radio UI (the same as the show/hide key)
setTalkgroup(id, zoneId?) Select a talkgroup. Without zoneId it stays in the current zone if the talkgroup is there, otherwise it uses the first zone that has it. Returns false if the radio is off or can’t use that talkgroup
setZone(zoneId) Select a zone (and its first talkgroup). Returns false if the radio is off or doesn’t have that zone
setVolume(percent) 0–150
setEmergency(active) Raise or clear this radio’s emergency (raised on the selected talkgroup). Returns false if the radio is off or not connected
setPtt(down) Press (true) or release (false) push-to-talk. Always release what you press
setHeadless(on) Hide the built-in radio UI for good, so your own HUD can replace it. The radio keeps working
setBuiltinAnimation(on) Turn the built-in transmit animation on or off, so you can play your own
useItem() Show or hide the radio, like the show/hide key (for inventory item scripts)

The radio enforces its normal rules: a player can only select talkgroups their radio is programmed with, an inhibited radio stays silent, and so on. setTalkgroup returning true means the request was accepted; watch talkgroupChanged for the result.

-- A panic button in your own script
RegisterCommand("panic", function()
if not exports.meridian:setEmergency(true) then
print("Your radio is off or has no signal")
end
end)
-- Jump to the mutual aid talkgroup
exports.meridian:setTalkgroup(501)

Both are replicated convars (setr) so each player’s game can read them. Neither is secret.

setr meridian_headless "true" # hide the built-in radio UI for everyone (a HUD resource replaces it)
setr meridian_animation "false" # turn off the built-in transmit animation for everyone
setr meridian_proximity "false" # nearby players no longer hear the talker through proximity voice

A resource can also change either setting for one player at runtime with setHeadless or setBuiltinAnimation.