How Integrations Work#
Biohazard Creator is standalone: nothing inside it depends on a framework. Everything that touches another resource lives in two open files, client/custom.lua and server/custom.lua, which are never encrypted. Edit them freely, and keep a copy before you update.
What | Out of the box | Where to change it |
|---|---|---|
Notifications | qs-interface when it is running, the GTA feed otherwise. |
|
Clothes after the zombie model | qs-appearance's reload event. |
|
Is the player dead? | The |
|
Reviving a killed zombie player | The | A bridge in client/custom.lua — see below |
Player identifier | The Rockstar license. |
|
Name on the leaderboard | The FiveM player name. |
|
Survivor rewards | Printed in the console only. |
|
Progression is stored per identifier. Changing
GetIdentifieron a live server starts everyone's level from zero under the new key, so decide on it before players build up XP.
Identifiers and Names#
Out of the box, progression is kept per Rockstar license and the leaderboard shows the FiveM name. To keep it per character and show the character's name, replace the two functions in server/custom.lua with the version for your framework:
local ESX = exports['es_extended']:getSharedObject()
function GetIdentifier(source)
local xPlayer = ESX.GetPlayerFromId(source)
if xPlayer then return xPlayer.identifier end
return ('src:%s'):format(source)
end
function GetDisplayName(source)
local xPlayer = ESX.GetPlayerFromId(source)
if xPlayer then
return ('%s %s'):format(xPlayer.get('firstName') or '', xPlayer.get('lastName') or '')
end
return GetPlayerName(source)
endlocal QBCore = exports['qb-core']:GetCoreObject()
function GetIdentifier(source)
local Player = QBCore.Functions.GetPlayer(source)
if Player then return Player.PlayerData.citizenid end
return ('src:%s'):format(source)
end
function GetDisplayName(source)
local Player = QBCore.Functions.GetPlayer(source)
if Player then
local c = Player.PlayerData.charinfo
return ('%s %s'):format(c.firstname, c.lastname)
end
return GetPlayerName(source)
endfunction GetIdentifier(source)
local Player = exports.qbx_core:GetPlayer(source)
if Player then return Player.PlayerData.citizenid end
return ('src:%s'):format(source)
end
function GetDisplayName(source)
local Player = exports.qbx_core:GetPlayer(source)
if Player then
local c = Player.PlayerData.charinfo
return ('%s %s'):format(c.firstname, c.lastname)
end
return GetPlayerName(source)
endSurvivor Rewards#
GiveReward runs once for every player who ends an outbreak as a human, with that event's Rewards section: { enable, money, item, itemCount }. The shipped version only prints [Biohazard] Survivor reward for 12 -> money: 5000, item: medikit x1 in the console. Replace it with the one for your server:
local ESX = exports['es_extended']:getSharedObject()
function GiveReward(source, rewards)
if not rewards or not rewards.enable then return end
local xPlayer = ESX.GetPlayerFromId(source)
if not xPlayer then return end
if rewards.money > 0 then xPlayer.addMoney(rewards.money) end
if rewards.item ~= '' then xPlayer.addInventoryItem(rewards.item, rewards.itemCount) end
endlocal QBCore = exports['qb-core']:GetCoreObject()
function GiveReward(source, rewards)
if not rewards or not rewards.enable then return end
local Player = QBCore.Functions.GetPlayer(source)
if not Player then return end
if rewards.money > 0 then Player.Functions.AddMoney('cash', rewards.money) end
if rewards.item ~= '' then Player.Functions.AddItem(rewards.item, rewards.itemCount) end
endfunction GiveReward(source, rewards)
if not rewards or not rewards.enable then return end
local Player = exports.qbx_core:GetPlayer(source)
if not Player then return end
if rewards.money > 0 then Player.Functions.AddMoney('cash', rewards.money) end
if rewards.item ~= '' then exports.ox_inventory:AddItem(source, rewards.item, rewards.itemCount) end
endfunction GiveReward(source, rewards)
if not rewards or not rewards.enable or rewards.item == '' then return end
exports.ox_inventory:AddItem(source, rewards.item, rewards.itemCount)
-- exports['qs-inventory']:AddItem(source, rewards.item, rewards.itemCount)
endNotifications and Chat#
Messages such as You turned into a zombie! Infect someone to survive. go through Notify in client/custom.lua: qs-interface when it is running, the GTA feed when it is not. While the creator is open, they appear as toasts inside it instead. For another notification resource, replace the function:
-- client/custom.lua
function Notify(msg)
exports['okokNotify']:Alert('Biohazard', msg, 3500, 'info')
endWith the chat resource running, every outbreak is announced in chat (Config.AutoStart.AnnounceInChat) and /biohazardcreator appears in the command suggestions.
Clothing and Revives#
Clothing#
Infected players wear the zombie model. When they turn human again, or the outbreak ends, ReloadSkin puts their own clothes back. It calls qs-appearance; for another clothing script, swap the line:
-- client/custom.lua
function ReloadSkin()
TriggerEvent('qs-appearance:client:reloadSkin', true)
-- TriggerEvent('illenium-appearance:client:reloadSkin')
endRevives#
A zombie player who is shot down is revived with the client event ambulance:revivePlayer. If your ambulance script revives with another event, bridge it at the end of client/custom.lua:
AddEventHandler('ambulance:revivePlayer', function()
TriggerEvent('esx_ambulancejob:revive') -- esx_ambulancejob
-- TriggerEvent('hospital:client:Revive') -- qb-ambulancejob
end)If your death system marks dead players with a state other than LocalPlayer.state.isDead, adjust IsAlive in the same file so the horde stops targeting downed players.
The Phone App#

phone-biohazard is a companion app for Quasar Smartphone. Start it and Biohazard Creator detects it by itself — there is nothing to switch on, and it is picked up even if it starts after the outbreak script.
In the app | What it shows |
|---|---|
Live outbreak | The running event, its countdown, the participants, the area, weather and hour, the horde and infection rules, and the live kill ranking. |
Outbreak types | Your saved presets, read-only, with the one running marked — and when the next Auto Start may come. |
Profile | Level, rank, XP progress, kills, infections, games, wins, losses, best kills, MVPs, win rate and leaderboard position. Updated the moment an outbreak ends, with the XP just earned. |
Leaderboard | The server's best players, sorted by level, kills, wins, games or MVPs, with your own row highlighted. |
Notification | A push to every phone when an outbreak starts. |
Config.Phone = {
Enabled = DependencyCheck({ ['phone-biohazard'] = true }), -- automatic
BroadcastMs = 2000, -- how often the live outbreak is refreshed
LeaderboardMax = 50, -- rows in the leaderboard
ExposePresets = true, -- list your presets as outbreak types
NotifyOnStart = true -- phone notification when an outbreak starts
}Languages#
Two languages ship in locales/: English (en) and Spanish (es). Pick one with Config.Language.
To add another, copy en.json to locales/<key>.json, translate the values and set Config.Language to that key. Any line missing from your file falls back to English, so a partial translation never breaks anything. The _ui block holds the labels of the creator and the scoreboard; the codes such as ~o~ are GTA text colours.
{
"notify_event_start": "The Biohazard night has begun!",
"hud_time": "~o~BIOHAZARD EVENT~s~ | Time:",
"_ui": {
"creator_title": "Biohazard Event Creator",
"sb_title": "BIOHAZARD"
}
}


