API Reference

Server exports for oxide-pestcontroljob — IsOnShift, GetSetting, SetSetting, GetInfo, GetShift, GetProgression and SetUpdateHandler, with integration examples.

Reference for developers integrating another resource with oxide-pestcontroljob. Everything here is a server-side export; there are no client exports. If you just run the resource as a server owner, you don't need anything here.

Server Exports

All exports are called on the server.

IsOnShift

Tells you whether a player is currently on a pest control shift. Use it to stop a player from starting another job while they're already working this one.

local onShift = exports['oxide-pestcontroljob']:IsOnShift(source)

Parameters:

NameTypeDescription
sourcenumberThe player's server id

Returns: boolean: true from the moment the player clocks in until the shift ends, whether they clock out, log out, disconnect, or the shift is ended for them (going down, too many missed calls, the complaint limit, a destroyed van). false otherwise, including for an id that isn't a player.

A player who joined someone else's shift through a crew invite counts as on shift too.

GetSetting

Reads one of the resource's database-backed settings, keyed by the setting name without the Config. prefix (see Configuration for the names).

local maxSlots = exports['oxide-pestcontroljob']:GetSetting('MaxSlotsPerLocation')
local unlocks = exports['oxide-pestcontroljob']:GetSetting('Unlocks')  -- table

Parameters:

NameTypeDescription
keystringThe setting name, for example 'Payment' or 'usePhone'

Returns: any: the current value, as the server uses it now. nil for a name that isn't a setting.

SetSetting

Changes one of the resource's settings.

local ok = exports['oxide-pestcontroljob']:SetSetting('uniformsEnabled', true)

Parameters:

NameTypeDescription
keystringThe setting name, without Config.
valueanyThe new value. For a table setting, pass the whole table

Returns: boolean: true when the change was applied. The change is live: the server uses it right away, it saves to the database, and it syncs to players' games (except Properties, which stays on the server). It persists across restarts. Returns false if:

  • the resource hasn't finished loading its settings yet
  • the value contains a number that isn't finite
  • the value is for Properties or Crew and fails the same checks the settings editor uses
  • the database write fails (the old value stays)

Other settings are not checked against the editor's limits, so pass values of the same shape as the factory default.

GetInfo

The depots, whether each has room for another technician, and the base pay. Read-only.

local info = exports['oxide-pestcontroljob']:GetInfo()

Returns: table:

FieldTypeDescription
locationstable[]One entry per depot: name (string, translated), coords (vector3, the clerk's spot) and open (boolean, false while it has as many technicians as MaxSlotsPerLocation allows)
basePaytablemin and max: the lowest and highest base pay per call in Config.Payment.basePay, before the property multiplier and bonuses
crewbooleanWhether players can work as a crew of two (Config.Crew.maxSize 2)

GetShift

A player's shift as the job holds it now. Read-only.

local shift = exports['oxide-pestcontroljob']:GetShift(source)

Parameters:

NameTypeDescription
sourcenumberThe player's server id

Returns: table|false: false when the player is not on a shift; otherwise:

FieldTypeDescription
locationstring or nilThe depot the shift started at (translated name); nil if that depot has since been removed
rolestring'solo', 'leader' (leads a crew) or 'partner' (in someone else's crew)
stagestring'waiting' for a call, 'offer' while a call waits to be accepted, 'working' on an accepted call
taskstring or nilThe name of the property for the call on offer or in progress; nil otherwise
done, totalnumberAlways 0, 0 (calls come one at a time)
jobsnumberCalls reported this shift so far
earnednumberPay earned so far: the calls' totals plus the co-op bonus, before the gas fee, tax, van damage and treatment charges taken at clock-out

GetProgression

A player's level with this job. Read-only: a character who has never worked the job reads as level 1, and no record is created.

local progression = exports['oxide-pestcontroljob']:GetProgression(source)

Parameters:

NameTypeDescription
sourcenumberThe player's server id

Returns: table|false: false when the player has no character; otherwise:

FieldTypeDescription
levelnumberCurrent level
titlestringThe level's name, translated (for example "Senior Technician")
countnumberCalls reported in total
streaknumberDaily streak, in days
prevAtnumberThe call count where the current level starts
nextAtnumber or nilThe call count where the next level begins; nil at the top level
nextTitlestring or nilThe next level's name; nil at the top level
timedOutbooleanSuspended after too many complaints
timeoutRemainingnumberSeconds left on the suspension (0 when not suspended)

SetUpdateHandler

Lets another resource, such as a phone app, show this job's shift updates itself. While a handler is set and its resource runs, each update goes to it first. When the handler returns true, the job sends nothing else; when it returns anything else or errors, the job sends the update as before (text, mail or phone notification). One handler at a time: setting one replaces the last.

Updates are only produced while the job's usePhone setting is on. They are:

  • each phone message from the depot: the welcome, a destroyed van, a cancelled shift, customer callbacks and the pay summary
  • each incoming call (title "Incoming Call", message such as "Pest complaint at Diner, La Mesa" or "Wasp nest at Forum Drive (Strawberry)")
exports['oxide-pestcontroljob']:SetUpdateHandler(function(source, update)
    -- update.title:   the sender, for example "Bugstars - Bugstars Pest Control", or "Incoming Call"
    -- update.message: the message
    -- update.summary: { jobs = number, net = number } on the pay summary, sent when a shift ends
    -- (on a clock-out only with Config.shiftSummary = 'text'; never on a disconnect or logout)
    return true -- shown; the job sends nothing else
end)

Parameters:

NameTypeDescription
handlerfunction or nilhandler(source, update). nil (or false) removes the handler your resource set

Returns: boolean: true, or false when you tried to remove a handler another resource set (it stays). A handler is also removed automatically when the resource that set it stops.

Integration Examples

Stop a player from working two jobs at once

Check before your own job lets the player clock in:

RegisterNetEvent('my-job:server:clockIn', function()
    local src = source
    if GetResourceState('oxide-pestcontroljob') == 'started'
        and exports['oxide-pestcontroljob']:IsOnShift(src) then
        -- tell the player to finish their pest control shift first
        return
    end
    -- start your job
end)

Check every gig job at once

The same IsOnShift(source) export exists on oxide-postaljob, oxide-pizzajob, oxide-landscapingjob, oxide-roadsideassistancejob, oxide-animalcontroljob, oxide-newspaperjob and oxide-pestcontroljob. Skip any you don't run:

local GIG_JOBS = {
    'oxide-postaljob',
    'oxide-pizzajob',
    'oxide-landscapingjob',
    'oxide-roadsideassistancejob',
    'oxide-animalcontroljob',
    'oxide-newspaperjob',
    'oxide-pestcontroljob',
}

local function isOnGigShift(src)
    for _, resource in ipairs(GIG_JOBS) do
        if GetResourceState(resource) == 'started' and exports[resource]:IsOnShift(src) then
            return true
        end
    end
    return false
end

Show a player's current call

local function describeShift(src)
    if GetResourceState('oxide-pestcontroljob') ~= 'started' then return nil end
    local shift = exports['oxide-pestcontroljob']:GetShift(src)
    if not shift then return 'Not on a pest control shift' end
    if shift.stage == 'working' then
        return ('Working a call at %s, $%d earned so far'):format(shift.task, shift.earned)
    end
    return ('Waiting for a call at %s'):format(shift.location or 'the depot')
end

Guard your calls. Check GetResourceState('oxide-pestcontroljob') == 'started' before calling an export so your resource still works when this job isn't installed.

Next Steps