Wert Ems Roster System
You can access the setup information you need about this product
Last updated
You can access the setup information you need about this product
Last updated
1 - Upload the script folder to the location of your resources
2 - Check config and editable file settings. If you are using different systems, you can make the necessary adjustments in these files, such as for , ox_lib
, etc.
3 - Load emsroster.sql file in ur database.
4 - Installation successful, have a good funs
There are many ox settings available in the files, if you want, you can configure them.
If you want to use ox_lib, please check if this link is enabled on fxmanifest.check it out from inside lua. this must be turned on before you can use ox_lib. After opening it, it will be enough to use the refresh and ensure commands.
Also be sure open this connection in fxmanifest.lua
The script comes with default settings. There are many settings in the configuration file, and you can customize all of them to your personal preferences. Below are the configuration files, feel free to check them out.
Config = {}
Config.UseTarget = true -- # If u want use target set true | true or false | boolean | (editable_client have more option for select target system)
Config.OxLib = true -- # If u want use ox lib set true | true or false | boolean
Config.DebugPoly = false -- # If you want draw zones set true | true or false | boolean
-- # No target interaction key
Config.NoTargetInteractionKey = 38 -- https://docs.fivem.net/docs/game-references/controls/
-- # Search players jobs (Players who have which job will be shown in the Roster)
Config.WhitelistJobs = {
['ambulance'] = true,
}
-- # Roster open settings
Config.OpenRosterCommand = {
active = true, -- If you want to open the roster with command | true or false | boolean
command = 'emsroster', -- Command name
description = 'Open ems roster tablet!', -- Command description
job = {
['ambulance'] = 0, -- [jobname] = mingrade for open
}
}
Config.OpenRosterKey = { -- Hotkey for open ems roster
active = true, -- If you want to open the roster with key | true or false | boolean
key = 'F10', -- Key : https://docs.fivem.net/docs/game-references/input-mapper-parameter-ids/keyboard/
description = 'Open ems roster tablet!', -- Key description
job = {
['ambulance'] = 0, -- [jobname] = mingrade for open
}
}
Config.OpenRosterZones = { -- Open target infos
{
coord = vector3(310.3, -593.22, 43.28),
sizeA = 0.8,
sizeB = 1.0,
heading = 0,
minZ = 42.28,
maxZ = 44.28,
icon = 'fa-solid fa-laptop',
label = 'Roster',
job = {['ambulance'] = 0}, -- If u want edit here for more job or if u want add grade check like : job = {['ambulamce'] = 0}
distance = 1.5, -- Interaction size, If u use no target please set correct coord and this is interaction size. | If u use target it's target distance
isComputer = true, -- If going to perform an access via a computer, make it true computer animation takes place. | true or false | boolean
},
}
-- # Staff (Boss) menu settings and zones
-- !IMPORTANT : Don't forget edit the boss grade levels for ur job list. If u change anything in ur job list.
Config.BossMenuCommand = {
active = true, -- If you want to open the roster staff with command | true or false | boolean
command = 'emsrosterstaff', -- Command name
description = 'Ems roster staff menu!', -- Command description
job = {
['ambulance'] = 4, -- [jobname] = mingrade for open
}
}
Config.BossMenuZones = {
{
coord = vector3(335.48, -594.48, 43.28),
sizeA = 1.4,
sizeB = 1.0,
heading = 340,
minZ = 42.28,
maxZ = 44.28,
icon = 'fa-solid fa-server',
label = 'Personel database',
job = {['ambulance'] = 4}, -- If u want edit here for more job or if u want add grade check like : job = {['ambulamce'] = 4}
distance = 1.5, -- Interaction size, If u use no target please set correct coord and this is interaction size. | If u use target it's target distance
isComputer = true, -- If going to perform an access via a computer, make it true computer animation takes place. | true or false | boolean
},
}
-- # Open object and animation settings
Config.TabletModel = `prop_cs_tablet`
Config.TabletAnimationSettings = {
dict = "amb@code_human_in_bus_passenger_idles@female@tablet@idle_a",
clip = "idle_a",
flag = 50,
}
Config.TabletObjectSettings = {
bone = 28422,
pos = {-0.05, 0.0, 0.0}, -- Position
rot = {0.0, 0.0, 0.0}, -- Rotation
}
Config.ComputerAnimationSettings = {
dict = "mp_prison_break",
clip = "hack_loop",
flag = 49,
}
-- # Badge Settings
-- If u want edit here what u want. If u want select specific icon from https://fontawesome.com/icons or if u want edit for image. What u want exactly ...
Config.BadgeSettings = {
-- [Grade] = inner
['0'] = '<i class="fa-solid fa-star"></i>',
['1'] = '<i class="fa-solid fa-star"></i><i class="fa-solid fa-star"></i>',
['2'] = '<i class="fa-solid fa-star"></i><i class="fa-solid fa-star"></i><i class="fa-solid fa-star"></i>',
['3'] = '<i class="fa-solid fa-star"></i><i class="fa-solid fa-star"></i><i class="fa-solid fa-star"></i><i class="fa-solid fa-star"></i>',
['4'] = '<i class="fa-solid fa-star"></i><i class="fa-solid fa-star"></i><i class="fa-solid fa-star"></i><i class="fa-solid fa-star"></i><i class="fa-solid fa-star"></i>',
}
-- # Department settings
-- If u want add more or edit specializations here ...
Config.Departments = {
-- [value] = label
["emergency"] = "Emergency",
["surgery"] = "Surgery",
["cardiology"] = "Cardiology",
["orthopedics"] = "Orthopedics",
["pediatrics"] = "Pediatrics",
["neurology"] = "Neurology",
["internalmedicine"] = "Internal Medicine",
["dermatology"] = "Dermatology",
["anesthesiology"] = "Anesthesiology",
["psychiatry"] = "Psychiatry",
["gastroenterology"] = "Gastroenterology",
["ophthalmology"] = "Ophthalmology",
["gynecology"] = "Gynecology",
["otolaryngology"] = "Otolaryngology",
["urology"] = "Urology",
["radiology"] = "Radiology",
["oncology"] = "Oncology",
["infectiousdiseases"] = "Infectious Diseases",
["physiotherapy"] = "Physiotherapy",
-- Nothing option for the default this is requid | If u want edit default table in config
['nothing'] = 'Not Selected',
}
-- # Specialization settings
-- If u want add more or edit specializations here ...
Config.Specializations = {
-- [value] = label
["cardiologist"] = "Cardiologist",
["orthopedicsurgeon"] = "Orthopedic Surgeon",
["neurologist"] = "Neurologist",
["pediatrician"] = "Pediatrician",
["oncologist"] = "Oncologist",
["generalsurgeon"] = "General Surgeon",
["psychiatrist"] = "Psychiatrist",
["dermatologist"] = "Dermatologist",
["endocrinologist"] = "Endocrinologist",
["anesthesiologist"] = "Anesthesiologist",
["gastroenterologist"] = "Gastroenterologist",
["pulmonologist"] = "Pulmonologist",
["ophthalmologist"] = "Ophthalmologist",
["physiotherapist"] = "Physiotherapist",
-- Nothing option for the default this is requid | If u want edit default table in config
['nothing'] = 'Nothing',
}
-- # Status settings
-- If u want add more or edit statuses here ...
Config.Statuses = {
-- [value] = label
['active'] = 'Active',
['deactive'] = 'Deactive',
-- Nothing option for the default this is requid | If u want edit default table in config
['nothing'] = 'Uncertain',
}
-- # Default datas (If player not have saved data before time ...)
Config.DefaultDatas = {
badgeno = 'NOT',
department = 'nothing', -- Must be a valid value in Config.Departments table
rank = 'None',
ranklevel = 0, -- Must be number
specialization = 'nothing', -- Must be a valid value in Config.Specializations
surgeries = 0, -- Must be number
activitytime = 0, -- Must be number
consultations = 0, -- Must be number
certificates = 'None',
status = 'nothing',
picture = nil, -- If u want change default picture for everyone u can change with string
}
local ESX = exports["es_extended"]:getSharedObject()
local PlayerJob = nil
-- # Functions
function GetJobData()
local mydata = ESX.GetPlayerData()
if not mydata then return 'unemployed', 0 end
local jobname = mydata.job.name
local grade = mydata.job.grade and tonumber(mydata.job.grade) or 0
return jobname, grade
end
function CustomNotifVariation(text, style, time)
ESX.ShowNotification(text, style or 'info', time or 3000)
end
function ShowTextUI(text)
if Config.OxLib then
lib.showTextUI(text, {position = 'left-center'})
else
-- # If u use another system if u want edit here
end
end
function HideTextUI()
if Config.OxLib then
lib.hideTextUI()
else
-- # If u use another system if u want edit here
end
end
function CustomTargetAddBoxZone(data, options)
exports.ox_target:addBoxZone({
name = data.name,
coords = data.coord,
size = vec3(data.sizeA, data.sizeB, data.sizeA),
rotation = data.heading,
debug = Config.DebugPoly,
options = options
})
end
-- # Events
RegisterNetEvent('wert-emsroster:client:custom-notify', function(text, style, time)
CustomNotifVariation(text, style, time)
end)
RegisterNetEvent('esx:playerLoaded', function()
Wait(1000)
PlayerJob = ESX.GetPlayerData().job.name
TriggerServerEvent('wert-emsroster:server:ply-join-game')
end)
RegisterNetEvent('esx:setJob', function(JobInfo)
local old_job = PlayerJob
PlayerJob = JobInfo.name
if Config.WhitelistJobs[old_job] or Config.WhitelistJobs[PlayerJob] then TriggerServerEvent('wert-emsroster:server:ply-update-job', old_job) end
end)
AddEventHandler('onResourceStart', function(resource)
if resource == GetCurrentResourceName() then
Wait(1000)
PlayerJob = ESX.GetPlayerData().job.name
TriggerServerEvent('wert-emsroster:server:ply-join-game')
end
end)
local ESX = exports["es_extended"]:getSharedObject()
local TimeData = {}
function CustomGetPlayerWithSource(src)
if not src then return nil end
return ESX.GetPlayerFromId(src)
end
function CustomGetOnlinePlayers()
local mergePlayers = {}
local players = ESX.GetPlayers()
for k,v in pairs(players) do
local ply = ESX.GetPlayerFromId(v)
if ply then mergePlayers[#mergePlayers+1] = ply end
end
return mergePlayers
end
function CustomGetPlayerWithIdentifier(identifier)
return ESX.GetPlayerFromIdentifier(identifier)
end
function GetPlayerJobAndGrade(ply)
if not ply then return 'unemployed', 0 end
local job = ply.job.name
local grade = ply.job.grade and tonumber(ply.job.grade) or 0
return job, grade
end
function GetOnlinePlayerData(ply)
if not ply or not Config.WhitelistJobs[ply.job.name] then return nil end
local data = {fullname = nil, jobData = nil}
local myjob = ply.job
data.fullname = ply.getName()
data.jobData = {onduty = true, grade = {name = myjob.grade_label, level = myjob.grade}}
return data
end
function GetFullNameForOnlinePlayer(ply)
return ply.getName()
end
function GetDutyStatusForOnlinePlayer(ply)
-- If u use a duty system u can make intergate
return true
end
function OfflineFindGradeLabel(jobname, gradelevel)
local myLabel = 'Undefined'
local jobs = ESX.GetJobs()
local findTable = jobs[jobname]
if findTable and findTable.grades then
local convLevel = tostring(gradelevel)
if findTable.grades[convLevel] then
myLabel = findTable.grades[convLevel].label or 'Undefined'
end
end
return myLabel
end
function GetOfflinePlayerData(identifier)
local response = MySQL.query.await('SELECT `firstname`, `lastname`, `job`, `job_grade` FROM `users` WHERE `citizenid` = ?', {identifier})
if not response or not response[1] then return nil end
local data = {fullname = nil, jobData = nil}
local plyJobName = response[1].job
local plyJobGradeLevel = response[1].job_grade and tonumber(response[1].job_grade) or 0
local plyJobGradeLabel = OfflineFindGradeLabel(plyJobName, plyJobGradeLevel)
data.fullname = response[1].firstname .. ' ' .. response[1].lastname
data.jobData = {onduty = false, grade = {name = plyJobGradeLabel, level = plyJobGradeLevel}}
return data
end
function GetAllPlayersFromSql()
local likeClauses = {}
for jobname, jobstate in pairs(Config.WhitelistJobs) do likeClauses[#likeClauses+1] = "`job` LIKE '%" .. jobname .. "%'" end
local whereClause = table.concat(likeClauses, " OR ")
local players = MySQL.query.await("SELECT identifier, job, firstname, lastname, job_grade FROM `users` WHERE " .. whereClause, {})
return players
end
function GetOfflinePlayerDataWithRow(value)
if not value then return nil end
local data = {fullname = nil, jobData = nil}
local plyJobName = value.job
local plyJobGradeLevel = value.job_grade and tonumber(value.job_grade) or 0
local plyJobGradeLabel = OfflineFindGradeLabel(plyJobName, plyJobGradeLevel)
data.fullname = value.firstname .. ' ' .. value.lastname
data.jobData = {onduty = false, grade = {name = plyJobGradeLabel, level = plyJobGradeLevel}}
return data
end
function ActivityTimeInterval()
local players = CustomGetOnlinePlayers()
for k, ply in pairs(players) do
if ply and Config.WhitelistJobs[ply.job.name] then
local src = tostring(ply.source)
if TimeData[src] then
local citizenid = ply.getIdentifier()
local now = os.time()
local secondDiff = os.difftime(now, TimeData[src])
exports['wert-emsroster']:AddUserData(citizenid, 'activitytime', tonumber(secondDiff))
TimeData[src] = os.time()
end
end
end
SetTimeout(5 * (60 * 1000), ActivityTimeInterval)
end
-- # If u have a duty system please intergate
--[[ RegisterNetEvent('QBCore:Server:SetDuty', function(id, duty)
if not id then return end
local src = tonumber(id)
local ply = CustomGetPlayerWithSource(src)
if not ply then return end
if not Config.WhitelistJobs[ply.job.name] then return end
local citizenid = ply.getIdentifier()
id = tostring(id)
if duty then
TimeData[id] = os.time()
elseif not duty and TimeData[id] then
local old_data = TimeData[id]
TimeData[id] = nil
local now = os.time()
local secondDiff = os.difftime(now, old_data)
exports['wert-emsroster']:AddUserData(citizenid, 'activitytime', tonumber(secondDiff))
end
end) ]]
RegisterNetEvent('wert-emsroster:server:ply-join-game', function()
local src = source
local ply = CustomGetPlayerWithSource(src)
if not ply then return end
if not Config.WhitelistJobs[ply.job.name] then return end
local id = tostring(src)
TimeData[id] = os.time()
end)
RegisterNetEvent('wert-emsroster:server:ply-update-job', function(oldjob)
local src = source
Wait(1000)
local ply = CustomGetPlayerWithSource(src)
if not ply then return end
local id = tostring(src)
local jobname = ply.job.name
if not Config.WhitelistJobs[jobname] and TimeData[id] then
TimeData[id] = nil
elseif Config.WhitelistJobs[jobname] and not TimeData[id] then
TimeData[id] = os.time()
end
end)
AddEventHandler('playerDropped', function(reason)
local src = source
local conv = tostring(src)
if TimeData[conv] then TimeData[conv] = nil end
end)
CreateThread(function()
Wait(3000)
ActivityTimeInterval()
end)
LANG = {
error = {
permission_error = 'You do not have permission for the this action!',
},
interaction = {
notargetOpen = '[E] Open Ems Roster',
notargetBossmenu = '[E] Open Ems Roster Boss Menu',
},
ui = {
induty = 'In Duty',
offduty = 'Off Duty',
activityTime = '%s Hour.',
certificate_popui_label = '%s Certificates',
certificate_popui_close = 'Close',
labels = {
badgeno = 'Badge No',
name = 'Name',
department = 'Department',
rank = 'Rank',
badge = 'Badge',
specialization = 'Specialization',
duty = 'Duty',
surgeries = 'Surgeries',
activitytime = 'Activity Time',
consultations = 'Consultations',
certificates = 'Certificates',
status = 'Status',
},
bossmenu = {
noData = 'No personnel data found!',
clickDesc = 'Click for more information',
label = 'EMS ROSTER EDITOR',
placeholder = 'Search Player',
informationHeader = 'Welcome, %s (%s)',
informationText = 'From this menu, you can edit the roster data of EMS personnel. You can check and edit the listed individuals in the area below. Simply click the corresponding button to edit.',
save = 'Save Datas',
badgeno_placeholder = 'Select Badge No',
surgeries_placeholder = 'Select Surgeries',
consultations_placeholder = 'Select Consultations',
certificates_placeholder = 'Add Certificates',
editlabel_badgeno = 'Badge No',
editlabel_department = 'Department',
editlabel_specialization = 'Specialization',
editlabel_surgeries = 'Surgeries',
editlabel_consultations = 'Consultations',
editlabel_certificates = 'Certificates',
editlabel_status = 'Status',
userdataerrorheader = 'User Not Found!',
userdataerrordescription = 'User data not found from database. Please refresh and try again!',
refresherrorheader = 'Datas Not Loaded!',
refresherrordescription = 'An error occurred while fetching the data, please try again later.',
refreshedHeader = 'Page Has Been Updated!',
refreshedDescription = 'Success! You can continue work on page.',
saveactionfailedheader = 'Save Failed!',
saveactionfaileddescription = 'Registration failed due to an unknown error, try again later!',
savedheader = 'User Saved!',
saveddescription = 'Successfully! User informations saved.',
editlabel_picture = 'Picture',
picture_placeholder = 'Picture URL',
}
},
time = {
less_than_minute = "0 min.",
minute_and_seconds = "%d min. %d sec.",
hours_and_minutes = "%d hour, %d min.",
day_and_hours = "%d day, %d hour."
},
}