In EndCore a vehicle key is a real inventory item (vehicle_key). Its metadata holds the plate it opens, so keys can be dropped, traded, stolen or looted like anything else. If you carry the key, or you belong to the group that owns the vehicle, you can lock and unlock it from a distance and start the engine.
Without a key you have two options. You can lockpick a locked vehicle, using a lockpick item and a minigame. That can snap the pick and set off an alarm that draws zombies. Once you're in the driver seat you can hotwire it with a second minigame. Anyone can drive a hotwired vehicle, but hotwiring doesn't let you lock or unlock it. Bicycles need no key.
At a glance
| Depends on | /onesync, en-core, en-inventory |
| Start after | en-core, en-inventory; start before en-garages |
| Database tables | None (keys live in inventories) |
| Config files | config/shared.lua |
| Key binds | en_vehiclekeys_lock (L), en_vehiclekeys_engine (G), en_vehiclekeys_hotwire (H) |
| Target options | en-vehiclekeys:lockpick (door bones), en-vehiclekeys:toggle |
How it works
Access
A player has access to a vehicle when they carry a vehicle_key for its plate. With groupAccess on, members of the group whose id matches the vehicle's groupId state bag also have access. en-garages sets that bag on group-owned vehicles.
A player can drive a vehicle when it's in a no-key class (cycles by default), it's hotwired, or they have access.
Driving without rights
If you sit in the driver seat without the right to drive, the engine is forced off, accelerate and brake are disabled, and a "Hotwire" prompt appears. GTA's own hotwire animation is suppressed.
Lockpicking
The en-vehiclekeys:lockpick target option appears on door bones when the vehicle is locked, you have no access and you carry a lockpick. It runs encore.minigame.lockpick with your lockpick skill bonus. On success the vehicle unlocks and, with probability alarmChance, the alarm sounds for alarmSeconds. An alarm also sends a horn noise to en-zombies. On failure the pick is lost with probability loseOnFail. A snapped pick is always lost. Lockpicking awards thievery XP.
Hotwiring
From the driver seat, press H to run encore.minigame.hotwire with your hotwire skill bonus. Success sets the hotwired state bag. After a failure you must wait retryDelay seconds before trying again. Hotwiring awards thievery and mechanics XP.
Anti-cheat
The server enforces minimum durations (1.5 s for lockpicking, 2 s for hotwiring) and a 4 m distance, so a modified client can't skip the minigames.
Configuration
| Key | Default | What it does |
|---|---|---|
Config.item | 'vehicle_key' | Key item. Metadata is { plate, vehicle } |
Config.keys | lock = 'L', engine = 'G', hotwire = 'H' | Default key binds |
Config.lockDistance | 12.0 | Metres a key can lock or unlock from |
Config.groupAccess | true | Group members can use vehicles whose groupId matches their group |
Config.noKeyClasses | { [13] = true } | Vehicle classes that need no key (13 = cycles) |
Config.lockpick | item = 'lockpick', difficulty = 'medium', loseOnFail = 0.35, alarmChance = 0.5, alarmSeconds = 20, xp = { thievery = 15 } | Lockpicking vehicle doors |
Config.hotwire | difficulty = 'medium', retryDelay = 4, xp = { thievery = 10, mechanics = 4 } | Hotwiring |
Harder, noisier break-ins, and no key needed for motorcycles:
Config.noKeyClasses = { [8] = true, [13] = true } -- 8 = motorcycles
Config.lockpick = {
item = 'lockpick', difficulty = 'hard',
loseOnFail = 0.5, alarmChance = 0.75, alarmSeconds = 30,
xp = { thievery = 20 },
}Exports
Server
| Export | Arguments | Returns |
|---|---|---|
GiveKey | source, plate, label? | boolean. Adds a vehicle_key with { plate, vehicle = label } |
HasKey | source, plate | boolean |
RemoveKey | source, plate | Result of encore.inventory.removeItem |
HasAccess | source, vehicle | boolean: key or group ownership (hotwiring doesn't count) |
SetLocked | vehicle, locked | Sets the door lock and the locked state bag. Anything other than false locks |
IsLocked | vehicle | boolean |
SetHotwired | vehicle, hotwired | Sets the hotwired state bag |
NormalisePlate | plate | Upper-cased, trimmed plate string |
Client
| Export | Arguments | Returns |
|---|---|---|
HasKey | plate | boolean, from the local inventory |
HasAccess | vehicle | boolean: key or group |
CanDrive | vehicle | boolean: no-key class, hotwired, or access |
ToggleLock | vehicle? | Toggles the lock on the given or nearest vehicle (async) |
Commands
| Command | Restricted | What it does |
|---|---|---|
/givekey [target] | group.admin | Gives a key for the vehicle you're sitting in. The target defaults to you |
Events
Server-local events:
| Event | Payload |
|---|---|
en-vehiclekeys:server:lockpicked | source, vehicle, alarmTriggered |
en-vehiclekeys:server:hotwired | source, vehicle |
Client events, sent to players within 60 m:
| Event | Payload |
|---|---|
en-vehiclekeys:client:lockFeedback | { netId, locked } |
en-vehiclekeys:client:alarm | { netId, seconds } |
State bags
| Key | Meaning |
|---|---|
locked | Mirror of the server's lock status |
hotwired | Anyone can drive this vehicle |
groupId | Read only; set by en-garages on group-owned vehicles |
Examples
Hand a player a key for a vehicle your script spawned:
-- server
local vehicle = CreateVehicleServerSetter(`rebel`, 'automobile', coords.x, coords.y, coords.z, heading)
local plate = exports['en-vehiclekeys']:NormalisePlate(GetVehicleNumberPlateText(vehicle))
exports['en-vehiclekeys']:GiveKey(source, plate, 'Karin Rebel')
exports['en-vehiclekeys']:SetLocked(vehicle, true)Only let a player open a vehicle's trunk if they have access:
-- client
local vehicle = GetVehiclePedIsIn(PlayerPedId(), true)
if vehicle ~= 0 and exports['en-vehiclekeys']:HasAccess(vehicle) then
-- open the trunk inventory
endReact to break-ins, for example to raise a player's wanted status in your own script:
AddEventHandler('en-vehiclekeys:server:lockpicked', function(source, vehicle, alarmTriggered)
if alarmTriggered then
print(('%s set off a car alarm'):format(GetPlayerName(source)))
end
end)