FiveM-Rettungsdienst-Skript: Erstelle ein realistisches EMS-System
Erstelle einen kompletten Rettungsdienst für deinen FiveM-Server. Mit Wiederbelebung, Klinikabläufen, ESX- und QBCore-Integration sowie starken EMS-Skripten.
Agency Scripts
Gründer und leitender Entwickler bei Agency Scripts
Übersicht über das Krankenwagensystem
Ein Krankenwagen-Job-Script ist für jeden Roleplay-Server unverzichtbar, der ein immersives Spielerlebnis rund um Rettungsdienste bieten möchte. Das EMS-System übernimmt alles, von Dispatch-Meldungen, wenn ein Spieler außer Gefecht gesetzt wird, über Behandlungen am Einsatzort und den Transport ins Krankenhaus bis hin zur medizinischen Abrechnung. Ein gut entwickeltes Krankenwagen-Script bietet EMS-Spielern sinnvolles Gameplay und sorgt gleichzeitig dafür, dass am Boden liegende Spieler nicht endlos warten müssen. Die Architektur gliedert sich in vier Hauptsysteme: das Dispatch- und Benachrichtigungssystem, das EMS über Vorfälle informiert, die Behandlungs- und Stabilisierungsmechaniken, die Sanitätern konkrete Aufgaben geben, die Anmeldung und Genesung im Krankenhaus sowie das Abrechnungssystem, das Verletzungen mit Kosten verbindet. Jedes System muss eigenständig funktionieren, damit automatische Ausweichsysteme die Genesung von Spielern übernehmen, wenn keine EMS-Spieler im Dienst sind.
Job-Konfiguration und Dienstsystem
Der Krankenwagen-Job braucht klar definierte Ränge mit unterschiedlichen Fähigkeiten für jede Stufe. Auszubildende können vielleicht nur Erste Hilfe leisten, während leitende Rettungssanitäter fortgeschrittene Behandlungen durchführen und auf beschränkte medizinische Vorräte zugreifen können. Verwende eine Konfigurationstabelle, die Jobränge den verfügbaren Aktionen, erforderlichen Gegenständen und Vergütungssätzen zuordnet. Das Dienstsystem sollte erfassen, welche EMS-Spieler gerade aktiv sind, damit der Server weiß, ob er die automatische Respawn-Ausweichlösung verwenden soll:
Config.AmbulanceJob = {
name = 'ambulance',
grades = {
[0] = {
label = 'Trainee',
treatments = {'bandage', 'painkillers'},
canRevive = false,
salary = 250,
},
[1] = {
label = 'EMT',
treatments = {'bandage', 'painkillers', 'splint', 'iv_drip'},
canRevive = true,
salary = 400,
},
[2] = {
label = 'Paramedic',
treatments = {'bandage', 'painkillers', 'splint', 'iv_drip',
'defibrillator', 'blood_transfusion'},
canRevive = true,
salary = 550,
},
[3] = {
label = 'Chief',
treatments = {'all'},
canRevive = true,
salary = 750,
},
},
minOnDutyForNoAutoRespawn = 2,
respawnTimer = 300, -- seconds before auto-respawn when no EMS
hospitalCoords = vector3(311.2, -584.3, 43.3),
bedSpawns = {
vector4(309.7, -583.8, 43.3, 70.0),
vector4(313.0, -585.2, 43.3, 70.0),
vector4(316.3, -586.6, 43.3, 70.0),
},
}
Die minOnDutyForNoAutoRespawn Die Einstellung steuert, wann der Server zwischen EMS-abhängiger und automatischer Genesung wechselt. Wenn weniger als zwei EMS-Spieler im Dienst sind, erhalten am Boden liegende Spieler nach der konfigurierten Wartezeit eine zeitgesteuerte Respawn-Option. So müssen Spieler nicht auf medizinische Hilfe warten, die niemals eintreffen wird.
Dispatch- und Benachrichtigungssystem
Wenn ein Spieler außer Gefecht gesetzt wird, sendet das System eine Dispatch-Meldung an alle EMS-Spieler im Dienst. Sie enthält den Standort, die Art des Notfalls und eine Möglichkeit, den Einsatz anzunehmen. Mehrere EMS-Spieler können die Meldung sehen, aber nur einer sollte den Einsatz übernehmen, um Verwirrung zu vermeiden. Implementiere ein Annahmesystem, bei dem der erste Helfer, der den Einsatz annimmt, zugeteilt wird. Für die anderen EMS-Spieler wird der Einsatz als angenommen angezeigt, zusammen mit der Kennung der antwortenden Einheit:
-- Server: handle player down event
local ActiveCalls = {}
RegisterNetEvent('ambulance:server:playerDown', function(deathCause)
local src = source
local Player = QBCore.Functions.GetPlayer(src)
if not Player then return end
local ped = GetPlayerPed(src)
local coords = GetEntityCoords(ped)
local streetHash, _ = GetStreetNameAtCoord(coords.x, coords.y, coords.z)
local streetName = GetStreetNameFromHashKey(streetHash)
local callId = 'EMS-' .. os.time() .. '-' .. src
ActiveCalls[callId] = {
source = src,
patient = Player.PlayerData.charinfo.firstname .. ' ' ..
Player.PlayerData.charinfo.lastname,
coords = coords,
street = streetName,
cause = deathCause,
time = os.time(),
claimed = false,
responder = nil,
}
-- Notify all on-duty EMS
local emsList = QBCore.Functions.GetPlayersOnDuty('ambulance')
for _, emsId in ipairs(emsList) do
TriggerClientEvent('ambulance:client:newCall', emsId, callId, ActiveCalls[callId])
end
end)
RegisterNetEvent('ambulance:server:claimCall', function(callId)
local src = source
local call = ActiveCalls[callId]
if not call or call.claimed then return end
local Player = QBCore.Functions.GetPlayer(src)
if not Player or Player.PlayerData.job.name ~= 'ambulance' then return end
call.claimed = true
call.responder = src
-- Notify all EMS that call is claimed
local emsList = QBCore.Functions.GetPlayersOnDuty('ambulance')
for _, emsId in ipairs(emsList) do
TriggerClientEvent('ambulance:client:callClaimed', emsId, callId, Player.PlayerData.charinfo.firstname)
end
-- Set GPS waypoint for responding EMT
TriggerClientEvent('ambulance:client:setWaypoint', src, call.coords)
end)
Nimm die Todesursache in die Dispatch-Informationen auf, damit sich der eintreffende EMT vorab mit den passenden Behandlungsmitteln ausstatten kann. Häufige Ursachen wie Schusswunden, Verkehrsunfälle, Stürze und Ertrinken erfordern jeweils unterschiedliche Behandlungen. Das sorgt für mehr Tiefe im EMS-Roleplay.
Behandlung und Wiederbelebung
Die Behandlung sollte mehr umfassen, als nur einen Knopf zu drücken, um jemanden wiederzubeleben. Erstelle einen mehrstufigen Ablauf, bei dem der EMT den Patienten zunächst mit grundlegenden Maßnahmen stabilisieren muss, bevor die eigentliche Wiederbelebung erfolgt. Jeder Behandlungsschritt verbraucht einen Gegenstand aus dem Inventar des EMT und dauert eine festgelegte Zeit. Währenddessen wird eine Animation mit Fortschrittsbalken angezeigt. Der Zustand des Patienten lässt sich mit einem einfachen Gesundheitsstatus modellieren, der sich mit jeder durchgeführten Behandlung verbessert:
-- Client: treatment system
local TreatmentSteps = {
['bandage'] = {
label = 'Apply Bandage',
duration = 5000,
anim = {dict = 'mini@cpr@char_a@cpr_str', name = 'cpr_pumpchest'},
healthRestore = 10,
item = 'bandage',
},
['painkillers'] = {
label = 'Administer Painkillers',
duration = 3000,
anim = {dict = 'mp_arresting', name = 'a_uncuff'},
healthRestore = 15,
item = 'painkillers',
},
['defibrillator'] = {
label = 'Use Defibrillator',
duration = 8000,
anim = {dict = 'mini@cpr@char_a@cpr_str', name = 'cpr_pumpchest'},
healthRestore = 0,
item = 'defibrillator',
canRevive = true,
},
}
function PerformTreatment(targetId, treatmentType)
local treatment = TreatmentSteps[treatmentType]
if not treatment then return end
-- Check if EMT has required item
if not HasItem(treatment.item) then
QBCore.Functions.Notify('Missing: ' .. treatment.label, 'error')
return
end
-- Play animation and progress bar
TaskPlayAnim(PlayerPedId(), treatment.anim.dict, treatment.anim.name,
8.0, -8.0, treatment.duration, 1, 0, false, false, false)
QBCore.Functions.Progressbar('treatment_' .. treatmentType,
treatment.label, treatment.duration, false, true, {}, {}, {}, {},
function() -- success
TriggerServerEvent('ambulance:server:applyTreatment',
targetId, treatmentType)
ClearPedTasks(PlayerPedId())
end,
function() -- cancel
ClearPedTasks(PlayerPedId())
QBCore.Functions.Notify('Treatment cancelled', 'error')
end
)
end
Der Fortschrittsbalken mit Animation sorgt für eine realistische Behandlungsszene, die andere Spieler beobachten können und die so die Roleplay-Atmosphäre verstärkt. Die Defibrillation sollte der letzte Schritt sein, der den Patienten tatsächlich wiederbelebt. Dafür muss der EMT den Patienten zuvor mit Verbänden und Schmerzmitteln stabilisieren. Dieser mehrstufige Ablauf macht die EMS-Rolle interessanter als eine einfache Wiederbelebung mit nur einem Klick.
Anmeldung und Genesung im Krankenhaus
Nach der Wiederbelebung am Einsatzort oder dem Transport ins Krankenhaus kann ein EMS-Spieler den Patienten für eine vollständige Genesung in einem Krankenhausbett anmelden. Bei der Anmeldung wird der Patient vollständig geheilt, eine Arztrechnung erstellt und der Besuch protokolliert. Krankenhausbetten sollten erfasst werden, damit nicht mehrere Patienten demselben Bett zugewiesen werden. Erstelle ein Bettenverwaltungssystem, das belegte Betten markiert und sie nach einer konfigurierbaren Genesungszeit wieder freigibt:
-- Server: hospital bed management
local OccupiedBeds = {}
RegisterNetEvent('ambulance:server:checkInPatient', function(patientId)
local src = source
local EMT = QBCore.Functions.GetPlayer(src)
local Patient = QBCore.Functions.GetPlayer(patientId)
if not EMT or not Patient then return end
if EMT.PlayerData.job.name ~= 'ambulance' then return end
-- Find available bed
local bedIndex = nil
for i, bed in ipairs(Config.AmbulanceJob.bedSpawns) do
if not OccupiedBeds[i] then
bedIndex = i
break
end
end
if not bedIndex then
TriggerClientEvent('QBCore:Notify', src, 'No beds available', 'error')
return
end
OccupiedBeds[bedIndex] = patientId
-- Calculate and charge medical bill
local bill = CalculateMedicalBill(Patient)
Patient.Functions.RemoveMoney('bank', bill, 'medical-bill')
-- Heal patient and teleport to bed
local bed = Config.AmbulanceJob.bedSpawns[bedIndex]
TriggerClientEvent('ambulance:client:bedRecovery', patientId, bed, bill)
-- Pay EMT for service
local salary = Config.AmbulanceJob.grades[EMT.PlayerData.job.grade.level].salary
EMT.Functions.AddMoney('bank', salary, 'ems-treatment-pay')
-- Release bed after recovery
SetTimeout(60000, function()
OccupiedBeds[bedIndex] = nil
end)
end)
function CalculateMedicalBill(Patient)
local baseCost = 500
local injuryMultiplier = 1.0
-- Could factor in injury severity, treatment count, etc.
return math.floor(baseCost * injuryMultiplier)
end
Die Arztrechnung sorgt für wirtschaftliche Folgen beim Tod und trägt dazu bei, die Serverwirtschaft auszubalancieren. Du kannst die Rechnungshöhe davon abhängig machen, wie sich der Spieler verletzt hat: Höhere Kosten bei rücksichtslosem Verhalten wie Hochgeschwindigkeitsunfällen, geringere Kosten, wenn jemand Opfer eines Verbrechens wurde. Das fördert vorsichtiges Fahren und verleiht gefährlichen Situationen mehr Gewicht.
Automatisches Respawn-Ausweichsystem
Wenn keine EMS-Spieler im Dienst sind, muss der Server einen alternativen Weg zur Genesung anbieten, damit am Boden liegende Spieler nicht dauerhaft feststecken. Implementiere einen Countdown, der nach einer konfigurierbaren Verzögerung angezeigt wird und dem Spieler ermöglicht, gegen eine automatisch abgezogene Pauschalgebühr für medizinische Versorgung im Krankenhaus zu respawnen. Der Respawn-Ort sollte der Krankenhauseingang oder ein festgelegter Genesungsbereich sein. Prüfe vor der Anzeige der automatischen Respawn-Option immer die aktuelle Anzahl der EMS-Spieler und blende sie sofort aus, wenn ein EMT den Einsatz während des Countdowns übernimmt. Dieses System mit zwei Wegen stellt sicher, dass Spieler sich immer erholen können, und gibt gleichzeitig dem Roleplay mit EMS-Spielern Vorrang, wenn Sanitäter verfügbar sind.
Medizinische Vorräte und Inventarintegration
EMS-Spieler benötigen über ein jobbeschränktes Lager im Krankenhaus sowie ein Herstellungs- oder Kaufsystem Zugang zu medizinischen Vorräten. Bestücke das Krankenhauslager mit Verbänden, Schmerzmitteln, Schienen, Infusionen, Blutbeuteln und Defibrillator-Ladungen. Bei jeder Behandlung wird der entsprechende Gegenstand verbraucht, wodurch ein laufender Nachschubbedarf entsteht. Erfasse den Verbrauch in der Datenbank, um Nutzungsmuster zu beobachten und Krankenhauslager in konfigurierbaren Abständen automatisch aufzufüllen. Ziehe in Betracht, einige Vorräte von Spielern mit der Rolle Apotheker oder Arzt herstellen zu lassen. So entstehen zusätzliche Roleplay-Möglichkeiten und wirtschaftliche Verbindungen zwischen verschiedenen Jobs auf dem Server.
Protokollierung und Performance-Überwachung
Protokolliere jede EMS-Interaktion zur administrativen Überprüfung, einschließlich der behandelten Person, der durchgeführten Behandlungen, des antwortenden EMT und der endgültigen Arztrechnung. Speichere diese Protokolle in einer eigenen Datenbanktabelle und sende Zusammenfassungen optional über einen Discord-Webhook zur Echtzeitüberwachung an das Staff-Team. Diese Protokolle helfen dabei, Streitfälle zu klären, EMS-Spieler zu identifizieren, die ihren Pflichten nicht nachkommen, und den allgemeinen Systemzustand im Blick zu behalten. Halte die Todesprüfung aus Performance-Sicht schlank, indem du sie nur bei Spielern ausführst, deren Gesundheit auf null gesunken ist, und nicht bei jedem Spieler in jedem Frame. Nutze eine ereignisgesteuerte Architektur, bei der der Todesstatus ein einzelnes Server-Event auslöst, anstatt ihn wiederholt abzufragen. Das Dispatch-Benachrichtigungssystem sollte Meldungen bündeln, statt einzelne Events an jeden EMS-Spieler zu senden. So wird die Netzwerklast bei Massenunfällen reduziert, bei denen mehrere Spieler gleichzeitig außer Gefecht gesetzt werden.