How Integrations Work#
Lifeguard Job looks at what is already running when it starts and wires itself to it. Everything that talks to another resource lives in a small, unencrypted file — client/framework/, server/framework/, client/vehiclekeys/ and config/ — so supporting something new never means touching the encrypted core.
Layer | Supported | Without it |
|---|---|---|
Framework | es_extended · qb-core · qbx_core | Required — the stations never appear without one. |
Target | ox_target, with | Walk-up prompts on |
Vehicle keys | qs-vehiclekeys · qb-vehiclekeys · qbx_vehiclekeys · wasabi_carlock · vehicles_keys · ti_vehicleKeys · xd_locksystem · mono_carkeys · glfp10_carkeys · fivecode_carkeys · F_RealCarKeysSystem | The keys step does nothing — right for servers with no lock script. |
Uniform | esx_skin + skinchanger · qb-clothing | Set |
Fuel | Any script with a | With |
Progress bars | qs-interface | ox_lib's progress bar. |
Job pay | qs-job-management | Pay goes straight into the player's cash. |
Notifications | Built in, or any system you point it at | The job's own notifications. |
Detection runs once, when the resource starts, and only sees resources that are already started. Anything you want detected has to be above
ensure qs-lifeguardinserver.cfg.
Target or Prompts#
Config.Target decides how a lifeguard interacts with the captain and with everything in a call-out:
Config.Target = false. Walk up and a [E] prompt appears beside the person or object; press E. With qs-textui running the prompt is drawn by it, otherwise as 3D text in the world. Nothing else to install.
Config.Target = true. The same options appear on the third eye: the station option is named after the station, and each call-out adds its own options to the people and places involved. Needs ox_target started before the job.
The CPR minigame always uses a key press, set by Config.InteractKey (a control id, 38 is E) and the letter shown for it, Config.InteractKeyLabel.
Vehicle Keys#
Whichever supported lock script is running gets the keys of the ATV or jetski when it is signed out, and takes them back when it is stored, so nobody keeps keys to a plate that no longer exists. To support another one, add a file to client/vehiclekeys/ — copy the closest existing one:
-- client/vehiclekeys/my_keys.lua
if Config.Vehiclekeys ~= 'my_keys' then
return
end
function AddVehiclekeys(vehicle, plate)
exports['my_keys']:GiveKeys(plate)
end
function RemoveVehiclekeys(vehicle, plate)
exports['my_keys']:RemoveKeys(plate)
endThen add it to the detection list in config/config.lua, resource name on the left, file name on the right:
local vehicleKeys = {
['qs-vehiclekeys'] = 'qs-vehiclekeys',
-- ...
['my_keys'] = 'my_keys',
}Fuel#
Turn Config.Fuel on and every vehicle a lifeguard signs out is filled to 100. Point Config.FuelExport at any fuel script that exposes SetFuel(vehicle, amount):
Config.Fuel = true
Config.FuelExport = exports['LegacyFuel'] -- or exports['ps-fuel'], exports['cdn-fuel'], ...The Uniform#
With Config.Clothing = true the uniform goes on when a shift starts and the player's own skin comes back when it ends. It is set per gender in config/clothing.lua, using skinchanger's component names; uncomment a line to dress that slot too:
male = {
['arms'] = 15,
['tshirt_1'] = 15, ['tshirt_2'] = 0,
['torso_1'] = 15, ['torso_2'] = 0,
['pants_1'] = 18, ['pants_2'] = 3,
['shoes_1'] = 34, ['shoes_2'] = 0,
['helmet_1'] = -1, ['helmet_2'] = 0,
['chain_1'] = 0, ['chain_2'] = 0,
-- ['glasses_1'] = 0, ['glasses_2'] = 0,
},On ESX it is applied through esx_skin and skinchanger; on QBCore through qb-clothing's outfit event. For another clothing resource, the two functions that put the uniform on and take it off — ApplyJobClothes and RemoveJobClothes — are in the same file and can be pointed at it. Or set Config.Clothing = false and let players use a wardrobe of their own.
Notifications and Progress Bars#
Pop-up messages — pay received, level up, a call-out failed — are the job's own by default. To send them through your notification system instead, edit CreateNotification in client/framework/esx.lua (or qb.lua) and replace the line that calls Notify. Leave the rest of the function alone: it also drives the help panel that explains each call-out.
if Config.DefaultNotifications and action == 'notify' then
-- Notify({ title = type, message = text }) -- the built-in one
lib.notify({
type = type == 'info' and 'inform' or type, -- success · error · info
description = text,
})
else
SendNUIMessage({ action = action, type = type, text = text })
endProgress bars use qs-interface when it is running and ox_lib's otherwise; the choice is the ProgressBar function in the same file.
Discord Logs#
Off by default. Each event below can be posted to Discord as a coloured embed, with the player's name and identifier in the footer:
Event | Sent when |
|---|---|
| A call-out is issued to a lifeguard. |
| A call-out is finished and pays out. |
| A call-out ran out of time or was left behind. |
| Money is handed to a player for a call-out. |
| Experience is granted, with the level before and after. |
| A setting is changed or reset from the settings panel. |
Switch them on in config/config.lua:
Config.Webhooks = {
Enabled = true,
Name = 'qs-lifeguard', -- the bot's name
Avatar = '', -- an image URL, or '' for none
Timestamp = true,
Events = {
MissionStarted = true,
MissionFinished = true,
MissionAbandoned = true,
MoneyPaid = true,
ExperienceGiven = true,
ConfigChanged = true,
},
}The URLs go in server.cfg, not in the config. One for everything, plus an optional channel of its own for any event — its name in lower case:
set qs_lifeguard_webhook "https://discord.com/api/webhooks/..."
# Optional: money and experience to a staff-only channel
set qs_lifeguard_webhook_moneypaid "https://discord.com/api/webhooks/..."
set qs_lifeguard_webhook_experiencegiven "https://discord.com/api/webhooks/..."Sending is fire-and-forget: a webhook that is down never delays or costs anybody a payout.
Other Quasar Resources#
Resource | What happens when it runs |
|---|---|
Every payout, solo and cooperative, is paid through it under the | |
Reads lifeguard levels from | |
qs-interface · qs-textui | Progress bars and on-screen prompts in the Quasar style. |
Keys for every ATV and jetski signed out. |
Adding a Framework#
ESX, QBCore and Qbox are covered. A renamed or forked core is supported through the two framework files, which are not encrypted:
Copy the closest bridge
Copy
esx.luaorqb.luain bothclient/framework/andserver/framework/, change the guard on the first line to your framework's name and the exports to your core's resource name.Keep every function
The server file answers who the player is, their name and job, pays them and grants experience:
AddMoney,GetPlayeridentifier,GetUserName,GetPlayerJobName,OnPlayerJobChanged,OnPlayerCharacterLoadedandAddXP. The client file sets up the stations for players with the job and reacts to job changes and character loads, and providesProgressBar,SpawnVehicle,DeleteJobVehicleandCreateNotification.Register it
Add your core to the detection list at the top of
config/config.lua:lua local frameworks = { ['es_extended'] = 'esx', ['qb-core'] = 'qb', ['qbx_core'] = 'qb', ['my-core'] = 'mycore', }
Languages#
Eighteen translations ship in locales/: English (en), Spanish (es), Portuguese (pt), French (fr), German (de), Italian (it), Dutch (nl), Romanian (ro), Danish (da), Hungarian (hu), Turkish (tr), Russian (ru), Bulgarian (bg), Arabic (ar), Hindi (hi), Japanese (ja), Korean (ko) and Simplified Chinese (zh-CN). Pick one with Config.Language or from the settings panel.
Every line on screen is a key in those files — the station names (STATION_NORTH…), the call-out names, the guide and the panel — so changing a word is editing the JSON. A key missing from a translation falls back to English. For a language that does not ship, copy en.json to a new file, translate it and set Config.Language to its name in config.lua — the panel only offers the eighteen that ship.



