# Job в DarkRP, как надо

Где на самом деле живут job, что делает каждое поле и пять ошибок, которые стоят вечера. В том числе та, что перезаписывает job вообще без ошибок.

- Платформа: Garry's Mod
- Каноническая страница: https://devtoolsgg.com/ru/guides/gmod/darkrp-jobs

DarkRP настраивается правкой Lua, и самый распространённый способ сломать сервер
— править не тот Lua. Этот гайд о том, где на самом деле живут job, что делает
каждое поле и какие ошибки дают именно те сообщения, на которые вы иначе
потратите вечер.

## Никогда не правьте сам DarkRP

Гейммод поставляется с папкой `darkrpmodification`. Именно туда идут ваши
изменения.

```text
garrysmod/addons/darkrpmodification/lua/darkrp_customthings/
    jobs.lua
    entities.lua
    shipments.lua
    doorgroups.lua
    ...
```

Правьте `gamemodes/darkrp` напрямую — и ваша работа исчезнет со следующим
обновлением. Правьте `darkrpmodification` — и она переживёт его, потому что
обновление DarkRP этот аддон не трогает.

> [!IMPORTANT]
> Если у вас нет `darkrpmodification`, поставьте его прежде всего остального. Это
> отдельная загрузка, не часть DarkRP, а править гейммод «просто пока не поставлю
> нормально» — это как люди теряют выходные.

## Как устроен job

Job — это вызов `DarkRP.createJob`, присвоенный глобальной переменной `TEAM_`:

```lua
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",
})
```

[Генератор job для DarkRP](/ru/gmod/darkrp-job) напишет это за вас, включая
вариант с whitelist, и не даст сделать имя `TEAM_`, которое не является
корректной глобальной переменной Lua. Разобраться всё равно стоит, потому что
чужие job вы будете читать постоянно.

### Для чего на самом деле нужно каждое поле

| Поле | Что означает |
|---|---|
| `color` | Цвет в scoreboard и над головой. |
| `model` | Одна строка или таблица. Таблица даёт игроку выбор. |
| `description` | Показывается в меню F4. Длинные скобки, а не кавычки. |
| `weapons` | Loadout при спавне, по классам оружия. |
| `command` | Набирается как `/policeofficer`. Только буквы и цифры. |
| `max` | 0 — без ограничений. 4 — четверо одновременно. |
| `salary` | Выплачивается каждый интервал payday. |
| `admin` | 0 все, 1 админы, 2 суперадмины. |
| `vote` | Голосуют ли игроки за приём в job. |
| `hasLicense` | Может выдавать лицензии на оружие. |
| `candemote` | Можно ли снять с этого job голосованием. |

Классы оружия не угадывают: [список классов оружия](/ru/gmod/list/weapons) — это
все классы, которые регистрирует игра, и в нём указано, какие из них существуют
только когда смонтирован Half-Life: Source.

## Пять ошибок, которые стоят вечера

### 1. Два job с одним именем TEAM

```lua
TEAM_POLICE = DarkRP.createJob("Police Officer", { ... })
TEAM_POLICE = DarkRP.createJob("Police Chief", { ... })
```

Второй молча перезаписывает первый. Никаких ошибок, один пропавший job и час
недоумения. Каждому job нужна своя глобальная переменная.

### 2. `]]` внутри description

```lua
description = [[Guard the vault [[loot]] and stay alert.]],
```

Строка заканчивается на первом же `]]`, и всё, что идёт дальше, превращается в
синтаксис, который парсер не может разобрать. Используйте `[==[ ... ]==]`, когда
в тексте есть квадратные скобки, или обойдитесь без них.

### 3. Модель, которая не смонтирована

Job, указывающий на модель, которой нет на сервере, спавнит игроков в виде знака
ошибки. [Список playermodel](/ru/gmod/list/player-models) — это все модели,
которые Garry's Mod регистрирует по умолчанию; всё остальное должно лежать в
аддоне, реально установленном на **сервере**, а не только на вашем клиенте.

### 4. Правка на работающем сервере

DarkRP читает эти файлы при запуске. Сохранение `jobs.lua` на живом сервере
ничего не меняет до перезапуска — вот почему на «мой job не появляется» чаще
всего отвечают «перезапусти».

### 5. Command с пробелом или дефисом

```lua
command = "police officer",
```

`command` становится командой в чате. Пробелы, дефисы и буквы с диакритикой его
ломают. Буквы и цифры, ничего больше.

> [!TIP]
> Когда job не появляется, читайте консоль сервера при запуске, а не гадайте.
> DarkRP печатает понятную ошибку с файлом и строкой для всего, что не смог
> загрузить.

## Категории, чтобы меню F4 не было стеной

После десятка job меню нужно группировать. Категория создаётся один раз, а потом
на неё ссылаются по имени:

```lua
DarkRP.createCategory{
    name = "Civil Protection",
    categorises = "jobs",
    startExpanded = true,
    color = Color(25, 25, 170, 255),
    canSee = fp{fn.Id, true},
    sortOrder = 101,
}
```

Поле `category` у job должно совпадать с `name` **в точности**, включая регистр.
Несовпадение не даёт ошибки: job просто попадает в группу по умолчанию.
[Генератор категорий](/ru/gmod/darkrp-category) держит их согласованными.

## Whitelist для job

Есть два способа, и они не равнозначны.

**Встроенный whitelist** — это `customCheck`, который выполняется, когда кто-то
пытается взять job:

```lua
customCheck = function(ply)
    return table.HasValue({"vip", "admin", "superadmin"}, ply:GetUserGroup())
end,
CustomCheckFailMsg = "This job is reserved for VIP members.",
```

Всегда задавайте `CustomCheckFailMsg`. Без него игрок получает отказ без
объяснений и идёт спрашивать вас.

**Поле `admin`** проще, но грубее: `admin = 1` ограничивает job админами, без
сообщения и без места для донатерского ранга.

## Когда job заработали

- [Door group](/ru/gmod/darkrp-doorgroup), чтобы участком владела только полиция.
  Учтите, что функция — это глобальная `AddDoorGroup`, а не вызов
  `DarkRP.create`.
- [Agenda](/ru/gmod/darkrp-agenda) — текст с задачами, который босс пишет своей
  команде.
- [Shipment и entity](/ru/gmod/darkrp-shipment) — то, что продаёт торговец
  оружием.
- [Demote group](/ru/gmod/darkrp-demotegroup), чтобы demote с одного полицейского
  job закрывал и остальные.


## Как цитировать

Job в DarkRP, как надо, devtoolsgg.com. https://devtoolsgg.com/ru/guides/gmod/darkrp-jobs
