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

FieldMeaning
colorThe colour in the scoreboard and above the head.
modelOne string, or a table. A table gives players a choice.
descriptionShown in the F4 menu. Long brackets, not quotes.
weaponsSpawn loadout, by weapon class.
commandTypes as /policeofficer. Letters and digits only.
max0 means unlimited. 4 means four at a time.
salaryPaid every payday interval.
admin0 everyone, 1 admins, 2 superadmins.
voteWhether players vote the job in.
hasLicenseMay give gun licences.
candemoteWhether 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 a DarkRP.create call.
  • 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.

Tools this guide uses