A job gives a survivor a role: scavenger, medic, craftsman or trader. Each character has one active job and remembers the grade they reached in every job they have held. Other resources read the job to unlock shops, crafting benches, doors and more.
How jobs work
PlayerData.jobis the active job:{ name, label, grade, payment, isboss, onduty, type }.PlayerData.jobsmaps every job the character has held to its grade, for example{ survivor = 0, medic = 2 }.SetJobrecords the entry each time.- Changing job resets
ondutyto that job'sdefaultDuty. A savedonduty = falseis kept across logins. - If a character's saved job no longer exists in
shared/jobs.lua, they fall back tosurvivorgrade 0 on login.
Jobs store payment and offDutyPay, but en-core has no paycheck loop. Nothing in en-core pays players on a timer.
Default jobs
| Job | Type | Grades (pay) |
|---|---|---|
survivor (the fallback job) | civilian | 0 Wanderer (0) |
scavenger | survivor | 0 Novice (50), 1 Experienced (75), 2 Expert (100), 3 Master (150, boss) |
medic | medical | 0 First Responder (75), 1 Paramedic (100), 2 Doctor (150), 3 Chief Medical Officer (200, boss) |
craftsman | crafting | 0 Apprentice (50), 1 Craftsman (75), 2 Master Craftsman (100), 3 Guild Master (150, boss) |
trader | merchant | 0 Peddler (40), 1 Merchant (75), 2 Senior Merchant (100), 3 Trade Master (150, boss) |
Adding a job
Jobs live in shared/jobs.lua, which is loaded on both server and client. Each entry is:
| Field | What it does |
|---|---|
label | Display name |
defaultDuty | Whether the player is on duty when they get the job |
offDutyPay | Stored with the job; not used by en-core |
type | A free-form category other resources can check |
grades | A table keyed by grade number, each { name, payment, isboss? } |
-- shared/jobs.lua
mechanic = {
label = 'Mechanic',
defaultDuty = true,
offDutyPay = false,
type = 'crafting',
grades = {
[0] = { name = 'Grease Monkey', payment = 40 },
[1] = { name = 'Mechanic', payment = 80 },
[2] = { name = 'Workshop Boss', payment = 120, isboss = true },
},
},Restart the server after editing jobs. Keep survivor in the table, because it is the fallback job.
Changing a job
- In code:
player.Functions.SetJob(jobName, grade). It returnsfalseif the job or grade does not exist. - As an admin:
/setjob <player> <job> [grade].
Toggle duty with player.Functions.SetDuty(onduty), or with no argument to flip it. A client can toggle its own duty by sending the net event encore:server:toggleDuty.
Exports and functions
| Where | Name | Arguments | Returns |
|---|---|---|---|
| Player object | Functions.SetJob | jobName, grade?, skipUpdate? | boolean |
| Player object | Functions.SetDuty | onduty? | boolean (the new duty state) |
| Server export | GetJobs() | none | The job table |
| Client export | GetJobs() | none | The job table |
Events
| Side | Event | Payload |
|---|---|---|
| Server | encore:server:onJobUpdate | source, job |
| Server | encore:server:onDutyUpdate | source, onduty |
| Client (net) | encore:client:onJobUpdate | job |
| Client (net) | encore:client:onDutyUpdate | onduty |
| Client sends | encore:server:toggleDuty | none |
Examples
Hire a player as a medic and check their grade later:
local player = exports['en-core']:GetPlayer(source)
if player and player.Functions.SetJob('medic', 1) then
encore.notify(source, { description = 'You joined the medics.', type = 'success' })
end
-- elsewhere
local data = exports['en-core']:GetPlayer(source).PlayerData
if data.job.name == 'medic' and data.job.onduty and data.job.grade >= 2 then
-- allow surgery
endA duty toggle key on the client:
RegisterCommand('duty', function()
TriggerServerEvent('encore:server:toggleDuty')
end, false)
RegisterNetEvent('encore:client:onDutyUpdate', function(onduty)
print(onduty and 'On duty' or 'Off duty')
end)React to job changes on the server:
AddEventHandler('encore:server:onJobUpdate', function(source, job)
print(('%s is now %s (%s)'):format(GetPlayerName(source), job.label, job.grade))
end)