Configuration
All gameplay configuration for legends_firefighter lives in two files:
config/config.lua— job-wide settings (NPC, depot, fire, loot, rewards, blips, leveling, mission tiers)config/routes.lua— route definitions and per-location fire data
System behavior (notifications, progress bars, inventory, money, callbacks) is configured in:
client/editable.lua—ClientSystemsand per-event client hooksserver/editable.lua—ServerSystems,CanStartJob,CalculateBonus,OnRewardGiven
All files above are outside the escrow block and fully editable.
General Settings
debug
debug = false,Description: Enables in-game zone visualization and extra console prints — helpful when adding new routes or locations.
Type: boolean
Default: false
interactionType
interactionType = 'ox_target',Description: Which interaction system to use for the NPC and depot return point.
Type: string — 'ox_target', 'qb-target', or 'textui'
Default: 'ox_target'
If the chosen system isn't running, the resource falls back to a native textui prompt so players are never locked out of the NPC.
NPC
npc
npc = {
model = 's_m_y_fireman_01',
coords = vec4(-1067.91, -2378.78, 14.08, 146.92),
label = 'Fire Department',
icon = 'fas fa-fire-extinguisher',
blip = {
enabled = true,
sprite = 60,
color = 1,
scale = 0.8,
label = 'Fire Station',
},
},| Property | Type | Description |
|---|---|---|
model | string | Ped model name for the fire-station NPC |
coords | vec4 | Spawn position and heading |
label | string | Label shown on the target/textui prompt |
icon | string | Font Awesome icon for the target prompt |
blip.enabled | boolean | Whether to show a map blip for the station |
blip.sprite | number | GTA V blip sprite ID |
blip.color | number | GTA V blip color ID |
blip.scale | number | Blip size multiplier |
blip.label | string | Blip label on the pause map |
Depot
depot
depot = {
returnRadius = 8.0,
label = 'Return Vehicle',
icon = 'fas fa-truck',
},| Property | Type | Description |
|---|---|---|
returnRadius | number | Radius (meters) around the vehicle spawn point that counts as "returned" |
label | string | Label shown on the return-vehicle target prompt |
icon | string | Font Awesome icon for the return prompt |
The depot return point is per-tier — it uses the tier's vehicle.spawnPoint. Tier 1 (on-foot rookie) doesn't require a vehicle return; it finishes at the NPC.
Fire
fire
fire = {
spreadRadius = 5.0,
blazeRadius = 1.0,
},Description: Default fire behavior. Per-tier overrides live inside missionTiers[n].fire.
| Property | Type | Description |
|---|---|---|
spreadRadius | number | Radius for fireType = 'spread' locations (fires spread outward over an area) |
blazeRadius | number | Radius for fireType = 'blaze' locations (concentrated point fire) |
Loot / Salvage
loot
loot = {
enabled = true,
searchDuration = 5000,
searchTimeLimit = 60000,
searchRadius = 3.0,
icon = 'fas fa-search',
label = 'Search Area',
tables = { ... },
},| Property | Type | Description |
|---|---|---|
enabled | boolean | Master toggle for the salvage/loot system |
searchDuration | number | Progress-bar duration per search (ms) |
searchTimeLimit | number | Time window after a fire is extinguished in which the area can still be searched (ms). 0 = unlimited |
searchRadius | number | Distance (meters) a player must be within to trigger a search |
icon | string | Font Awesome icon for the search prompt |
label | string | Label shown on the search prompt |
Loot Tables
Four built-in tables are used by route locations via lootTable = 'vehicle' | 'street' | 'dumpster' | 'yard':
tables = {
vehicle = {
{ item = 'phone', min = 1, max = 1, chance = 8 },
{ item = 'wallet', min = 1, max = 1, chance = 15 },
{ item = 'lighter', min = 1, max = 1, chance = 20 },
{ item = 'metalscrap', min = 1, max = 5, chance = 40 },
{ item = 'plastic', min = 1, max = 3, chance = 35 },
},
street = { ... },
dumpster = { ... },
yard = { ... },
},| Property | Type | Description |
|---|---|---|
item | string | Item name as it appears in your inventory system |
min / max | number | Quantity range (inclusive) |
chance | number | Percentage chance (0–100) the item drops on a given search |
Each roll is independent. You can tune drop frequency by lowering chances or by shortening searchTimeLimit.
Rewards
rewards
rewards = {
moneyType = 'cash',
},| Property | Type | Description |
|---|---|---|
moneyType | string | 'cash' or 'bank' — which account payout goes into |
Per-tier payout amounts live inside missionTiers[n].rewards.perLocation and missionTiers[n].rewards.completionBonus (see below).
Blips
blips
blips = {
fire = {
sprite = 436,
color = 1,
scale = 0.9,
route = true,
label = 'Fire Location',
},
depot = {
sprite = 60,
color = 2,
scale = 0.8,
route = true,
label = 'Return Truck',
},
},| Property | Type | Description |
|---|---|---|
sprite | number | GTA V blip sprite ID |
color | number | GTA V blip color ID |
scale | number | Blip size multiplier |
route | boolean | Whether the blip auto-draws a GPS route |
label | string | Blip label on the pause map |
Leveling
leveling
leveling = {
enabled = true,
levels = {
[1] = { name = 'Rookie', xpRequired = 0 },
[2] = { name = 'Firefighter', xpRequired = 500 },
[3] = { name = 'Aerial Specialist', xpRequired = 3500 },
},
},| Property | Type | Description |
|---|---|---|
enabled | boolean | Master toggle for the leveling/rank system |
levels | table | Array of { name, xpRequired } entries, ordered by rank |
Levels gate mission tiers — each tier's unlockLevel (see below) must match a defined level. Adding a new level requires a new tier or a matching unlockLevel change.
Per-tier XP values live inside missionTiers[n].xp (see below).
Mission Tiers
missionTiers
Three tiers are included by default. Each tier is fully self-contained — its vehicle, fire behavior, required item, rewards, XP, and unlock level live together.
Tier 1 — Rookie (on foot)
[1] = {
name = 'Rookie Mission',
description = 'Use your fire extinguisher on small fires',
icon = 'fas fa-fire-extinguisher',
image = './assets/rookie.png',
unlockLevel = 1,
vehicle = nil,
requiredItem = 'weapon_fireextinguisher',
consumeItem = false,
fire = {
progressPerExtinguish = 1.2,
extinguishRange = 5.0,
countPerLocation = 5,
size = 15,
},
requireOnFoot = true,
anim = { dict = 'weapons@misc@jerrycan@', clip = 'fire' },
rewards = { perLocation = 75, completionBonus = 500 },
xp = { perLocation = 2, routeBonus = 8 },
},| Property | Type | Description |
|---|---|---|
name / description | string | Shown on the UI tier-select screen |
icon / image | string | UI icon + preview image path |
unlockLevel | number | Level required to pick this tier |
vehicle | table or nil | Vehicle spawned for this tier (see below); nil = on foot |
requiredItem | string or nil | Inventory item required to start (e.g. weapon_fireextinguisher) |
consumeItem | boolean | Whether the item is removed on job start |
fire.progressPerExtinguish | number | Progress added per spray tick (higher = fires die faster) |
fire.extinguishRange | number | Meters from which a fire can be hit |
fire.countPerLocation | number | Default fire count per location (route can override) |
fire.size | number | Default fire size per location (route can override) |
requireOnFoot | boolean | If true, player must exit the vehicle to extinguish |
anim.dict / anim.clip | string | Animation played while extinguishing |
rewards.perLocation | number | Payout per completed location |
rewards.completionBonus | number | Full-route completion bonus |
xp.perLocation | number | XP per completed location |
xp.routeBonus | number | XP granted for completing the full route |
Tier 2 — Standard (firetruck)
[2] = {
name = 'Standard Mission',
unlockLevel = 2,
requiredItem = nil,
fire = {
progressPerExtinguish = 0.7,
extinguishRange = 35.0,
countPerLocation = 10,
size = 25,
},
requireOnFoot = false,
rewards = { perLocation = 150, completionBonus = 1500 },
xp = { perLocation = 3, routeBonus = 13 },
vehicle = {
model = 'firetruk',
spawnPoint = vec4(-1078.93, -2376.69, 14.01, 149.89),
plate = 'FIRET',
rental = { enabled = false, cost = 500 },
},
},| Property | Type | Description |
|---|---|---|
vehicle.model | string | GTA V vehicle model spawned for this tier |
vehicle.spawnPoint | vec4 | Spawn position + heading (also the depot return point) |
vehicle.plate | string | License plate text |
vehicle.rental.enabled | boolean | Whether players pay to rent the vehicle |
vehicle.rental.cost | number | Rental cost if enabled |
Tier 3 — Aerial (helicopter)
[3] = {
name = 'Aerial Mission',
unlockLevel = 3,
fire = {
progressPerExtinguish = 0.5,
extinguishRange = 20.0,
countPerLocation = 40,
size = 25,
spreadRadius = 15.0,
},
helicopter = {
sprayControl = 38,
minAltitude = 0.0,
maxAltitude = 10.0,
sprayInterval = 100,
horizontalRange = 20.0,
},
rewards = { perLocation = 250, completionBonus = 3000 },
xp = { perLocation = 5, routeBonus = 20 },
vehicle = {
model = 'conada',
spawnPoint = vec4(-1092.41, -2378.12, 13.95, 236.28),
plate = 'FIREH',
rental = { enabled = false, cost = 1000 },
},
},| Property | Type | Description |
|---|---|---|
helicopter.sprayControl | number | Input control index to hold for spraying (default 38 = E key) |
helicopter.minAltitude | number | Minimum altitude (meters) above the fire to spray |
helicopter.maxAltitude | number | Maximum altitude (meters) above the fire to spray |
helicopter.sprayInterval | number | Spray tick interval (ms) |
helicopter.horizontalRange | number | Horizontal distance (meters) within which the spray counts as "over" the fire |
Want to add a Tier 4 (e.g., a water-bomber plane)? Add a new missionTiers[4] block, a matching leveling.levels[4] entry, and tier-4 routes in config/routes.lua. The UI automatically picks up new tiers.
Routes
All route definitions live in config/routes.lua.
randomizeLocationOrder
randomizeLocationOrder = true,Description: If true, locations within a route are visited in random order each run. If false, they're visited in the order they appear in the config.
Type: boolean
Default: true
routes
routes = {
[101] = {
name = 'Fire Training Route 1',
tier = 1,
locations = { ... },
},
[201] = { ... },
[301] = { ... },
}| Property | Type | Description |
|---|---|---|
[id] | number | Unique numeric route ID. Convention: 1xx = tier 1, 2xx = tier 2, 3xx = tier 3 |
name | string | Route label shown in UI and blips |
tier | number | Mission tier this route belongs to (1, 2, or 3) |
locations | table | Ordered array of fire locations (see below) |
Location format
{
coords = vec3(1255.85, -2567.91, 41.72),
label = 'Training Fire 1',
fireType = 'blaze',
fireCount = 3,
fireSize = 10,
spreadRadius = 2.0,
lootTable = 'vehicle',
searchable = true,
},| Property | Type | Description |
|---|---|---|
coords | vec3 | Center of the fire scene |
label | string | Location label on blip and UI |
fireType | string | 'blaze' (concentrated) or 'spread' (spreads outward) |
fireCount | number | Number of fire instances at this location (overrides tier default) |
fireSize | number | Size of each fire (overrides tier default) |
spreadRadius | number (optional) | Per-location spread radius override |
lootTable | string or nil | Which config.loot.tables.* to roll against; nil disables search |
searchable | boolean | Whether the scene is searchable after fire extinguish |
Editable Client Systems
In client/editable.lua:
ClientSystems
ClientSystems = {
notifications = { system = 'auto', position = 'top-right', duration = 5000 },
progress = { system = 'auto', position = 'bottom', color = '#FF6B35' },
menus = { system = 'auto' },
textui = { system = 'auto', position = 'right-center' },
callbacks = { system = 'auto' },
}Each subsystem accepts 'auto' (auto-detect best available) or a specific backend name ('ox_lib', 'qb-core', 'esx', 'native', 'simple', 'progressbar', 'cd_drawtextui', 'custom'). Set any to 'custom' to use your own implementation (templates are provided at the bottom of the file).
Client Event Hooks
function OnJobStart(routeId, routeData) end
function OnFireExtinguished(locationIndex, fireData) end
function OnJobComplete(completed, locationsCompleted, reward) endUse these for custom sounds, chat messages, UI overlays, or analytics. Each is called at the obvious moment — no teardown required.
Editable Server Systems
In server/editable.lua:
ServerSystems
ServerSystems = {
inventory = { system = 'auto' }, -- 'auto', 'ox_inventory', 'framework', 'custom'
money = { system = 'auto' }, -- 'auto', 'framework', 'custom'
callbacks = { system = 'auto' }, -- 'auto', 'ox_lib', 'qb-core', 'esx', 'native', 'custom'
}CanStartJob
function CanStartJob(source)
-- return false to block job start
return true
endGate job entry on items, jobs, cooldowns, whitelist, metadata — anything you can check server-side. Returning false blocks the NPC interaction with no side effects.
CalculateBonus
function CalculateBonus(source, locationsCompleted, totalLocations, defaultBonus)
return defaultBonus
endTweak the completion bonus per-player. Common use cases: weekend double-pay, level-scaled bonuses, random "lucky" bonuses.
OnRewardGiven
function OnRewardGiven(source, totalReward, locationsCompleted, totalLocations, lootCollected)
-- Post-payout hook
endFires after the player has been paid. Use for Discord webhooks, metadata updates (fires_extinguished), reputation systems, or database logging.
Localization
All player-facing text lives in locales/en.json. To add another language:
- Copy
locales/en.jsontolocales/<lang>.json(e.g.locales/es.json) - Translate the values, keep the keys
- If you use ox_lib's locale system, players on that locale will automatically see the translated strings
The resource declares ox_lib 'locale' in fxmanifest.lua — ox_lib picks the right file based on the server convar or client locale.
Need Help?
Join our Discord for support: discord.gg/lgnds (opens in a new tab)