返回博客
Tutorial3 分钟阅读

FiveM 医院与 EMS 系统:脚本真实医疗工作

为 FiveM 设计完整的医院和 EMS 循环。复活、患者登记、药房、救护车链接及最佳医疗角色扮演脚本。

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响应者可通过调度UI接听呼叫,标记呼叫为已接收,并提供前往患者的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)

医院登记和治疗UI

医院登记系统管理患者从到达至出院的流程。当 EMS 急救人员将患者送至医院或玩家自行前往时,他们与接待台 NPC 或目标点交互进行登记。登记过程创建患者记录,包含当前伤情、生命体征及用于计费的唯一访问 ID。值班医生在医院管理 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 获取支持、更新以及新功能预告。