العودة إلى المدونة
Tutorial9 دقيقة قراءة

نظام المستشفى والطوارئ في FiveM: برمجة وظائف طبية واقعية

تصميم مستشفى كامل ودورة EMS لـ FiveM. الإنعاش، تسجيل المرضى، الصيدلية، روابط الإسعاف وأفضل السكربتات الطبية للعب الأدوار.

Agency Scripts

المؤسس والمطور الرئيسي في Agency Scripts

هيكل نظام المستشفى

نظام مستشفى و EMS يحول كيفية تجربة اللاعبين للصحة والإصابات على خادم رول بلاي FiveM. بدلاً من إعادة الظهور ببساطة بعد السقوط، يدخل اللاعبون في خط أنابيب رول بلاي طبي حيث يمكن لـ EMS تثبيتهم في الميدان، نقلهم بسيارة إسعاف، تسجيلهم في المستشفى، تشخيصهم، علاجهم، وفوترتهم مقابل الخدمات. تنقسم بنية النظام إلى أربع طبقات مترابطة: نظام الإصابات الذي يتتبع ما حدث للاعب وأين على جسده، أدوات استدعاء EMS والاستجابة الميدانية، سير عمل تسجيل الدخول والعلاج في المستشفى، ونظام الفوترة الذي يربط الرعاية الطبية باقتصاد الخادم. تتواصل كل طبقة من خلال أحداث الخادم بحيث يمكن للطبيب المعالج رؤية الإصابات التي وثقها مستجيب EMS أثناء الفرز الميداني. بناء هذا كنظام موحد بدلاً من سكريبتات منفصلة يضمن تدفق بيانات المرضى بسلاسة من لحظة اتصال شخص ما بـ 911 إلى لحظة خروجه من المستشفى مع فاتورة في يده.

نظام نوع الإصابة

نظام إصابات مفصل يستبدل حالة الحياة أو الموت الثنائية بطيف من الحالات التي تتطلب علاجات مختلفة. تتبع الإصابات حسب منطقة الجسم، الشدة، والسبب حتى يتمكن EMS والأطباء من تمثيل سيناريوهات طبية واقعية. عند تلقي اللاعب ضررًا، حدد نوع الإصابة بناءً على السلاح أو رمز سبب الوفاة وطبقها على منطقة الجسم المناسبة. جروح الطلقات النارية في الجذع أكثر خطورة من لكمة في الذراع، ولكل نوع إصابة متطلبات علاج محددة يجب على الأطباء اتباعها:

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 والاستجابة الميدانية

يربط نظام إرسال EMS اللاعبين المصابين بالمستجيبين الطبيين المناوبين. عندما يدخل اللاعب حالة الإصابة، يمكنه اختيار الاتصال بـ 911 مما ينشئ تنبيه إرسال مرئي لجميع أفراد EMS المناوبين. يتضمن التنبيه إحداثيات GPS للمتصل، وصفًا موجزًا مولدًا من بيانات إصابته، ومستوى أولوية بناءً على شدة الإصابة. يمكن لمستجيبي EMS قبول المكالمة عبر واجهة إرسال، مما يعلّم المكالمة كمطالبة ويوفر توجيه GPS للمريض. نفذ مؤقت استجابة يتتبع مدة كل مكالمة من الإنشاء حتى الاتصال بالمريض، مفيد لتتبع أداء EMS وضبط متطلبات التوظيف. العلاج الميداني هو نسخة مبسطة من العلاج في المستشفى حيث يمكن لـ EMS تثبيت المرضى باستخدام مستلزمات أساسية مثل الضمادات، الأربطة، وحقن الأدرينالين لمنع الوفاة أثناء النقل:

-- 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)

واجهة تسجيل الدخول والعلاج في المستشفى

نظام تسجيل الدخول بالمستشفى يدير تدفق المرضى من الوصول إلى الخروج. عندما يحضر مستجيب EMS مريضًا إلى المستشفى أو يدخل لاعب بمفرده، يتفاعلون مع NPC مكتب استقبال أو نقطة هدف لتسجيل الدخول. عملية التسجيل تنشئ سجل مريض يتضمن إصاباتهم الحالية، العلامات الحيوية، ومعرف زيارة فريد لأغراض الفوترة. الأطباء المناوبون يرون المرضى القادمين على لوحة إدارة المستشفى NUI التي تعرض قائمة الانتظار، أولوية الفرز لكل مريض، وإصاباتهم الموثقة. عند اختيار الطبيب لمريض، تفتح واجهة العلاج التي تعرض مخطط جسم المريض مع مواقع الإصابات المميزة. ينقر الطبيب على كل إصابة لرؤية خطوات العلاج المطلوبة ويمكنه تنفيذ كل خطوة بالتسلسل، مما يطلق الرسوم المتحركة ويستهلك عناصر الإمدادات الطبية من جردهم. كل خطوة علاج لها شريط تقدم وفحص نجاح يعتمد على بيانات مهارة الطبيب، مضيفًا عنصر تقدم إلى تمثيل الدور الطبي.

سير العمل للعلاج

تصميم سير عمل العلاج كعملية خطوة بخطوة حيث يتطلب كل إصابة إجراءات محددة تُنفذ بالترتيب. قد تتطلب جرح طلقة في الجذع تنظيف الجرح، استخراج الرصاصة بالملاقط، خياطة الجرح بمجموعة خياطة، وتطبيق ضمادة. تستهلك كل خطوة العنصر المناسب من جرد الطبيب وتعرض حركة علاج. تخطي الخطوات أو تنفيذها بترتيب خاطئ يجب أن يفشل أو يقلل الفعالية، مما يشجع على لعب الأدوار الطبية بشكل صحيح. بعد علاج جميع الإصابات، يدخل المريض فترة تعافي حيث تتجدد صحته تدريجياً مع الوقت بدلاً من استعادتها فوراً:

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)

نظام العمل أثناء الخدمة وخارج الخدمة

نظام الخدمة يتحكم في متى يكون موظفو EMS والمستشفى نشطين ومؤهلين لتلقي مكالمات الإرسال. عندما يقوم لاعب بوظيفة الإسعاف بتسجيل الدخول في نقطة خدمة داخل المستشفى، يحصل على وصول إلى أوامر طبية، يتلقى إشعارات الإرسال، ويظهر في قائمة EMS النشطة المرئية للموظفين الآخرين. يجب أن يتتبع نظام الخدمة أوقات الدخول والخروج لحساب الرواتب إذا كان خادمك يستخدم مدفوعات الرواتب التلقائية. نفذ أدوار خدمة مختلفة داخل وظيفة EMS، مثل المسعف، الطبيب، والجراح، حيث يمتلك كل دور وصولًا إلى قدرات علاج مختلفة. يمكن للمسعف إجراء التثبيت الميداني والعلاجات الأساسية، يمكن للطبيب التعامل مع الإجراءات المستشفى القياسية، ويمكن للجراح إجراء عمليات معقدة مثل استخراج الرصاص وتثبيت العظام. خزّن قائمة الخدمة في حالة خادم مشتركة حتى يتمكن نظام الإرسال من حساب المستجيبين المتاحين بدقة وتعديل مؤقت الإحياء التلقائي للاعبين المصابين بناءً على توفر EMS.

نظام الفوترة الطبية

تربط الفوترة الطبية نظام المستشفى باقتصاد الخادم وتخلق عواقب مالية للسلوكيات الخطرة. عند علاج المريض، يولد النظام فاتورة مفصلة تسرد كل علاج تم، والإمدادات المستخدمة، وأي رسوم منشأة. يمكن دفع الفواتير عند الخروج من خلال مكتب الاستقبال، أو تحميلها مباشرة على حساب المريض البنكي، أو إرسالها كفاتورة يجب على المريض دفعها ضمن إطار زمني محدد. نفذ نظام تأمين طبي حيث يمكن للاعبين شراء بوليصات تأمين تغطي نسبة من تكاليفهم الطبية، مما يقلل من العبء المالي للزيارات المتكررة للمستشفى. يمكن أن تكون أقساط التأمين رسومًا متكررة تضيف إلى محاكاة الاقتصاد في الخادم. بالنسبة للاعبين الذين لا يستطيعون الدفع، نفذ نظام ديون طبية حيث تتراكم الفواتير غير المدفوعة بفوائد وفي النهاية تؤدي إلى عواقب مثل حجز الأجور من رواتب الوظائف أو تقييد الوصول إلى خدمات معينة حتى يتم تسوية الدين. خزّن جميع سجلات الفواتير لمراجعة الإدارة واربطها بنظام تسجيل المعاملات حتى يمكن تدقيق تدفق الأموال من المريض إلى المستشفى.

مركبة الإسعاف والمعدات

يجب أن تكون سيارة الإسعاف أكثر من مجرد سيارة سريعة مع صفارة إنذار. نفذ ميزات خاصة بالمركبة تجعل سيارة الإسعاف محطة علاج متنقلة. عندما يفتح مستجيب EMS أبواب الخلفية لسيارة الإسعاف من خلال تفاعل المركبة، يصل إلى قائمة علاج متنقلة تحتوي على مجموعة فرعية من قدرات المستشفى مثل تضميد الجروح، إعطاء مسكنات الألم، تطبيق الجبائر، واستخدام جهاز إزالة الرجفان. خزّن المستلزمات الطبية في مخزون صندوق سيارة الإسعاف بحيث يحتاج المستجيبون إلى إعادة التزود في المستشفى بين المكالمات. جهاز إزالة الرجفان هو عنصر خاص يمكنه إحياء اللاعبين الذين دخلوا حالة الموت، لكنه يجب أن يتطلب لعبة صغيرة مع مدخلات توقيت لمحاكاة تقنية الإنعاش القلبي الرئوي الصحيحة. نفذ نظام نقالة حيث يمكن لـ EMS وضع لاعب مصاب على نقالة متصلة بسيارة الإسعاف، مما يقفل المريض في حركة استلقاء داخل المركبة أثناء النقل. استخدم AttachEntityToEntity للتعامل مع وضع الحمالة و SetPedIntoVehicle لتحميل المرضى.

الدمج وجودة الحياة

نظام المستشفى الخاص بك يجب أن يندمج مع موارد الهاتف في الخادم حتى يتمكن اللاعبون من الاتصال برقم 911 مباشرة من تطبيق الهاتف، عرض تاريخهم الطبي والفواتير المستحقة، والتحقق من أوقات انتظار EMS قبل اتخاذ قرار طلب المساعدة أو العلاج الذاتي باستخدام عناصر أساسية من الصيدلية. اربط نظام الإصابات بعقوبات الحركة بحيث تقلل إصابات الساق من سرعة الحركة وتؤثر إصابات الذراع على دقة التصويب، مما يخلق عواقب ملموسة في اللعب تحفز اللاعبين على طلب العلاج بدلاً من تجاهل إصاباتهم. نفذ نظام سجلات طبية يمكن الوصول إليه عبر MDT الخاص بالمستشفى حيث يمكن للأطباء عرض تاريخ العلاج الكامل للمريض، والحساسيات التي سجلها أطباء آخرون، والأدوية الحالية. صدّر وظائف الإصابات والعلاج بحيث يمكن لموارد أخرى مثل تأثيرات المخدرات، التسمم الغذائي، أو المخاطر البيئية أن تغذي نفس خط الأنابيب الطبي. أضف نظام إعادة إحياء تلقائي مع مؤقت قابل للتكوين ينشط عندما لا يكون هناك EMS في الخدمة، مما يضمن ألا يبقى اللاعبون في حالة الإغماء إلى أجل غير مسمى مع إعطاء الأولوية للعب الدور الطبي الذي يقوده اللاعبون عندما يكون الطاقم متاحًا.

جاهز للبدء؟

احصل على السكربتات من متجرنا، أو انضم إلى Discord للدعم والتحديثات ونظرة على ما هو قادم.