Vehicle Emergency Lighting (ELS)
Last updated
May be stale
This page was last updated ago, on 25 August 2026. Check what it says against the code before relying on it.
Civilian-installable emergency lighting is handled by the Vehicles plugin
(core/plugins/vehicles/sh_init.lua / sv_init.lua). A player uses one of four items on a
vehicle they own, and the plugin swaps in a Photon lighting preset for that model.
Groups
| Constant | Item (uniqueID) |
Photon flag | Gate |
|---|---|---|---|
POLICE |
veh_pwl |
CityRP_IsPoliceELS |
LEO pass/orange, Presidential pass/red, IsLawenforcement(), IsPresident(), or IsRescue() (ERT) |
WARNING |
veh_awl |
CityRP_IsAmbers |
None (amber warning lights) |
ARROWS |
veh_arrows |
CityRP_IsArrowboard |
None (amber + directional arrowboard) |
MEDICAL |
veh_mwl |
CityRP_IsMedicalELS |
IsDoctor() or IsRescue() (ERT; covers Paramedic and Fire Chief) |
Gates live in onVehicleLightsUsed in sv_init.lua. Each item's onUse just calls
onVehicleLightsUsed(ply, <GROUP>). The Photon flag column is the field a preset sets to claim the
group for itself — see Self-registering from a Photon file.
carLighting — model to Photon preset
carLighting[string.lower(model)][GROUP] maps a vehicle model to the name a Photon preset was
registered under (list.Set("Vehicles", name, V) — the key, which is conventionally also
V.Name). onVehicleLightsUsed looks the preset up with list.Get("Vehicles")[loadout] and
merges it onto the vehicle's VehicleTable.
Most entries are hand-written at the top of sh_init.lua:
carLighting["models/metrohd/audi_a6.mdl"] = {"AudiA6_RB", "AudiA6_AW"}
-- array-style: index 1 = POLICE, 2 = WARNING, 3 = ARROWS (matches the constants below)
carLighting["models/tdmcars/trucks/gmc_c5500.mdl"] = {[WARNING] = "GMCC5500_AW"}
-- or explicit group keys when a model only supports some groups
Self-registering from a Photon file
A Photon vehicle registration (an addons/vehicles_emvu/lua/autorun/*.lua file, or any other
list.Set("Vehicles", name, V) call) can set its group's flag from the Groups table to
claim itself as that group's preset, instead of requiring a hand-written carLighting entry:
local V = {
Name = name,
Model = "models/metrohd/audi_a6.mdl",
-- ...
CityRP_IsPoliceELS = true,
}
list.Set("Vehicles", V.Name, V)
mergeSelfRegisteredLighting() (in sh_init.lua, runs once from the CityRP.Core.PostItemLoad
hook) scans every registered Photon vehicle and fills in any carLighting[model][group] slot that
isn't already set. A hand-written entry always wins — self-registration only fills gaps, it
never overwrites a hand-authored mapping.
Either kind of clash is dropped instead of silently picking one, and logged via
PLUGIN.logger:Warning(...) (cityrp.logging, namespace plugin.Vehicles; see
logging.md) so it shows up in console/DB without being confused for an audit event:
- A self-registered preset tries to claim a group another self-registered preset already claimed for that model.
- A self-registered preset tries to claim a group a hand-written
carLightingentry already set for that model.
Use self-registration for new Photon presets going forward — it keeps the "which vehicle supports
which lighting" fact next to the preset that answers it, instead of requiring a second edit in
sh_init.lua that's easy to forget. The hand-written table isn't being migrated off; it stays for
existing entries and as an override when you need one preset for a model to win over another's
self-registration.