DirkScripts
Exports
A keypad has two halves:
- Server: you register it with its code, its attempt limit, and what happens when someone gets it right. The code never leaves the server.
- Client: you place the prop and call
Keypadwhen a player uses it. The client only draws the keypad and sends what was typed.
⚠️ Never trust the client with a code. Do the real thing (open the door, hand over the loot) in onGranted on the server, not after Keypad returns on the client.
A full example
{% code title="server.lua" %}
luaexports.dirk_keypad:register('bank_vault', { code = '4821', maxAttempts = 3, lockout = 60, coords = vector3(254.1, 225.3, 101.9), light = { color = 'amber', leds = { red = 1 } }, onGranted = function(src) -- the vault opens here, on the server TriggerClientEvent('mybank:openVault', -1) end, })
{% endcode %}
{% code title="client.lua" %}
lua-- when the player uses the keypad prop: CreateThread(function() exports.dirk_keypad:Keypad(keypadEntity, { id = 'bank_vault' }) end)
{% endcode %}
#Server
#register
Registers a keypad, or replaces one with the same id. A resource's keypads are removed when that resource stops.
luaexports.dirk_keypad:register(id, options)
| Argument | Type | Purpose |
|---|---|---|
id | string | Your name for this keypad. The client opens it with the same id. |
options.code | string | The code, digits only. Give this or check. |
options.check | function? | function(src, code) -> boolean, for your own rules (a code per player, a code from the database). |
options.length | number? | How many digits the keypad asks for. Default: the length of code, or 4. |
options.title | string? | The prompt on the screen. Default: ENTER CODE in the server's language. |
options.maxAttempts | number? | Wrong codes allowed before the player is locked out. Default: no limit. |
options.lockout | number? | How long the lockout lasts, in seconds. Default 30. |
options.lockScope | string? | 'keypad' (default): a lockout locks the keypad for everyone, whoever typed the wrong codes. 'player': each player gets their own attempts and their own lockout. |
options.coords | vector3? | Where the keypad is. With it, a player further than radius away can't try a code, and a lockout shows on the wall keypad there for players nearby (a red padlock screen). The server only tells players within 150 m, so a keypad's location is never sent to the whole server. |
options.radius | number? | How close the player must be to coords, in metres. Default 3.0. |
options.light | table? | This keypad's own light: color (a named colour (see Colours below) or { r, g, b }), level (backlight brightness 0–1), leds = { red, green } (0 off, 1 on, above 1 blinks that many times a second) and screen (brightness 0–1). Leave it out for the default cool white. |
options.onGranted | function? | function(src, id). Runs on the server when a player gets the code right. |
options.prompt | string? | How a player walking up is told to use it. Leave it out to use the server's Prompt style setting (see Getting Started). 'dui': a plate in the house style laid flat on the wall beside the keypad, with an arrow pointing at it, in the server's colours and language. 'text': GTA's help text. 'target' / 'interact': an option on your server's target or interact resource, through dirk_lib (falls back to 'dui' when dirk_lib isn't running). 'none': your script does its own. Needs coords. |
options.duiPosition | string? | Where the plate sits round the keypad. Leave it out to use the server's Plate position setting. 'top-right', 'top', 'top-left', 'left', 'right', 'bottom-left', 'bottom' or 'bottom-right'. |
options.heading | number? | The keypad's heading, only needed when no dirk_keypad prop stands at coords (the plate lies on its wall). |
A keypad registered with coords gets its prompt automatically: players within 25 m are told about it (only them) and pressing E next to it opens it. A keypad prop your script places itself (with no fixed coords) gets one from the client with KeypadPrompt.
By default attempts count per keypad: three wrong codes from anyone lock it for everyone, and every nearby player sees the red padlock on its screen. With lockScope = 'player', each player has their own attempts and lockout. A player can try at most one code every 0.8 seconds.
#setCode
Changes a keypad's code. Everyone's wrong attempts so far are forgotten.
luaexports.dirk_keypad:setCode('bank_vault', '7730')
#Colours
Use any { r, g, b }, or one of these names:
| Name | Colour |
|---|---|
white | 205, 225, 240: a cool white (the default) |
blue | 90, 170, 255 |
cyan | 90, 230, 240 |
green | 110, 255, 140 |
amber | 255, 176, 60 |
red | 255, 70, 60 |
purple | 190, 120, 255 |
pink | 255, 110, 190 |
The colour shows on the keypad while someone is using it. On the wall, when nobody is using it, the keys show the standard white glow.
#setCoords
Tells the server where a keypad is, when you only know once it's placed. Same as options.coords.
luaexports.dirk_keypad:setCoords('bank_vault', vector3(254.1, 225.3, 101.9))
#reset
Lifts a lockout. For a lockScope = 'player' keypad, pass a player to lift only theirs.
luaexports.dirk_keypad:reset('bank_vault') -- the keypad (everyone) exports.dirk_keypad:reset('bank_vault', src) -- one player, on a lockScope = 'player' keypad
#unregister
Removes a keypad.
luaexports.dirk_keypad:unregister('bank_vault')
#Events
Server events, for scripts that would rather listen than pass onGranted:
| Event | Arguments | When |
|---|---|---|
dirk_keypad:granted | src, id | A player got the code right. |
dirk_keypad:lockedOut | src, id | A player used the last attempt and the keypad (or, with lockScope = 'player', that player) is now locked out. |
luaAddEventHandler('dirk_keypad:lockedOut', function(src, id) if id == 'bank_vault' then -- set the alarm off end end)
#Client
#Keypad
Puts the player on a keypad. The call waits until the player finishes or steps away, so run it inside a thread.
lualocal code, ok, why = exports.dirk_keypad:Keypad(entity, options?)
| Argument | Type | Purpose |
|---|---|---|
entity | number | A placed dirk_keypad prop. See Placing a keypad in Getting Started. |
options.id | string? | The id you registered on the server. Its length, title, attempts and lockout come from there. |
options.length | number? | Only without an id: how many digits to ask for. Default 4. |
options.title | string? | Only without an id: the prompt on the screen. |
options.camDistance | number? | How far the camera sits from the keypad, in metres. Default 0.38. |
options.camAngle | vector2? | Turns the camera round to the right (x) and up (y), in degrees. Default vec2(0, 0), straight on. |
options.fov | number? | The camera's field of view. Default 32. |
| Returns | Type | Meaning |
|---|---|---|
code | string? | What the player typed, or nil if they stepped away or got locked out. |
ok | boolean | true if the server accepted the code. |
why | string | granted, locked, left, unknown (no keypad with that id on the server) or submitted (no id, so nothing was checked). |
Without an id, Keypad just returns what was typed. Only use that when you check the code on your server yourself.
#KeypadPrompt
Puts the "use the keypad" prompt on a keypad prop your script placed itself. Pressing E next to it opens the keypad with its id, so the code is still checked on the server.
lualocal handle = exports.dirk_keypad:KeypadPrompt(entity, { id = 'my_lab_door', -- the id you registered on the server duiPosition = 'top-right', canUse = function() return not doorOpen end, -- false hides the prompt }) exports.dirk_keypad:KeypadPromptRemove(handle)
| Argument | Type | Purpose |
|---|---|---|
entity | number | The dirk_keypad prop. |
options.id | string? | The id you registered on the server. E opens the keypad with it. |
options.prompt | string? | 'dui', 'text', 'target' or 'interact', as on register. Default: the server's setting. |
options.duiPosition | string? | Where the plate sits round the keypad, as on register. Default: the server's setting. |
options.canUse | function? | Return false to hide the prompt for now (a door already open, a player without access). |
options.onUse | function? | Runs on E instead of opening the keypad. |
A resource's prompts are removed when it stops. Try it with /lockpad, then /lockpad prompt dui left, /lockpad prompt text or /lockpad prompt target.
#KeypadLight
Sets the key backlight: the colour of the glowing numbers, and the glow they throw on the wall. It sets this player's default and changes the keypad live if one is in use. A keypad registered with its own light uses that instead.
luaexports.dirk_keypad:KeypadLight(color?, level?)
| Argument | Type | Purpose |
|---|---|---|
color | string | table? | A named colour (see Colours under register) or { r, g, b }, each 0–255. Default white. |
level | number? | Brightness from 0 (off) to 1. |
luaexports.dirk_keypad:KeypadLight('blue', 1.0) exports.dirk_keypad:KeypadLight({ 255, 120, 0 }) -- any colour exports.dirk_keypad:KeypadLight(nil, 0.0) -- backlight off
#KeypadLeds
Sets the red and green status LEDs above the screen. While ACCESS GRANTED, ACCESS DENIED or LOCKED is showing, the keypad sets the LEDs itself.
luaexports.dirk_keypad:KeypadLeds(red?, green?)
| Argument | Type | Purpose |
|---|---|---|
red | number? | 0 off, 1 on, or a number above 1 to blink that many times a second. |
green | number? | Same as red. |
luaexports.dirk_keypad:KeypadLeds(0, 1) -- green on: unlocked exports.dirk_keypad:KeypadLeds(2, 0) -- red blinking twice a second: alarm
#KeypadScreen
Sets the screen brightness.
luaexports.dirk_keypad:KeypadScreen(level)
| Argument | Type | Purpose |
|---|---|---|
level | number | 0 (off) to 1 (full). |
Last updated on 2 October 2026
