Назад к блогу
Tutorial7 мин чтения

Система аренды автомобилей FiveM: Скриптинг временных транспортных средств

Добавьте арендованные транспортные средства на ваш сервер FiveM. Ключи с таймером, депозиты, логика автоматического возврата и лучшие скрипты аренды для QBCore, ESX и standalone.

Agency Scripts

Основатель и ведущий разработчик Agency Scripts

Почему системы аренды улучшают ролевую игру

Не каждый игрок на ролевом сервере владеет транспортом, особенно новые персонажи. Система аренды автомобилей и мотоциклов заполняет этот пробел, предоставляя временный транспорт по доступным ценам, создавая естественные ролевые ситуации у пунктов аренды и давая новичкам свободу исследовать карту без зависимости от общественного транспорта или пеших прогулок. Помимо базового транспорта, системы аренды поддерживают туристическую ролевую игру, где посетители арендуют кабриолеты для живописных поездок, доставочные задания с определёнными типами транспорта и сценарии событий, где игрокам нужны одинаковые машины для организованных заездов или гонок. Система также генерирует пассивный доход для экономики сервера через арендные платежи, залоги за повреждения и штрафы за поздний возврат.

Конфигурация флота и категории транспортных средств

Организуйте ваш автопарк аренды по категориям, которые соответствуют разным потребностям и бюджетам игроков. Экономичные автомобили обеспечивают доступный базовый транспорт, автомобили среднего класса предлагают больше комфорта и производительности, премиальные автомобили предназначены для роскошного опыта, а мотоциклы дают игрокам альтернативу на двух колёсах. Каждая категория должна иметь несколько вариантов транспортных средств с чёткими ценами. Включите почасовые и суточные тарифы аренды, чтобы игроки могли выбрать наиболее экономичный вариант. Определите автопарк в таблице конфигурации, которая указывает каждое доступное транспортное средство с ценой аренды, требуемым депозитом, категорией и моделью для спавна:

Config.RentalLocations = {
    ['airport'] = {
        label = 'LS Airport Car Rental',
        pedModel = 's_f_y_airhostess_01',
        pedCoords = vector4(-1037.34, -2736.82, 20.17, 238.52),
        spawnPoint = vector4(-1029.12, -2728.91, 20.17, 148.76),
        returnZone = vector3(-1035.00, -2730.00, 20.17),
        returnRadius = 10.0,
        categories = {'economy', 'midrange', 'premium', 'motorcycle'},
    },
    ['downtown'] = {
        label = 'Downtown Bike Rental',
        pedModel = 'a_m_y_business_02',
        pedCoords = vector4(-259.68, -892.41, 31.08, 69.24),
        spawnPoint = vector4(-264.30, -888.12, 31.08, 339.87),
        returnZone = vector3(-260.00, -890.00, 31.08),
        returnRadius = 8.0,
        categories = {'motorcycle', 'bicycle'},
    },
}

Config.RentalFleet = {
    economy = {
        {model = 'blista', label = 'Blista', priceHour = 150, priceDay = 800, deposit = 500},
        {model = 'asea', label = 'Asea', priceHour = 120, priceDay = 650, deposit = 400},
        {model = 'stanier', label = 'Stanier', priceHour = 130, priceDay = 700, deposit = 450},
    },
    midrange = {
        {model = 'schafter2', label = 'Schafter', priceHour = 300, priceDay = 1600, deposit = 1000},
        {model = 'oracle', label = 'Oracle', priceHour = 280, priceDay = 1500, deposit = 900},
    },
    premium = {
        {model = 'felon', label = 'Felon GT', priceHour = 600, priceDay = 3200, deposit = 2500},
        {model = 'exemplar', label = 'Exemplar', priceHour = 550, priceDay = 3000, deposit = 2000},
    },
    motorcycle = {
        {model = 'pcj', label = 'PCJ-600', priceHour = 100, priceDay = 500, deposit = 300},
        {model = 'sanchez', label = 'Sanchez', priceHour = 80, priceDay = 400, deposit = 250},
    },
    bicycle = {
        {model = 'cruiser', label = 'Cruiser Bike', priceHour = 30, priceDay = 150, deposit = 50},
        {model = 'tribike', label = 'Tri-Cycles Race', priceHour = 25, priceDay = 120, deposit = 50},
    },
}

Процесс аренды и интерфейс NUI

Взаимодействие с арендой начинается, когда игрок подходит к NPC за стойкой аренды. С помощью системы прицеливания или проверки близости открывается меню NUI с доступными категориями транспортных средств и опциями фильтрации. В каждом списке транспортных средств отображается название модели, изображение-превью при возможности, почасовая и суточная ставка, требуемый депозит и статус доступности. Когда игрок выбирает транспорт и подтверждает длительность аренды, сервер обрабатывает транзакцию. Общая сумма , это плата за аренду на выбранный срок плюс залог за повреждения. Залог удерживается системой и возвращается при возврате транспортного средства без повреждений. Подтверждение аренды реализуется как серверное событие, которое проверяет наличие у игрока достаточных средств, доступность выбранного транспорта, списывает деньги и спавнит арендованный транспорт в указанной точке:

RegisterNetEvent('rental:server:rentVehicle', function(locationId, vehicleModel, duration)
    local src = source
    local Player = QBCore.Functions.GetPlayer(src)
    if not Player then return end

    local location = Config.RentalLocations[locationId]
    if not location then return end

    -- Check if player already has an active rental
    if ActiveRentals[Player.PlayerData.citizenid] then
        TriggerClientEvent('QBCore:Notify', src, 'You already have an active rental', 'error')
        return
    end

    -- Find vehicle config
    local vehicleConfig = nil
    for _, category in pairs(Config.RentalFleet) do
        for _, v in ipairs(category) do
            if v.model == vehicleModel then
                vehicleConfig = v
                break
            end
        end
        if vehicleConfig then break end
    end

    if not vehicleConfig then return end

    -- Calculate cost
    local rentalFee = duration == 'day' and vehicleConfig.priceDay or vehicleConfig.priceHour
    local totalCost = rentalFee + vehicleConfig.deposit

    if Player.Functions.GetMoney('bank') < totalCost then
        TriggerClientEvent('QBCore:Notify', src, 'Insufficient funds. Need $' .. totalCost, 'error')
        return
    end

    -- Charge player
    Player.Functions.RemoveMoney('bank', totalCost, 'vehicle-rental')

    -- Generate rental plate
    local plate = 'RNT' .. math.random(10000, 99999)

    -- Store active rental
    ActiveRentals[Player.PlayerData.citizenid] = {
        model = vehicleModel,
        plate = plate,
        deposit = vehicleConfig.deposit,
        rentalFee = rentalFee,
        startTime = os.time(),
        duration = duration,
        expiresAt = os.time() + (duration == 'day' and 86400 or 3600),
        locationId = locationId,
        initialHealth = 1000,
    }

    TriggerClientEvent('rental:client:spawnVehicle', src, vehicleModel, plate, location.spawnPoint)
    TriggerClientEvent('QBCore:Notify', src, 'Vehicle rented! Return before your time expires.', 'success')
end)

Механика залога за ущерб и возврата

Система залога за повреждения создаёт ответственность за обращение игроков с арендованными транспортными средствами. При возврате автомобиля сравнивайте текущие значения здоровья с начальными, зафиксированными при аренде. В GTA у транспортных средств отдельные показатели здоровья двигателя, кузова и отдельных компонентов, что даёт вам детальный контроль оценки повреждений. Рассчитайте стоимость ремонта на основе нанесённого ущерба и вычтите её из залога перед возвратом остатка. Если ущерб превышает сумму залога, игрок не получает возврат и может быть дополнительно оштрафован. Если автомобиль возвращён в идеальном состоянии, залог возвращается полностью. Эта система стимулирует аккуратное вождение без излишних наказаний за мелкие царапины, неизбежные в физике вождения GTA:

RegisterNetEvent('rental:server:returnVehicle', function(vehicleNet)
    local src = source
    local Player = QBCore.Functions.GetPlayer(src)
    if not Player then return end

    local citizenid = Player.PlayerData.citizenid
    local rental = ActiveRentals[citizenid]
    if not rental then return end

    local vehicle = NetworkGetEntityFromNetworkId(vehicleNet)
    if not DoesEntityExist(vehicle) then return end

    -- Check plate matches
    local plate = GetVehicleNumberPlateText(vehicle)
    if plate:trim() ~= rental.plate then
        TriggerClientEvent('QBCore:Notify', src, 'This is not your rental vehicle', 'error')
        return
    end

    -- Calculate damage
    local bodyHealth = GetVehicleBodyHealth(vehicle)
    local engineHealth = GetVehicleEngineHealth(vehicle)
    local damagePercent = 1.0 - ((bodyHealth + engineHealth) / 2000.0)
    local repairCost = math.floor(rental.deposit * damagePercent)

    -- Calculate late fee
    local lateFee = 0
    if os.time() > rental.expiresAt then
        local overHours = math.ceil((os.time() - rental.expiresAt) / 3600)
        lateFee = overHours * 200
    end

    -- Refund deposit minus costs
    local refund = math.max(0, rental.deposit - repairCost - lateFee)

    if refund > 0 then
        Player.Functions.AddMoney('bank', refund, 'rental-deposit-refund')
    end

    DeleteEntity(vehicle)
    ActiveRentals[citizenid] = nil

    local message = string.format('Vehicle returned. Deposit: $%d | Repairs: $%d | Late fee: $%d | Refund: $%d',
        rental.deposit, repairCost, lateFee, refund)
    TriggerClientEvent('QBCore:Notify', src, message, refund > 0 and 'success' or 'warning')
end)

Система истечения срока и автоматического возврата

Арендованные транспортные средства не должны существовать бесконечно. Реализуйте систему таймера, которая отслеживает срок аренды и принимает соответствующие меры. Отправляйте игроку уведомление за тридцать минут до истечения срока, затем ещё одно за десять минут и последнее предупреждение за пять минут. По истечении срока аренды начинайте начислять почасовые штрафы до максимального порога. Если игрок не вернёт транспортное средство в льготный период после окончания аренды, автоматически удаляйте машину и конфискуйте весь депозит. Это предотвращает захламление сервера заброшенными арендованными машинами. Проверка срока должна выполняться на сервере с регулярным интервалом, проходя по всем активным арендам и принимая соответствующие меры в зависимости от оставшегося времени. Сохраняйте сетевой ID транспортного средства для возможности удалённого удаления при необходимости и обрабатывайте случай, когда транспортное средство было уничтожено до окончания аренды, автоматически закрывая аренду с полной конфискацией депозита.

Несколько пунктов аренды

Размещайте пункты аренды в стратегически важных местах карты, где временный транспорт наиболее логичен. Аэропорт , очевидный выбор, обслуживающий игроков, только что прибывших в город. Центр города рядом с правительственными зданиями обслуживает игроков, посещающих суды или деловые встречи. Пляжные локации предлагают мотоциклы и велосипеды для досуга вдоль побережья. Каждое место может предлагать разный набор транспорта: аэропорт , полный ассортимент от эконом до премиум, пляж , только мотоциклы и велосипеды. Настраивайте модель NPC в каждой локации под окружение. Аренда в аэропорту использует профессиональный бизнес-стиль, пляж , непринуждённый стиль серфера, центр , костюмированного клерка. Такое внимание к деталям делает каждое место аренды уникальным бизнесом, а не копией одной системы.

GPS отслеживание и защита от кражи

Арендованные транспортные средства должны иметь встроенное GPS-отслеживание, позволяющее компании по аренде и игроку в любое время определить местоположение машины. Отображайте местоположение арендованного транспортного средства на карте игрока с помощью отдельного значка. Если транспортное средство покидает настраиваемую зону, отправляйте предупреждающее уведомление. Реализуйте меры против кражи, которые не позволяют другим игрокам хранить или ставить арендованное транспортное средство в гараж, обеспечивая контроль системы аренды. Если игрок пытается поставить арендованное транспортное средство в личный гараж, система должна блокировать действие с уведомлением, объясняющим, что арендованные машины нельзя хранить. Для мотоциклов и велосипедов добавьте виртуальный замок, который может открыть только арендующий игрок, предотвращая случайные кражи. Если арендованное транспортное средство украдено, арендующий игрок должен иметь возможность сообщить об этом через приложение телефона, что активирует GPS-пинг для поиска машины. Отслеживайте общий пробег во время аренды для возможных дополнительных сборов за большой пробег, добавляя ещё один уровень реалистичного управления арендой транспорта.

Интеграция бизнеса и аренда, принадлежащая игрокам

Для серверов с системой владения бизнесом разрешите игрокам покупать и управлять собственным арендным бизнесом. Владелец бизнеса формирует автопарк, покупая транспорт для аренды, устанавливает цены, нанимает сотрудников для обслуживания и собирает доход от аренды. Владельцы должны иметь панель управления с активными арендами, ежедневным доходом, коэффициентом использования автопарка и затратами на обслуживание повреждённых транспортных средств. Сотрудники обрабатывают операции на ресепшене: оформление аренды и возврата, осмотр повреждений и эскалацию споров владельцу. Такой подход превращает систему аренды из статичной игровой механики в динамичный бизнес, отражающий предпринимательский дух ролевых серверов и создающий рабочие места для игроков, предпочитающих клиентский сервис активному геймплею.

Готовы начать?

Возьмите скрипты в нашем магазине или заходите в Discord за поддержкой, обновлениями и анонсами.