Exports & API
legends_firefighter exposes client and server exports for integrations (admin panels, anti-cheat kicks, custom UI, analytics) plus editable hooks in client/editable.lua and server/editable.lua for deeper customization.
Client Exports
IsOnJob
Returns whether the local player is currently on a firefighter mission.
local onJob = exports.legends_firefighter:IsOnJob()Returns: boolean
Example:
-- Block a different job from starting while on the firefighter run
RegisterCommand('start_mechanic', function()
if exports.legends_firefighter:IsOnJob() then
lib.notify({ description = 'Finish your firefighter shift first!', type = 'error' })
return
end
-- ...
end)GetJobState
Returns the current job state of the local player.
local state = exports.legends_firefighter:GetJobState()Returns: string — one of:
'idle'— not on a job'en_route'— traveling to a fire location'extinguishing'— at a fire location, putting fires out'searching'— searching the scene for salvage'returning'— returning the vehicle to the depot
CancelJob
Cancels the current firefighter mission (if any). Triggers the same cleanup as the player canceling from the in-game menu.
local ok = exports.legends_firefighter:CancelJob()Returns: boolean — true if a job was canceled, false if the player wasn't on one.
Example:
-- Cancel on arrest
AddEventHandler('police:onArrested', function()
exports.legends_firefighter:CancelJob()
end)GetActiveFireCount
Returns the number of fires currently active at the player's current location.
local remaining = exports.legends_firefighter:GetActiveFireCount()Returns: number
Use this for custom HUDs or when scripting branching objectives ("if more than 3 fires remain, trigger backup").
Server Exports
GetActiveJobCount
Returns how many firefighter jobs are currently running across the server.
local count = exports.legends_firefighter:GetActiveJobCount()Returns: number
Example:
-- Simple load cap: block new firefighter jobs if the server already has 10 running
AddEventHandler('firefighter:onJobRequest', function(src)
if exports.legends_firefighter:GetActiveJobCount() >= 10 then
CancelEvent()
end
end)GetActiveJobs
Returns the full active-jobs table, keyed by player source.
local jobs = exports.legends_firefighter:GetActiveJobs()
-- jobs[source] = { ...internal job data... }Returns: table<number, table>
Useful for admin panels or /who is firefighting commands.
ForceEndJob
Force-ends a specific player's active job. Cleans up the vehicle entity and notifies the client.
local ended = exports.legends_firefighter:ForceEndJob(source)Returns: boolean — true if a job was ended, false if that player wasn't on one.
Example:
-- Admin command
RegisterCommand('endfirefighter', function(src, args)
local target = tonumber(args[1])
if target and exports.legends_firefighter:ForceEndJob(target) then
TriggerClientEvent('chat:addMessage', src, { args = { 'ADMIN', 'Firefighter job ended.' } })
end
end, true)Editable Client Hooks
In client/editable.lua:
OnJobStart
function OnJobStart(routeId, routeData)
-- routeId: numeric route ID (e.g., 201)
-- routeData: full route table from config/routes.lua
endCalled client-side the moment a job starts — after payment for the rental (if any) and after the vehicle has spawned.
Example — play a radio sound:
function OnJobStart(routeId, routeData)
PlaySoundFrontend(-1, 'Menu_Accept', 'Phone_SoundSet_Default', true)
lib.notify({ description = ('Dispatched to: %s'):format(routeData.name), type = 'inform' })
endOnFireExtinguished
function OnFireExtinguished(locationIndex, fireData)
-- locationIndex: index into the current route's locations array
-- fireData: { coords, fireType, fireCount, fireSize, ... }
endCalled every time a fire is fully put out.
Example — award XP in an external skill system:
function OnFireExtinguished(locationIndex, fireData)
TriggerServerEvent('myskills:addXp', 'firefighting', 10)
endOnJobComplete
function OnJobComplete(completed, locationsCompleted, reward)
-- completed: true if the full route was finished, false if canceled early
-- locationsCompleted: how many locations were cleared
-- reward: total money paid out
endCalled when the job ends for any reason (natural finish, early return, cancel).
Editable Server Hooks
In server/editable.lua:
CanStartJob
function CanStartJob(source)
-- return false to block
return true
endGate job entry on inventory checks, job whitelist, cooldowns, metadata — anything server-side.
Example — require a firefighter badge item:
function CanStartJob(source)
local count = exports.ox_inventory:Search(source, 'count', 'firefighter_badge')
if count < 1 then
Framework.notify(source, 'You need a firefighter badge to start this job!', 'error')
return false
end
return true
endCalculateBonus
function CalculateBonus(source, locationsCompleted, totalLocations, defaultBonus)
return defaultBonus
endModify the completion bonus per player/per event.
Example — weekend double-bonus:
function CalculateBonus(source, locationsCompleted, totalLocations, defaultBonus)
local day = os.date('%A')
if day == 'Saturday' or day == 'Sunday' then
return defaultBonus * 2
end
return defaultBonus
endOnRewardGiven
function OnRewardGiven(source, totalReward, locationsCompleted, totalLocations, lootCollected)
-- Post-payment hook
endFires after the player has been paid. Use for:
- Discord webhook logs
- Metadata updates (
fires_extinguished,firefighter_shifts) - Reputation or prestige systems
- Long-term database logging
Example — bump a metadata counter:
function OnRewardGiven(source, totalReward, locationsCompleted, totalLocations, lootCollected)
local player = Framework.getPlayer(source)
if player and player.Functions and player.Functions.SetMetaData then
local current = player.PlayerData.metadata.fires_extinguished or 0
player.Functions.SetMetaData('fires_extinguished', current + locationsCompleted)
end
endCustom System Implementations
Both client/editable.lua and server/editable.lua include commented-out templates for swapping in your own notification / progress bar / menu / textui / inventory / money / callback backends. To enable a custom backend:
- Uncomment the relevant function (
CustomNotify,CustomInventory, etc.) - Set the matching
ClientSystemsorServerSystemsentry to'custom'
Example:
-- server/editable.lua
ServerSystems = {
inventory = { system = 'custom' }, -- swap from 'auto'
money = { system = 'auto' },
callbacks = { system = 'auto' },
}
CustomInventory = {
addItem = function(source, item, amount, metadata)
return exports.my_inventory:AddItem(source, item, amount, metadata) == true
end,
removeItem = function(source, item, amount)
return exports.my_inventory:RemoveItem(source, item, amount) == true
end,
getItemCount = function(source, item)
return exports.my_inventory:GetItemCount(source, item) or 0
end,
hasItem = function(source, item, amount)
return (exports.my_inventory:GetItemCount(source, item) or 0) >= (amount or 1)
end,
}Localization
Language strings live in locales/en.json. The file is grouped by feature area:
{
"menu": { "title": "Fire Department", "rent_truck": "Rent Firetruck", ... },
"npc": { "talk_to": "Talk to Firefighter" },
"info": { "job_started": "...", "fire_extinguished": "...", ... },
"error": { "equip_extinguisher": "...", "vehicle_destroyed": "...", ... },
"progress": { "extinguishing": "Extinguishing Fire...", "searching": "Searching Area..." },
"loot": { "found": "Salvage Found", "nothing_found": "Nothing of value found." },
"rewards": { "received": "...", "bonus": "..." },
"depot": { "return_truck": "...", "finish_mission": "..." },
"leveling": { "xp_gained": "+%s XP", "level_up": "..." },
"waterbomber":{ "tank_empty": "...", "tank_full": "...", ... },
"helicopter": { "spraying": "...", "too_low": "...", ... }
}Adding a New Language
- Copy
locales/en.jsontolocales/<lang>.json(e.g.locales/es.json) - Translate the values, keep the keys
- ox_lib picks the correct file automatically based on your server/player locale (the resource declares
ox_lib 'locale'infxmanifest.lua)
If you're not using ox_lib, the resource still loads en.json as the default. You can swap the default file path in bridge/shared/init.lua if needed.
Need Help?
Join our Discord for support: discord.gg/lgnds (opens in a new tab)