Volver al blog
Tutorial12 min de lectura

Sistema de mecánicos para FiveM: mejoras, reparaciones y trabajos con vehículos

Crea un sistema completo de mecánicos para FiveM, con reparaciones, mejoras, remolques al depósito e interfaces para talleres. Para QBCore y ESX.

Agency Scripts

Fundador y desarrollador principal en Agency Scripts

Diseño de la arquitectura del trabajo de mecánico

Un sistema de trabajo de mecánico es una de las funciones más populares y gratificantes que puedes desarrollar para un servidor de roleplay de FiveM. A diferencia de los scripts de reparación simples que solo llaman a SetVehicleFixed() , un sistema de mecánico bien diseñado introduce toda una economía laboral con puestos especializados, inventarios de repuestos e interacciones entre jugadores que impulsan el roleplay. La arquitectura debe tener en cuenta varios talleres mecánicos repartidos por el mapa, cada uno potencialmente propiedad de distintos grupos de jugadores, con una jerarquía de rangos que determina quién puede realizar cada reparación. Como base, necesitas una configuración compartida que defina las ubicaciones de los talleres, los servicios disponibles en cada nivel, los precios de los repuestos y los rangos necesarios para desbloquear reparaciones avanzadas como los cambios de motor o las instalaciones de turbo. El sistema debe integrarse con el framework de trabajos existente en tu servidor, ya sea QBCore, ESX o una solución personalizada, para que los jugadores puedan fichar al entrar y salir del trabajo de mecánico, con la gestión correcta de los sueldos y el seguimiento del estado de servicio.

Rangos y sistema de permisos

Un sistema de rangos por niveles le da profundidad al trabajo de mecánico y anima a los jugadores a ascender. Empieza definiendo rangos claros con permisos específicos: un aprendiz quizá solo pueda lavar vehículos y reparar daños menores en la carrocería; un mecánico estándar puede encargarse de reparaciones de motor y cambios de neumáticos; un mecánico sénior desbloquea la puesta a punto de rendimiento y la pintura con aerosol; y el propietario del taller puede gestionar empleados y fijar los precios de los servicios. Guarda estas definiciones de rangos en una configuración compartida para que tanto el cliente como el servidor puedan consultarlas de forma coherente. Este es un ejemplo de configuración que asigna los servicios permitidos a cada rango:

Config.MechanicGrades = {
    [0] = {
        label = 'Trainee',
        services = {'wash', 'body_minor'},
        payMultiplier = 0.7
    },
    [1] = {
        label = 'Mechanic',
        services = {'wash', 'body_minor', 'body_major', 'engine_repair', 'tire_replace', 'brake_repair'},
        payMultiplier = 1.0
    },
    [2] = {
        label = 'Senior Mechanic',
        services = {'wash', 'body_minor', 'body_major', 'engine_repair', 'tire_replace',
                    'brake_repair', 'spray_paint', 'performance_tune', 'turbo_install'},
        payMultiplier = 1.3
    },
    [3] = {
        label = 'Shop Owner',
        services = 'all',
        payMultiplier = 1.5,
        canManage = true
    }
}

Config.ServicePrices = {
    wash = 200,
    body_minor = 800,
    body_major = 2500,
    engine_repair = 3500,
    tire_replace = 1200,
    brake_repair = 1500,
    spray_paint = 5000,
    performance_tune = 15000,
    turbo_install = 25000
}

En el lado del servidor, valida siempre el rango del jugador antes de permitir que se ejecute un servicio. Nunca confíes en que el cliente indique qué servicios están disponibles, porque un tramposo podría modificar la NUI para enviar cualquier solicitud de servicio. La función callback del servidor debe comprobar el trabajo actual del jugador, su rango y si el servicio solicitado está en la lista de servicios de su rango antes de continuar con la reparación.

Mecánicas de reparación de vehículos y sistema de repuestos

Las mecánicas de reparación realistas van más allá de una sola llamada nativa. En lugar de reparar un vehículo al instante, divide el proceso en pasos que lleven tiempo y consuman repuestos del inventario del mecánico. Cuando un jugador lleva su coche para una reparación de motor, el mecánico debe tener los repuestos adecuados en su inventario personal o en el almacén compartido del taller. Usa un sistema de barra de progreso para simular el tiempo que lleva la reparación, lo que crea momentos naturales de roleplay en los que el cliente espera e interactúa con el mecánico. La lógica de reparación debe apuntar a componentes específicos del vehículo mediante funciones nativas, para que puedas reparar el motor sin reparar los daños de la carrocería, o cambiar los neumáticos sin afectar el estado del motor:

local RepairFunctions = {
    engine_repair = function(vehicle)
        local parts = {'engine_oil', 'spark_plugs', 'coolant'}
        if not HasRequiredParts(parts) then
            return false, 'Missing required parts'
        end

        RemovePartsFromInventory(parts)

        -- Animate the repair
        TaskTurnPedToFaceEntity(PlayerPedId(), vehicle, 1000)
        Wait(1000)

        if not StartProgressBar('Repairing engine...', 15000, 'mechanic_repair') then
            return false, 'Repair cancelled'
        end

        SetVehicleEngineHealth(vehicle, 1000.0)
        SetVehicleEngineOn(vehicle, true, true, false)
        return true
    end,

    body_major = function(vehicle)
        local parts = {'body_panel', 'filler_putty', 'paint_primer'}
        if not HasRequiredParts(parts) then
            return false, 'Missing required parts'
        end

        RemovePartsFromInventory(parts)

        if not StartProgressBar('Repairing body damage...', 20000, 'mechanic_repair') then
            return false, 'Repair cancelled'
        end

        SetVehicleBodyHealth(vehicle, 1000.0)
        SetVehicleDeformationFixed(vehicle)
        return true
    end,

    tire_replace = function(vehicle, tireIndex)
        local parts = {'tire_set'}
        if not HasRequiredParts(parts) then
            return false, 'Missing required parts'
        end

        RemovePartsFromInventory(parts)

        if not StartProgressBar('Replacing tire...', 8000, 'mechanic_repair') then
            return false, 'Repair cancelled'
        end

        SetVehicleTyreFixed(vehicle, tireIndex)
        return true
    end
}

El sistema de repuestos añade otra capa económica a tu servidor. Almacena repuestos de mayoristas NPC o permite que los jugadores los fabriquen en ubicaciones industriales. Los talleres mecánicos pueden comprar repuestos al por mayor a precios mayoristas y guardarlos en un inventario compartido del taller, lo que significa que el propietario debe gestionar la cadena de suministro para mantener el negocio en marcha. Esta dinámica de oferta y demanda añade mucha profundidad a la experiencia de roleplay.

Pintura con aerosol y servicios estéticos

La pintura con aerosol es uno de los servicios visualmente más satisfactorios que puede ofrecer un taller mecánico, y para implementarla bien hay que trabajar con varias funciones nativas de colores de vehículos. FiveM ofrece funciones nativas para el color principal, el secundario, el perlado, el de las ruedas y valores RGB personalizados. Crea una interfaz para elegir colores que permita al mecánico seleccionar colores predefinidos o introducir valores RGB personalizados a un precio superior. La NUI debe mostrar una vista previa en tiempo real aplicando temporalmente el color al vehículo mientras el mecánico explora las opciones. Así puedes gestionar la aplicación del color en el servidor después de que el mecánico confirme el trabajo de pintura y el cliente pague:

RegisterNetEvent('mechanic:server:applyPaint', function(netId, paintData, customerId)
    local src = source
    local Mechanic = QBCore.Functions.GetPlayer(src)
    local Customer = QBCore.Functions.GetPlayer(customerId)

    if not Mechanic or not Customer then return end
    if Mechanic.PlayerData.job.name ~= 'mechanic' then return end

    local gradeServices = Config.MechanicGrades[Mechanic.PlayerData.job.grade.level].services
    if gradeServices ~= 'all' and not TableContains(gradeServices, 'spray_paint') then
        return TriggerClientEvent('QBCore:Notify', src, 'Not authorized', 'error')
    end

    local price = paintData.isCustomRGB and Config.ServicePrices.spray_paint * 1.5
        or Config.ServicePrices.spray_paint

    if Customer.Functions.RemoveMoney('cash', price, 'mechanic-paint') then
        local shopCut = math.floor(price * 0.6)
        local mechanicCut = price - shopCut
        Mechanic.Functions.AddMoney('cash', mechanicCut, 'mechanic-paint-commission')
        AddToShopFunds(Mechanic.PlayerData.job.grade.level >= 3 and src, shopCut)

        TriggerClientEvent('mechanic:client:applyPaint', customerId, netId, paintData)
        TriggerClientEvent('QBCore:Notify', src, 'Paint applied - earned $' .. mechanicCut, 'success')
        TriggerClientEvent('QBCore:Notify', customerId, 'Vehicle painted for $' .. price, 'success')
    else
        TriggerClientEvent('QBCore:Notify', src, 'Customer cannot afford this', 'error')
    end
end)

Además de la pintura básica, considera añadir la aplicación de liveries, la instalación de luces de neón y el tintado de ventanas como servicios estéticos separados. Cada servicio debe tener sus propios requisitos de repuestos y precio. Las luces de neón, por ejemplo, requieren kits de neón del inventario de repuestos y usan las SetVehicleNeonLightEnabled y SetVehicleNeonLightsColour funciones nativas para aplicar el efecto visual. El tintado de ventanas usa SetVehicleWindowTint con distintos niveles de tinte que podrían estar restringidos por las leyes locales del servidor, dando a la policía un motivo para detener a los jugadores que lleven tintados ilegales.

Mejoras de rendimiento y puesta a punto

La puesta a punto de rendimiento es donde los mecánicos pueden destacar y ganar mucho dinero en el servidor. FiveM ofrece numerosas funciones nativas para modificar vehículos mediante la función SetVehicleMod , que acepta un tipo de modificación y un índice de modificación. Los tipos de modificación incluyen mejoras de motor (tipo 11), frenos (tipo 12), transmisión (tipo 13), suspensión (tipo 15), blindaje (tipo 16) y turbo (tipo 18). Cada tipo de modificación tiene varios niveles que mejoran progresivamente el rendimiento del vehículo. Crea una interfaz de puesta a punto que muestre las mejoras disponibles para el vehículo actual, el coste de cada nivel y, de ser posible, una comparación de estadísticas con los valores de velocidad, aceleración, frenado y manejo antes y después:

function GetAvailableUpgrades(vehicle)
    local upgrades = {}
    local modTypes = {
        {type = 11, label = 'Engine', icon = 'fa-engine'},
        {type = 12, label = 'Brakes', icon = 'fa-brake'},
        {type = 13, label = 'Transmission', icon = 'fa-gears'},
        {type = 15, label = 'Suspension', icon = 'fa-car'},
        {type = 16, label = 'Armor', icon = 'fa-shield'},
        {type = 18, label = 'Turbo', icon = 'fa-bolt'}
    }

    SetVehicleModKit(vehicle, 0)

    for _, mod in ipairs(modTypes) do
        local currentLevel = GetVehicleMod(vehicle, mod.type)
        local maxLevel = GetNumVehicleMods(vehicle, mod.type)
        local isTurbo = mod.type == 18

        table.insert(upgrades, {
            type = mod.type,
            label = mod.label,
            icon = mod.icon,
            currentLevel = currentLevel,
            maxLevel = isTurbo and 1 or maxLevel,
            installed = isTurbo and IsToggleModOn(vehicle, mod.type) or currentLevel >= 0,
            price = CalculateUpgradePrice(mod.type, currentLevel + 1)
        })
    end

    return upgrades
end

function ApplyPerformanceUpgrade(vehicle, modType, level)
    SetVehicleModKit(vehicle, 0)

    if modType == 18 then
        ToggleVehicleMod(vehicle, 18, true)
    else
        SetVehicleMod(vehicle, modType, level, false)
    end
end

Las mejoras de rendimiento deben requerir repuestos de alto valor, como kits de turbo, transmisiones de competición o conjuntos de frenos deportivos. Estos repuestos pueden obtenerse de proveedores especializados o ser fabricados por jugadores con las habilidades adecuadas, creando dependencias entre trabajos que enriquecen la economía del servidor. Valida siempre las solicitudes de mejora en el servidor para evitar que los clientes apliquen modificaciones que no hayan pagado o para las que no tengan los repuestos necesarios.

Sistema de facturación y reparto de ingresos

Un sistema de facturación bien diseñado integra toda la experiencia del mecánico y gestiona las transacciones financieras entre el mecánico, el cliente y el taller. Cuando un mecánico completa un servicio, genera una factura detallada que enumere cada servicio realizado y su coste. Muestra la factura al cliente mediante una notificación o una ventana emergente de la NUI, que debe aceptar antes de que se procese el pago. Reparte los ingresos entre el mecánico que realizó el trabajo y la cuenta de empresa del taller, con una proporción configurable por el propietario. Este es un sistema de facturación en el servidor que gestiona la creación de facturas y el procesamiento de pagos:

local activeInvoices = {}

RegisterNetEvent('mechanic:server:createInvoice', function(customerId, services)
    local src = source
    local Mechanic = QBCore.Functions.GetPlayer(src)
    local Customer = QBCore.Functions.GetPlayer(customerId)

    if not Mechanic or not Customer then return end
    if Mechanic.PlayerData.job.name ~= 'mechanic' then return end

    local totalPrice = 0
    local lineItems = {}

    for _, service in ipairs(services) do
        local price = Config.ServicePrices[service.name]
        if price then
            totalPrice = totalPrice + price
            table.insert(lineItems, {
                name = service.label,
                price = price
            })
        end
    end

    local invoiceId = 'INV-' .. os.time() .. '-' .. math.random(1000, 9999)
    activeInvoices[invoiceId] = {
        mechanic = src,
        customer = customerId,
        total = totalPrice,
        items = lineItems,
        shopId = Mechanic.PlayerData.metadata.currentShop,
        timestamp = os.time()
    }

    TriggerClientEvent('mechanic:client:showInvoice', customerId, invoiceId, lineItems, totalPrice)
end)

RegisterNetEvent('mechanic:server:payInvoice', function(invoiceId)
    local src = source
    local invoice = activeInvoices[invoiceId]
    if not invoice or invoice.customer ~= src then return end

    local Customer = QBCore.Functions.GetPlayer(src)
    local Mechanic = QBCore.Functions.GetPlayer(invoice.mechanic)

    if Customer.Functions.RemoveMoney('cash', invoice.total, 'mechanic-invoice') then
        local mechanicShare = math.floor(invoice.total * 0.4)
        local shopShare = invoice.total - mechanicShare

        if Mechanic then
            Mechanic.Functions.AddMoney('cash', mechanicShare, 'mechanic-wage')
            TriggerClientEvent('QBCore:Notify', invoice.mechanic,
                'Received $' .. mechanicShare .. ' for services', 'success')
        end

        UpdateShopBalance(invoice.shopId, shopShare)
        activeInvoices[invoiceId] = nil

        TriggerClientEvent('QBCore:Notify', src, 'Paid $' .. invoice.total, 'success')
    else
        TriggerClientEvent('QBCore:Notify', src, 'Not enough cash', 'error')
    end
end)

Considera admitir varios métodos de pago, incluidos efectivo, transferencias bancarias e incluso criptomonedas si tu servidor tiene un sistema de criptomonedas. Registra todas las transacciones en una base de datos para que los propietarios puedan consultar el historial de ingresos, identificar a sus mecánicos con mejor rendimiento y detectar patrones de facturación sospechosos. Este seguimiento financiero también permite crear sistemas de impuestos e interacciones de roleplay con el gobierno, en las que el estado puede auditar los talleres mecánicos.

Gestión del almacén y del inventario del taller

Todos los talleres mecánicos necesitan un almacén compartido donde se guarden los repuestos y al que puedan acceder todos los empleados de servicio. Intégralo con el sistema de inventario del servidor, ya sea ox_inventory, qb-inventory o una solución personalizada, para crear un almacén exclusivo del taller al que solo puedan acceder los mecánicos autorizados. El propietario del taller debe poder pedir repuestos a un NPC proveedor mayorista; el dinero se descuenta de la cuenta de empresa del taller y los repuestos se añaden al almacén tras un plazo de entrega configurable. Este plazo simula la logística real de la cadena de suministro y evita que se reponga el inventario al instante. Registra el acceso al almacén para que el propietario pueda ver qué mecánicos retiraron qué repuestos y prevenir robos internos. En el lado del cliente, usa una interacción de target con un objeto específico dentro del taller, como un armario de herramientas o una estantería de repuestos, para abrir el almacén. Combina el almacén con un sistema de fabricación en el que los mecánicos puedan ensamblar piezas complejas a partir de materias primas, como combinar una carcasa de turbo, un impulsor y una válvula de descarga para crear un kit de turbo completo, añadiendo otra capa basada en habilidades al trabajo.

Grúa y asistencia en carretera

Ampliar el trabajo de mecánico para incluir servicios de grúa y asistencia en carretera aumenta mucho la actividad y el potencial de ingresos del trabajo. Los mecánicos deben poder retirar una grúa del taller, conducir hasta la ubicación de un jugador varado, enganchar el vehículo averiado mediante la función nativa AttachEntityToEntity y remolcarlo hasta el taller para repararlo. Implementa un sistema de despacho en el que los jugadores puedan solicitar asistencia en carretera desde su teléfono, lo que crea un blip en el mapa visible para todos los mecánicos de servicio. El primer mecánico que acepte la llamada se queda con el trabajo y se traza una ruta GPS hasta la ubicación del cliente. Para el sistema de enganche, calcula las posiciones de desplazamiento adecuadas según el modelo de la grúa para que el vehículo remolcado quede bien colocado en la plataforma. Añade una tarifa por distancia al servicio de grúa para que los remolques más largos cuesten más al cliente, lo que incentiva a los mecánicos a atender llamadas en su zona sin impedirles aceptar trabajos lucrativos de larga distancia por todo el mapa.

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.