Skrypt pracy medyka FiveM: stwórz realistyczny system EMS
Zaprojektuj kompletną pracę medyka na swój serwer FiveM. Ożywianie pacjentów, procedury szpitalne, integracja z ESX i QBCore oraz najlepsze dostępne skrypty EMS.
Agency Scripts
Założyciel i główny deweloper w Agency Scripts
Przegląd systemu Ambulance Job
Skrypt pracy pogotowia (ambulance job) jest niezbędny dla każdego serwera roleplay stawiającego na immersyjną rozgrywkę służb ratunkowych. System EMS obsługuje wszystko: od odbierania zgłoszeń dyspozytorskich, gdy gracz zostanie powalony, po mechaniki leczenia na miejscu zdarzenia, transport do szpitala i wystawianie rachunków medycznych. Dobrze zaprojektowany skrypt pogotowia tworzy angażujący gameplay dla medyków z EMS, jednocześnie dbając o to, by powaleni gracze nie tkwili w nieskończonym oczekiwaniu. Architektura dzieli się na cztery główne podsystemy: system dyspozytorski i powiadomień ostrzegający EMS o zdarzeniach, mechaniki leczenia i stabilizacji dające medykom realne zadania do wykonania, proces przyjęcia do szpitala i rekonwalescencji oraz system fakturowania generujący ekonomiczny koszt obrażeń. Każdy podsystem musi działać niezależnie, aby w przypadku braku graczy EMS na służbie automatyczne systemy awaryjne zajęły się powrotem gracza do zdrowia.
Konfiguracja prac i system służby
Praca w pogotowiu (ambulance job) wymaga jasno określonych stopni z różnymi uprawnieniami na każdym poziomie. Stażyści mogą być w stanie udzielić tylko podstawowej pierwszej pomocy, podczas gdy starsi ratownicy medyczni mogą wdrażać zaawansowane leczenie i mieć dostęp do zastrzeżonych leków. Użyj tabeli konfiguracyjnej przypisującej stopnie do dostępnych akcji, wymaganych przedmiotów i stawek wynagrodzenia. System służby powinien monitorować, którzy gracze EMS są aktualnie aktywni, aby serwer wiedział, kiedy zastosować automatyczny fallback respawnu:
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),
},
}
Ten minOnDutyForNoAutoRespawn ustawienie kontroluje, kiedy serwer przełącza się między powrotem do zdrowia zależnym od EMS a automatycznym. Gdy na służbie jest mniej niż dwóch ratowników EMS, powaleni gracze otrzymują czasową opcję odrodzenia po odczekaniu skonfigurowanej liczby sekund. Zapobiega to sytuacji, gdy gracze czekają bez końca na pomoc medyczną, która nigdy nie nadejdzie.
System dispatch i powiadomień
Gdy gracz zostanie obezwładniony, system wysyła powiadomienie dyspozytorskie do wszystkich graczy EMS na służbie, pokazując lokalizację, charakter zgłoszenia oraz możliwość przyjęcia wezwania. Zgłoszenie widzi wielu ratowników EMS, ale tylko jeden powinien je przyjąć, aby uniknąć zamieszania. Zaimplementuj system przyjmowania, w którym pierwsza jednostka akceptująca wezwanie ma je przypisane, a pozostali EMS widzą je jako zajęte wraz z identyfikatorem jednostki reagującej:
-- 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)
Dołącz przyczynę śmierci do informacji w dispatchu, aby ratownik EMT mógł przygotować odpowiednie przedmioty medyczne przed przybyciem na miejsce. Typowe przyczyny, takie jak rany postrzałowe, kolizje drogowe, upadki czy utonięcia, wymagają odmiennego podejścia do leczenia, co pogłębia immersję roleplay dla EMS.
Mechaniki leczenia i reanimacji
Mechaniki leczenia powinny być bardziej rozbudowane niż zwykłe naciśnięcie przycisku w celu reanimacji gracza. Stwórz wieloetapowy proces, w którym ratownik medyczny (EMT) musi najpierw ustabilizować pacjenta za pomocą podstawowych zabiegów przed wykonaniem właściwej reanimacji. Każdy etap leczenia zużywa przedmiot z ekwipunku ratownika i zajmuje określony czas z animacją paska postępu. Stan pacjenta można zamodelować za pomocą prostego stanu zdrowia, który poprawia się po każdym zastosowanym zabiegu:
-- 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
Pasek postępu z animacją tworzy realistyczną scenę leczenia, którą mogą obserwować inni gracze, co wzbogaca klimat roleplay. Ustaw defibrylator jako ostatni krok, który faktycznie przywraca do życia, wymagając od ratownika wcześniejszego ustabilizowania pacjenta bandażami i środkami przeciwbólowymi. To wieloetapowe podejście sprawia, że rola EMS jest znacznie ciekawsza niż zwykłe podniesienie jednym kliknięciem.
Rejestracja i rekonwalescencja w szpitalu
Po reanimacji pacjenta w terenie lub przetransportowaniu go do szpitala gracz EMS może zameldować go w łóżku szpitalnym w celu pełnego powrotu do zdrowia. Proces przyjęcia leczy pacjenta całkowicie, nalicza rachunek medyczny i rejestruje wizytę. Łóżka szpitalne powinny być śledzone, aby zapobiec przypisaniu wielu pacjentów do tego samego łóżka. Stwórz system zarządzania łóżkami, który oznacza łóżka jako zajęte i zwalnia je po konfigurowalnym czasie regeneracji:
-- 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
Rachunek medyczny tworzy ekonomiczne konsekwencje śmierci, które równoważą gospodarkę serwera. Rozważ skalowanie rachunku w zależności od tego, jak gracz został ranny, z wyższymi kosztami za lekkomyślne zachowania, takie jak wypadki przy dużej prędkości, w porównaniu z niższymi kosztami za bycie ofiarą przestępstwa. Zachęca to do ostrożnej jazdy i nadaje wagę niebezpiecznym sytuacjom.
Awaryjny system automatycznego respawnu
Gdy żaden gracz EMS nie jest na służbie, serwer musi zapewnić alternatywną ścieżkę powrotu do zdrowia, aby powaleni gracze nie utknęli na stałe. Zaimplementuj odliczanie, które pojawia się po konfigurowalnym opóźnieniu i pozwala graczowi na respawn w szpitalu z automatycznie pobieraną stałą opłatą medyczną. Lokalizacja respawnu powinna znajdować się przy wejściu do szpitala lub w wyznaczonym obszarze rekonwalescencji. Zawsze sprawdzaj aktualną liczbę EMS przed wyświetleniem opcji automatycznego respawnu i natychmiast ją zamykaj, jeśli medyk przyjmie wezwanie podczas odliczania. Ten dwutorowy system gwarantuje, że gracze zawsze mają możliwość odzyskania przytomności, jednocześnie stawiając na pierwszym miejscu interakcję roleplay z EMS, gdy medycy są dostępni.
Materiały medyczne i integracja z ekwipunkiem
Gracze EMS potrzebują dostępu do materiałów medycznych poprzez schowek szpitalny z ograniczeniem frakcyjnym oraz poprzez system wytwarzania lub zakupu. Zaopatrz schowek szpitalny w bandaże, środki przeciwbólowe, szyny, kroplówki, worki z krwią oraz ładunki do defibrylatora. Każda czynność lecznicza zużywa odpowiedni przedmiot, generując stałe zapotrzebowanie na dostawy. Śledź zużycie zapasów w bazie danych, aby monitorować wzorce zużycia i automatycznie uzupełniać schowki szpitalne w konfigurowalnych odstępach czasu. Rozważ umożliwienie wytwarzania części zapasów graczom z rolą farmaceuty lub lekarza, co stworzy dodatkowe możliwości roleplayu i powiązania ekonomiczne między różnymi pracami na serwerze.
Logowanie i monitorowanie wydajności
Rejestruj każdą interakcję EMS do weryfikacji administracyjnej, w tym dane leczonego gracza, zastosowane procedury medyczne, reagującego ratownika medycznego oraz końcowy rachunek medyczny. Zapisuj te logi w dedykowanej tabeli bazy danych i opcjonalnie wysyłaj podsumowania na webhook Discord do monitorowania przez administrację w czasie rzeczywistym. Logi te pomagają rozwiązywać spory, identyfikować graczy EMS niewykonujących swoich obowiązków i śledzić ogólny stan systemu. Pod kątem wydajności zachowaj lekkość logiki sprawdzania śmierci, uruchamiając ją tylko dla graczy, których zdrowie spadło do zera, a nie dla każdego gracza w każdej klatce. Zastosuj architekturę sterowaną zdarzeniami, w której stan śmierci wywołuje pojedyncze zdarzenie serwerowe zamiast odpytywania (polling). System powiadomień dyspozytorni powinien grupować alerty w pakiety zamiast wysyłać pojedyncze zdarzenia do każdego gracza EMS, zmniejszając obciążenie sieci podczas wypadków masowych, gdy wielu graczy pada jednocześnie.