676 lines
		
	
	
	
		
			23 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			676 lines
		
	
	
	
		
			23 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
local QBCore = exports['qb-core']:GetCoreObject()
 | 
						|
local currentVehicle = nil
 | 
						|
local anchoredBoats = {} -- Speichert verankerte Boote
 | 
						|
 | 
						|
-- Boot-Klassen für spezielle Behandlung
 | 
						|
local boatClasses = {
 | 
						|
    [14] = true, -- Boats
 | 
						|
}
 | 
						|
 | 
						|
-- Sitz-Namen für bessere Anzeige
 | 
						|
local seatNames = {
 | 
						|
    [-1] = "Kapitän",
 | 
						|
    [0] = "Beifahrer",
 | 
						|
    [1] = "Hinten Links",
 | 
						|
    [2] = "Hinten Rechts",
 | 
						|
    [3] = "Hinten Mitte",
 | 
						|
    [4] = "Deck 1",
 | 
						|
    [5] = "Deck 2",
 | 
						|
    [6] = "Deck 3",
 | 
						|
    [7] = "Deck 4",
 | 
						|
    [8] = "Deck 5",
 | 
						|
    [9] = "Deck 6"
 | 
						|
}
 | 
						|
 | 
						|
-- Funktion um aktuellen Sitz zu bekommen
 | 
						|
local function getCurrentSeat(ped, vehicle)
 | 
						|
    if not IsPedInVehicle(ped, vehicle, false) then
 | 
						|
        return nil
 | 
						|
    end
 | 
						|
    
 | 
						|
    -- Prüfe Fahrersitz
 | 
						|
    if GetPedInVehicleSeat(vehicle, -1) == ped then
 | 
						|
        return -1
 | 
						|
    end
 | 
						|
    
 | 
						|
    -- Prüfe Passagiersitze
 | 
						|
    local maxSeats = GetVehicleMaxNumberOfPassengers(vehicle)
 | 
						|
    for i = 0, maxSeats - 1 do
 | 
						|
        if GetPedInVehicleSeat(vehicle, i) == ped then
 | 
						|
            return i
 | 
						|
        end
 | 
						|
    end
 | 
						|
    
 | 
						|
    return nil
 | 
						|
end
 | 
						|
 | 
						|
-- Prüfe ob Fahrzeug ein Boot ist
 | 
						|
local function isBoat(vehicle)
 | 
						|
    local vehicleClass = GetVehicleClass(vehicle)
 | 
						|
    return boatClasses[vehicleClass] or false
 | 
						|
end
 | 
						|
 | 
						|
-- Lade verankerte Boote vom Server
 | 
						|
local function loadAnchoredBoats()
 | 
						|
    QBCore.Functions.TriggerCallback('nordi_seats:server:getAnchoredBoats', function(serverAnchors)
 | 
						|
        if serverAnchors then
 | 
						|
            for plate, anchorData in pairs(serverAnchors) do
 | 
						|
                -- Finde Fahrzeug mit dieser Kennzeichen
 | 
						|
                local vehicles = GetGamePool('CVehicle')
 | 
						|
                for _, vehicle in pairs(vehicles) do
 | 
						|
                    if DoesEntityExist(vehicle) then
 | 
						|
                        local vehicleProps = QBCore.Functions.GetVehicleProperties(vehicle)
 | 
						|
                        if vehicleProps.plate == plate and isBoat(vehicle) then
 | 
						|
                            -- Setze Boot an gespeicherte Position
 | 
						|
                            SetEntityCoords(vehicle, anchorData.coords.x, anchorData.coords.y, anchorData.coords.z)
 | 
						|
                            SetEntityHeading(vehicle, anchorData.heading)
 | 
						|
                            FreezeEntityPosition(vehicle, true)
 | 
						|
                            SetEntityInvincible(vehicle, true)
 | 
						|
                            
 | 
						|
                            local vehicleNetId = NetworkGetNetworkIdFromEntity(vehicle)
 | 
						|
                            anchoredBoats[vehicleNetId] = anchorData
 | 
						|
                            
 | 
						|
                            print("^2[Anker]^7 Boot mit Kennzeichen " .. plate .. " wurde verankert geladen.")
 | 
						|
                            break
 | 
						|
                        end
 | 
						|
                    end
 | 
						|
                end
 | 
						|
            end
 | 
						|
        end
 | 
						|
    end)
 | 
						|
end
 | 
						|
 | 
						|
-- Speichere Anker auf Server
 | 
						|
local function saveAnchorToServer(vehicle, anchorData)
 | 
						|
    local vehicleProps = QBCore.Functions.GetVehicleProperties(vehicle)
 | 
						|
    if vehicleProps.plate then
 | 
						|
        TriggerServerEvent('nordi_seats:server:saveAnchor', vehicleProps.plate, anchorData)
 | 
						|
    end
 | 
						|
end
 | 
						|
 | 
						|
-- Entferne Anker vom Server
 | 
						|
local function removeAnchorFromServer(vehicle)
 | 
						|
    local vehicleProps = QBCore.Functions.GetVehicleProperties(vehicle)
 | 
						|
    if vehicleProps.plate then
 | 
						|
        TriggerServerEvent('nordi_seats:server:removeAnchor', vehicleProps.plate)
 | 
						|
    end
 | 
						|
end
 | 
						|
 | 
						|
-- Anker setzen/entfernen
 | 
						|
local function toggleAnchor(vehicle)
 | 
						|
    if not isBoat(vehicle) then
 | 
						|
        QBCore.Functions.Notify('Nur Boote können verankert werden!', 'error')
 | 
						|
        return
 | 
						|
    end
 | 
						|
    
 | 
						|
    local vehicleNetId = NetworkGetNetworkIdFromEntity(vehicle)
 | 
						|
    
 | 
						|
    if anchoredBoats[vehicleNetId] then
 | 
						|
        -- Anker lichten (ohne Wackel-Effekt)
 | 
						|
        FreezeEntityPosition(vehicle, false)
 | 
						|
        SetEntityInvincible(vehicle, false)
 | 
						|
        anchoredBoats[vehicleNetId] = nil
 | 
						|
        
 | 
						|
        -- Entferne vom Server
 | 
						|
        removeAnchorFromServer(vehicle)
 | 
						|
        
 | 
						|
        QBCore.Functions.Notify('⚓ Anker gelichtet! Das Boot kann wieder bewegt werden.', 'success')
 | 
						|
    else
 | 
						|
        -- Anker werfen (ohne Sound und Effekte)
 | 
						|
        local coords = GetEntityCoords(vehicle)
 | 
						|
        local heading = GetEntityHeading(vehicle)
 | 
						|
        
 | 
						|
        FreezeEntityPosition(vehicle, true)
 | 
						|
        SetEntityInvincible(vehicle, true)
 | 
						|
        
 | 
						|
        local anchorData = {
 | 
						|
            coords = coords,
 | 
						|
            heading = heading,
 | 
						|
            time = GetGameTimer()
 | 
						|
        }
 | 
						|
        
 | 
						|
        anchoredBoats[vehicleNetId] = anchorData
 | 
						|
        
 | 
						|
        -- Speichere auf Server
 | 
						|
        saveAnchorToServer(vehicle, anchorData)
 | 
						|
        
 | 
						|
        QBCore.Functions.Notify('⚓ Anker geworfen! Das Boot ist jetzt verankert.', 'success')
 | 
						|
    end
 | 
						|
end
 | 
						|
 | 
						|
-- Prüfe ob Boot verankert ist
 | 
						|
local function isBoatAnchored(vehicle)
 | 
						|
    local vehicleNetId = NetworkGetNetworkIdFromEntity(vehicle)
 | 
						|
    return anchoredBoats[vehicleNetId] ~= nil
 | 
						|
end
 | 
						|
 | 
						|
-- Überwache gespawnte Fahrzeuge für Anker-Wiederherstellung
 | 
						|
CreateThread(function()
 | 
						|
    local checkedVehicles = {}
 | 
						|
    
 | 
						|
    while true do
 | 
						|
        local vehicles = GetGamePool('CVehicle')
 | 
						|
        
 | 
						|
        for _, vehicle in pairs(vehicles) do
 | 
						|
            if DoesEntityExist(vehicle) and not checkedVehicles[vehicle] then
 | 
						|
                checkedVehicles[vehicle] = true
 | 
						|
                
 | 
						|
                if isBoat(vehicle) then
 | 
						|
                    -- Prüfe ob dieses Boot einen gespeicherten Anker hat
 | 
						|
                    local vehicleProps = QBCore.Functions.GetVehicleProperties(vehicle)
 | 
						|
                    if vehicleProps.plate then
 | 
						|
                        QBCore.Functions.TriggerCallback('nordi_seats:server:getAnchorByPlate', function(anchorData)
 | 
						|
                            if anchorData then
 | 
						|
                                -- Setze Boot an gespeicherte Position
 | 
						|
                                SetEntityCoords(vehicle, anchorData.coords.x, anchorData.coords.y, anchorData.coords.z)
 | 
						|
                                SetEntityHeading(vehicle, anchorData.heading)
 | 
						|
                                FreezeEntityPosition(vehicle, true)
 | 
						|
                                SetEntityInvincible(vehicle, true)
 | 
						|
                                
 | 
						|
                                local vehicleNetId = NetworkGetNetworkIdFromEntity(vehicle)
 | 
						|
                                anchoredBoats[vehicleNetId] = anchorData
 | 
						|
                                
 | 
						|
                                print("^2[Anker]^7 Boot " .. vehicleProps.plate .. " automatisch verankert.")
 | 
						|
                            end
 | 
						|
                        end, vehicleProps.plate)
 | 
						|
                    end
 | 
						|
                end
 | 
						|
            end
 | 
						|
        end
 | 
						|
        
 | 
						|
        -- Cleanup nicht mehr existierende Fahrzeuge
 | 
						|
        for vehicle, _ in pairs(checkedVehicles) do
 | 
						|
            if not DoesEntityExist(vehicle) then
 | 
						|
                checkedVehicles[vehicle] = nil
 | 
						|
            end
 | 
						|
        end
 | 
						|
        
 | 
						|
        Wait(5000) -- Prüfe alle 5 Sekunden
 | 
						|
    end
 | 
						|
end)
 | 
						|
 | 
						|
-- Funktion um verfügbare Sitze zu bekommen
 | 
						|
local function getAvailableSeats(vehicle)
 | 
						|
    local seats = {}
 | 
						|
    local maxSeats = GetVehicleMaxNumberOfPassengers(vehicle)
 | 
						|
    
 | 
						|
    -- Fahrersitz (-1)
 | 
						|
    if IsVehicleSeatFree(vehicle, -1) then
 | 
						|
        local seatName = isBoat(vehicle) and seatNames[-1] or "Fahrer"
 | 
						|
        table.insert(seats, {
 | 
						|
            index = -1,
 | 
						|
            name = seatName,
 | 
						|
            icon = isBoat(vehicle) and "fas fa-anchor" or "fas fa-steering-wheel"
 | 
						|
        })
 | 
						|
    end
 | 
						|
    
 | 
						|
    -- Passagiersitze (0 bis maxSeats-1)
 | 
						|
    for i = 0, maxSeats - 1 do
 | 
						|
        if IsVehicleSeatFree(vehicle, i) then
 | 
						|
            table.insert(seats, {
 | 
						|
                index = i,
 | 
						|
                name = seatNames[i] or "Sitz " .. (i + 1),
 | 
						|
                icon = "fas fa-user"
 | 
						|
            })
 | 
						|
        end
 | 
						|
    end
 | 
						|
    
 | 
						|
    return seats
 | 
						|
end
 | 
						|
 | 
						|
-- Funktion um belegte Sitze zu bekommen
 | 
						|
local function getOccupiedSeats(vehicle)
 | 
						|
    local occupiedSeats = {}
 | 
						|
    local maxSeats = GetVehicleMaxNumberOfPassengers(vehicle)
 | 
						|
    
 | 
						|
    -- Fahrersitz prüfen
 | 
						|
    if not IsVehicleSeatFree(vehicle, -1) then
 | 
						|
        local ped = GetPedInVehicleSeat(vehicle, -1)
 | 
						|
        local playerName = "Unbekannt"
 | 
						|
        
 | 
						|
        if IsPedAPlayer(ped) then
 | 
						|
            local playerId = NetworkGetPlayerIndexFromPed(ped)
 | 
						|
            if playerId ~= -1 then
 | 
						|
                playerName = GetPlayerName(playerId)
 | 
						|
            end
 | 
						|
        else
 | 
						|
            playerName = "NPC"
 | 
						|
        end
 | 
						|
        
 | 
						|
        local seatName = isBoat(vehicle) and seatNames[-1] or "Fahrer"
 | 
						|
        table.insert(occupiedSeats, {
 | 
						|
            index = -1,
 | 
						|
            name = seatName,
 | 
						|
            occupant = playerName,
 | 
						|
            icon = isBoat(vehicle) and "fas fa-anchor" or "fas fa-steering-wheel"
 | 
						|
        })
 | 
						|
    end
 | 
						|
    
 | 
						|
    -- Passagiersitze prüfen
 | 
						|
    for i = 0, maxSeats - 1 do
 | 
						|
        if not IsVehicleSeatFree(vehicle, i) then
 | 
						|
            local ped = GetPedInVehicleSeat(vehicle, i)
 | 
						|
            local playerName = "Unbekannt"
 | 
						|
            
 | 
						|
            if IsPedAPlayer(ped) then
 | 
						|
                local playerId = NetworkGetPlayerIndexFromPed(ped)
 | 
						|
                if playerId ~= -1 then
 | 
						|
                    playerName = GetPlayerName(playerId)
 | 
						|
                end
 | 
						|
            else
 | 
						|
                playerName = "NPC"
 | 
						|
            end
 | 
						|
            
 | 
						|
            table.insert(occupiedSeats, {
 | 
						|
                index = i,
 | 
						|
                name = seatNames[i] or "Sitz " .. (i + 1),
 | 
						|
                occupant = playerName,
 | 
						|
                icon = "fas fa-user"
 | 
						|
            })
 | 
						|
        end
 | 
						|
    end
 | 
						|
    
 | 
						|
    return occupiedSeats
 | 
						|
end
 | 
						|
 | 
						|
-- Funktion zum direkten Einsteigen (für Boote)
 | 
						|
local function teleportToSeat(vehicle, seatIndex)
 | 
						|
    local playerPed = PlayerPedId()
 | 
						|
    
 | 
						|
    if IsPedInAnyVehicle(playerPed, false) then
 | 
						|
        QBCore.Functions.Notify('Du bist bereits in einem Fahrzeug!', 'error')
 | 
						|
        return
 | 
						|
    end
 | 
						|
    
 | 
						|
    if not IsVehicleSeatFree(vehicle, seatIndex) then
 | 
						|
        QBCore.Functions.Notify('Dieser Sitz ist bereits belegt!', 'error')
 | 
						|
        return
 | 
						|
    end
 | 
						|
    
 | 
						|
    -- Prüfe ob Fahrzeug abgeschlossen ist
 | 
						|
    if GetVehicleDoorLockStatus(vehicle) == 2 then
 | 
						|
        QBCore.Functions.Notify('Das Fahrzeug ist abgeschlossen!', 'error')
 | 
						|
        return
 | 
						|
    end
 | 
						|
    
 | 
						|
    -- Direkte Teleportation ohne Animation
 | 
						|
    SetPedIntoVehicle(playerPed, vehicle, seatIndex)
 | 
						|
    currentVehicle = vehicle
 | 
						|
    
 | 
						|
    local seatName = seatNames[seatIndex] or "Sitz " .. (seatIndex + 1)
 | 
						|
    if isBoat(vehicle) then
 | 
						|
        QBCore.Functions.Notify('Willkommen an Bord! (' .. seatName .. ')', 'success')
 | 
						|
        
 | 
						|
        -- Zeige Anker-Status wenn Kapitän
 | 
						|
        if seatIndex == -1 and isBoatAnchored(vehicle) then
 | 
						|
            QBCore.Functions.Notify('⚓ Das Boot ist verankert. Nutze das Menü um den Anker zu lichten.', 'primary')
 | 
						|
        end
 | 
						|
    else
 | 
						|
        QBCore.Functions.Notify('Du bist eingestiegen (' .. seatName .. ')', 'success')
 | 
						|
    end
 | 
						|
end
 | 
						|
 | 
						|
-- Funktion zum normalen Einsteigen (für Autos)
 | 
						|
local function enterVehicleSeat(vehicle, seatIndex)
 | 
						|
    local playerPed = PlayerPedId()
 | 
						|
    
 | 
						|
    if IsPedInAnyVehicle(playerPed, false) then
 | 
						|
        QBCore.Functions.Notify('Du bist bereits in einem Fahrzeug!', 'error')
 | 
						|
        return
 | 
						|
    end
 | 
						|
    
 | 
						|
    if not IsVehicleSeatFree(vehicle, seatIndex) then
 | 
						|
        QBCore.Functions.Notify('Dieser Sitz ist bereits belegt!', 'error')
 | 
						|
        return
 | 
						|
    end
 | 
						|
    
 | 
						|
    -- Prüfe ob Fahrzeug abgeschlossen ist
 | 
						|
    if GetVehicleDoorLockStatus(vehicle) == 2 then
 | 
						|
        QBCore.Functions.Notify('Das Fahrzeug ist abgeschlossen!', 'error')
 | 
						|
        return
 | 
						|
    end
 | 
						|
    
 | 
						|
    TaskEnterVehicle(playerPed, vehicle, 10000, seatIndex, 1.0, 1, 0)
 | 
						|
    currentVehicle = vehicle
 | 
						|
    
 | 
						|
    local seatName = seatNames[seatIndex] or "Sitz " .. (seatIndex + 1)
 | 
						|
    QBCore.Functions.Notify('Steige in das Fahrzeug ein (' .. seatName .. ')...', 'primary')
 | 
						|
end
 | 
						|
 | 
						|
-- Funktion zum Sitzwechsel
 | 
						|
local function switchSeat(vehicle, newSeatIndex)
 | 
						|
    local playerPed = PlayerPedId()
 | 
						|
    
 | 
						|
    if not IsPedInVehicle(playerPed, vehicle, false) then
 | 
						|
        QBCore.Functions.Notify('Du bist nicht in diesem Fahrzeug!', 'error')
 | 
						|
        return
 | 
						|
    end
 | 
						|
    
 | 
						|
    if not IsVehicleSeatFree(vehicle, newSeatIndex) then
 | 
						|
        QBCore.Functions.Notify('Dieser Sitz ist bereits belegt!', 'error')
 | 
						|
        return
 | 
						|
    end
 | 
						|
    
 | 
						|
    -- Für Boote: Direkte Teleportation
 | 
						|
    if isBoat(vehicle) then
 | 
						|
        SetPedIntoVehicle(playerPed, vehicle, newSeatIndex)
 | 
						|
    else
 | 
						|
        -- Für Autos: Normale Animation
 | 
						|
        TaskShuffleToNextVehicleSeat(playerPed, vehicle)
 | 
						|
        Wait(100)
 | 
						|
        SetPedIntoVehicle(playerPed, vehicle, newSeatIndex)
 | 
						|
    end
 | 
						|
    
 | 
						|
    local seatName = seatNames[newSeatIndex] or "Sitz " .. (newSeatIndex + 1)
 | 
						|
    QBCore.Functions.Notify('Gewechselt zu: ' .. seatName, 'success')
 | 
						|
    
 | 
						|
    -- Zeige Anker-Status wenn zum Kapitän gewechselt
 | 
						|
    if isBoat(vehicle) and newSeatIndex == -1 and isBoatAnchored(vehicle) then
 | 
						|
        QBCore.Functions.Notify('⚓ Das Boot ist verankert. Nutze das Menü um den Anker zu lichten.', 'primary')
 | 
						|
    end
 | 
						|
end
 | 
						|
 | 
						|
-- Hauptmenü für Sitzauswahl
 | 
						|
local function showSeatMenu(vehicle)
 | 
						|
    local playerPed = PlayerPedId()
 | 
						|
    local isInVehicle = IsPedInVehicle(playerPed, vehicle, false)
 | 
						|
    local availableSeats = getAvailableSeats(vehicle)
 | 
						|
    local occupiedSeats = getOccupiedSeats(vehicle)
 | 
						|
    local isVehicleBoat = isBoat(vehicle)
 | 
						|
    local isAnchored = isBoatAnchored(vehicle)
 | 
						|
    local options = {}
 | 
						|
    
 | 
						|
    -- Header
 | 
						|
    local vehicleName = GetDisplayNameFromVehicleModel(GetEntityModel(vehicle))
 | 
						|
    local vehicleLabel = GetLabelText(vehicleName)
 | 
						|
    if vehicleLabel == "NULL" then
 | 
						|
        vehicleLabel = vehicleName
 | 
						|
    end
 | 
						|
    
 | 
						|
    -- Boot-spezifische Anzeige mit Anker-Status
 | 
						|
    if isVehicleBoat then
 | 
						|
        vehicleLabel = (isAnchored and "⚓ " or "⛵ ") .. vehicleLabel
 | 
						|
    else
 | 
						|
        vehicleLabel = "🚗 " .. vehicleLabel
 | 
						|
    end
 | 
						|
    
 | 
						|
    -- Anker-Kontrolle (nur für Boote und nur wenn im Boot)
 | 
						|
    if isVehicleBoat and isInVehicle then
 | 
						|
        local currentSeat = getCurrentSeat(playerPed, vehicle)
 | 
						|
        -- Nur Kapitän kann Anker bedienen
 | 
						|
        if currentSeat == -1 then
 | 
						|
            table.insert(options, {
 | 
						|
                title = isAnchored and '⚓ Anker lichten' or '⚓ Anker werfen',
 | 
						|
                description = isAnchored and 'Boot wieder beweglich machen' or 'Boot an aktueller Position verankern',
 | 
						|
                icon = 'fas fa-anchor',
 | 
						|
                onSelect = function()
 | 
						|
                    toggleAnchor(vehicle)
 | 
						|
                end
 | 
						|
            })
 | 
						|
            
 | 
						|
            -- Trennlinie
 | 
						|
            table.insert(options, {
 | 
						|
                title = '─────────────────',
 | 
						|
                disabled = true
 | 
						|
            })
 | 
						|
        end
 | 
						|
    end
 | 
						|
    
 | 
						|
    -- Verfügbare Sitze
 | 
						|
    if #availableSeats > 0 then
 | 
						|
        local headerText = isVehicleBoat and '🟢 Verfügbare Plätze' or '🟢 Verfügbare Sitze'
 | 
						|
        table.insert(options, {
 | 
						|
            title = headerText,
 | 
						|
            description = isVehicleBoat and 'Freie Plätze an Bord' or 'Freie Sitzplätze',
 | 
						|
            disabled = true
 | 
						|
        })
 | 
						|
        
 | 
						|
        for _, seat in pairs(availableSeats) do
 | 
						|
            local actionText = isInVehicle and 'Zu diesem Platz wechseln' or (isVehicleBoat and 'An Bord gehen' or 'In das Fahrzeug einsteigen')
 | 
						|
            table.insert(options, {
 | 
						|
                title = seat.name,
 | 
						|
                description = actionText,
 | 
						|
                icon = seat.icon,
 | 
						|
                onSelect = function()
 | 
						|
                    if isInVehicle then
 | 
						|
                        switchSeat(vehicle, seat.index)
 | 
						|
                    else
 | 
						|
                        if isVehicleBoat then
 | 
						|
                            teleportToSeat(vehicle, seat.index)
 | 
						|
                        else
 | 
						|
                            enterVehicleSeat(vehicle, seat.index)
 | 
						|
                        end
 | 
						|
                    end
 | 
						|
                end
 | 
						|
            })
 | 
						|
        end
 | 
						|
    end
 | 
						|
    
 | 
						|
    -- Belegte Sitze anzeigen
 | 
						|
    if #occupiedSeats > 0 then
 | 
						|
        local headerText = isVehicleBoat and '🔴 Belegte Plätze' or '🔴 Belegte Sitze'
 | 
						|
        table.insert(options, {
 | 
						|
            title = headerText,
 | 
						|
            description = isVehicleBoat and 'Bereits besetzte Plätze' or 'Bereits besetzte Sitzplätze',
 | 
						|
            disabled = true
 | 
						|
        })
 | 
						|
        
 | 
						|
        for _, seat in pairs(occupiedSeats) do
 | 
						|
            table.insert(options, {
 | 
						|
                title = seat.name,
 | 
						|
                description = 'Besetzt von: ' .. seat.occupant,
 | 
						|
                icon = seat.icon,
 | 
						|
                disabled = true
 | 
						|
            })
 | 
						|
        end
 | 
						|
    end
 | 
						|
    
 | 
						|
    -- Aussteigen Option (nur wenn im Fahrzeug)
 | 
						|
    if isInVehicle then
 | 
						|
        local exitText = isVehicleBoat and '🚪 Von Bord gehen' or '🚪 Aussteigen'
 | 
						|
        local exitDesc = isVehicleBoat and 'Das Boot verlassen' or 'Das Fahrzeug verlassen'
 | 
						|
        table.insert(options, {
 | 
						|
            title = exitText,
 | 
						|
            description = exitDesc,
 | 
						|
            icon = 'fas fa-door-open',
 | 
						|
            onSelect = function()
 | 
						|
                TaskLeaveVehicle(playerPed, vehicle, 0)
 | 
						|
                local exitMsg = isVehicleBoat and 'Du gehst von Bord...' or 'Du steigst aus dem Fahrzeug aus...'
 | 
						|
                QBCore.Functions.Notify(exitMsg, 'primary')
 | 
						|
            end
 | 
						|
        })
 | 
						|
    end
 | 
						|
    
 | 
						|
    -- Fahrzeuginfo
 | 
						|
    table.insert(options, {
 | 
						|
        title = '📋 Fahrzeuginfo',
 | 
						|
        description = 'Informationen über das Fahrzeug',
 | 
						|
        icon = 'fas fa-info-circle',
 | 
						|
        onSelect = function()
 | 
						|
            showVehicleInfo(vehicle)
 | 
						|
        end
 | 
						|
    })
 | 
						|
    
 | 
						|
    if #options == 0 then
 | 
						|
        QBCore.Functions.Notify('Keine verfügbaren Aktionen!', 'error')
 | 
						|
        return
 | 
						|
    end
 | 
						|
    
 | 
						|
    lib.registerContext({
 | 
						|
        id = 'vehicle_seat_menu',
 | 
						|
        title = vehicleLabel,
 | 
						|
        options = options
 | 
						|
    })
 | 
						|
    
 | 
						|
    lib.showContext('vehicle_seat_menu')
 | 
						|
end
 | 
						|
 | 
						|
-- Fahrzeuginfo anzeigen
 | 
						|
function showVehicleInfo(vehicle)
 | 
						|
    local vehicleProps = QBCore.Functions.GetVehicleProperties(vehicle)
 | 
						|
    local vehicleName = GetDisplayNameFromVehicleModel(GetEntityModel(vehicle))
 | 
						|
    local vehicleLabel = GetLabelText(vehicleName)
 | 
						|
    if vehicleLabel == "NULL" then
 | 
						|
        vehicleLabel = vehicleName
 | 
						|
    end
 | 
						|
    
 | 
						|
    local maxSeats = GetVehicleMaxNumberOfPassengers(vehicle) + 1 -- +1 für Fahrer
 | 
						|
    local engineHealth = math.floor(GetVehicleEngineHealth(vehicle) / 10)
 | 
						|
    local bodyHealth = math.floor(GetVehicleBodyHealth(vehicle) / 10)
 | 
						|
    local isVehicleBoat = isBoat(vehicle)
 | 
						|
    local isAnchored = isBoatAnchored(vehicle)
 | 
						|
    
 | 
						|
    local options = {
 | 
						|
        {
 | 
						|
            title = (isVehicleBoat and 'Boot: ' or 'Fahrzeug: ') .. vehicleLabel,
 | 
						|
            description = 'Kennzeichen: ' .. (vehicleProps.plate or 'Unbekannt'),
 | 
						|
            icon = isVehicleBoat and 'fas fa-ship' or 'fas fa-car',
 | 
						|
            disabled = true
 | 
						|
        },
 | 
						|
        {
 | 
						|
            title = (isVehicleBoat and 'Plätze: ' or 'Sitzplätze: ') .. maxSeats,
 | 
						|
            description = 'Maximale Anzahl Personen',
 | 
						|
            icon = 'fas fa-users',
 | 
						|
            disabled = true
 | 
						|
        }
 | 
						|
    }
 | 
						|
    
 | 
						|
    -- Anker-Status für Boote
 | 
						|
    if isVehicleBoat then
 | 
						|
        table.insert(options, {
 | 
						|
            title = 'Anker-Status: ' .. (isAnchored and 'Verankert ⚓' or 'Gelichtet ⛵'),
 | 
						|
            description = isAnchored and 'Das Boot ist an der aktuellen Position verankert' or 'Das Boot kann frei bewegt werden',
 | 
						|
            icon = 'fas fa-anchor',
 | 
						|
            disabled = true
 | 
						|
        })
 | 
						|
    end
 | 
						|
    
 | 
						|
    table.insert(options, {
 | 
						|
        title = (isVehicleBoat and 'Motor: ' or 'Motor: ') .. engineHealth .. '%',
 | 
						|
        description = 'Zustand des Motors',
 | 
						|
        icon = 'fas fa-cog',
 | 
						|
        disabled = true
 | 
						|
    })
 | 
						|
    
 | 
						|
    table.insert(options, {
 | 
						|
        title = (isVehicleBoat and 'Rumpf: ' or 'Karosserie: ') .. bodyHealth .. '%',
 | 
						|
        description = isVehicleBoat and 'Zustand des Rumpfes' or 'Zustand der Karosserie',
 | 
						|
        icon = isVehicleBoat and 'fas fa-ship' or 'fas fa-car-crash',
 | 
						|
        disabled = true
 | 
						|
    })
 | 
						|
    
 | 
						|
    -- Kraftstoff nur für Nicht-Boote
 | 
						|
    if not isVehicleBoat then
 | 
						|
        local fuelLevel = math.floor(GetVehicleFuelLevel(vehicle))
 | 
						|
        table.insert(options, {
 | 
						|
            title = 'Kraftstoff: ' .. fuelLevel .. '%',
 | 
						|
            description = 'Aktueller Tankstand',
 | 
						|
            icon = 'fas fa-gas-pump',
 | 
						|
            disabled = true
 | 
						|
        })
 | 
						|
    end
 | 
						|
    
 | 
						|
    table.insert(options, {
 | 
						|
        title = '← Zurück',
 | 
						|
        description = 'Zurück zum Sitzmenü',
 | 
						|
        icon = 'fas fa-arrow-left',
 | 
						|
        onSelect = function()
 | 
						|
            showSeatMenu(vehicle)
 | 
						|
        end
 | 
						|
    })
 | 
						|
    
 | 
						|
    lib.registerContext({
 | 
						|
        id = 'vehicle_info_menu',
 | 
						|
        title = '📋 Fahrzeuginfo',
 | 
						|
        options = options
 | 
						|
    })
 | 
						|
    
 | 
						|
    lib.showContext('vehicle_info_menu')
 | 
						|
end
 | 
						|
 | 
						|
-- QB-Target Setup
 | 
						|
CreateThread(function()
 | 
						|
    exports['qb-target']:AddGlobalVehicle({
 | 
						|
        options = {
 | 
						|
            {
 | 
						|
                type = "client",
 | 
						|
                event = "vehicle:openSeatMenu",
 | 
						|
                icon = "fas fa-car",
 | 
						|
                label = "Sitzplatz wählen",
 | 
						|
            }
 | 
						|
        },
 | 
						|
        distance = 3.0
 | 
						|
    })
 | 
						|
end)
 | 
						|
 | 
						|
-- Event Handler
 | 
						|
RegisterNetEvent('vehicle:openSeatMenu', function(data)
 | 
						|
    local vehicle = data.entity
 | 
						|
    if DoesEntityExist(vehicle) and IsEntityAVehicle(vehicle) then
 | 
						|
        showSeatMenu(vehicle)
 | 
						|
    else
 | 
						|
        QBCore.Functions.Notify('Kein gültiges Fahrzeug gefunden!', 'error')
 | 
						|
    end
 | 
						|
end)
 | 
						|
 | 
						|
-- Lade Anker beim Start
 | 
						|
CreateThread(function()
 | 
						|
    Wait(2000) -- Warte bis QBCore geladen ist
 | 
						|
    loadAnchoredBoats()
 | 
						|
end)
 | 
						|
 | 
						|
-- Cleanup verankerte Boote bei Resource Stop
 | 
						|
AddEventHandler('onResourceStop', function(resourceName)
 | 
						|
    if GetCurrentResourceName() == resourceName then
 | 
						|
        -- Alle verankerten Boote wieder freigeben (aber nicht vom Server löschen)
 | 
						|
        for vehicleNetId, _ in pairs(anchoredBoats) do
 | 
						|
            local vehicle = NetworkGetEntityFromNetworkId(vehicleNetId)
 | 
						|
            if DoesEntityExist(vehicle) then
 | 
						|
                FreezeEntityPosition(vehicle, false)
 | 
						|
                SetEntityInvincible(vehicle, false)
 | 
						|
            end
 | 
						|
        end
 | 
						|
        anchoredBoats = {}
 | 
						|
        currentVehicle = nil
 | 
						|
    end
 | 
						|
end)
 | 
						|
 | 
						|
-- Keybind für schnellen Zugriff
 | 
						|
RegisterCommand('seats', function()
 | 
						|
    local playerPed = PlayerPedId()
 | 
						|
    local vehicle = GetVehiclePedIsIn(playerPed, false)
 | 
						|
    
 | 
						|
    if vehicle ~= 0 then
 | 
						|
        showSeatMenu(vehicle)
 | 
						|
    else
 | 
						|
        local coords = GetEntityCoords(playerPed)
 | 
						|
        local closestVehicle = GetClosestVehicle(coords.x, coords.y, coords.z, 5.0, 0, 71)
 | 
						|
        
 | 
						|
        if DoesEntityExist(closestVehicle) then
 | 
						|
            showSeatMenu(closestVehicle)
 | 
						|
        else
 | 
						|
            QBCore.Functions.Notify('Kein Fahrzeug in der Nähe!', 'error')
 | 
						|
        end
 | 
						|
    end
 | 
						|
end, false)
 | 
						|
 | 
						|
-- Schneller Anker-Befehl für Kapitäne
 | 
						|
RegisterCommand('anchor', function()
 | 
						|
    local playerPed = PlayerPedId()
 | 
						|
    local vehicle = GetVehiclePedIsIn(playerPed, false)
 | 
						|
    
 | 
						|
    if vehicle ~= 0 and isBoat(vehicle) then
 | 
						|
        local currentSeat = getCurrentSeat(playerPed, vehicle)
 | 
						|
        if currentSeat == -1 then -- Nur Kapitän
 | 
						|
            toggleAnchor(vehicle)
 | 
						|
        else
 | 
						|
            QBCore.Functions.Notify('Nur der Kapitän kann den Anker bedienen!', 'error')
 | 
						|
        end
 | 
						|
    else
 | 
						|
        QBCore.Functions.Notify('Du musst Kapitän eines Bootes sein!', 'error')
 | 
						|
    end
 | 
						|
end, false)
 | 
						|
 | 
						|
-- Keybinds registrieren (F1 statt F6)
 | 
						|
RegisterKeyMapping('seats', 'Sitzplatz Menü öffnen', 'keyboard', 'F1')
 | 
						|
RegisterKeyMapping('anchor', 'Anker werfen/lichten', 'keyboard', 'H')
 |