سكريبت وظيفة الإسعاف في FiveM: بناء نظام EMS واقعي
تصميم وظيفة إسعاف كاملة لخادم FiveM الخاص بك. إحياء المرضى، سير العمل في المستشفى، تكامل ESX و QBCore بالإضافة إلى أفضل سكربتات EMS المتاحة.
Agency Scripts
المؤسس والمطور الرئيسي في Agency Scripts
نظرة عامة على نظام وظيفة الإسعاف
نص برمجي لوظيفة الإسعاف ضروري لأي خادم لعب أدوار يهدف إلى تجربة خدمات الطوارئ الغامرة. يتعامل نظام EMS مع كل شيء من استقبال مكالمات الإرسال عند سقوط لاعب، إلى آليات العلاج في الموقع، النقل إلى المستشفى، والفوترة الطبية. يخلق نص الإسعاف المصمم جيدًا تجربة لعب ذات معنى للاعبي EMS مع ضمان عدم انتظار اللاعبين المصابين لفترة غير محددة. ينقسم الهيكل إلى أربعة أنظمة فرعية رئيسية: نظام الإرسال والإشعارات الذي ينبه EMS للحوادث، آليات العلاج والاستقرار التي تعطي المسعفين مهام فعلية لأدائها، عملية تسجيل الدخول إلى المستشفى والتعافي، ونظام الفوترة الذي يخلق تكلفة اقتصادية للإصابات. يجب أن يكون كل نظام فرعي وظيفيًا بشكل مستقل بحيث إذا لم يكن هناك لاعبو EMS في الخدمة، تتولى أنظمة الطوارئ التلقائية استعادة اللاعب.
تكوين الوظائف ونظام الدوام
وظيفة الإسعاف تحتاج إلى درجات محددة بوضوح مع قدرات مختلفة في كل مستوى. قد يتمكن المتدربون من أداء الإسعافات الأولية الأساسية فقط، بينما يمكن للمسعفين الكبار تقديم علاجات متقدمة والوصول إلى الإمدادات الطبية المقيدة. استخدم جدول تكوين يربط درجات الوظيفة بالإجراءات المتاحة، والعناصر المطلوبة، ومعدلات الدفع. يجب أن يتتبع نظام الخدمة اللاعبين النشطين في EMS حاليًا حتى يعرف الخادم ما إذا كان يجب استخدام إعادة الظهور التلقائية كخطة بديلة:
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),
},
}
ال minOnDutyForNoAutoRespawn الإعداد يتحكم في متى يتحول الخادم بين الاعتماد على EMS والاسترداد التلقائي. عندما يكون أقل من اثنين من EMS في الخدمة، يحصل اللاعبون المصابون على خيار إعادة إحياء معتمد على مؤقت بعد انتظار عدد الثواني المُكوّن. هذا يمنع اللاعبين من الانتظار بلا جدوى للحصول على رعاية طبية لن تصل أبدًا.
نظام الإرسال والإشعارات
عندما يكون اللاعب عاجزاً، يرسل النظام تنبيهاً إلى جميع لاعبي EMS المناوبين يعرض الموقع، طبيعة الطوارئ، وطريقة للمطالبة بالمكالمة. يمكن لعدة لاعبي EMS رؤية التنبيه، لكن يجب أن يطالب به واحد فقط لتجنب الارتباك. نفذ نظام مطالبة حيث يحصل أول مستجيب يقبل المكالمة على تعيينها، ويرى الآخرون أنها مُطالَب بها مع معرف الوحدة المستجيبة:
-- 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)
تضمين سبب الوفاة في معلومات الإرسال حتى يتمكن EMT المستجيب من تجهيز عناصر العلاج المناسبة قبل الوصول إلى الموقع. الأسباب الشائعة مثل جروح الطلقات النارية، تصادمات المركبات، السقوط، والغرق تتطلب كل منها نهج علاج مختلف، مما يضيف عمقًا لتجربة لعب دور EMS.
ميكانيكيات العلاج والإنعاش
يجب أن تكون ميكانيكيات العلاج أكثر تعقيدًا من مجرد الضغط على زر لإنعاش شخص ما. أنشئ عملية متعددة الخطوات حيث يجب على EMT أولاً تثبيت المريض بالعلاجات الأساسية قبل إجراء الإنعاش الفعلي. يستهلك كل خطوة علاج عنصرًا من مخزون EMT ويستغرق وقتًا محددًا مع رسوم متحركة لشريط التقدم. يمكن نمذجة حالة المريض بحالة صحية بسيطة تتحسن مع كل علاج يُطبق:
-- 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
شريط التقدم مع الرسوم المتحركة يخلق مشهد علاج واقعي يمكن للاعبين الآخرين ملاحظته، مما يعزز جو لعب الأدوار. اجعل جهاز إزالة الرجفان الخطوة النهائية التي تنفذ الإنعاش فعليًا، مما يتطلب من المسعف تثبيت المريض أولاً باستخدام الضمادات ومسكنات الألم. هذا النهج متعدد الخطوات يجعل دور EMS أكثر تشويقًا من مجرد إحياء بنقرة واحدة.
تسجيل الدخول إلى المستشفى والتعافي
بعد إنعاش مريض في الميدان أو نقله إلى المستشفى، يمكن للاعب EMS تسجيله في سرير مستشفى للتعافي الكامل. عملية التسجيل تعالج المريض بالكامل، تفرض فاتورة طبية، وتسجل الزيارة. يجب تتبع الأسرة لمنع تعيين عدة مرضى لنفس السرير. أنشئ نظام إدارة الأسرة الذي يعلّم الأسرة كمشغولة ويحررها بعد وقت تعافي قابل للتكوين:
-- 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
تخلق فاتورة طبية عاقبة اقتصادية للموت توازن اقتصاد الخادم. فكر في مقياس الفاتورة بناءً على كيفية إصابة اللاعب، مع تكاليف أعلى للسلوك المتهور مثل الحوادث عالية السرعة مقابل تكاليف أقل لكونه ضحية جريمة. هذا يشجع على القيادة الحذرة ويضيف وزنًا للمواقف الخطرة.
نظام الاستعادة التلقائية للظهور
عندما لا يكون هناك لاعبو EMS في الخدمة، يجب على الخادم توفير مسار بديل للتعافي حتى لا يبقى اللاعبون المصابون عالقين بشكل دائم. نفذ مؤقت عد تنازلي يظهر بعد تأخير قابل للتكوين، يسمح للاعب بالولادة من جديد في المستشفى مع خصم رسوم طبية ثابتة تلقائيًا. يجب أن يكون موقع الولادة من جديد عند مدخل المستشفى أو منطقة تعافي مخصصة. تحقق دائمًا من عدد EMS الحالي قبل عرض خيار الولادة التلقائية، وألغِه فورًا إذا استجاب EMT للنداء خلال العد التنازلي. يضمن هذا النظام ذو المسارين أن يكون لدى اللاعبين دائمًا طريقة للتعافي مع الحفاظ على تجربة لعب الأدوار الخاصة بتفاعل EMS عندما يتوفر المسعفون.
تكامل الإمدادات الطبية والمخزون
يحتاج لاعبو EMS إلى الوصول إلى المستلزمات الطبية من خلال مخزن مقيد بالوظيفة في المستشفى ومن خلال نظام تصنيع أو شراء. قم بتخزين مخزن المستشفى بالضمادات ومسكنات الألم والجبائر والحقن الوريدية وأكياس الدم وشحنات جهاز إزالة الرجفان. كل إجراء علاج يستهلك العنصر المقابل، مما يخلق طلبًا مستمرًا على إعادة التوريد. تتبع استخدام الإمدادات في قاعدة البيانات لمراقبة أنماط الاستهلاك وإعادة تخزين مخازن المستشفى تلقائيًا بفواصل زمنية قابلة للتكوين. فكر في جعل بعض الإمدادات قابلة للتصنيع من قبل اللاعبين الذين لديهم دور الصيدلي أو الطبيب، مما يخلق فرص لعب أدوار إضافية وروابط اقتصادية بين الوظائف المختلفة على الخادم.
التسجيل ومراقبة الأداء
سجل كل تفاعل مع EMS للمراجعة الإدارية، بما في ذلك من تم علاجه، وما العلاجات التي تم تطبيقها، ومسعف الطوارئ المستجيب، والفاتورة الطبية النهائية. خزّن هذه السجلات في جدول قاعدة بيانات مخصص وأرسل ملخصات اختيارية إلى Discord webhook لمراقبة الطاقم في الوقت الحقيقي. تساعد هذه السجلات في حل النزاعات، وتحديد لاعبي EMS الذين لا يؤدون واجباتهم، وتتبع صحة النظام بشكل عام. من ناحية الأداء، اجعل منطق فحص الوفاة خفيف الوزن عن طريق تشغيله فقط على اللاعبين الذين انخفضت صحتهم إلى الصفر، وليس على كل لاعب في كل إطار. استخدم بنية معتمدة على الأحداث حيث يؤدي حالة الوفاة إلى تشغيل حدث خادم واحد بدلاً من الاستطلاع. يجب أن يقوم نظام إشعارات الإرسال بتجميع التنبيهات بدلاً من إرسال أحداث فردية لكل لاعب EMS، مما يقلل من الحمل الشبكي خلال سيناريوهات الكوارث الجماعية حيث يسقط عدة لاعبين في نفس الوقت.