Zurück zum Blog
Tutorial8 Min. Lesezeit

FiveM-Mietwagensystem: Temporäre Fahrzeuge skripten

Ergänze deinen FiveM-Server um Mietwagen. Mit befristeten Schlüsseln, Kautionen, automatischer Rückgabe und Mietskripten für QBCore, ESX und standalone.

Agency Scripts

Gründer und leitender Entwickler bei Agency Scripts

Warum Vermietungssysteme das Roleplay bereichern

Nicht jeder Spieler auf einem Roleplay-Server besitzt ein Fahrzeug, besonders neue Charaktere, die gerade erst anfangen. Ein Mietwagen- und Motorradsystem schließt diese Lücke, indem es vorübergehende Mobilität zu erschwinglichen Preisen bietet, natürliche Roleplay-Möglichkeiten an Mietstationen schafft und neuen Spielern ermöglicht, die Karte zu erkunden, ohne auf öffentliche Verkehrsmittel oder Fußwege angewiesen zu sein. Neben der grundlegenden Mobilität unterstützen Vermietungssysteme touristisches Roleplay, bei dem Besucher Cabrios für Panoramafahrten mieten, Lieferjobs mit bestimmten Fahrzeugtypen und Events, bei denen Spieler passende Fahrzeuge für organisierte Ausfahrten oder Rennen benötigen. Das System generiert außerdem durch Mietgebühren, Schadenskautionen und Gebühren für verspätete Rückgaben eine passive Einnahmequelle für die Serverwirtschaft.

Fuhrpark-Konfiguration und Fahrzeugkategorien

Teile deinen Mietfuhrpark in Kategorien auf, die den unterschiedlichen Bedürfnissen und Budgets der Spieler entsprechen. Economy-Fahrzeuge bieten erschwingliche Grundmobilität, Mittelklassewagen mehr Komfort und Leistung, Premiumfahrzeuge eignen sich für luxuriöse Erlebnisse und Motorräder bieten eine zweirädrige Alternative. Jede Kategorie sollte mehrere Fahrzeuge mit klaren Preisen enthalten. Biete sowohl Stunden- als auch Tagespreise an, damit Spieler die für ihren Bedarf günstigste Option wählen können. Definiere den Fuhrpark in einer Konfigurationstabelle, in der alle verfügbaren Fahrzeuge mit Mietpreis, erforderlicher Kaution, Kategorie und Spawn-Modell festgelegt sind:

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

Mietvorgang und NUI-Oberfläche

Die Anmietung beginnt, wenn sich ein Spieler dem NPC am Mietschalter nähert. Öffne über ein Target-System oder eine Näherungsprüfung ein NUI-Menü, das die verfügbaren Fahrzeugkategorien mit Filteroptionen anzeigt. Jeder Fahrzeugeintrag sollte den Modellnamen, nach Möglichkeit eine Bildvorschau, Stunden- und Tagespreise, die erforderliche Kaution sowie den Verfügbarkeitsstatus anzeigen. Wählt der Spieler ein Fahrzeug aus und bestätigt die Mietdauer, wickelt der Server die Transaktion ab. Die Gesamtkosten setzen sich aus der Mietgebühr für den gewählten Zeitraum und der Schadenskaution zusammen. Das System behält die Kaution ein und erstattet sie zurück, wenn das Fahrzeug unbeschädigt zurückgegeben wird. Implementiere die Mietbestätigung als Server-Event, das prüft, ob der Spieler über ausreichend Geld verfügt, kontrolliert, ob das ausgewählte Fahrzeug verfügbar ist, dem Spieler den Betrag berechnet und das Mietfahrzeug am vorgesehenen Spawnpunkt erstellt:

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)

Schadenskaution und Rückgabe-Mechaniken

Das Schadenskautionssystem sorgt dafür, dass Spieler verantwortungsvoll mit Mietfahrzeugen umgehen. Vergleiche bei der Rückgabe die aktuellen Fahrzeugwerte mit den bei der Anmietung gespeicherten Ausgangswerten. GTA-Fahrzeuge haben separate Zustandswerte für Motor, Karosserie und einzelne Komponenten, sodass du Schäden detailliert bewerten kannst. Berechne die Reparaturkosten anhand der entstandenen Schäden und ziehe sie von der Kaution ab, bevor du den Rest erstattest. Übersteigen die Schäden die Kaution, erhält der Spieler keine Rückerstattung und kann zusätzlich zur Kasse gebeten werden. Wird das Fahrzeug in einwandfreiem Zustand zurückgegeben, wird die volle Kaution erstattet. Dieses System fördert umsichtiges Fahren, ohne Spieler für kleine Kratzer zu bestrafen, die in der Fahrphysik von GTA unvermeidbar sind:

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)

Ablauf- und automatische Rückgabe

Mietfahrzeuge sollten nicht unbegrenzt bestehen bleiben. Implementiere ein Timersystem, das die Ablaufzeit jeder Anmietung erfasst und entsprechend reagiert. Benachrichtige den Spieler dreißig Minuten vor Ablauf, dann erneut zehn Minuten vorher und schließlich fünf Minuten vorher mit einer letzten Warnung. Nach Ablauf der Mietzeit fallen pro Minute Verspätungsgebühren bis zu einem festgelegten Höchstbetrag an. Gibt der Spieler das Fahrzeug nicht innerhalb der Kulanzfrist nach Ablauf zurück, despawne es automatisch und behalte die gesamte Kaution ein. So verhinderst du, dass herrenlose Mietfahrzeuge den Server überfüllen. Die Ablaufprüfung sollte regelmäßig serverseitig ausgeführt werden. Dabei werden alle aktiven Anmietungen durchlaufen und je nach verbleibender Zeit die entsprechenden Aktionen ausgeführt. Speichere die Netzwerk-ID des Fahrzeugs, damit du es bei Bedarf aus der Ferne löschen kannst. Berücksichtige außerdem den Fall, dass das Fahrzeug vor Ablauf der Mietzeit zerstört wurde, indem du die Anmietung automatisch schließt und die gesamte Kaution einbehältst.

Mehrere Mietstationen

Platziere Mietstationen an strategischen Orten auf der Karte, an denen temporäre Fortbewegungsmittel besonders sinnvoll sind. Der Flughafen ist naheliegend, da er Spieler bedient, die gerade in der Stadt angekommen sind. Standorte in der Innenstadt, nahe Regierungsgebäuden, sind für Spieler gedacht, die zu Gerichtsverhandlungen oder Geschäftsterminen müssen. An Stränden bieten sich Motorräder und Fahrräder für Freizeitaktivitäten entlang der Küste an. Jede Station kann eine andere Auswahl des Fuhrparks anbieten. Am Flughafen gibt es die gesamte Auswahl von Economy- bis Premiumfahrzeugen, während an den Strandstationen nur Motorräder und Fahrräder bereitstehen. Passe das NPC-Modell an jedem Standort an die Umgebung an. An der Flughafenstation kommt ein professionell gekleidetes Geschäftsmodell zum Einsatz, an Strandstationen ein lässiges Surfer-Modell und in der Innenstadt ein Angestellter im Anzug. Durch diese Liebe zum Detail wirkt jede Mietstation wie ein eigenes Geschäft und nicht wie eine identische Kopie desselben Systems.

GPS-Ortung und Diebstahlschutz

Mietfahrzeuge sollten über eine integrierte GPS-Ortung verfügen, mit der der Vermieter und der Spieler das Fahrzeug jederzeit finden können. Zeige den Standort des Mietfahrzeugs auf der Karte des Spielers mit einem eigenen Blip-Symbol an. Bewegt sich das Fahrzeug außerhalb eines konfigurierbaren Bereichs, sende eine Warnmeldung. Implementiere Diebstahlschutz, der andere Spieler daran hindert, ein Mietfahrzeug einzulagern oder in einer Garage abzustellen, damit es unter der Kontrolle des Mietsystems bleibt. Wenn ein Spieler versucht, ein Mietfahrzeug in seiner persönlichen Garage abzustellen, sollte das System die Aktion blockieren und per Meldung erklären, dass Mietfahrzeuge nicht eingelagert werden können. Ergänze für Motorräder und Fahrräder ein virtuelles Schloss, das nur der Spieler öffnen kann, der das Fahrzeug gemietet hat, um Gelegenheitsdiebstähle zu verhindern. Wird ein Mietfahrzeug gestohlen, sollte der Mieter den Diebstahl über eine Telefon-App melden können. Dadurch wird ein GPS-Ping ausgelöst, der ihm hilft, das Fahrzeug zu finden. Erfasse die während der Anmietung zurückgelegte Gesamtstrecke, um bei Fahrzeugen mit hoher Laufleistung gegebenenfalls Aufpreise zu berechnen. Das sorgt für eine weitere Ebene realistischer Mietwagenverwaltung.

Geschäftsintegration und Spielervermietungen

Auf Servern mit einem System für Geschäftsbesitz kannst du Spielern ermöglichen, ihr eigenes Vermietungsunternehmen zu kaufen und zu betreiben. Der Geschäftsinhaber stellt den Fuhrpark zusammen, indem er Fahrzeuge für den Mietbestand kauft, legt die Preise fest, stellt Mitarbeiter für den Schalter ein und erhält Einnahmen aus den Vermietungen. Das Verwaltungs-Dashboard für Geschäftsinhaber sollte aktive Anmietungen, Tageseinnahmen, die Auslastung des Fuhrparks und Wartungskosten für Fahrzeuge anzeigen, an denen sich über mehrere Vermietungen hinweg Schäden ansammeln. Mitarbeiter können Aufgaben am Empfang übernehmen, etwa Anmietungen und Rückgaben abwickeln, zurückgegebene Fahrzeuge auf Schäden prüfen und Streitfälle an den Inhaber weiterleiten. Dieser spielergesteuerte Ansatz macht aus dem Mietsystem eine dynamische Geschäftssimulation statt einer statischen Spielmechanik. Er spiegelt den Unternehmergeist von Roleplay-Servern wider und schafft Arbeitsmöglichkeiten für Spieler, die lieber im Kundenservice als in actionreichen Spielsituationen tätig sind.

Bereit loszulegen?

Hol dir die Scripts in unserem Shop, oder komm auf den Discord für Support, Updates und einen Blick auf das, was kommt.