local QBCore = exports['qb-core']:GetCoreObject() local spawnedNPCs = {} local currentRental = nil -- NPCs spawnen CreateThread(function() for i = 1, #Config.RentalLocations do local location = Config.RentalLocations[i] RequestModel(location.npc.model) while not HasModelLoaded(location.npc.model) do Wait(1) end local npc = CreatePed(4, location.npc.model, location.npc.coords.x, location.npc.coords.y, location.npc.coords.z - 1.0, location.npc.coords.w, false, true) FreezeEntityPosition(npc, true) SetEntityInvincible(npc, true) SetBlockingOfNonTemporaryEvents(npc, true) spawnedNPCs[location.id] = npc -- QB-Target für NPC exports['qb-target']:AddTargetEntity(npc, { options = { { type = "client", event = "vehiclerental:client:openMenu", icon = "fas fa-car", label = "Fahrzeug mieten", locationId = location.id }, { type = "client", event = "vehiclerental:client:returnVehicle", icon = "fas fa-car-side", label = "Fahrzeug zurückgeben", locationId = location.id } }, distance = 2.0 }) end end) -- Mietmenü öffnen RegisterNetEvent('vehiclerental:client:openMenu', function(data) local locationId = data.locationId local location = nil for i = 1, #Config.RentalLocations do if Config.RentalLocations[i].id == locationId then location = Config.RentalLocations[i] break end end if not location then return end local options = {} for i = 1, #location.vehicles do local vehicle = location.vehicles[i] table.insert(options, { title = vehicle.label, description = '$' .. vehicle.price .. ' pro Stunde', icon = 'car', onSelect = function() openRentalDialog(vehicle, location) end }) end lib.registerContext({ id = 'vehicle_rental_menu', title = location.name, options = options }) lib.showContext('vehicle_rental_menu') end) -- Mietdialog function openRentalDialog(vehicle, location) local input = lib.inputDialog('Fahrzeug mieten', { { type = 'number', label = 'Mietdauer (Stunden)', description = 'Maximale Mietdauer: ' .. Config.MaxRentalTime .. ' Stunden', required = true, min = 1, max = Config.MaxRentalTime } }) if not input or not input[1] then return end local hours = tonumber(input[1]) if not hours or hours < 1 or hours > Config.MaxRentalTime then QBCore.Functions.Notify('Ungültige Mietdauer!', 'error') return end local totalCost = vehicle.price * hours local plate = GeneratePlate() QBCore.Functions.TriggerCallback('vehiclerental:server:rentVehicle', function(success) if success then spawnRentalVehicle(vehicle.model, location.spawnPoint, plate) end end, { vehicleModel = vehicle.model, pricePerHour = vehicle.price, hours = hours, locationId = location.id, plate = plate }) end -- Fahrzeug spawnen function spawnRentalVehicle(model, spawnPoint, plate) RequestModel(model) while not HasModelLoaded(model) do Wait(1) end local vehicle = CreateVehicle(model, spawnPoint.x, spawnPoint.y, spawnPoint.z, spawnPoint.w, true, false) SetVehicleNumberPlateText(vehicle, plate) SetEntityAsMissionEntity(vehicle, true, true) TaskWarpPedIntoVehicle(PlayerPedId(), vehicle, -1) TriggerEvent("vehiclekeys:client:SetOwner", plate) SetModelAsNoLongerNeeded(model) -- Registriere das Fahrzeug im Parking-System TriggerEvent('vehiclerental:client:vehicleRented', vehicle, plate) end -- Fahrzeug zurückgeben (KORRIGIERT - ohne im Auto zu sitzen) RegisterNetEvent('vehiclerental:client:returnVehicle', function(data) -- Hole alle aktiven Mietverhältnisse des Spielers QBCore.Functions.TriggerCallback('vehiclerental:server:getPlayerRentals', function(rentals) if not rentals or #rentals == 0 then QBCore.Functions.Notify('Du hast keine aktiven Mietverhältnisse!', 'error') return end -- Erstelle Menü mit allen gemieteten Fahrzeugen local options = {} for i = 1, #rentals do local rental = rentals[i] table.insert(options, { title = rental.vehicle_model .. " - " .. rental.vehicle_plate, description = "Zurückgeben " .. rental.timeText, icon = 'car', onSelect = function() returnSpecificVehicle(rental.vehicle_plate, data.locationId) end }) end lib.registerContext({ id = 'return_vehicle_menu', title = 'Fahrzeug zurückgeben', options = options }) lib.showContext('return_vehicle_menu') end) end) -- Spezifisches Fahrzeug zurückgeben function returnSpecificVehicle(plate, locationId) -- Finde das Fahrzeug in der Nähe local playerPos = GetEntityCoords(PlayerPedId()) local vehicle = nil local closestDistance = 50.0 -- Maximale Entfernung -- Suche nach dem Fahrzeug mit dem Kennzeichen for veh in EnumerateVehicles() do local vehPlate = GetVehicleNumberPlateText(veh) if string.gsub(vehPlate, "%s+", "") == string.gsub(plate, "%s+", "") then local vehPos = GetEntityCoords(veh) local distance = #(playerPos - vehPos) if distance < closestDistance then vehicle = veh closestDistance = distance end end end if not vehicle then QBCore.Functions.Notify('Fahrzeug nicht in der Nähe gefunden! Bringe es zum Mietort zurück.', 'error') return end -- Prüfe ob das Fahrzeug am richtigen Ort ist local location = nil for i = 1, #Config.RentalLocations do if Config.RentalLocations[i].id == locationId then location = Config.RentalLocations[i] break end end if location then local returnPos = vector3(location.returnPoint.x, location.returnPoint.y, location.returnPoint.z) local vehPos = GetEntityCoords(vehicle) local distance = #(returnPos - vehPos) if distance > 10.0 then QBCore.Functions.Notify('Bringe das Fahrzeug näher zum Rückgabeort!', 'error') return end end -- Fahrzeug zurückgeben QBCore.Functions.TriggerCallback('vehiclerental:server:returnVehicle', function(success) if success then DeleteVehicle(vehicle) end end, plate) end -- Fahrzeug-Enumerator function EnumerateVehicles() return coroutine.wrap(function() local handle, vehicle = FindFirstVehicle() local success repeat coroutine.yield(vehicle) success, vehicle = FindNextVehicle(handle) until not success EndFindVehicle(handle) end) end -- Kennzeichen generieren (GEÄNDERT - RENTAL + 3 zufällige Zeichen) function GeneratePlate() local plate = "RENT" for i = 1, 4 do if math.random(1, 2) == 1 then plate = plate .. string.char(math.random(65, 90)) -- A-Z else plate = plate .. tostring(math.random(0, 9)) -- 0-9 end end return plate end -- Cleanup beim Ressourcen-Stop AddEventHandler('onResourceStop', function(resourceName) if GetCurrentResourceName() ~= resourceName then return end for _, npc in pairs(spawnedNPCs) do if DoesEntityExist(npc) then DeleteEntity(npc) end end end) -- Integration mit mh_Parking RegisterNetEvent('vehiclerental:client:vehicleRented') AddEventHandler('vehiclerental:client:vehicleRented', function(vehicle, plate) -- Warte kurz, bis das Fahrzeug vollständig gespawnt ist Citizen.Wait(1000) -- Aktualisiere das Fahrzeug im Parking-System if DoesEntityExist(vehicle) then TriggerEvent("mh_Parking:updateVehicle", vehicle) print("Mietfahrzeug im Parking-System registriert: " .. plate) end end) -- Wenn ein Mietfahrzeug zurückgegeben wird RegisterNetEvent('vehiclerental:client:vehicleReturned') AddEventHandler('vehiclerental:client:vehicleReturned', function(plate) -- Entferne das Fahrzeug aus dem Parking-System TriggerServerEvent("mh_Parking:deleteVehicle", plate, true) print("Mietfahrzeug aus dem Parking-System entfernt: " .. plate) end)