Hospital System Architecture
A hospital and EMS system transforms how players experience health and injury on a FiveM roleplay server. Instead of simply respawning after being downed, players enter a medical roleplay pipeline where they can be stabilized by EMS in the field, transported by ambulance, checked into the hospital, diagnosed, treated, and billed for services. The system architecture breaks into four interconnected layers: the injury system that tracks what happened to the player and where on their body, the EMS dispatch and field response tools, the hospital check-in and treatment workflow, and the billing system that connects medical care to the server economy. Each layer communicates through server events so that the doctor treating a patient can see exactly what injuries the EMS responder already documented during field triage. Building this as a unified system rather than separate scripts ensures that patient data flows seamlessly from the moment someone calls 911 to the moment they walk out of the hospital with a bill in hand.
Injury Type System
A detailed injury system replaces the binary alive-or-dead state with a spectrum of conditions that require different treatments. Track injuries by body region, severity, and cause so that EMS and doctors can roleplay realistic medical scenarios. When a player takes damage, determine the injury type based on the weapon or cause of death hash and apply it to the appropriate body region. Gunshot wounds to the torso are more severe than a punch to the arm, and each injury type has specific treatment requirements that doctors must follow:
Config.InjuryTypes = {
gunshot = {
label = 'Gunshot Wound',
severity = { min = 60, max = 100 },
bleedRate = 2.5,
treatments = {'clean_wound', 'remove_bullet', 'stitch', 'bandage'},
requiredItems = {'tweezers', 'suture_kit', 'bandage'},
healTime = 120,
},
stabbing = {
label = 'Stab Wound',
severity = { min = 40, max = 80 },
bleedRate = 1.8,
treatments = {'clean_wound', 'stitch', 'bandage'},
requiredItems = {'suture_kit', 'bandage'},
healTime = 90,
},
blunt = {
label = 'Blunt Force Trauma',
severity = { min = 20, max = 60 },
bleedRate = 0.5,
treatments = {'examine', 'ice_pack', 'painkillers'},
requiredItems = {'ice_pack', 'painkillers'},
healTime = 60,
},
burn = {
label = 'Burn Injury',
severity = { min = 30, max = 90 },
bleedRate = 0,
treatments = {'cool_burn', 'apply_cream', 'bandage'},
requiredItems = {'burn_cream', 'bandage'},
healTime = 100,
},
fracture = {
label = 'Bone Fracture',
severity = { min = 50, max = 70 },
bleedRate = 0,
treatments = {'x_ray', 'set_bone', 'apply_cast'},
requiredItems = {'splint', 'cast_material'},
healTime = 180,
},
vehicle_crash = {
label = 'Vehicle Collision Injury',
severity = { min = 30, max = 95 },
bleedRate = 1.0,
treatments = {'examine', 'clean_wound', 'stitch', 'bandage', 'painkillers'},
requiredItems = {'suture_kit', 'bandage', 'painkillers'},
healTime = 110,
},
}
Config.BodyRegions = {
'head', 'torso', 'left_arm', 'right_arm', 'left_leg', 'right_leg'
}
-- Severity multipliers per body region
Config.RegionMultipliers = {
head = 1.5,
torso = 1.3,
left_arm = 0.8,
right_arm = 0.8,
left_leg = 0.9,
right_leg = 0.9,
}
EMS Dispatch and Field Response
The EMS dispatch system connects downed players with on-duty medical responders. When a player enters the downed state, they can choose to call 911 which creates a dispatch alert visible to all on-duty EMS personnel. The alert includes the caller's GPS coordinates, a brief description generated from their injury data, and a priority level based on injury severity. EMS responders can accept the call through a dispatch UI, which marks the call as claimed and provides GPS navigation to the patient. Implement a response timer that tracks how long each call takes from creation to patient contact, useful for tracking EMS performance and adjusting staffing requirements. Field treatment is a simplified version of hospital treatment where EMS can stabilize patients using basic supplies like bandages, tourniquets, and adrenaline shots to prevent death during transport:
-- Server-side dispatch handler
local activeDispatches = {}
RegisterNetEvent('hospital:server:call911', function(description)
local src = source
local Player = QBCore.Functions.GetPlayer(src)
if not Player then return end
local ped = GetPlayerPed(src)
local coords = GetEntityCoords(ped)
local injuries = Player.Functions.GetMetaData('injuries') or {}
-- Determine priority from injury severity
local maxSeverity = 0
for _, injury in ipairs(injuries) do
if injury.severity > maxSeverity then
maxSeverity = injury.severity
end
end
local priority = maxSeverity >= 80 and 'CRITICAL' or maxSeverity >= 50 and 'URGENT' or 'STANDARD'
local dispatch = {
id = #activeDispatches + 1,
callerId = src,
citizenid = Player.PlayerData.citizenid,
callerName = Player.PlayerData.charinfo.firstname .. ' ' .. Player.PlayerData.charinfo.lastname,
coords = { x = coords.x, y = coords.y, z = coords.z },
description = description or GenerateInjuryDescription(injuries),
priority = priority,
injuries = injuries,
timestamp = os.time(),
status = 'pending',
responderId = nil,
}
table.insert(activeDispatches, dispatch)
-- Notify all on-duty EMS
local emsPlayers = QBCore.Functions.GetQBPlayers()
for _, emsPlayer in pairs(emsPlayers) do
if emsPlayer.PlayerData.job.name == 'ambulance' and emsPlayer.PlayerData.job.onduty then
TriggerClientEvent('hospital:client:newDispatch', emsPlayer.PlayerData.source, dispatch)
end
end
end)
RegisterNetEvent('hospital:server:acceptDispatch', function(dispatchId)
local src = source
local Player = QBCore.Functions.GetPlayer(src)
if not Player or Player.PlayerData.job.name ~= 'ambulance' then return end
for i, dispatch in ipairs(activeDispatches) do
if dispatch.id == dispatchId and dispatch.status == 'pending' then
dispatch.status = 'responding'
dispatch.responderId = src
dispatch.responseTime = os.time()
-- Notify caller
TriggerClientEvent('QBCore:Notify', dispatch.callerId, 'EMS is on the way!', 'success')
-- Set GPS blip for responder
TriggerClientEvent('hospital:client:setDispatchGPS', src, dispatch.coords)
break
end
end
end)
Hospital Check-In and Treatment UI
The hospital check-in system manages patient flow from arrival to discharge. When an EMS responder brings a patient to the hospital or a player walks in on their own, they interact with a reception desk NPC or target point to check in. The check-in process creates a patient record that includes their current injuries, vital signs, and a unique visit ID for billing purposes. On-duty doctors see incoming patients on a hospital management NUI panel that displays the waiting room queue, each patient's triage priority, and their documented injuries. When a doctor selects a patient, the treatment UI opens showing the patient's body diagram with highlighted injury locations. The doctor clicks on each injury to see required treatment steps and can perform each step in sequence, triggering animations and consuming medical supply items from their inventory. Each treatment step has a progress bar and success check that depends on the doctor's skill metadata, adding a progression element to the medical roleplay.
Treatment Workflow
Design the treatment workflow as a step-by-step process where each injury requires specific actions performed in order. A gunshot wound to the torso might require cleaning the wound, extracting the bullet using tweezers, stitching the wound with a suture kit, and applying a bandage. Each step consumes the appropriate item from the doctor's inventory and plays a treatment animation. Skipping steps or performing them out of order should either fail or reduce effectiveness, encouraging proper medical roleplay. After all injuries are treated, the patient enters a recovery period where their health gradually regenerates over time rather than being instantly restored:
RegisterNetEvent('hospital:server:treatInjury', function(patientId, injuryIndex, treatmentStep)
local src = source
local Doctor = QBCore.Functions.GetPlayer(src)
local Patient = QBCore.Functions.GetPlayer(patientId)
if not Doctor or not Patient then return end
if Doctor.PlayerData.job.name ~= 'ambulance' or not Doctor.PlayerData.job.onduty then
TriggerClientEvent('QBCore:Notify', src, 'You must be on duty', 'error')
return
end
local injuries = Patient.Functions.GetMetaData('injuries') or {}
local injury = injuries[injuryIndex]
if not injury then return end
local injuryConfig = Config.InjuryTypes[injury.type]
if not injuryConfig then return end
-- Validate treatment step order
local expectedStep = injury.currentStep or 1
if treatmentStep ~= expectedStep then
TriggerClientEvent('QBCore:Notify', src, 'Complete previous treatment steps first', 'error')
return
end
local stepName = injuryConfig.treatments[treatmentStep]
if not stepName then return end
-- Check required item
local requiredItem = Config.TreatmentItems[stepName]
if requiredItem then
local hasItem = Doctor.Functions.GetItemByName(requiredItem.name)
if not hasItem or hasItem.amount < 1 then
TriggerClientEvent('QBCore:Notify', src, 'Missing: ' .. requiredItem.label, 'error')
return
end
Doctor.Functions.RemoveItem(requiredItem.name, 1)
end
-- Apply treatment
injury.currentStep = treatmentStep + 1
injury.treated = treatmentStep >= #injuryConfig.treatments
if injury.treated then
injury.bleedRate = 0
injury.healStartTime = os.time()
end
injuries[injuryIndex] = injury
Patient.Functions.SetMetaData('injuries', injuries)
-- Notify both parties
TriggerClientEvent('QBCore:Notify', src, 'Treatment step complete: ' .. stepName, 'success')
TriggerClientEvent('QBCore:Notify', patientId, 'You received treatment: ' .. stepName, 'success')
TriggerClientEvent('hospital:client:updateInjuries', patientId, injuries)
end)
On-Duty and Off-Duty System
The duty system controls when EMS and hospital staff are active and eligible to receive dispatch calls. When a player with the ambulance job clocks in at a duty point inside the hospital, they gain access to medical commands, receive dispatch notifications, and appear on the active EMS roster visible to other staff. The duty system should track clock-in and clock-out times for payroll calculations if your server uses automatic salary payments. Implement different duty roles within the EMS job, such as paramedic, doctor, and surgeon, where each role has access to different treatment capabilities. A paramedic can perform field stabilization and basic treatments, a doctor can handle standard hospital procedures, and a surgeon can perform complex operations like bullet extraction and bone setting. Store the duty roster in a shared server state so that the dispatch system can accurately count available responders and adjust the auto-respawn timer for downed players based on EMS availability.
Medical Billing System
Medical billing connects the hospital system to the server economy and creates a financial consequence for risky behavior. When a patient is treated, the system generates an itemized bill that lists each treatment performed, the supplies consumed, and any facility fees. Bills can be paid at checkout through the reception desk, charged directly to the patient's bank account, or sent as an invoice that the patient must pay within a set timeframe. Implement a medical insurance system where players can purchase insurance policies that cover a percentage of their medical costs, reducing the financial sting of frequent hospital visits. Insurance premiums can be a recurring charge that adds to the server's economic simulation. For players who cannot pay, implement a medical debt system where unpaid bills accumulate interest and eventually trigger consequences like wage garnishment from job paychecks or restricted access to certain services until the debt is cleared. Store all billing records for admin review and connect them to the transaction logging system so that the flow of money from patient to hospital can be audited.
Ambulance Vehicle and Equipment
The ambulance vehicle should be more than just a fast car with a siren. Implement vehicle-specific features that make the ambulance a mobile treatment station. When an EMS responder opens the rear doors of the ambulance through a vehicle interaction, they access a mobile treatment menu with a subset of hospital capabilities like bandaging, administering painkillers, applying splints, and using a defibrillator. Store medical supplies in the ambulance's trunk inventory so responders need to restock at the hospital between calls. The defibrillator is a special item that can revive players who have entered the death state, but it should require a minigame with timing-based inputs to simulate proper CPR technique. Implement a stretcher system where EMS can place a downed player on a stretcher attached to the ambulance, which locks the patient into a lying animation inside the vehicle during transport. Use AttachEntityToEntity to handle the stretcher placement and SetPedIntoVehicle for patient loading.
Integration and Quality of Life
Your hospital system should integrate with the server's phone resource so players can call 911 directly from their phone app, view their medical history and outstanding bills, and check EMS wait times before deciding whether to call for help or self-treat with basic items from a pharmacy. Connect the injury system to movement penalties so that leg injuries reduce movement speed and arm injuries affect aim accuracy, creating tangible gameplay consequences that motivate players to seek treatment rather than ignoring their injuries. Implement a medical records system accessible through the hospital MDT where doctors can view a patient's complete treatment history, allergies noted by other physicians, and current medications. Export your injury and treatment functions so that other resources like drug effects, food poisoning, or environmental hazards can all feed into the same medical pipeline. Add an auto-respawn system with a configurable timer that activates when no EMS are on duty, ensuring players are never stuck in a downed state indefinitely while still prioritizing player-driven medical roleplay when staff are available.