Description
A working ESX police job: an officer aims at the nearest player and runs /cuff to toggle handcuffs, then jails them for a set number of minutes. The jail teleports and freezes the convict, counts down, and releases them at the police station. This is the core law-enforcement loop every roleplay server needs.
Prompt Template
You are writing a FiveM resource for es_extended (stable, exports getSharedObject).
Produce TWO files (client.lua + server.lua) for a police job:
Client:
- A getClosestPlayer(maxDist) helper that iterates GetActivePlayers(), skips the
local PlayerPedId(), and returns the closest player index within range.
- RegisterCommand("cuff") that finds the nearest player and fires
TriggerServerEvent("police:toggleCuff", GetPlayerServerId(pid)). Do NOT apply
cuffs locally — wait for the server's reply.
- RegisterNetEvent("police:setCuffState", state) that plays/clears the
mp_arresting anim (RequestAnimDict + a `while not HasAnimDictLoaded` loop).
- RegisterNetEvent("police:sendToJail", seconds) that teleports, FreezeEntityPosition,
counts down with Wait(1000) in a CreateThread, then unfreezes and releases.
Server:
- Validate the caller is job.name == "police" via ESX.GetPlayerFromId(source).
- Validate the target exists before toggling/jailing.
- police:jail takes minutes; the SERVER computes seconds and owns the timer.
Use PlayerPedId(), never GetPlayerPed(-1). Return only Lua, separated by
"-- ===== client.lua =====" and "-- ===== server.lua =====" banners.
Expected Output
The reference Lua lives at content/expected-outputs/jobs/02-police-arrest-cuff-jail.lua. It implements the closest-player scan, server-validated cuff toggle, and a server-driven jail timer. The fxmanifest splits the file into a client_script (commands, anims, teleport) and a server_script (job check, cuff state map, jail dispatch).
-- 02-police-arrest-cuff-jail.lua
-- ESX police job: cuff/uncuff a nearby player, arrest, and a server-tracked jail timer.
-- This file holds BOTH sides; deploy as client.lua + server.lua per the banners.
-- ===== client.lua =====
local ESX = exports["es_extended"]:getSharedObject()
local isCuffed = false
-- Find the closest player ped within range of the local player.
local function getClosestPlayer(maxDist)
local myPed = PlayerPedId()
local myCoords = GetEntityCoords(myPed)
local closest, closestDist = -1, maxDist or 2.5
for _, pid in ipairs(GetActivePlayers()) do
local target = GetPlayerPed(pid)
if target ~= myPed then
local d = #(myCoords - GetEntityCoords(target))
if d < closestDist then
closest, closestDist = pid, d
end
end
end
return closest
end
-- /cuff toggles cuffs on the nearest player (police only enforced server-side).
RegisterCommand("cuff", function()
local pid = getClosestPlayer(2.5)
if pid == -1 then
ESX.ShowNotification("No one nearby to cuff.")
return
end
TriggerServerEvent("police:toggleCuff", GetPlayerServerId(pid))
end, false)
-- Apply or clear the cuff animation/state on this client.
RegisterNetEvent("police:setCuffState", function(state)
isCuffed = state
local ped = PlayerPedId()
if state then
RequestAnimDict("mp_arresting")
while not HasAnimDictLoaded("mp_arresting") do Wait(0) end
TaskPlayAnim(ped, "mp_arresting", "idle", 8.0, -8.0, -1, 49, 0, false, false, false)
SetEnableHandcuffs(ped, true)
else
ClearPedTasks(ped)
SetEnableHandcuffs(ped, false)
end
end)
-- Jail teleport + freeze for the duration the server dictates.
RegisterNetEvent("police:sendToJail", function(seconds)
local ped = PlayerPedId()
SetEntityCoords(ped, 1641.8, 2570.3, 45.5, false, false, false, false)
FreezeEntityPosition(ped, true)
CreateThread(function()
local remaining = seconds
while remaining > 0 do
Wait(1000)
remaining = remaining - 1
end
FreezeEntityPosition(ped, false)
SetEntityCoords(ped, 441.0, -982.0, 30.7, false, false, false, false)
ESX.ShowNotification("You have been released.")
end)
end)
-- ===== server.lua =====
local ESX = exports["es_extended"]:getSharedObject()
local cuffedPlayers = {}
local function isCop(xPlayer)
return xPlayer and xPlayer.job and xPlayer.job.name == "police"
end
RegisterNetEvent("police:toggleCuff", function(targetId)
local copPlayer = ESX.GetPlayerFromId(source)
local target = ESX.GetPlayerFromId(targetId)
if not isCop(copPlayer) or not target then return end
local newState = not cuffedPlayers[targetId]
cuffedPlayers[targetId] = newState or nil
TriggerClientEvent("police:setCuffState", targetId, newState)
end)
RegisterNetEvent("police:jail", function(targetId, minutes)
local copPlayer = ESX.GetPlayerFromId(source)
local target = ESX.GetPlayerFromId(targetId)
if not isCop(copPlayer) or not target then return end
local seconds = (tonumber(minutes) or 5) * 60
TriggerClientEvent("police:sendToJail", targetId, seconds)
end)
Known Failure Modes
- Client-trusted authority — Claude often applies cuffs/jail directly client-side. Force the cuff toggle and jail dispatch through the server with an
xPlayer.job.name == "police"check and target validation. - Wrong ped/player scan —
GetPlayerPed(-1)is deprecated; iterateGetActivePlayers()and useGetPlayerPed(pid)+GetPlayerServerId(pid). - Client-side timer — a countdown on the client can be edited away. Keep the duration and release logic authoritative; the client only renders the freeze.
- Missing anim load —
TaskPlayAnimbefore the dict loads silently no-ops; alwaysRequestAnimDict+while not HasAnimDictLoaded do Wait(0) end.
Integration Notes
- Split the banners into
client.luaandserver.lua; list both infxmanifest.lua(client_script 'client.lua',server_script 'server.lua'). - Requires
es_extendedstarted first, plus apolicejob seeded in yourjobstable. - Test on a dev server with two connected clients: one set to
police, then/cuffand/jailthe other and confirm the release teleport fires after the timer.
Profit Potential
$500–$7000/mo on Tebex (expected ~$1800). [INFERRED] priced inside the $50-389 script band against the signal-scraper tebex_snapshot corpus (median seller $11.85K/mo, n=100), scaled for a hot job-systems niche at intermediate difficulty — police is a top-demand category every RP server buys.
Trend Signal
🔥 hot — custom FiveM job systems = niche-selection LAUNCH #1 (4.75).
Sales Angle
Position as the anti-cheat police core: server-validated cuffing, target checks, and a server-owned jail timer no modded client can edit. Law enforcement is a must-have on every RP server — list at $189.
Difficulty & Ship Time
intermediate · ships in 1 day.