Wert Med 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
['bandage'] = {
label = 'Bandage',
weight = 115,
rate = { id = "common", background = "#2d703b5c" }
},
['painkillers'] = {
label = 'Painkillers',
weight = 400,
},
['antibiotics'] = {
label = 'Antibiotics',
weight = 400,
},
['adrenaline'] = {
label = 'Adrenaline Shot',
weight = 400,
},
['antiseptic'] = {
label = 'Antiseptic Spray',
weight = 400,
},
['vitamins'] = {
label = 'Vitamins',
weight = 400,
},
['insulin'] = {
label = 'Insulin Injection',
weight = 400,
},
['morphine'] = {
label = 'Morphine',
weight = 400,
},
['oxygenmask'] = {
label = 'Oxygen Mask',
weight = 400,
},
['ivfluid'] = {
label = 'IV Fluid',
weight = 400,
},bandage = {
name = 'bandage',
label = 'Bandage',
weight = 115,
type = 'item',
image = 'bandage.png',
},
painkillers = {
name = 'painkillers',
label = 'Painkillers',
weight = 400,
type = 'item',
image = 'painkillers.png',
},
antibiotics = {
name = 'antibiotics',
label = 'Antibiotics',
weight = 400,
type = 'item',
image = 'antibiotics.png',
},
adrenaline = {
name = 'adrenaline',
label = 'Adrenaline Shot',
weight = 400,
type = 'item',
image = 'adrenaline.png',
},
antiseptic = {
name = 'antiseptic',
label = 'Antiseptic Spray',
weight = 400,
type = 'item',
image = 'antiseptic.png',
},
vitamins = {
name = 'vitamins',
label = 'Vitamins',
weight = 400,
type = 'item',
image = 'vitamins.png',
unique = false, useable = true, shouldClose = true, combinable = nil, description = ''
},
insulin = {
name = 'insulin',
label = 'Insulin Injection',
weight = 400,
type = 'item',
image = 'insulin.png',
unique = false, useable = true, shouldClose = true, combinable = nil, description = ''
},
morphine = {
name = 'morphine',
label = 'Morphine',
weight = 400,
type = 'item',
image = 'morphine.png',
unique = false, useable = true, shouldClose = true, combinable = nil, description = ''
},
oxygenmask = {
name = 'oxygenmask',
label = 'Oxygen Mask',
weight = 400,
type = 'item',
image = 'oxygenmask.png',
unique = false, useable = true, shouldClose = true, combinable = nil, description = ''
},
ivfluid = {
name = 'ivfluid',
label = 'IV Fluid',
weight = 400,
type = 'item',
image = 'ivfluid.png',
unique = false, useable = true, shouldClose = true, combinable = nil, description = ''
},-- # General Settings
Config = {
Framework = 'qb', -- 'qb' or 'esx' or 'qbox'
}
Config.MedsSystem = {
Jobs = { ['ambulance'] = 0 },
Keys = {
OpenMyPrescriptions = 'F9'
},
CanWriteSelf = false,
Adherence = {
OverdueToleranceMin = 1,
DamageEveryMinutes = 5,
DamageAmount = 5,
BannerIcon = 'fa-solid fa-pills',
},
WhitelistMeds = {
{ value = 'bandage', label = 'Bandage', icon = 'nui://ox_inventory/web/images/bandage.png' },
{ value = 'painkillers', label = 'Painkillers', icon = 'nui://ox_inventory/web/images/painkillers.png' },
{ value = 'antibiotics', label = 'Antibiotics', icon = 'nui://ox_inventory/web/images/antibiotics.png' },
{ value = 'adrenaline', label = 'Adrenaline Shot', icon = 'nui://ox_inventory/web/images/adrenaline.png' },
{ value = 'antiseptic', label = 'Antiseptic Spray',icon = 'nui://ox_inventory/web/images/antiseptic.png' },
{ value = 'vitamins', label = 'Vitamins', icon = 'nui://ox_inventory/web/images/vitamins.png' },
{ value = 'insulin', label = 'Insulin Injection', icon = 'nui://ox_inventory/web/images/insulin.png' },
{ value = 'morphine', label = 'Morphine', icon = 'nui://ox_inventory/web/images/morphine.png' },
{ value = 'oxygenmask', label = 'Oxygen Mask', icon = 'nui://ox_inventory/web/images/oxygenmask.png' },
{ value = 'ivfluid', label = 'IV Fluid', icon = 'nui://ox_inventory/web/images/ivfluid.png' },
},
Consume = {
Default = {
duration = 3000,
label = 'Taking medicine ...',
canCancel = false,
disable = { move = true, car = true, combat = true },
anim = { dict = 'amb@world_human_clipboard@male@base', clip = 'base', flag = 49 },
},
Overrides = {
bandage = {
duration = 4000,
label = 'Applying bandage ...',
anim = { dict = 'missheistdockssetup1clipboard@base', clip = 'base', flag = 49 },
},
painkillers = {
duration = 3500,
label = 'Taking painkillers ...',
anim = { dict = 'mp_player_intdrink', clip = 'loop_bottle', flag = 49 },
},
antibiotics = {
duration = 4000,
label = 'Taking antibiotics ...',
anim = { dict = 'mp_player_intdrink', clip = 'loop_bottle', flag = 49 },
},
adrenaline = {
duration = 4500,
label = 'Injecting adrenaline ...',
anim = { dict = 'amb@world_human_clipboard@male@idle_a', clip = 'idle_a', flag = 49 },
prop = { model = 'prop_syringe_01', bone = 57005, pos = vec3(0.14, 0.03, -0.02), rot = vec3(90.0, 0.0, 0.0) },
},
antiseptic = {
duration = 3000,
label = 'Spraying antiseptic ...',
anim = { dict = 'mp_player_intdrink', clip = 'loop_bottle', flag = 49 },
},
vitamins = {
duration = 3000,
label = 'Taking vitamins ...',
anim = { dict = 'mp_player_intdrink', clip = 'loop_bottle', flag = 49 },
},
insulin = {
duration = 4000,
label = 'Injecting insulin ...',
anim = { dict = 'amb@world_human_clipboard@male@idle_a', clip = 'idle_a', flag = 49 },
prop = { model = 'prop_syringe_01', bone = 57005, pos = vec3(0.12, 0.03, -0.03), rot = vec3(90.0, 0.0, 0.0) },
},
morphine = {
duration = 5000,
label = 'Injecting morphine ...',
anim = { dict = 'amb@world_human_clipboard@male@idle_a', clip = 'idle_a', flag = 49 },
prop = { model = 'prop_syringe_01', bone = 57005, pos = vec3(0.12, 0.03, -0.03), rot = vec3(90.0, 0.0, 0.0) },
},
oxygenmask = {
duration = 4500,
label = 'Applying oxygen mask ...',
anim = { dict = 'missheistdocksprep1hold_cellphone', clip = 'static', flag = 49 },
prop = { model = 'prop_mask_ballistic', bone = 12844, pos = vec3(0.0, 0.0, 0.0), rot = vec3(0.0, 0.0, 0.0) },
},
ivfluid = {
duration = 6000,
label = 'Setting up IV fluid ...',
anim = { dict = 'amb@world_human_clipboard@male@idle_a', clip = 'idle_a', flag = 49 },
},
},
Sound = {
enabled = true,
default = {
enabled = true,
file = 'default_medsound.ogg',
volume = 0.6,
},
overrides = {
bandage = { enabled = true, file = 'bandage.ogg', volume = 0.6 },
painkillers = { enabled = true, file = 'painkillers.ogg', volume = 0.6 },
antibiotics = { enabled = true, file = 'painkillers.ogg', volume = 0.6 },
adrenaline = { enabled = true, file = 'injection.ogg', volume = 0.7 },
antiseptic = { enabled = true, file = 'spray.ogg', volume = 0.6 },
vitamins = { enabled = true, file = 'painkillers.ogg', volume = 0.6 },
insulin = { enabled = true, file = 'injection.ogg', volume = 0.6 },
morphine = { enabled = true, file = 'painkillers.ogg', volume = 0.6 },
oxygenmask = { enabled = true, file = 'oxygen.ogg', volume = 0.6 },
ivfluid = { enabled = true, file = 'fluid.ogg', volume = 0.6 },
}
}
},
}
Config.Tablet = {
Enabled = true,
Jobs = { ['ambulance'] = 0 },
OpenKey = 'F10',
Command = 'recipetablet',
}
LANG = {
MedsSystem = {
notify_title = 'Medication',
notify_only_doctor = 'Only doctors can write prescriptions.',
notify_created = 'Prescription created for %s.',
notify_taken = 'You have taken %s.',
notify_not_due = 'This medicine is not due yet.',
notify_no_prescriptions = 'You have no active prescriptions.',
ui_doctor_title = 'Write Prescription',
ui_doctor_sub = 'Create a new prescription for a patient',
ui_patient = 'Patient',
ui_add_med = 'Add Medicine',
ui_med_name = 'Name',
ui_med_interval = 'Interval (min)',
ui_med_units = 'Units per dose',
ui_med_total = 'Total doses',
ui_notes = 'Notes (optional)',
ui_submit = 'Create',
ui_cancel = 'Cancel',
ui_patient_title = 'My Prescriptions',
ui_patient_sub = 'Your active treatments and schedule',
ui_take_now = 'Take Now',
ui_due_in = 'due in %sm',
ui_due_now = 'due now',
ui_banner_take_meds = 'You must take your medicine',
menu_open_prescriptions = 'My Prescriptions',
menu_open_presc = 'Open',
progress_take = 'Taking medicine ...',
notify_item_enough_error = 'You are not has this med! Please go pharmacy and take it!',
progress_take = 'Taking medicine ...',
ui_clear_eraser = 'Clear',
ui_signature = 'Signature',
ui_med_inf_name = 'Name',
ui_med_info_int = 'Interval (Min)',
ui_med_info_per = 'Units Per Dose',
ui_med_info_total = 'Total Doses',
ui_med_info_note = 'Note',
Prescription_title_new = 'Prescription #%s',
Doses_Description_new = '%s / %s doses',
Completed_Treatment = 'Treatment successfully completed!',
},
Tablet = {
title = 'EMS Tablet',
subtitle = 'Prescription dashboard',
search_placeholder = 'Search Patient / CID / Doctor',
filter_all = 'All',
filter_active = 'Active',
filter_completed = 'Completed',
col_patient = 'Patient',
col_doctor = 'Doctor',
col_status = 'Status',
col_created = 'Created',
col_progress = 'Progress',
status_active = 'Active',
status_completed = 'Completed',
open_details = 'Open',
empty_list = 'No prescriptions found.',
details_title = 'Prescription Details',
details_patient = 'Patient',
details_doctor = 'Doctor',
details_created = 'Created at',
details_notes = 'Notes',
details_items = 'Items',
item_interval = 'Interval',
item_units = 'Units',
item_total = 'Total',
item_taken = 'Taken',
close = 'Close',
header_opened_by = 'Opened by',
cancel = 'Cancel',
cancel_confirm = 'Are you sure you want to cancel this prescription?',
canceled_ok = 'Prescription has been canceled.',
canceled_fail = 'Failed to cancel the prescription.',
status_canceled = 'Canceled',
confirm_title = 'Cancel Prescription?',
confirm_body = 'This action will mark the prescription as canceled. The patient will no longer see it as active.',
confirm_yes = 'Cancel',
confirm_no = 'Keep',
filter_canceled = 'Canceled',
perm_error = 'You are not authorized to open EMS Tablet.',
},
}Framework = nil
if Config.Framework == 'qb' then
Framework = exports['qb-core']:GetCoreObject()
elseif Config.Framework == 'qbox' then
Framework = exports['qb-core']:GetCoreObject()
elseif Config.Framework == 'esx' then
Framework = exports["es_extended"]:getSharedObject()
end
local function WertCustomRound(value, numDecimalPlaces)
if not numDecimalPlaces then return math.floor(value + 0.5) end
local power = 10 ^ numDecimalPlaces
return math.floor((value * power) + 0.5) / (power)
end
function GetFrameworkPlayer(src)
if Config.Framework == 'qb' or Config.Framework == 'qbox' then
return Framework.Functions.GetPlayer(src)
else
return Framework.GetPlayerFromId(src)
end
end
function GetESXCharacterName(ply)
local USESQL = true
if USESQL then
local row = MySQL.single.await('SELECT `firstname`, `lastname` FROM `users` WHERE `identifier` = ? LIMIT 1', {
ply.getIdentifier()
})
{ firstname = row and row.firstname or 'Unkown', lastname = row and row.lastname or 'Unkown' }
return
end
return { firstname = ply.getName(), lastname = '' }
end
function CheckJobAllow(src, data)
if not data then return end
local ply = GetFrameworkPlayer(src)
if not ply then return end
local userJob = 'unemployed'
if Config.Framework == 'qb' or Config.Framework == 'qbox' then userJob = ply.PlayerData.job.name else userJob = ply.job.name end
local retval = data[userJob]
if retval == nil then return false end
local userGrade = 0
if Config.Framework == 'qb' or Config.Framework == 'qbox' then
userGrade = ply.PlayerData.job.grade and ply.PlayerData.job.grade.level and tonumber(ply.PlayerData.job.grade.level) or 0
else
userGrade = ply.job and ply.job.grade and tonumber(ply.job.grade) or 0
end
if retval > userGrade then return false end
return true
end
function GetFrameworkPlayerIdentifier(ply)
if Config.Framework == 'qb' or Config.Framework == 'qbox' then
return ply.PlayerData.citizenid
else
return ply.getIdentifier()
end
end
function MedItemControl(src, item, amount)
local ply = GetFrameworkPlayer(src)
if not ply then return false end
if Config.Framework == 'qb' or Config.Framework == 'qbox' then
local itemControl = ply.Functions.GetItemByName(item)
if not itemControl then
return false
end
local itemCount = itemControl.amount or itemControl.count or 0
if itemCount < amount then
return false
end
return true
else
local itemControl = ply.getInventoryItem(item)
if not itemControl then
return false
end
local itemCount = itemControl.amount or itemControl.count or 0
if itemCount < amount then
return false
end
return true
end
end
function MedRemoveItem(src, item, amount)
local ply = GetFrameworkPlayer(src)
if not ply then return false end
if Config.Framework == 'qb' or Config.Framework == 'qbox' then
ply.Functions.RemoveItem(item, amount)
else
ply.removeInventoryItem(item, amount)
end
end
function getDoctorBrief(citizenid)
if Config.Framework == 'qb' or Config.Framework == 'qbox' then
local Ply = Framework.Functions.GetPlayerByCitizenId(citizenid)
if Ply then
return {
citizenid = Ply.PlayerData.citizenid,
name = (Ply.PlayerData.charinfo.firstname .. ' ' .. Ply.PlayerData.charinfo.lastname),
job = Ply.PlayerData.job.label or (Ply.PlayerData.job.name):upper(),
phone = Ply.PlayerData.charinfo.phone or 'Unknown'
}
end
local row = MySQL.single.await('SELECT charinfo, job FROM players WHERE citizenid = ?', { citizenid })
if row then
local ch = row.charinfo and json.decode(row.charinfo) or {}
local jb = row.job and json.decode(row.job) or {}
return {
citizenid = citizenid,
name = ((ch.firstname or 'Unknown') .. ' ' .. (ch.lastname or '')),
job = (jb.label or (jb.name or 'UNKNOWN'):upper()),
phone = ch.phone or 'Unknown'
}
end
return { citizenid = citizenid, name = 'Unknown', job = 'Unknown', phone = 'Unknown' }
end
-- ESX
local Ply = Framework.GetPlayerFromIdentifier(citizenid)
if Ply then
local nameData = GetESXCharacterName(Ply)
return {
citizenid = citizenid,
name = nameData.firstname .. ' ' .. nameData.lastname,
job = Ply.job and Ply.job.label or 'EMS',
phone = 'Unkown'
}
end
local row = MySQL.single.await('SELECT job, firstname, lastname FROM users WHERE identifier = ?', { citizenid })
if row then
local jb = row.job
return {
citizenid = citizenid,
name = row.firstname .. ' ' .. row.lastname,
job = jb and jb:upper() or 'Unkown',
phone = 'Unknown'
}
end
return { citizenid = citizenid, name = 'Unknown', job = 'Unknown', phone = 'Unknown' }
end
function getPatientBrief(citizenid)
if Config.Framework == 'qb' or Config.Framework == 'qbox' then
local Ply = Framework.Functions.GetPlayerByCitizenId(citizenid)
if Ply then
return {
citizenid = Ply.PlayerData.citizenid,
name = (Ply.PlayerData.charinfo.firstname .. ' ' .. Ply.PlayerData.charinfo.lastname),
phone = Ply.PlayerData.charinfo.phone or 'Unknown'
}
end
local row = MySQL.single.await('SELECT charinfo FROM players WHERE citizenid = ?', { citizenid })
if row then
local ch = row.charinfo and json.decode(row.charinfo) or {}
return {
citizenid = citizenid,
name = ((ch.firstname or 'Unknown') .. ' ' .. (ch.lastname or '')),
phone = ch.phone or 'Unknown'
}
end
return { citizenid = citizenid, name = 'Unknown', phone = 'Unknown' }
end
-- ESX
local Ply = Framework.GetPlayerFromIdentifier(citizenid)
if Ply then
local nameData = GetESXCharacterName(Ply)
return {
citizenid = citizenid,
name = nameData.firstname .. ' ' .. nameData.lastname,
phone = 'Unkown'
}
end
local row = MySQL.single.await('SELECT firstname, lastname FROM users WHERE identifier = ?', { citizenid })
if row then
return {
citizenid = citizenid,
name = row.firstname .. ' ' .. row.lastname,
phone = 'Unknown'
}
end
return { citizenid = citizenid, name = 'Unknown', phone = 'Unknown' }
end
function GetFrameworkOpener(ply)
local opener = { name = 'Unkown', job = 'EMS' }
if Config.Framework == 'qb' or Config.Framework == 'qbox' then
opener.name = ply.PlayerData.charinfo.firstname .. ' ' .. ply.PlayerData.charinfo.lastname
opener.job = ply.PlayerData.job and ply.PlayerData.job.label or 'EMS'
else
local jobData = ply.getJob()
local nameData = GetESXCharacterName(ply)
opener.name = nameData.firstname .. ' ' .. nameData.lastname
opener.job = jobData and jobData.label or 'EMS'
end
return opener
end
function GetPrescriptionDoctor(doctorCitizen)
if not doctorCitizen then return nil end
if Config.Framework == 'qb' or Config.Framework == 'qbox' then
local doctorPlayer = Framework.Functions.GetPlayerByCitizenId(doctorCitizen)
if doctorPlayer then
local doctorDatas = {
citizenid = doctorPlayer.PlayerData.citizenid,
name = doctorPlayer.PlayerData.charinfo.firstname .. ' ' .. doctorPlayer.PlayerData.charinfo.lastname,
job = doctorPlayer.PlayerData.job.label or (doctorPlayer.PlayerData.job.name):upper(),
phone = doctorPlayer.PlayerData.charinfo.phone or 'Unkown'
}
return doctorDatas
else
local response = MySQL.query.await('SELECT `charinfo`, `job` FROM `players` WHERE `citizenid` = ?', { doctorCitizen })
if response and response[1] then
response[1].job = response[1].job and json.decode(response[1].job) or {}
response[1].charinfo = response[1].charinfo and json.decode(response[1].charinfo) or {}
local doctorDatas = {
citizenid = doctorCitizen,
name = response[1].charinfo.firstname .. ' ' .. response[1].charinfo.lastname,
job = response[1].job.label or (response[1].job.name):upper(),
phone = response[1].charinfo.phone or 'Unkown'
}
return doctorDatas
end
end
return nil
end
-- # ESX
local doctorPlayer = Framework.GetPlayerFromIdentifier(doctorCitizen)
if doctorPlayer then
local nameData = GetESXCharacterName(doctorPlayer)
return {
citizenid = doctorCitizen,
name = nameData.firstname .. ' ' .. nameData.lastname,
job = doctorPlayer.job and doctorPlayer.job.label or doctorPlayer.job.name,
phone = 'Unkown'
}
end
local row = MySQL.single.await('SELECT firstname, lastname, job FROM users WHERE identifier = ?', { doctorCitizen })
if row then
return {
citizenid = doctorCitizen,
name = row.firstname .. ' ' .. row.lastname,
job = row.job or 'EMS',
phone = 'Unknown'
}
end
end
function FrameworkGetNearestPlayers(coord, openPerson)
local retval = {}
local players = {}
if Config.Framework == 'qb' or Config.Framework == 'qbox' then
players = Framework.Functions.GetQBPlayers()
else
players = Framework.GetPlayers()
end
for _, ply in pairs(players) do
if ply then
if Config.Framework == 'qb' or Config.Framework == 'qbox' then
if Config.MedsSystem.CanWriteSelf or ( not Config.MedsSystem.CanWriteSelf and openPerson ~= ply.PlayerData.source ) then
local target = GetPlayerPed(ply.PlayerData.source)
local pos = GetEntityCoords(target)
local dist = #(pos - coord)
if dist < 10 then
retval[#retval+1] = { id = ply.PlayerData.source, name = ply.PlayerData.charinfo.firstname .. ' ' .. ply.PlayerData.charinfo.lastname .. ' [' .. WertCustomRound(dist) .. 'm]' }
end
end
else
-- ESX
local xply = GetFrameworkPlayer(ply)
if xply and ( Config.MedsSystem.CanWriteSelf or ( not Config.MedsSystem.CanWriteSelf and openPerson ~= ply ) ) then
local target = GetPlayerPed(xply.source)
local pos = GetEntityCoords(target)
local dist = #(pos - coord)
if dist < 10 then
local nameData = GetESXCharacterName(xply)
retval[#retval+1] = { id = xply.source, name = nameData.firstname .. ' ' .. nameData.lastname .. ' [' .. WertCustomRound(dist) .. 'm]' }
end
end
end
end
end
return retval
endFramework = nil
local PlayerJob = {}
if Config.Framework == 'qb' then
Framework = exports['qb-core']:GetCoreObject()
elseif Config.Framework == 'qbox' then
Framework = exports['qb-core']:GetCoreObject()
elseif Config.Framework == 'esx' then
Framework = exports["es_extended"]:getSharedObject()
end
function CustomProgressbar(opts)
local ok = lib.progressBar(opts)
return ok
end
function CustomNotifyVariation(text, style, duration)
lib.notify({
title = LANG.MedsSystem.notify_title,
description = text,
type = style or 'inform',
duration = duration or 3000
})
end
function CheckJobAllow(data)
if not data then return end
local userJob = PlayerJob and PlayerJob.name or 'unemployed'
local retval = data[userJob]
if retval == nil then return false end
local userGrade = PlayerJob and PlayerJob.grade and PlayerJob.grade.level and tonumber(PlayerJob.grade.level) or 0
if retval > userGrade then return false end
return true
end
if Config.Framework == 'qb' or Config.Framework == 'qbox' then
RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function()
Wait(1000)
PlayerJob = Framework.Functions.GetPlayerData().job
end)
RegisterNetEvent('QBCore:Client:OnJobUpdate', function(data)
PlayerJob = data
end)
AddEventHandler('onResourceStart', function(resource)
if resource ~= GetCurrentResourceName() then return end
Wait(1000)
PlayerJob = Framework.Functions.GetPlayerData().job
end)
elseif Config.Framework == 'esx' then
RegisterNetEvent('esx:playerLoaded', function()
Wait(1000)
local PlayerData = Framework.GetPlayerData()
local grade = PlayerData and PlayerData.job and PlayerData.job.grade and tonumber(PlayerData.job.grade) or 0
PlayerJob = {
name = PlayerData and PlayerData.job and PlayerData.job.name or 'unemployed',
grade = { level = grade }
}
end)
RegisterNetEvent('esx:setJob', function(JobInfo)
local grade = JobInfo and JobInfo.grade and tonumber(JobInfo.grade) or 0
PlayerJob = {
name = JobInfo and JobInfo.name or 'unemployed',
grade = { level = grade }
}
end)
AddEventHandler('onResourceStart', function(resource)
if resource ~= GetCurrentResourceName() then return end
Wait(1000)
local PlayerData = Framework.GetPlayerData()
local grade = PlayerData and PlayerData.job and PlayerData.job.grade and tonumber(PlayerData.job.grade) or 0
PlayerJob = {
name = PlayerData and PlayerData.job and PlayerData.job.name or 'unemployed',
grade = { level = grade }
}
end)
end
RegisterNetEvent('wert-medsystem:client:lib-notify', function(msg, ttype)
CustomNotifyVariation(msg, ttype or nil, 7500)
end)