Tutorial 2026-04-06

Criar um Sistema de Job de Mecânico para FiveM

TDYSKY

TDYSKY

Fundador & Lead Developer na Agency Scripts

Projetando a arquitetura do trabalho mecânico

Um sistema de trabalho mecânico é um dos recursos mais populares e gratificantes a serem desenvolvidos para um servidor de roleplay FiveM. Ao contrário de scripts de reparo simples que apenas chamam SetVehicleFixed(), um sistema mecânico adequado introduz uma economia de trabalho completa com funções especializadas, estoques de peças e interações entre jogadores que impulsionam a interpretação. A arquitetura precisa levar em conta diversas oficinas mecânicas espalhadas pelo mapa, cada uma potencialmente pertencente a diferentes grupos de jogadores, com uma hierarquia de níveis de trabalho que determina quem pode realizar quais reparos. Na base, você precisa de uma configuração compartilhada que defina os locais das oficinas, os serviços disponíveis em cada nível, os preços das peças e os níveis de trabalho necessários para desbloquear reparos avançados, como trocas de motores ou instalações de turbo. O sistema deve se integrar à estrutura de trabalho existente do seu servidor, seja QBCore, ESX ou uma solução personalizada, para que os jogadores entrem e saiam da função de mecânico com tratamento adequado de contracheque e rastreamento de status de serviço.

Notas de trabalho e sistema de permissão

Um sistema de classificação de trabalho escalonado dá profundidade ao seu trabalho mecânico e incentiva os jogadores a subir na hierarquia. Comece definindo notas claras com permissões específicas: um estagiário só pode ser capaz de lavar veículos e reparar pequenos danos corporais, um mecânico padrão pode cuidar de reparos de motores e substituições de pneus, um mecânico sênior desbloqueia ajustes de desempenho e pintura em spray, e o dono da oficina pode gerenciar funcionários e definir preços de serviços. Armazene essas definições de notas em uma configuração compartilhada para que o cliente e o servidor possam referenciá-las de forma consistente. Aqui está um exemplo de configuração que mapeia notas para seus serviços permitidos:

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
}

Do lado do servidor, sempre valide a nota do jogador antes de permitir a execução de qualquer serviço. Nunca confie no cliente para informar quais serviços estão disponíveis porque um trapaceiro pode modificar o NUI para enviar qualquer solicitação de serviço. O retorno de chamada do servidor deve verificar o trabalho atual do jogador, seu nível de classificação e se o serviço solicitado existe na lista de serviços de seu nível antes de prosseguir com o reparo.

Mecânica de reparação de veículos e sistema de peças

A mecânica de reparo realista vai além de uma única chamada nativa. Em vez de consertar um veículo instantaneamente, divida o processo de reparo em etapas que exigem tempo e consomem peças do estoque do mecânico. Quando um jogador traz seu carro para consertar o motor, o mecânico deve precisar ter as peças corretas em seu inventário pessoal ou no estoque compartilhado da oficina. Use um sistema de barra de progresso para simular o tempo de reparo, o que cria momentos naturais de roleplay onde o cliente espera e interage com o mecânico. A lógica de reparo deve ter como alvo componentes específicos do veículo usando funções nativas para que você possa reparar o motor sem reparar danos à carroceria ou substituir pneus sem afetar a saúde do 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
}

O sistema de peças cria uma camada adicional de economia em seu servidor. Estoque peças em atacadistas NPC ou deixe os jogadores fabricá-las em locais industriais. As oficinas mecânicas podem comprar peças a granel a preços de atacado e armazená-las em um estoque compartilhado, o que significa que o dono da loja precisa gerenciar sua cadeia de suprimentos para manter o bom funcionamento do negócio. Essa dinâmica de oferta e demanda acrescenta uma enorme profundidade à experiência de roleplay.

Pintura em spray e serviços cosméticos

A pintura em spray é um dos serviços visualmente mais satisfatórios que uma oficina mecânica pode oferecer, e implementá-la bem requer trabalhar com diversas funções nativas de cores de veículos. FiveM fornece nativos para cores primárias, cores secundárias, peroladas, cores de roda e valores RGB personalizados. Crie uma IU de seletor de cores que permita ao mecânico selecionar cores predefinidas ou inserir valores RGB personalizados por um preço premium. O NUI deve exibir uma visualização em tempo real aplicando temporariamente a cor ao veículo enquanto o mecânico navega pelas opções. Veja como lidar com a aplicação de cores no servidor depois que o mecânico confirmar a pintura e o cliente pagar:

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)

Além da pintura básica, considere adicionar aplicação de pintura, instalação de luz neon e pintura de janelas como serviços cosméticos separados. Cada serviço deve ter seus próprios requisitos de peças e faixa de preço. As luzes neon, por exemplo, exigem kits neon do estoque de peças e utilizam os nativos SetVehicleNeonLightEnabled e SetVehicleNeonLightsColour para aplicar o efeito visual. A coloração de janelas usa SetVehicleWindowTint com diferentes níveis de tonalidade que podem ser restringidos pelas leis do servidor local, dando à polícia um motivo para prender os jogadores por tonalidades ilegais.

Atualizações e ajustes de desempenho

O ajuste de desempenho é onde a mecânica pode realmente brilhar e ganhar muito dinheiro no servidor. FiveM fornece extensos nativos de modificação de veículos por meio da função SetVehicleMod, que aceita um tipo de mod e um índice de mod. Os tipos de mod cobrem atualizações de motor (tipo 11), freios (tipo 12), transmissão (tipo 13), suspensão (tipo 15), blindagem (tipo 16) e turbo (tipo 18). Cada tipo de mod possui vários níveis que melhoram progressivamente o desempenho do veículo. Crie uma interface de ajuste que mostre as atualizações disponíveis para o veículo atual, o custo de cada nível e, idealmente, uma comparação de estatísticas mostrando os valores antes e depois de velocidade, aceleração, frenagem e manuseio:

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

As atualizações de desempenho devem exigir peças de alto valor, como kits turbo, transmissões de corrida ou conjuntos de freios esportivos. Essas peças podem ser adquiridas de fornecedores especializados ou fabricadas por jogadores com as habilidades certas, criando dependências entre empregos que enriquecem a economia do servidor. Sempre valide as solicitações de atualização no servidor para evitar que os clientes apliquem modificações pelas quais não pagaram ou para as quais não possuem as peças.

Sistema de faturamento e participação nos lucros

Um sistema de faturamento limpo une toda a experiência mecânica e lida com as transações financeiras entre o mecânico, o cliente e a oficina. Quando um mecânico conclui um serviço, gere uma fatura detalhada que liste cada serviço realizado e seu custo. Apresente a fatura ao cliente por meio de uma notificação ou pop-up NUI que ele deve aceitar antes que o pagamento seja processado. Divida a receita entre o mecânico que executou a obra e a conta comercial da oficina, com proporção de divisão configurável pelo lojista. Aqui está um sistema de faturamento do lado do servidor que gerencia a criação de faturas e o processamento de pagamentos:

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)

Considere oferecer suporte a vários métodos de pagamento, incluindo dinheiro, transferências bancárias e até criptomoedas, se o seu servidor tiver um sistema criptográfico. Rastreie todas as transações em um registro de banco de dados para que os proprietários de lojas possam revisar seu histórico de receitas, identificar seus mecânicos de melhor desempenho e detectar quaisquer padrões de cobrança suspeitos. Esse acompanhamento financeiro também permite sistemas tributários e interações governamentais onde o estado pode auditar oficinas mecânicas.

Gerenciamento de estoque de estoque e loja

Toda oficina mecânica precisa de um estoque compartilhado onde as peças sejam armazenadas e acessíveis a todos os funcionários em serviço. Integre-se ao sistema de inventário do seu servidor, seja ox_inventory, qb-inventory ou uma solução personalizada, para criar um estoque específico da loja que somente mecânicos autorizados possam acessar. O dono da loja deve ter a capacidade de solicitar peças de um NPC fornecedor atacadista, que deduz o dinheiro da conta comercial da loja e adiciona as peças ao estoque após um atraso de entrega configurável. Este atraso simula a logística da cadeia de abastecimento do mundo real e evita o reabastecimento instantâneo. Rastreie o acesso ao estoque em um registro para que o dono da loja possa ver quais mecânicos levaram quais peças, evitando roubos internos. Do lado do cliente, use uma interação alvo em um objeto específico dentro da loja, como um armário de ferramentas ou uma prateleira de peças, para abrir o estoque. Combine o estoque com um sistema de artesanato onde os mecânicos podem montar peças complexas a partir de matérias-primas, como combinar uma carcaça de turbo, impulsor e válvula de descarga em um kit turbo completo, adicionando outra camada baseada em habilidade ao trabalho.

Caminhão de reboque e assistência rodoviária

Ampliar o trabalho de mecânico para incluir serviços de guincho e assistência rodoviária aumenta muito a atividade do trabalho e o potencial de receita. Os mecânicos devem ser capazes de retirar um caminhão de reboque de sua oficina, dirigir até o local de um jogador preso, prender o veículo quebrado usando o AttachEntityToEntity nativo e rebocá-lo de volta à oficina para reparos. Implemente um sistema de despacho onde os jogadores possam solicitar assistência rodoviária através de seus telefones, o que cria um ponto no mapa visível para todos os mecânicos em serviço. O primeiro mecânico a aceitar a chamada fica com o trabalho e uma rota GPS é traçada até a localização do cliente. Para o sistema de fixação, calcule as posições de deslocamento adequadas com base no modelo do caminhão de reboque para garantir que o veículo rebocado fique corretamente assentado na plataforma. Adicione uma taxa baseada na distância ao serviço de reboque para que reboques mais longos custem mais ao cliente, incentivando os mecânicos a atender chamadas em sua área e ainda permitindo que eles realizem trabalhos lucrativos de longa distância em todo o mapa.

Partilhar este artigo

Pronto para melhorar o teu servidor?

Explora os nossos scripts FiveM premium na loja Agency Scripts ou junta-te à nossa comunidade no Discord para suporte e atualizações.