Wróć do bloga
Tutorial8 min czytania

System wynajmu aut w FiveM: skryptowanie pojazdów tymczasowych

Dodaj pojazdy na wynajem do swojego serwera FiveM. Kluczyki czasowe, kaucje, logika automatycznego zwrotu i najlepsze skrypty wynajmu dla prac QBCore, ESX oraz standalone.

Agency Scripts

Założyciel i główny deweloper w Agency Scripts

Dlaczego systemy wynajmu wzbogacają Roleplay

Nie każdy gracz na serwerze roleplay ma własny pojazd, zwłaszcza nowe postacie, które dopiero zaczynają. System wynajmu samochodów i rowerów wypełnia tę lukę, zapewniając tymczasowy transport w przystępnych cenach, stwarzając naturalne okazje do roleplayu przy stanowiskach wynajmu i dając nowym graczom swobodę eksploracji mapy bez polegania na transporcie publicznym lub chodzeniu pieszo. Poza podstawowym transportem systemy wynajmu wspierają roleplay turystyczny, w którym turyści wynajmują kabriolety na malownicze przejażdżki, prace dostawcze wymagające określonych typów pojazdów oraz scenariusze eventowe, w których gracze potrzebują pasujących pojazdów na zorganizowane przejazdy lub wyścigi. System generuje także pasywny strumień przychodów dla ekonomii serwera z opłat za wynajem, kaucji za szkody i kar za spóźniony zwrot.

Konfiguracja floty i kategorie pojazdów

Podziel swoją flotę wynajmu na kategorie odpowiadające różnym potrzebom i budżetom graczy. Pojazdy ekonomiczne zapewniają przystępny, podstawowy transport, samochody średniej klasy oferują większy komfort i osiągi, pojazdy premium zaspokajają potrzeby luksusowych doświadczeń, a motocykle dają graczom dwukołową alternatywę. Każda kategoria powinna zawierać wiele opcji pojazdów z przejrzystym cennikiem. Uwzględnij stawki wynajmu za godzinę i za dzień, aby gracze mogli wybrać najbardziej ekonomiczną opcję dla swoich potrzeb. Zdefiniuj flotę w tabeli konfiguracyjnej, która określa każdy dostępny pojazd wraz z ceną wynajmu, wymaganą kaucją, kategorią i modelem spawnu:

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

Proces wynajmu i interfejs NUI

Interakcja z wypożyczalnią rozpoczyna się, gdy gracz podchodzi do NPC w punkcie wynajmu. Przy użyciu systemu target lub sprawdzania odległości otwórz menu NUI, które wyświetla dostępne kategorie pojazdów z opcjami filtrowania. Każda pozycja na liście pojazdów powinna zawierać nazwę modelu, podgląd graficzny (jeśli to możliwe), stawki godzinowe i dzienne, wymaganą kaucję oraz status dostępności. Gdy gracz wybierze pojazd i potwierdzi czas trwania wynajmu, serwer przetwarza transakcję. Łączna opłata to koszt wynajmu za wybrany okres plus kaucja za uszkodzenia. Kaucja jest blokowana przez system i zwracana, gdy pojazd zostanie oddany w stanie nienaruszonym. Zaimplementuj potwierdzenie wynajmu jako zdarzenie serwerowe, które weryfikuje wystarczające środki gracza, sprawdza dostępność wybranego pojazdu, pobiera opłatę i respi wypożyczony pojazd w wyznaczonym punkcie:

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)

Kaucja za uszkodzenia i mechanika zwrotu

System kaucji za uszkodzenia uczy odpowiedzialności za traktowanie wynajmowanych pojazdów. Przy zwrocie pojazdu porównaj jego aktualny stan z wartościami początkowymi zapisanymi w momencie wynajmu. Pojazdy w GTA mają oddzielne wartości stanu dla silnika, karoserii i poszczególnych komponentów, co daje ci pełną kontrolę nad oceną uszkodzeń. Oblicz koszt naprawy na podstawie powstałych szkód i potrąć go z kaucji przed zwrotem reszty. Jeśli uszkodzenia przekraczają kwotę kaucji, gracz nie otrzymuje zwrotu i może zostać obciążony dodatkową opłatą. Jeśli pojazd wróci w stanie idealnym, cała kaucja jest zwracana. Taki system zachęca do ostrożnej jazdy, nie karząc przesadnie za drobne rysy, które w fizyce jazdy GTA są nieuniknione:

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)

System wygasania i automatycznego zwrotu

Pojazdy na wynajem nie powinny istnieć w nieskończoność. Wdróż system timerów, który śledzi czas wygaśnięcia każdego wynajmu i podejmuje odpowiednie działania. Wyślij graczowi powiadomienie trzydzieści minut przed wygaśnięciem, kolejne dziesięć minut przed końcem i ostatnie ostrzeżenie na pięć minut przed upływem czasu. Gdy wynajem wygaśnie, zacznij naliczać opłaty za spóźnienie za każdą minutę, aż do osiągnięcia maksymalnego limitu. Jeśli gracz nie zwróci pojazdu w okresie karencji po wygaśnięciu, automatycznie zdespawnuj pojazd i zatrzymaj całą kaucję. Zapobiega to zaśmiecaniu serwera przez porzucone pojazdy z wypożyczalni. Sprawdzanie wygaśnięcia powinno działać po stronie serwera w regularnych odstępach czasu, iterując po wszystkich aktywnych wynajmach i podejmując odpowiednie kroki na podstawie pozostałego czasu. Zapisuj network ID pojazdu, aby w razie potrzeby móc go zdalnie usunąć, oraz obsłuż przypadek zniszczenia pojazdu przed wygaśnięciem wynajmu poprzez automatyczne zakończenie umowy z utratą pełnej kaucji.

Wiele lokalizacji wynajmu

Umieść punkty wynajmu w strategicznych miejscach na mapie, gdzie tymczasowy transport ma największy sens. Lotnisko jest oczywistym wyborem, obsługując graczy, którzy właśnie przybyli do miasta. Lokalizacje w Downtown w pobliżu budynków rządowych służą graczom uczestniczącym w rozprawach sądowych lub spotkaniach biznesowych. Lokalizacje na plaży oferują motocykle i rowery do rekreacji wzdłuż wybrzeża. Każda lokalizacja może oferować inny podzbiór floty: lotnisko dysponuje pełną ofertą od wersji ekonomicznej po premium, podczas gdy punkty na plaży mają na stanie wyłącznie motocykle i rowery. Dostosuj model NPC w każdej lokalizacji, aby pasował do otoczenia. Wypożyczalnie na lotnisku korzystają z profesjonalnego modelu biznesowego, wypożyczalnie na plaży z modelu wyluzowanego surfera, a lokalizacje w centrum z urzędnika w garniturze. Taka dbałość o szczegóły sprawia, że każdy punkt wynajmu sprawia wrażenie odrębnej firmy, a nie identycznej kopii tego samego systemu.

Śledzenie GPS i system antykradzieżowy

Pojazdy na wynajem powinny mieć wbudowane śledzenie GPS, które pozwala wypożyczalni i graczowi zlokalizować pojazd w dowolnym momencie. Wyświetlaj lokalizację wynajętego pojazdu na mapie gracza za pomocą wyróżniającej się ikony blipa. Jeśli pojazd wyjedzie poza konfigurowalną granicę, wyślij powiadomienie ostrzegawcze. Wdróż zabezpieczenia przed kradzieżą, które uniemożliwią innym graczom chowanie wynajętego pojazdu do garażu, zapewniając pełną kontrolę systemu wynajmu. Gdy gracz spróbuje zaparkować wynajęty pojazd w swoim prywatnym garażu, system powinien zablokować tę akcję i wyświetlić powiadomienie wyjaśniające, że pojazdów z wypożyczalni nie można garażować. W przypadku motocykli i rowerów dodaj wirtualną blokadę, którą może odblokować tylko wypożyczający gracz, co zapobiegnie przypadkowym kradzieżom. Jeśli wynajęty pojazd zostanie skradziony, gracz powinien móc to zgłosić w aplikacji na telefonie, co wywoła sygnał GPS ułatwiający jego odnalezienie. Zliczaj całkowity przebieg podczas wynajmu na potrzeby ewentualnych dopłat za duże przebiegi, dodając kolejny poziom realistycznego zarządzania flotą.

Integracja biznesowa i wypożyczalnie należące do graczy

W przypadku serwerów z systemem posiadania firm pozwól graczom na zakup i prowadzenie własnej wypożyczalni. Właściciel firmy ustala skład floty, kupując pojazdy do puli wynajmu, ustala ceny, zatrudnia pracowników do obsługi klienta i pobiera przychody z wynajmu. Właściciele firm powinni mieć panel zarządzania pokazujący aktywne wypożyczenia, dzienny przychód, stopień wykorzystania floty oraz koszty utrzymania pojazdów, które ulegają uszkodzeniom podczas kolejnych wypożyczeń. Pracownicy mogą zajmować się obsługą klienta, taką jak wydawanie i przyjmowanie pojazdów, sprawdzanie uszkodzeń zwracanych aut oraz przekazywanie sporów właścicielowi. To podejście oparte na działaniach graczy przekształca system wynajmu ze statycznej mechaniki gry w dynamiczny biznes, który odzwierciedla ducha przedsiębiorczości na serwerach roleplay i tworzy miejsca pracy dla graczy preferujących obsługę klienta zamiast dynamicznej akcji.

Gotowy, aby zacząć?

Kup skrypty w naszym sklepie lub dołącz do Discorda, aby uzyskać wsparcie, aktualizacje i sprawdzić nadchodzące nowości.