GKSHOP
GKSPHONE V2

Job Center

Define solo and group jobs for the Job Center app, and drive them from your own scripts.

The Job Center lists jobs players can pick up, alone or as a group, and tracks a task list while they work. Two ship as working examples — sanitation and carthief.

WhatWhere
Job listgksphone/config/jobs/sh_jobs.lua
Task listsgksphone/config/jobs/sh_tasks.lua
Example scriptsgksphone/server/jobs/, gksphone/client/apps/jobs/

Define a job

Add an entry to GKSJobs.Jobs, keyed by the job code:

gksphone/config/jobs/sh_jobs.lua
["carthief"] = {
    ["Name"]         = "carthief",
    ["Label"]        = "Car Thief",
    ["Description"]  = "We need someone with magic hands. Is that you?",
    ["Icon"]         = "directions_car",
    ["IconColor"]    = "red",
    ["Rating"]       = 4,
    ["Money"]        = math.random(100, 1000),
    ["MimWorkers"]   = 1,
    ["MaxWorkers"]   = 1,
    ["Location"]     = false,
    ["RequiredItem"] = true,
    ["ItemRequired"] = "lockpick",
    ["IsActive"]     = true
},
Field
NameJob code. Match the table key
LabelName shown in the app
DescriptionBlurb on the job card
IconA Google Material Symbols name
IconColorIcon colour
RatingDifficulty stars shown on the card
MoneyPayout. Your job script reads this — wrap it in math.random for a range
MimWorkers / MaxWorkersGroup size limits
Locationvector3 or vector4 start point, or false for none
RequiredItemtrue if an item is needed to see the job
ItemRequiredThe item's name. Only read when RequiredItem is true
IsActiveWhether the job is listed at all

RequiredItem and ItemRequired are two different fields. RequiredItem is the on/off switch, ItemRequired holds the item name — putting the name in RequiredItem does not work.

Define its tasks

Keyed by the same job code, in order:

gksphone/config/jobs/sh_tasks.lua
['sanitation'] = {
    { ["TaskId"] = 1, ["TaskText"] = "Get in the garbage truck", ["Finished"] = false },
    { ["TaskId"] = 2, ["TaskText"] = "Go to mission area",       ["Finished"] = false },
    {
        ["TaskId"]    = 3,
        ["TaskText"]  = "Collect trash %s",
        ["Finished"]  = false,
        ["ExtraDone"] = 0,
        ["ExtraNeed"] = 10
    },
}
Field
TaskIdStarts at 1, increments by one
TaskTextShown to the player. %s is replaced with progress
FinishedAlways false here — the phone flips it
ExtraDone / ExtraNeedFor counted tasks: starting count and target

Events

-- Fires for every group member when the job starts
RegisterNetEvent("gksphone:client:JobStartTask", function(jobInfoName, Tasks) end)

-- Fires for the group leader only
RegisterNetEvent("gksphone:client:jobStartLeader", function(jobInfoName) end)

-- Fires for every member when the task advances
RegisterNetEvent("gksphone:client:JobNextTask", function(NewTaskID) end)

There is no finish event. Your script decides when the job is done, and must delete the group itself with DeleteJobGroup.

Exports

Server

-- Group of the player who leads it
local group = exports["gksphone"]:GetJobGroupByLeader(identifier)

-- Group a player belongs to
local group = exports["gksphone"]:GetGroupByMember(identifier)

-- End the job
exports["gksphone"]:DeleteJobGroup("carthief", groupID)

Client

exports["gksphone"]:IsGroupLeader()              -- boolean
exports["gksphone"]:IsTaskStatus(taskId)         -- boolean, is that task finished
exports["gksphone"]:TaskList()                   -- the current task list

-- Mark a task done, or advance a counted one
exports["gksphone"]:TaskUpdate(taskId, true, extraDone)

-- Rewrite the whole list, e.g. to change task text mid-job
exports["gksphone"]:TaskListUpdate(taskList)

TaskUpdate's third argument is the new ExtraDone count for counted tasks — pass 0 for a plain one.

On this page