DarkRP Jobs, Done Properly
Where jobs actually belong, what every field does, and the five mistakes that cost an evening. Including the one that overwrites a job with no error at all.
5 minute read
DarkRP is configured by editing Lua, and the single most common way to break a server is editing the wrong Lua. This guide covers where jobs actually belong, what each field does, and the mistakes that produce the errors you will otherwise spend an evening on.
Never edit DarkRP itself
The gamemode ships a folder called darkrpmodification. That is where your
changes go.
garrysmod/addons/darkrpmodification/lua/darkrp_customthings/ jobs.lua entities.lua shipments.lua doorgroups.lua ...
Edit gamemodes/darkrp directly and your work is deleted by the next update.
Edit darkrpmodification and it survives, because updating DarkRP never touches
that addon.
If you do not have darkrpmodification, install it before anything else. It
is a separate download from DarkRP itself, and editing the gamemode "just
until I install it properly" is how people lose a weekend.
The shape of a job
A job is a call to DarkRP.createJob, assigned to a TEAM_ global:
TEAM_POLICE = DarkRP.createJob("Police Officer", { color = Color(25, 25, 170, 255), model = {"models/player/police.mdl", "models/player/police_fem.mdl"}, description = [[Keep the peace and arrest criminals.]], weapons = {"arrest_stick", "unarrest_stick", "stunstick", "weaponchecker"}, command = "policeofficer", max = 4, salary = 65, admin = 0, vote = true, hasLicense = true, candemote = true, category = "Civil Protection",})
The DarkRP Job Generator writes this for you, including the
whitelist variant, and it will not let you produce a TEAM_ name that is not a
valid Lua global. Worth understanding anyway, because you will read other
people's jobs constantly.
What each field is actually for
| Field | Meaning |
|---|---|
color | The colour in the scoreboard and above the head. |
model | One string, or a table. A table gives players a choice. |
description | Shown in the F4 menu. Long brackets, not quotes. |
weapons | Spawn loadout, by weapon class. |
command | Types as /policeofficer. Letters and digits only. |
max | 0 means unlimited. 4 means four at a time. |
salary | Paid every payday interval. |
admin | 0 everyone, 1 admins, 2 superadmins. |
vote | Whether players vote the job in. |
hasLicense | May give gun licences. |
candemote | Whether this job can be demote-voted. |
Weapon classes are not guessed: the weapon class list is every class the game registers, and it tells you which ones only exist when Half-Life: Source is mounted.
The five mistakes that cost an evening
1. Two jobs sharing a TEAM name
TEAM_POLICE = DarkRP.createJob("Police Officer", { ... })TEAM_POLICE = DarkRP.createJob("Police Chief", { ... })
The second silently overwrites the first. No error, one missing job, and a confusing hour. Every job needs its own global.
2. A ]] inside a description
description = [[Guard the vault [[loot]] and stay alert.]],
The string ends at the first ]], and everything after it becomes syntax the
parser cannot make sense of. Use [==[ ... ]==] when the text contains
brackets, or avoid them.
3. A model that is not mounted
A job pointing at a model your server does not have spawns players as an error sign. The player model list is every model Garry's Mod registers by default; anything else has to be in an addon that is actually installed on the server, not only on your own client.
4. Editing while the server runs
DarkRP reads these files at startup. Saving jobs.lua on a live server changes
nothing until it restarts, which is why "my job is not showing up" is usually
answered by restarting.
5. A command with a space or a dash
command = "police officer",
command becomes a chat command. Spaces, dashes and accents break it. Letters
and digits, nothing else.
When a job does not appear, read the server console at startup rather than guessing. DarkRP prints a clear error with the file and line for anything it could not load.
Categories, so the F4 menu is not a wall
Once you pass ten jobs the menu needs grouping. A category is created once and then referenced by name:
DarkRP.createCategory{ name = "Civil Protection", categorises = "jobs", startExpanded = true, color = Color(25, 25, 170, 255), canSee = fp{fn.Id, true}, sortOrder = 101,}
The category field on a job must match name exactly, including case. A
mismatch does not error; the job simply lands in the default group. The
category generator keeps them consistent.
Whitelisting a job
Two ways, and they are not equivalent.
The built-in whitelist is customCheck, run when someone tries to take the
job:
customCheck = function(ply) return table.HasValue({"vip", "admin", "superadmin"}, ply:GetUserGroup())end,CustomCheckFailMsg = "This job is reserved for VIP members.",
Always set CustomCheckFailMsg. Without it the player is refused with no
explanation and asks you instead.
The admin field is simpler but blunter: admin = 1 limits the job to
admins, with no message and no room for a donator rank.
Once jobs work
- Door groups, so only police can own the PD. Note the
function is the global
AddDoorGroup, not aDarkRP.createcall. - Agendas, the objective text a boss writes for their team.
- Shipments and entities for what the gun dealer sells.
- Demote groups, so demotion from one police job bars the others too.