API Reference
Exports, state bags and network events for driving tELS from another resource.
Read with GetLightState, drive with the write
exports. Every vehicle-taking export returns nil on a non-tELS entity.
Read exports
| Export | Arguments | Returns |
|---|---|---|
IsSirenActive | vehicle | Any siren playing — main, aux or burst |
AreLightsActive | vehicle | Emergency lights on, meaning stage > 0 |
GetLightState | vehicle | The whole replicated state — below |
GetTelsState | vehicle | A capture for replay — below |
IsPaActive | — | The calling client's own PA mic state. nil without pma-voice |
IsPaAvailable | — | Whether pma-voice is running |
For another player's PA, read lbarPaActive on the player state
bag.
GetLightState
A vehicle's whole replicated state in one read.
local st = exports['tELS']:GetLightState(vehicle)
if st and st.active and st.sirenOn then
-- running code 3
endReturns every tels:sync field — live local state, else the replicated
bag, else the documented defaults — plus:
| Field | Type | Notes |
|---|---|---|
modelKey | string | The model name this vehicle's config is stored under |
maxStage | number | Highest stage this model has rules for. 0 means no stages |
patternName | string | nil | The currently selected pattern |
isOwner | boolean | You own this vehicle and the server has confirmed it |
canWrite | boolean | A write export would be accepted right now |
canControl | boolean | The player sitting here can operate it — either front seat |
GetTelsState
Captures a vehicle's lighting for replay.
local captured = exports['tELS']:GetTelsState(vehicle)| Key | Holds |
|---|---|
| 20 look fields | active, stage, cruiseOn, takedownOn, blackout, taMode, the six siren fields, hornActive, chirpActive, rumblerOn, presenceEnabled, and the four arges fields, always inert in this build |
modelKey, patternIdx, patternName, livery | patternName is the stable identifier — editing the config renumbers patternIdx |
phase | { netTime, frameIdx, tickCount, lerpT } |
triggers | The live condition map, so rules re-fire on replay where they fired in the take, rising edges included |
SetTelsState
Drives lighting from a capture. Pass nil to return control to live triggers. Returns
false with no tELS config, and is safe every frame.
exports['tELS']:SetTelsState(vehicle, captured)
exports['tELS']:SetTelsState(vehicle, nil) -- releaseSetTelsCinematicAudio
The audio half of a replay. Call it each frame with the captured audio fields.
exports['tELS']:SetTelsCinematicAudio(vehicle, {
sirenOn = true, sirenTone = 2,
auxSirenOn = false,
sirenBurst = false, burstTone = 1,
hornActive = false,
rumblerOn = false,
})
exports['tELS']:SetTelsCinematicAudio(vehicle, nil) -- silencespec field | Type | Effect |
|---|---|---|
sirenOn | boolean | Hold the main siren on sirenTone |
sirenTone | number | A tone this vehicle does not have leaves the main siren silent |
auxSirenOn / auxSirenTone | boolean / number | The aux channel. Never takes the rumbler variant |
sirenBurst | boolean | One-shot on the rising edge, and only while sirenOn is false |
burstTone | number | Tone the burst plays. Defaults to 1 |
hornActive | boolean | Hold the airhorn |
rumblerOn | boolean | Changing it re-triggers whatever is playing |
Idempotent: an unchanged spec makes no sound.
- Returns
nilwith no tELS config - Returns
falsefor an untracked vehicle, or one with a real player in either front seat. It silences what it had started as it refuses - An NPC driver puppet is not a player, so a recorded take keeps its sound
Write exports
These run the same code the keybinds run.
| Return | Meaning |
|---|---|
nil | Not a tELS vehicle. The same signal the read exports give, so you can probe with it |
false | Refused: a bad argument, something this vehicle is not configured for, or a write this client may not make |
true | Applied |
When a write is refused
A write is accepted only on the vehicle the caller owns, has been confirmed as owning
by the server, and is currently sitting in. Test canWrite rather than branching on a
false.
canControlis a different question — whether the player sitting in the vehicle can operate it. Both front seats can, so a passenger hascanControltrue andcanWritefalse at once. A script sits nowhere and is judged oncanWrite- An open LED editor session refuses every write
- No User Controls does not. It only stops tELS taking the driver's keys
- Lights being off does not. Sirens, takedown, cruise, the traffic advisor and the rumbler are independent of the light stage
Lights
exports['tELS']:SetLights(vehicle, true) -- on (stage 1 if the model has stages)
exports['tELS']:SetStage(vehicle, 2) -- straight to stage 2; 0 is off
exports['tELS']:CycleLights(vehicle) -- off -> 1 -> 2 -> ... -> off| Export | Arguments | Notes |
|---|---|---|
SetLights | vehicle, on | on must be a boolean |
SetStage | vehicle, stage | 0 is off. A stage above maxStage is refused, and so is any stage on a model with no stages — use SetLights there |
CycleLights | vehicle | Exactly the driver's toggle key |
Patterns
exports['tELS']:SetPattern(vehicle, 'Slow Cross') -- by name
exports['tELS']:SetPattern(vehicle, 0) -- lights only
exports['tELS']:CyclePattern(vehicle, -1) -- step back one| Export | Arguments | Notes |
|---|---|---|
SetPattern | vehicle, nameOrIndex | 0 selects the lights-only slot |
CyclePattern | vehicle, delta | delta defaults to 1; negative steps backwards |
Sirens and horn
exports['tELS']:SetSiren(vehicle, true, 2) -- main siren on, tone 2
exports['tELS']:SetSiren(vehicle, true) -- main siren on, keep the current tone
exports['tELS']:SetAuxSiren(vehicle, false) -- aux siren off
exports['tELS']:SetAirhorn(vehicle, true) -- and false to release it
exports['tELS']:SetRumbler(vehicle, true)| Export | Arguments | Notes |
|---|---|---|
SetSiren | vehicle, on, tone? | tone keeps the selected tone when omitted, and is ignored when switching off |
SetAuxSiren | vehicle, on, tone? | Same shape. The aux channel never uses the rumbler variant |
SetAirhorn | vehicle, on | Airhorn with lights on, or when the config disabled the stock horn; the vehicle's own horn otherwise |
SetRumbler | vehicle, on | Restarts a running main siren so the change is audible |
SetChirp | vehicle, on | A latch, like SetAirhorn — nothing releases it but false |
A tone outside the vehicle's list is refused, and so is one whose slot is off. Trigger-only tones are available here.
Traffic advisor, takedown, cruise
exports['tELS']:SetTrafficAdvisor(vehicle, 'left')
exports['tELS']:CycleTrafficAdvisor(vehicle)
exports['tELS']:SetTakedown(vehicle, true)
exports['tELS']:SetCruise(vehicle, false)| Export | Arguments | Notes |
|---|---|---|
SetTrafficAdvisor | vehicle, mode | "off", "left", "right" or "center" |
CycleTrafficAdvisor | vehicle | Next mode this vehicle has configured |
SetTakedown | vehicle, on | |
SetCruise | vehicle, on |
A direction with no trigger rule is refused. "off" is always accepted.
Blackout
exports['tELS']:SetBlackout(vehicle, true) -- run dark
exports['tELS']:SetBlackout(vehicle, false) -- come back up exactly as beforeBlackout hides the lighting without switching it off.
- Stage, pattern, pattern position, cruise, takedown, traffic advisor and spotlight aim keep
running underneath, so
falserestores exactly what was showing - Visual only — the siren and horn keep playing
- It replicates.
GetLightStatereportsblackout, withactivestilltrue
PA
exports['tELS']:SetPa(vehicle, true) -- and false to releaseHold-style: the caller releases it. Check IsPaAvailable first — without
pma-voice this refuses where every other write export would succeed.
Spotlight
exports['tELS']:SetArges(vehicle, true) -- beam on
exports['tELS']:SetArgesAim(vehicle, 'left', true) -- start swinging left
exports['tELS']:SetArgesAim(vehicle, 'left', false) -- stop
exports['tELS']:ReleaseArgesAim(vehicle) -- stop, whatever was held| Export | Arguments | Notes |
|---|---|---|
SetArges | vehicle, on | Beam on or off |
SetArgesAim | vehicle, dir, down | dir is "up", "down", "left" or "right". Held, not absolute |
ReleaseArgesAim | vehicle | Releases every held direction at once |
Aim is held, not absolute: the beam swings while a direction is down.
- A direction left down sweeps forever. If your key-up can go missing, call
ReleaseArgesAim— it drops everything held and is safe when nothing is SetArges(vehicle, false)does not cancel a trigger rule holding the spotlight on
Example
-- Dispatch puts this unit into code 3.
local function goCode3()
local veh = GetVehiclePedIsIn(PlayerPedId(), false)
local st = exports['tELS']:GetLightState(veh)
if not st then return end -- not a tELS vehicle
if not st.canWrite then return end -- not ours to drive right now
if st.maxStage > 0 then
exports['tELS']:SetStage(veh, st.maxStage)
else
exports['tELS']:SetLights(veh, true)
end
exports['tELS']:SetSiren(veh, true, 1)
endState bags
Entity state bags
Read with Entity(vehicle).state['key'], from client or server. The server writes exactly
four keys.
| Key | Type | Description |
|---|---|---|
tels:sync | table | The whole lighting and siren state. Fields below |
tels:ownedBy | number | Server ID of the player who claimed this vehicle |
tels:presenceDetected | boolean | Presence condition currently satisfied |
tels:argesAim | table | { argesAimYaw, argesAimPitch }. Never written in this build |
tels:sync fields
A field is absent until first set, so always supply a default.
| Field | Type | Default | Description |
|---|---|---|---|
active | boolean | false | Emergency lights active |
patternIdx | number | 1 | Pattern index, 1-based. 0 is lights-only |
stage | number | 0 | 0 off, 1–3 |
sirenOn | boolean | false | Main siren playing |
sirenTone | number | 1 | Main siren tone index |
auxSirenOn | boolean | false | Aux siren playing |
auxSirenTone | number | 1 | Aux siren tone index |
sirenBurst | boolean | false | Burst tone currently held |
burstTone | number | 1 | Tone the burst plays. Does not change sirenTone |
hornActive | boolean | false | Horn or airhorn active |
cruiseOn | boolean | false | Cruise on |
takedownOn | boolean | false | Takedown on |
blackout | boolean | false | Running dark: lighting suppressed, state intact |
taMode | string | "off" | "off", "left", "right", "center" |
presenceEnabled | boolean | false | Presence detection armed |
chirpActive | boolean | false | Chirp tone running |
rumblerOn | boolean | false | Rumbler variant active |
argesOn | boolean | false | Spotlight active. Never true in this build |
argesAimYaw | number | 0.0 | Spotlight aim, horizontal degrees |
argesAimPitch | number | 0.0 | Spotlight aim, vertical degrees |
paActive | boolean | false | PA mic broadcasting from this vehicle's driver |
Player state bags
Read with Player(serverId).state['key'].
| Key | Type | Description |
|---|---|---|
tels:owner | boolean | true while that player owns any tELS vehicle. Used to filter other officers out of presence detection |
lbarPaActive | boolean | true on the player currently holding the PA key |
lbarPaActive and tels:sync.paActive are different facts: the vehicle field says the
speaker is live, this one says who is talking. A front passenger's PA is relayed by the
controller, so the two can differ.
Example
-- React to a nearby vehicle going Code 3
CreateThread(function()
while true do
Wait(500)
local veh = GetClosestVehicle(coords.x, coords.y, coords.z, 30.0, 0, 71)
local sync = veh ~= 0 and Entity(veh).state['tels:sync']
if sync and sync.active and (sync.stage or 0) >= 2 and sync.sirenOn then
-- code 3 behavior
end
end
end)tels:sync is nil on any vehicle tELS has never written state for. Check before indexing.
Network events
Server → client
| Event | Payload | Purpose |
|---|---|---|
tels:config_receive | configs (modelName → config), merge (boolean) | Vehicle configs, sent latently. merge true carries only the changed model — apply it on top of what you hold. merge absent or false carries the whole map and replaces it |
tels:serverDefaults | defaults | Admin display defaults, available layouts, isAdmin flag |
tels:sirenBanks | map (SoundSet → bank path) | Discovered third-party siren pack mappings |
tels:ownershipAck | netId | Your tels:claimOwnership was accepted. Wait for it — every tels:stateBagRelay sent before it arrives is discarded |
tels:frontSeatCommand | netId, action, a, b | A front passenger's control, forwarded to the controller. Sent to that one client |
tels:notify | msg | Inbound hook. Trigger it from your resource to show a tELS notification on the target client |
Client → server
| Event | Payload | ACE | Purpose |
|---|---|---|---|
tels:requestDefaults | — | — | Request server defaults and available layouts |
tels:sirenBanks_request | — | — | Request the SoundSet → bank map |
tels:saveServerDefaults | data | tlib.admin | Persist new server defaults |
tels:claimOwnership | netId | — | Claim ownership for state relay. Answered with tels:ownershipAck |
tels:releaseOwnership | netId | — | Give up the relay right and clear tels:owner. Ignored unless the server still records you as owner |
tels:paFlag | netId, active | — | Set lbarPaActive on yourself. A true needs a front seat in that vehicle; a false is always accepted. One per 100 ms |
tels:frontSeatCommand | netId, action, a, b | — | Hand a control to the controller. Only from a front passenger who is not the controller; a and b must be nil, boolean, number, or a string ≤32 chars. One per 25 ms |
tels:stateBagRelay | netId, delta, seq | — | Relay a state delta. seq is a required monotonic counter; a call omitting it is silently dropped. Only the registered owner is accepted |
tels:presenceSync | netId, detected | — | Report presence. Not ownership-gated. Aggregated per reporter; a true is a lease re-sent at least every 15 s. One per 500 ms per player, except re-sending a true you already hold |
tels:ref_edit_pattern_delta | model, patternName, editData | tlib.admin | Apply a pattern delta to a referenced source |
tels:ref_edit_trigger | model, triggerId, newTrigger | tlib.admin | Replace a trigger in a referenced source |
tels:ref_edit_siren | model, newSirenConfig | tlib.admin | Update tones, airhorn and chirp on a referenced source |
tels:ref_edit_settings | model, newConfig | tlib.admin | Update siren behaviour settings on a referenced source |
Discovery events
| Event | Direction | Purpose |
|---|---|---|
tels:config_receive | S → C | Authoritative config broadcast — see the merge flag above |
tels:externalSourceInfo | S → C | Which resource bundled each model's config |
tels:exportTargets | S → C | Models available for export or bundling |
tels:config_request | C → S | Ask for the whole map. Answered latently, to the requester only |
tels:config_save | C → S | Persist a model's config. The editor's channel — tlib.admin |
Discovery metadata
| Field | Value |
|---|---|
| Metadata key | tels_config |
| Default filename | tels.json |
| Local storage | data.json at the tELS resource root |
| Event prefix | tels |
Full setup: Configuration → Vehicle-developer export.
Internal globals
For scripts that merge into the tELS resource. Names and signatures may change.
| Global | Source | Purpose |
|---|---|---|
lbarGetLocalState(vehicle) | cl_lights.lua | Local state table. nil for a remote vehicle |
lbarGetMaxStage(modelName) | cl_lights.lua | Max configured stage for a model |
getVehicleConfig(modelName) | cl_lights.lua | Full resolved config |
getCustomPatterns(modelName) | cl_lights.lua | Resolved patterns, refs dereferenced |
getResolvedTriggers(modelName) | cl_lights.lua | Resolved triggers |
getSirenConfig(modelName) | cl_lights.lua | Resolved siren config |
resolveColorIndex(led, ledIndex, frame, alias) | shared/utils.lua | Pattern-cell lookup with legacy fallback. alias maps local → source keys for $ref patterns |
renderLEDSet(veh, leds, colors, opts) | cl_renderer.lua | Unified LED render entry point |
tELS
Still stuck? Support can answer it directly.
Was this page helpful?
TIMMYG Studios