Exports & API Reference
The developer side of oxide-fire — server exports to start, read and clear fires and calls, report lightning and read settings, plus global state, state bags, events and integrations.
The developer side of oxide-fire: what other resources can read, call and listen to. This page is for developers who connect their own scripts. Server owners do not need it to install or run the resource.
oxide-fire uses o-link, but does not add anything to it. There is no olink.fire namespace. Integration happens through the exports, events and state bags below.
Server exports
All exports are server-side.
CreateIncident
Starts a fire at a spot. This is a bare fire: it raises no dispatch alert, does not ring the station bell, does not appear on the call board, has no casualties, and does not end on its own after 30 minutes. Use StartCall for a full call.
local id, reason = exports['oxide-fire']:CreateIncident(vector3(215.0, -810.0, 30.7), {
nodes = 8, -- burning points to start with (default 5)
class = 'B', -- 'A', 'B', 'vehicle' or 'brush' (default 'A')
spread = true, -- true or false; leave out to follow the config
bucket = 0, -- routing bucket (default 0)
})
if not id then
print('fire not started: ' .. tostring(reason))
endParameters:
| Name | Type | Description |
|---|---|---|
| coords | vector3, vector4 or { x, y, z } | Where the fire burns, at ground level |
| opts | table (optional) | nodes, class, spread, bucket as above |
Returns: number incident id, or false, reason. reason is 'invalid' (bad coordinates) or 'cap' (the fire limits are reached).
An unknown class falls back to 'A'. The number of points is capped by Config.Fire.maxNodesPerIncident and maxNodesTotal.
StartCall
Starts a fire call, exactly like the call generator does: the fire, the dispatch alert, the station bell, the page-outs, the call board entry and, for structure fires, the chance of trapped casualties.
-- A structure fire at incident site 4 (set up in /fire admin)
local id, why = exports['oxide-fire']:StartCall('structure', { siteId = 4 })
-- A brush fire somewhere inside wildfire zone 2
local id2 = exports['oxide-fire']:StartCall('brush', { zoneId = 2 })
-- A vehicle fire at a spot of your choosing
local id3 = exports['oxide-fire']:StartCall('vehicle', {
coords = vector3(-1037.0, -2738.0, 20.2),
heading = 240.0,
})Parameters:
| Name | Type | Description |
|---|---|---|
| callType | string | 'vehicle', 'brush' or 'structure' |
| opts.siteId | number (optional) | An incident site id. Required for 'structure', which burns at the site's fire points. For 'vehicle', the wreck spawns at the site's spot |
| opts.zoneId | number (optional) | A wildfire zone id, for 'brush'. The fire starts at a random spot inside it and only spreads inside it |
| opts.coords | vector3 or { x, y, z } (optional) | Where to start a 'vehicle' or 'brush' call with no site or zone |
| opts.heading | number (optional) | The wreck's heading for a 'vehicle' call at coords |
| opts.bucket | number (optional) | Routing bucket (default 0) |
Returns: number incident id, or false, reason. reason is one of 'type' (unknown call type), 'no_site', 'no_zone', 'vehicle' (the wreck could not be spawned), 'cap' (the fire limits are reached) or 'invalid'.
Calls started this way end on their own after Config.Calls.expireMs (30 minutes) like any other call.
ClearIncident
Puts a fire out at once and closes its alert. Casualties still inside are removed.
local done = exports['oxide-fire']:ClearIncident(id)Parameters:
| Name | Type | Description |
|---|---|---|
| id | number | The incident id |
Returns: boolean. false when no fire has that id.
The oxide-fire:server:incidentEnded event fires with your resource's name as the reason.
GetIncident
Reads one fire.
local inc = exports['oxide-fire']:GetIncident(id)
if inc then
print(inc.type, inc.class, #inc.nodes)
endReturns: table or nil when no fire has that id.
| Field | Type | Description |
|---|---|---|
id | number | The incident id |
bucket | number | Routing bucket |
class | string | 'A', 'B', 'vehicle' or 'brush' |
type | string | 'vehicle', 'brush' or 'structure' for calls |
center | vector3 | The fire's centre. For a vehicle fire, it follows the car |
vehNet | number or nil | Network id of the burning car, for vehicle fires |
nodes | table[] | Every burning or smouldering point: { id, x, y, z, class, hp, s, gs, o }. hp is the strength left, from 0 to 100 (percent). s is 1 while the point smoulders |
GetStats
Counters for the fire system since the resource started. Useful for monitoring.
local stats = exports['oxide-fire']:GetStats()
print(('%d fires, %d points, %.3f ms/s'):format(stats.incidents, stats.nodes, stats.cpuMsPerSecond))Returns: table with incidents, nodes, created, cleared, extinguished, spread, knockedDown, soaked, overhauled, reignited, burntOut, hits and damage (each split by hose, extinguisher and cannon), the server tick timings (ticks, tickAvgMs, tickMaxMs, flushes, flushAvgMs, flushMaxMs, cpuMsPerSecond, clock), and fireEvents (how many times the game tried to copy these fires between players, and how many of those were stopped).
LightningStrike
Tells oxide-fire that lightning struck. If the strike lands inside an enabled wildfire zone, a brush fire call starts there.
local id = exports['oxide-fire']:LightningStrike(vector3(1500.0, 4500.0, 50.0), 0)Parameters:
| Name | Type | Description |
|---|---|---|
| coords | vector3 or { x, y, z } | Where the lightning struck |
| bucket | number (optional) | Routing bucket (default 0) |
Returns: number incident id, or false when the strike is outside every enabled wildfire zone, or the fire could not start.
This export does not apply the Lightning fires settings (on/off, chance, following the call generator). The calling resource decides when a strike should start a fire. oxide-weather does not need this export: oxide-fire listens for its strikes directly, and those strikes do follow the settings. See Weather.
GetSetting
Reads a setting's current value.
local generator = exports['oxide-fire']:GetSetting('FireCalls')
print(generator.enabled, generator.minFirefighters)Parameters:
| Name | Type | Description |
|---|---|---|
| key | string | A top-level config key, for example 'FireCalls', 'Scba', 'Rescue', 'FireDifficulty' |
Returns: the whole value (table or plain value). For settings that live in the database, this is the database value, not the file default. It also reads file-owned settings such as 'Fire' or 'Hose'.
SetSetting
Writes a setting that lives in the database. It saves, mirrors the value to every player and applies straight away.
local ok, err = exports['oxide-fire']:SetSetting('FireDifficulty', 'realistic')Parameters:
| Name | Type | Description |
|---|---|---|
| key | string | A key that /fire settings edits (see Configuration) |
| value | any | The whole new value. For a group such as 'Scba', pass the full table |
Returns: true, or false, reason. reason is 'not an editable setting' (a file-owned or unknown key), 'settings are still loading, try again shortly', 'contains a number that is not finite' or 'could not be saved, see the server console'.
SetSetting does not check the value's type or range. Prefer /fire settings for anything a person is doing. This export is for scripted setup.
Global state
Written by the server, readable from anywhere.
| Key | Value | Notes |
|---|---|---|
oxide:fire:onduty | number | Total on-duty firefighters across every department |
oxide-fire:config | string[] | The setting keys mirrored to players |
oxide-fire:config:<key> | varies | One setting's current value, mirrored per key |
oxide-fire:apparatusModels | table | Hose outlet and intake positions admins set per model in the Models screen |
Player state bags
Replicated, so any client can read them for any player.
oxide:fire:duty
Player(src).state['oxide:fire:duty']
-- { deptId, deptName, gradeRank, stationId } -- on duty
-- nil -- off dutyThe duty state. Present means on duty. This is the right thing for a HUD or another script to read. Do not keep your own copy: duty can be cleared by the server (a dismissal, a department deletion, a logout) without the player's game asking for it.
oxide:fire:scba
Player(src).state['oxide:fire:scba']
-- { on = true|false, air = seconds left, max = seconds in a full cylinder, stage = 'ok'|'warn'|'alarm'|'empty' }Set once a player has used their SCBA. air is the value when the bag was last written. While on is true, the air keeps running down between updates. The bag only changes when the mask goes on or off, the stage changes, or the cylinder is refilled.
oxide:fire:hose
Player(src).state['oxide:fire:hose']
-- { id = line source, on = spraying, pat = pattern number } -- holding a line
-- nil -- not holding onepat is the position of the pattern in Config.Hose.patterns (1 Jet, 2 Fog, 3 Foam by default).
oxide:carryingPlayer and oxide:carriedBy
Set during a rescue carry or drag: oxide:carryingPlayer on the carrier (holding the casualty's server id) and oxide:carriedBy on the casualty (holding the carrier's server id). These are the same bags oxide-police uses for its carry, so neither resource picks up a player the other is already carrying.
Entity state bags
Fleet apparatus
Written by the server on every fleet unit. Clients never write these.
| Key | Value | Notes |
|---|---|---|
oxide:fire:apparatus | number | The unit's database id. This is the unit's identity. Never trust a bare network id to identify a unit across sessions |
oxide:fire:fleetState | table | Plate, saved properties, livery, extras, health and class. Applied once by the first player's game that owns the vehicle |
oxide:fire:fleetDecorated | true | Set once that look has been applied |
oxide:fire:bodyHealth / oxide:fire:engineHealth | number | Damage reported by the driver and written by the server |
oxide:plate | string | The plate the server issued. A convention shared with other Oxide resources |
Water
| Key | Value | Notes |
|---|---|---|
oxide:fire:tank | { level, cap, foam, foamCap } | Litres of water and foam, and the tank sizes, on any vehicle used as a water source. Updated in whole-percent steps |
oxide:fire:supply | { x, y, z } or nil | The hydrant a vehicle's supply line is connected to |
Casualties
| Key | Value | Notes |
|---|---|---|
oxide:fire:victim | { id, state, pos, heading, carrier } | On each trapped person. state is 'trapped', 'carried', 'rescued' or 'lost' |
Events
Server-side, safe to listen to
AddEventHandler('oxide:fire:server:initialized', function() end)
AddEventHandler('oxide:fire:server:settingsReady', function() end)
AddEventHandler('oxide:fire:server:settingsApplied', function(keys) end)
AddEventHandler('oxide:fire:server:departmentsChanged', function(reason, data) end)
AddEventHandler('oxide:fire:firefighterJobMirror', function(action, charId, jobName, gradeRank, jobLabel) end)
AddEventHandler('oxide-fire:server:incidentEnded', function(id, reason, summary) end)| Event | Fires when |
|---|---|
oxide:fire:server:initialized | The departments, firefighters, fleet and bays have loaded and the resource is ready |
oxide:fire:server:settingsReady | Settings have been rebuilt from the database. Anything that reads a setting at start-up should wait for this |
oxide:fire:server:settingsApplied | Settings were saved. keys lists the setting keys that changed |
oxide:fire:server:departmentsChanged | A department, station, grade or bay was created, changed or removed. reason is a short description ('department created', 'station updated', 'bay removed', ...). data carries the ids involved |
oxide:fire:firefighterJobMirror | A firefighter was hired, changed grade or was dismissed. action is 'hired', 'gradeChanged' or 'fired'. Only fires with Multi-department enrollment on. This is what the g-multijob bridge listens to |
oxide-fire:server:incidentEnded | A fire ended. reason is 'extinguished', 'burnt out', 'expired', 'vehicle gone', 'admin', or the name of the resource that called ClearIncident. summary is { id, bucket, class, type, center, count } |
Server-side, listened to
| Event | Sent by | What oxide-fire does |
|---|---|---|
oxide:weather:lightningStrike (data) | oxide-weather, for every lightning strike | Reads data.coords ({ x, y, z }) and data.id. A strike inside an enabled wildfire zone may start a brush fire call, following the Lightning fires settings |
Client-side, safe to listen to
RegisterNetEvent('oxide:fire:departmentsUpdated', function() end)
RegisterNetEvent('oxide:fire:firefighterDataChanged', function() end)
RegisterNetEvent('oxide:fire:forceClockOut', function() end)
AddEventHandler('oxide-fire:client:configUpdated', function(key) end)
AddEventHandler('oxide-fire:client:scbaMask', function(on) end)| Event | Fires when |
|---|---|
oxide:fire:departmentsUpdated | Department data changed. Clients rebuild their station points, bays and blips |
oxide:fire:firefighterDataChanged | This player's employment changed (hired, dismissed, promoted, badge changed) |
oxide:fire:forceClockOut | The player went off duty for any reason: their own clock-out, a dismissal or a department deletion |
oxide-fire:client:configUpdated | A setting changed. key is the setting that changed, or nil on the first full load. Local to the player's game |
oxide-fire:client:scbaMask | See below |
oxide-fire:client:scbaMask
Fires on the wearer's own game, after the face piece goes on (on = true) or comes off (on = false). Clothing scripts can use it to swap in a full SCBA outfit:
-- In your clothing resource, client side
AddEventHandler('oxide-fire:client:scbaMask', function(on)
if on then
-- put on your SCBA variant of the turnout gear
else
-- put the normal turnout gear back
end
end)It is a local event (TriggerEvent), so listen with AddEventHandler, not RegisterNetEvent.
Internal events: do not trigger these
These carry the resource's own state between its server and client sides. They check what they receive, so triggering them from outside will not break anything, but they are not an API and can change:
every oxide-fire:client:*, oxide-fire:server:* and oxide-fire:hose:* net event, the oxide:fire:server:* net events, oxide:fire:openAdminPanel and oxide:fire:client:openSettings.
Integrations
Dispatch
oxide-fire raises alerts through olink.dispatch.CreateAlert on the server, and closes them with olink.dispatch.CloseAlert when the fire ends.
- With
oxide-dispatch, or with no dispatch resource (o-link's built-in fallback), the server-side alert works directly. - With another dispatch resource,
CreateAlertreturns nothing, so the alert is sent througholink.dispatch.SendAlerton the game of one on-duty firefighter. If no firefighter is on duty, the alert is skipped.
| Alert | Code | Sent to |
|---|---|---|
| Vehicle fire | 10-73 | Every enabled fire department's job name |
| Brush fire | 10-74 | Every enabled fire department's job name |
| Structure fire | 10-70 | Every enabled fire department's job name |
| Fire rescue casualty | 10-52 | The Medic jobs setting (ambulance, ems by default) |
With no fire department set up, fire alerts go to the job fire.
Weather
oxide-fire reads the wind and rain at each fire through olink.weather.GetWindAt and olink.weather.GetConditionsAt. Today only oxide-weather answers those. Without it, each fire gets a random wind and no rain.
Lightning comes from the oxide:weather:lightningStrike server event above. Another weather resource can send strikes with the LightningStrike export instead.
Smoke
Smoke is internal to oxide-fire. There is no export to add smoke zones from another resource.
Phones and the tablet
Page-outs use olink.phone.SendNotification when olink.phone.IsAvailable() says a phone resource runs. The boss desktop registers a tablet app (fire_boss, "Fire Command") through olink.tablet when oxide-tablet is running.
Integration examples
Start a structure fire from a scenario script
-- server side, in your own resource
local function startArson(siteId)
local id, why = exports['oxide-fire']:StartCall('structure', { siteId = siteId })
if not id then
print(('[arson] no fire: %s'):format(why))
return nil
end
return id -- keep it if you want to ClearIncident(id) later
endSite ids are shown on the Incident Sites screen of /fire admin.
Pay a bonus when a fire is put out
-- server side
AddEventHandler('oxide-fire:server:incidentEnded', function(id, reason, summary)
if reason ~= 'extinguished' then return end
print(('Fire %d (%s) put out at %s'):format(id, summary.type, tostring(summary.center)))
end)Show the fire department's on-duty count on a HUD
-- client side
CreateThread(function()
while true do
local onDuty = GlobalState['oxide:fire:onduty'] or 0
-- draw onDuty on your HUD
Wait(5000)
end
end)Features
What oxide-fire does — departments, stations, duty and pay, gear and uniforms, radio channels, apparatus, synced fires, fire calls, hoses and tools, breathing air, smoke, rescue and station life.
Admin Guide
Commands, the /fire admin panel, the in-world incident editor, live incidents, the boss management desktop and a step-by-step walkthrough for building a fire department from nothing.