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 值班时激活,确保玩家不会无限期处于倒地状态,同时在有工作人员时优先考虑玩家驱动的医疗角色扮演。