Volver al blog
Tutorial11 min de lectura

Sistema hospitalario y de emergencias para FiveM: trabajos médicos realistas

Crea un sistema médico completo para FiveM con reanimaciones, registro de pacientes, farmacia, ambulancias y scripts médicos para roleplay.

Agency Scripts

Fundador y desarrollador principal en Agency Scripts

Arquitectura del sistema hospitalario

Un sistema hospitalario y de EMS transforma la experiencia de salud y lesiones de los jugadores en un servidor de roleplay de FiveM. En lugar de reaparecer sin más al caer, los jugadores siguen un proceso médico de roleplay en el que EMS puede estabilizarlos en el lugar, transportarlos en ambulancia, ingresarlos en el hospital, diagnosticarlos, tratarlos y cobrarles por los servicios. La arquitectura del sistema se divide en cuatro capas interconectadas: el sistema de lesiones, que registra qué le ocurrió al jugador y en qué parte del cuerpo; las herramientas de despacho y respuesta de EMS; el flujo de ingreso y tratamiento del hospital; y el sistema de facturación que conecta la atención médica con la economía del servidor. Cada capa se comunica mediante eventos del servidor para que el médico que atiende a un paciente pueda ver exactamente qué lesiones documentó el personal de EMS durante la evaluación inicial en el lugar. Crear un sistema unificado en vez de scripts independientes garantiza que los datos del paciente fluyan sin interrupciones desde el momento en que alguien llama al 911 hasta que sale del hospital con una factura en la mano.

Sistema de tipos de lesiones

Un sistema detallado de lesiones reemplaza el estado binario de vivo o muerto por un conjunto de condiciones que requieren distintos tratamientos. Registra las lesiones por región del cuerpo, gravedad y causa para que EMS y los médicos puedan interpretar escenarios médicos realistas. Cuando un jugador recibe daño, determina el tipo de lesión según el hash del arma o de la causa de muerte y aplícalo a la región del cuerpo correspondiente. Las heridas de bala en el torso son más graves que un puñetazo en el brazo, y cada tipo de lesión tiene requisitos de tratamiento específicos que los médicos deben seguir:

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,
}

Despacho de EMS y respuesta en el lugar

El sistema de despacho de EMS conecta a los jugadores caídos con el personal médico de servicio. Cuando un jugador queda incapacitado, puede llamar al 911, lo que crea una alerta de despacho visible para todo el personal de EMS de servicio. La alerta incluye las coordenadas GPS de quien llama, una breve descripción generada a partir de los datos de sus lesiones y un nivel de prioridad según la gravedad. El personal de EMS puede aceptar la llamada mediante una interfaz de despacho, que marca la llamada como asignada y proporciona navegación GPS hasta el paciente. Implementa un temporizador de respuesta que registre cuánto tarda cada llamada desde su creación hasta el contacto con el paciente, útil para evaluar el desempeño de EMS y ajustar las necesidades de personal. El tratamiento en el lugar es una versión simplificada del tratamiento hospitalario, donde EMS puede estabilizar a los pacientes con suministros básicos, como vendas, torniquetes e inyecciones de adrenalina, para evitar que mueran durante el traslado:

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

Ingreso y tratamiento en la interfaz del hospital

El sistema de ingreso del hospital gestiona el flujo de pacientes desde su llegada hasta el alta. Cuando el personal de EMS lleva a un paciente al hospital o un jugador acude por su cuenta, interactúa con un NPC de recepción o un punto de interacción para registrarse. El proceso de ingreso crea un registro del paciente que incluye sus lesiones actuales, signos vitales y un ID de visita único para la facturación. Los médicos de servicio ven a los pacientes que llegan en un panel NUI de gestión hospitalaria que muestra la cola de espera, la prioridad de triaje de cada paciente y las lesiones documentadas. Cuando un médico selecciona a un paciente, se abre la interfaz de tratamiento y muestra un diagrama corporal con las zonas lesionadas resaltadas. El médico hace clic en cada lesión para ver los pasos de tratamiento necesarios y puede realizarlos en orden, activando animaciones y consumiendo suministros médicos del inventario. Cada paso de tratamiento tiene una barra de progreso y una comprobación de éxito que depende de los metadatos de habilidad del médico, lo que añade una mecánica de progresión al roleplay médico.

Flujo de tratamiento

Diseña el flujo de tratamiento como un proceso paso a paso en el que cada lesión requiera acciones específicas realizadas en orden. Una herida de bala en el torso podría requerir limpiar la herida, extraer la bala con pinzas, suturar la herida con un kit de sutura y aplicar una venda. Cada paso consume el objeto correspondiente del inventario del médico y reproduce una animación de tratamiento. Saltarse pasos o realizarlos fuera de orden debería provocar un fallo o reducir la eficacia, fomentando un roleplay médico adecuado. Una vez tratadas todas las lesiones, el paciente entra en un período de recuperación en el que su salud se regenera gradualmente en lugar de restaurarse al instante:

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)

Sistema de servicio y fuera de servicio

El sistema de servicio controla cuándo el personal de EMS y del hospital está activo y puede recibir llamadas de despacho. Cuando un jugador con el trabajo de ambulancia ficha en un punto de servicio dentro del hospital, obtiene acceso a comandos médicos, recibe notificaciones de despacho y aparece en la lista de EMS activos, visible para el resto del personal. Si tu servidor usa pagos automáticos de salario, el sistema debe registrar las horas de entrada y salida para calcular la nómina. Implementa distintos rangos dentro del trabajo de EMS, como paramédico, médico y cirujano, cada uno con acceso a diferentes capacidades de tratamiento. Un paramédico puede estabilizar a pacientes en el lugar y realizar tratamientos básicos, un médico puede encargarse de los procedimientos hospitalarios habituales y un cirujano puede realizar operaciones complejas, como extraer balas y colocar huesos. Guarda la lista del personal de servicio en un estado compartido del servidor para que el sistema de despacho pueda contar con precisión cuántos profesionales están disponibles y ajustar el temporizador de reaparición automática de los jugadores abatidos según la disponibilidad de EMS.

Sistema de facturación médica

La facturación médica conecta el sistema hospitalario con la economía del servidor y hace que las conductas arriesgadas tengan consecuencias económicas. Cuando se trata a un paciente, el sistema genera una factura desglosada que indica cada tratamiento realizado, los suministros utilizados y las tarifas de las instalaciones. Las facturas se pueden pagar al salir, en recepción, cobrar directamente de la cuenta bancaria del paciente o enviar como una factura que el paciente debe pagar dentro de un plazo determinado. Implementa un sistema de seguro médico para que los jugadores puedan contratar pólizas que cubran un porcentaje de sus gastos médicos y reduzcan el impacto económico de las visitas frecuentes al hospital. Las primas del seguro pueden ser un cargo recurrente que contribuya a la simulación económica del servidor. Para los jugadores que no puedan pagar, implementa un sistema de deuda médica en el que las facturas impagadas acumulen intereses y acaben generando consecuencias, como embargos de parte del sueldo recibido por su trabajo o acceso restringido a ciertos servicios hasta que salden la deuda. Guarda todos los registros de facturación para que los administradores puedan revisarlos y conéctalos al sistema de registro de transacciones para poder auditar el flujo de dinero del paciente al hospital.

Vehículo de ambulancia y equipo

La ambulancia debe ser mucho más que un coche rápido con sirena. Implementa funciones específicas del vehículo que lo conviertan en una unidad móvil de tratamiento. Cuando un profesional de EMS abra las puertas traseras de la ambulancia mediante una interacción con el vehículo, podrá acceder a un menú de tratamiento móvil con algunas de las funciones del hospital, como vendar, administrar analgésicos, colocar férulas y usar un desfibrilador. Guarda los suministros médicos en el inventario del maletero de la ambulancia para que el personal tenga que reabastecerse en el hospital entre llamadas. El desfibrilador es un objeto especial que puede reanimar a jugadores que hayan entrado en estado de muerte, pero su uso debe requerir un minijuego con pulsaciones sincronizadas para simular una técnica de RCP adecuada. Implementa un sistema de camillas para que EMS pueda colocar a un jugador abatido en una camilla acoplada a la ambulancia, que mantenga al paciente en una animación tumbada dentro del vehículo durante el traslado. Usa AttachEntityToEntity para gestionar la colocación de la camilla y SetPedIntoVehicle para cargar al paciente.

Integración y mejoras de calidad de vida

El sistema hospitalario debe integrarse con el recurso de teléfono del servidor para que los jugadores puedan llamar al 911 directamente desde la aplicación del teléfono, consultar su historial médico y las facturas pendientes, y comprobar los tiempos de espera de EMS antes de decidir si llaman para pedir ayuda o se tratan por su cuenta con productos básicos de una farmacia. Conecta el sistema de lesiones con las penalizaciones de movimiento para que las lesiones en las piernas reduzcan la velocidad de movimiento y las lesiones en los brazos afecten a la precisión al apuntar. Así, las consecuencias del juego serán tangibles y motivarán a los jugadores a buscar tratamiento en lugar de ignorar sus lesiones. Implementa un sistema de historiales médicos accesible desde el MDT del hospital, donde los médicos puedan consultar el historial completo de tratamientos de un paciente, las alergias anotadas por otros médicos y sus medicamentos actuales. Exporta tus funciones de lesiones y tratamientos para que otros recursos, como los efectos de las drogas, las intoxicaciones alimentarias o los peligros ambientales, puedan integrarse en el mismo flujo de atención médica. Añade un sistema de reaparición automática con un temporizador configurable que se active cuando no haya EMS de servicio. Así, los jugadores nunca se quedarán abatidos indefinidamente y, al mismo tiempo, se dará prioridad al roleplay médico entre jugadores cuando haya personal disponible.

El script adecuado

Listo para tu servidor, con actualizaciones incluidas.

¿Listo para empezar?

Consigue los scripts en nuestra tienda, o únete al Discord para soporte, novedades y un adelanto de lo que viene.