local QBCore = exports['qb-core']:GetCoreObject() local currentTaxi = nil local currentDriver = nil local taxiBlip = nil local mapBlip = nil local destinationBlip = nil local taxiMeter = { isRunning = false, startCoords = nil, currentFare = 0, pricePerKm = 0 } print("^2[TAXI DEBUG]^7 Main script loaded") -- Taxi rufen Command RegisterCommand('taxi', function() print("^2[TAXI DEBUG]^7 Taxi command executed") if currentTaxi and DoesEntityExist(currentTaxi) then print("^1[TAXI DEBUG]^7 Taxi already exists") lib.notify({ title = 'Taxi Service', description = 'Du hast bereits ein Taxi gerufen', type = 'error' }) return end CallTaxi() end) function CallTaxi() print("^2[TAXI DEBUG]^7 CallTaxi function started") lib.notify({ title = 'Taxi Service', description = 'Taxi wird gerufen...', type = 'info' }) CreateThread(function() local playerPed = PlayerPedId() local playerCoords = GetEntityCoords(playerPed) print("^2[TAXI DEBUG]^7 Player coords: " .. tostring(playerCoords)) -- Verbesserte Spawn-Position für Taxi finden local spawnCoords = GetImprovedTaxiSpawnPosition(playerCoords) if not spawnCoords then print("^1[TAXI DEBUG]^7 No spawn position found") lib.notify({ title = 'Taxi Service', description = 'Kein geeigneter Spawn-Punkt gefunden', type = 'error' }) return end print("^2[TAXI DEBUG]^7 Spawn coords found: " .. tostring(spawnCoords.x) .. ", " .. tostring(spawnCoords.y) .. ", " .. tostring(spawnCoords.z)) -- Taxi spawnen local taxi = SpawnTaxi(spawnCoords) if not taxi then print("^1[TAXI DEBUG]^7 Failed to spawn taxi") lib.notify({ title = 'Taxi Service', description = 'Taxi konnte nicht gespawnt werden', type = 'error' }) return end print("^2[TAXI DEBUG]^7 Taxi spawned: " .. taxi) currentTaxi = taxi -- Fahrer spawnen local driver = SpawnTaxiDriver(taxi) if driver then currentDriver = driver print("^2[TAXI DEBUG]^7 Driver spawned: " .. driver) -- Verbesserte Navigation zum Spieler NavigateToPlayer(driver, taxi, playerCoords) -- Blip für Taxi erstellen (Entity-Blip) CreateTaxiBlips(taxi) -- Überwachung der Ankunft MonitorTaxiArrival(taxi, driver, playerCoords) lib.notify({ title = 'Taxi Service', description = 'Taxi ist unterwegs zu dir! Verfolge es auf der Karte.', type = 'success' }) else print("^1[TAXI DEBUG]^7 Failed to spawn driver") lib.notify({ title = 'Taxi Service', description = 'Taxi ohne Fahrer gespawnt - Du kannst es selbst fahren', type = 'warning' }) end end) end function GetImprovedTaxiSpawnPosition(playerCoords) print("^2[TAXI DEBUG]^7 Finding improved spawn position...") -- Minimale und maximale Entfernung zum Spieler local minAcceptableDistance = 50.0 -- Mindestens 50 Meter entfernt local maxAcceptableDistance = 150.0 -- Maximal 150 Meter entfernt local bestPosition = nil local bestDistance = 999999.0 -- Versuche zuerst einen Straßenknotenpunkt zu finden local roadPosition = nil local foundNode = false local nodePos = vector3(0.0, 0.0, 0.0) -- Versuche einen Straßenknotenpunkt in optimaler Entfernung zu finden -- Suche in einem größeren Radius, um mehr Optionen zu haben foundNode, nodePos = GetClosestVehicleNode(playerCoords.x, playerCoords.y, playerCoords.z, 1, 3.0, 0) if foundNode then local nodeDistance = #(playerCoords - nodePos) if nodeDistance >= minAcceptableDistance and nodeDistance <= maxAcceptableDistance then roadPosition = nodePos print("^2[TAXI DEBUG]^7 Found road node for spawn at distance: " .. nodeDistance) return {x = roadPosition.x, y = roadPosition.y, z = roadPosition.z, w = 0.0} else -- Speichern für später, falls wir nichts Besseres finden if nodeDistance < bestDistance and nodeDistance >= minAcceptableDistance then bestDistance = nodeDistance bestPosition = {x = nodePos.x, y = nodePos.y, z = nodePos.z, w = 0.0} end end end -- Versuche mehrere Knotenpunkte in verschiedenen Richtungen zu finden for i = 1, 8 do local angle = (i - 1) * 45.0 -- 8 Richtungen (0, 45, 90, 135, 180, 225, 270, 315 Grad) local searchDistance = (minAcceptableDistance + maxAcceptableDistance) / 2 local searchX = playerCoords.x + math.cos(math.rad(angle)) * searchDistance local searchY = playerCoords.y + math.sin(math.rad(angle)) * searchDistance foundNode, nodePos = GetClosestVehicleNodeWithHeading(searchX, searchY, playerCoords.z, 1, 3.0, 0) if foundNode then local nodeDistance = #(playerCoords - nodePos) if nodeDistance >= minAcceptableDistance and nodeDistance <= maxAcceptableDistance then print("^2[TAXI DEBUG]^7 Found directional node for spawn at distance: " .. nodeDistance .. " in direction " .. angle) return {x = nodePos.x, y = nodePos.y, z = nodePos.z, w = 0.0} else -- Speichern für später, falls wir nichts Besseres finden if nodeDistance < bestDistance and nodeDistance >= minAcceptableDistance then bestDistance = nodeDistance bestPosition = {x = nodePos.x, y = nodePos.y, z = nodePos.z, w = 0.0} end end end end -- Versuche einen weiteren Knotenpunkt mit größerem Radius foundNode, nodePos = GetClosestMajorVehicleNode(playerCoords.x, playerCoords.y, playerCoords.z, 100.0, 0) if foundNode then local nodeDistance = #(playerCoords - nodePos) if nodeDistance >= minAcceptableDistance and nodeDistance <= maxAcceptableDistance then roadPosition = nodePos print("^2[TAXI DEBUG]^7 Found major road node for spawn at distance: " .. nodeDistance) return {x = roadPosition.x, y = roadPosition.y, z = roadPosition.z, w = 0.0} else -- Speichern für später, falls wir nichts Besseres finden if nodeDistance < bestDistance and nodeDistance >= minAcceptableDistance then bestDistance = nodeDistance bestPosition = {x = nodePos.x, y = nodePos.y, z = nodePos.z, w = 0.0} end end end -- Fallback auf Config-Positionen if Config.MobileTaxiSpawns and #Config.MobileTaxiSpawns > 0 then -- Alle Spawn-Positionen nach Entfernung sortieren local sortedSpawns = {} for i, spawnPos in ipairs(Config.MobileTaxiSpawns) do local distance = #(playerCoords - vector3(spawnPos.x, spawnPos.y, spawnPos.z)) if distance >= minAcceptableDistance then table.insert(sortedSpawns, { coords = spawnPos, distance = distance }) end end -- Nach Entfernung sortieren (nächste zuerst, aber mindestens minAcceptableDistance entfernt) table.sort(sortedSpawns, function(a, b) return a.distance < b.distance end) -- Prüfen ob die nächsten Positionen frei und nah genug sind for i, spawn in ipairs(sortedSpawns) do local spawnCoords = spawn.coords -- Wenn Position zu weit weg ist, überspringen if spawn.distance > maxAcceptableDistance then -- Speichern für später, falls wir nichts Besseres finden if spawn.distance < bestDistance then bestDistance = spawn.distance bestPosition = spawnCoords end goto continue end -- Prüfen ob Position frei ist local clearArea = true local vehicles = GetGamePool('CVehicle') -- Prüfen ob andere Fahrzeuge in der Nähe sind for _, vehicle in ipairs(vehicles) do local vehCoords = GetEntityCoords(vehicle) if #(vector3(spawnCoords.x, spawnCoords.y, spawnCoords.z) - vehCoords) < 5.0 then clearArea = false break end end -- Wenn Position frei ist, verwenden if clearArea then print("^2[TAXI DEBUG]^7 Using spawn position from config: " .. tostring(spawnCoords.x) .. ", " .. tostring(spawnCoords.y) .. ", " .. tostring(spawnCoords.z) .. " (Distance: " .. spawn.distance .. "m)") return spawnCoords end ::continue:: end end -- Wenn wir hier sind, haben wir keine ideale Position gefunden -- Wenn wir eine "beste" Position haben, die den Mindestabstand einhält, verwenden wir diese if bestPosition and bestDistance >= minAcceptableDistance then print("^3[TAXI DEBUG]^7 Using best available position at " .. bestDistance .. "m") return bestPosition end -- Wenn alles fehlschlägt: Generiere eine zufällige Position in der Nähe des Spielers print("^3[TAXI DEBUG]^7 Generating random position between " .. minAcceptableDistance .. "m and " .. maxAcceptableDistance .. "m of player") -- Versuche bis zu 15 Mal, eine gültige Position zu finden for attempt = 1, 15 do -- Zufällige Position im Umkreis, aber mindestens minAcceptableDistance entfernt local angle = math.random() * 2 * math.pi local distance = math.random(minAcceptableDistance, maxAcceptableDistance) local x = playerCoords.x + math.cos(angle) * distance local y = playerCoords.y + math.sin(angle) * distance local z = playerCoords.z -- Versuche eine gültige Z-Koordinate zu bekommen local success, groundZ = GetGroundZFor_3dCoord(x, y, z, true) if success then -- Prüfe ob die Position auf einer Straße ist local isOnRoad = IsPointOnRoad(x, y, groundZ) if isOnRoad then print("^2[TAXI DEBUG]^7 Found random position on road at distance: " .. distance) return {x = x, y = y, z = groundZ, w = 0.0} end end end -- Absolute Notfall-Fallback: Einfach irgendwo in der Nähe, aber mindestens minAcceptableDistance entfernt local angle = math.random() * 2 * math.pi local distance = math.random(minAcceptableDistance, maxAcceptableDistance) local x = playerCoords.x + math.cos(angle) * distance local y = playerCoords.y + math.sin(angle) * distance local z = playerCoords.z -- Versuche eine gültige Z-Koordinate zu bekommen local success, groundZ = GetGroundZFor_3dCoord(x, y, z, true) if success then z = groundZ end print("^3[TAXI DEBUG]^7 Using emergency random spawn position at distance: " .. distance) return {x = x, y = y, z = z, w = 0.0} end function SpawnTaxi(coords) print("^2[TAXI DEBUG]^7 Spawning taxi at: " .. tostring(coords.x) .. ", " .. tostring(coords.y) .. ", " .. tostring(coords.z)) -- Sicherstellen dass wir ein gültiges Taxi-Model haben local taxiModel = nil if Config.TaxiVehicles and #Config.TaxiVehicles > 0 then -- Zufälliges Taxi-Model aus Config wählen local randomIndex = math.random(1, #Config.TaxiVehicles) taxiModel = GetHashKey(Config.TaxiVehicles[randomIndex].model) else taxiModel = GetHashKey("taxi") -- Fallback end print("^2[TAXI DEBUG]^7 Taxi model hash: " .. taxiModel) -- Model laden mit Timeout RequestModel(taxiModel) local modelLoaded = false local timeout = GetGameTimer() + 10000 while not modelLoaded and GetGameTimer() < timeout do modelLoaded = HasModelLoaded(taxiModel) if not modelLoaded then print("^3[TAXI DEBUG]^7 Waiting for taxi model to load...") Wait(100) end end if not modelLoaded then print("^1[TAXI DEBUG]^7 Failed to load taxi model! Trying default model.") SetModelAsNoLongerNeeded(taxiModel) -- Versuche Standard-Taxi als Fallback taxiModel = GetHashKey("taxi") RequestModel(taxiModel) timeout = GetGameTimer() + 5000 while not HasModelLoaded(taxiModel) and GetGameTimer() < timeout do Wait(100) end if not HasModelLoaded(taxiModel) then print("^1[TAXI DEBUG]^7 Failed to load default taxi model!") return nil end end -- Fahrzeug erstellen local taxi = CreateVehicle(taxiModel, coords.x, coords.y, coords.z, coords.w or 0.0, true, false) if not DoesEntityExist(taxi) then print("^1[TAXI DEBUG]^7 Failed to create taxi vehicle!") return nil end print("^2[TAXI DEBUG]^7 Taxi created successfully: " .. taxi) -- Fahrzeug konfigurieren SetEntityAsMissionEntity(taxi, true, true) SetVehicleOnGroundProperly(taxi) SetVehicleEngineOn(taxi, true, true, false) SetVehicleDoorsLocked(taxi, 2) -- Locked initially -- Verbesserte Persistenz SetEntityInvincible(taxi, true) SetVehicleCanBeVisiblyDamaged(taxi, false) SetEntityProofs(taxi, true, true, true, true, true, true, true, true) SetVehicleExplodesOnHighExplosionDamage(taxi, false) SetVehicleHasBeenOwnedByPlayer(taxi, true) SetVehicleIsConsideredByPlayer(taxi, true) -- Taxi-Livery setzen falls verfügbar local liveryCount = GetVehicleLiveryCount(taxi) if liveryCount > 0 then SetVehicleLivery(taxi, 0) -- Erste Livery verwenden print("^2[TAXI DEBUG]^7 Taxi livery set") end -- Fahrzeug-Extras aktivieren falls vorhanden for i = 1, 14 do if DoesExtraExist(taxi, i) then SetVehicleExtra(taxi, i, false) -- Extra aktivieren end end -- Fahrzeug-Farbe setzen (Gelb für Taxis) SetVehicleColours(taxi, 88, 88) -- Taxi Yellow SetModelAsNoLongerNeeded(taxiModel) return taxi end -- Fortgeschrittenes Taxi-Fahrer-Verhaltenssystem function InitializeTaxiDriverAI(driver, vehicle) if not driver or not DoesEntityExist(driver) then return end print("^2[TAXI DEBUG]^7 Initializing advanced taxi driver AI") -- Fahrer-Persönlichkeit und Fähigkeiten zufällig festlegen local driverData = { personality = { patience = math.random(7, 10) / 10, -- 0.7-1.0: Wie geduldig ist der Fahrer caution = math.random(6, 10) / 10, -- 0.6-1.0: Wie vorsichtig fährt er speedPreference = math.random(15, 25), -- 15-25: Bevorzugte Geschwindigkeit trafficRuleCompliance = math.random(8, 10)/10 -- 0.8-1.0: Wie genau hält er Verkehrsregeln ein }, state = { stuckCounter = 0, lastStuckRecovery = 0, lastRouteRecalculation = 0, currentBehavior = "normal", -- normal, cautious, stuck, recovery lastSpeedCheck = 0, speedHistory = {}, lastPositions = {}, trafficLightWaitStart = 0, isWaitingAtTrafficLight = false }, settings = { maxStuckCounter = math.random(15, 25), -- Wie lange warten bis Befreiungsversuch stuckThreshold = 0.5, -- Bewegungsschwelle für Steckenbleiben checkInterval = 2000, -- Überprüfungsintervall in ms positionHistorySize = 5, -- Anzahl der zu speichernden Positionen minRecoveryInterval = 25000, -- Min. Zeit zwischen Befreiungsversuchen minRouteRecalcInterval = 30000, -- Min. Zeit zwischen Routenneuberechnungen trafficLightMaxWait = 45000 -- Max. Wartezeit an Ampeln } } -- Fahrer-Verhalten basierend auf Persönlichkeit einstellen SetDriverAbility(driver, driverData.personality.caution) SetDriverAggressiveness(driver, 1.0 - driverData.personality.caution) -- Fahrer-Daten im Entity speichern Entity(vehicle).state.driverData = driverData -- Fahrer-Verhalten-Thread starten CreateThread(function() local lastPos = GetEntityCoords(vehicle) local lastCheck = GetGameTimer() while DoesEntityExist(vehicle) and DoesEntityExist(driver) do Wait(driverData.settings.checkInterval) local currentTime = GetGameTimer() local timeDelta = currentTime - lastCheck lastCheck = currentTime -- Aktuelle Position und Geschwindigkeit local currentPos = GetEntityCoords(vehicle) local speed = GetEntitySpeed(vehicle) local distanceMoved = #(lastPos - currentPos) -- Position für Historie speichern table.insert(driverData.state.lastPositions, 1, currentPos) if #driverData.state.lastPositions > driverData.settings.positionHistorySize then table.remove(driverData.state.lastPositions) end -- Geschwindigkeit für Historie speichern table.insert(driverData.state.speedHistory, 1, speed) if #driverData.state.speedHistory > 5 then table.remove(driverData.state.speedHistory) end -- Durchschnittsgeschwindigkeit berechnen local avgSpeed = 0 for _, s in ipairs(driverData.state.speedHistory) do avgSpeed = avgSpeed + s end avgSpeed = avgSpeed / #driverData.state.speedHistory -- Ampel-Erkennung local isAtTrafficLight = IsVehicleStoppedAtTrafficLights(vehicle) -- Ampel-Wartezustand aktualisieren if isAtTrafficLight and not driverData.state.isWaitingAtTrafficLight then -- Gerade an Ampel angekommen driverData.state.isWaitingAtTrafficLight = true driverData.state.trafficLightWaitStart = currentTime print("^3[TAXI DEBUG]^7 Taxi waiting at traffic light") elseif isAtTrafficLight and driverData.state.isWaitingAtTrafficLight then -- Immer noch an Ampel local waitTime = currentTime - driverData.state.trafficLightWaitStart -- Wenn zu lange an Ampel, versuche weiterzufahren (Ampel könnte hängen) if waitTime > driverData.settings.trafficLightMaxWait then print("^3[TAXI DEBUG]^7 Taxi waited too long at traffic light, trying to continue") -- Kurz vorwärts fahren um Ampel zu überwinden TaskVehicleTempAction(driver, vehicle, 1, 2000) -- Forward Wait(2000) -- Dann normale Fahrt fortsetzen TaxiDriverContinueRoute(driver, vehicle) driverData.state.isWaitingAtTrafficLight = false end elseif not isAtTrafficLight and driverData.state.isWaitingAtTrafficLight then -- Ampel verlassen driverData.state.isWaitingAtTrafficLight = false print("^2[TAXI DEBUG]^7 Taxi continued after traffic light") end -- Steckenbleiben-Erkennung (nicht an Ampel und kaum Bewegung) if not isAtTrafficLight and distanceMoved < driverData.settings.stuckThreshold and speed < 0.5 then driverData.state.stuckCounter = driverData.state.stuckCounter + 1 -- Nur alle 5 Zähler-Erhöhungen loggen if driverData.state.stuckCounter % 5 == 0 then print("^3[TAXI DEBUG]^7 Taxi might be stuck: " .. driverData.state.stuckCounter .. "/" .. driverData.settings.maxStuckCounter) end -- Wenn lange genug steckengeblieben und genug Zeit seit letztem Versuch if driverData.state.stuckCounter >= driverData.settings.maxStuckCounter and (currentTime - driverData.state.lastStuckRecovery) > driverData.settings.minRecoveryInterval then print("^1[TAXI DEBUG]^7 Taxi is stuck, attempting intelligent recovery") driverData.state.lastStuckRecovery = currentTime driverData.state.currentBehavior = "recovery" -- Intelligente Befreiung basierend auf Umgebung TaxiDriverIntelligentRecovery(driver, vehicle) -- Steckenbleiben-Zähler teilweise zurücksetzen driverData.state.stuckCounter = math.floor(driverData.settings.maxStuckCounter * 0.4) end else -- Wenn sich das Fahrzeug bewegt oder an einer Ampel steht if isAtTrafficLight then -- An Ampel: Zähler langsamer reduzieren driverData.state.stuckCounter = math.max(0, driverData.state.stuckCounter - 0.2) else -- In Bewegung: Zähler reduzieren driverData.state.stuckCounter = math.max(0, driverData.state.stuckCounter - 1) -- Wenn Fahrzeug sich bewegt, aber sehr langsam über längere Zeit if avgSpeed < 2.0 and driverData.state.stuckCounter > driverData.settings.maxStuckCounter * 0.5 and (currentTime - driverData.state.lastRouteRecalculation) > driverData.settings.minRouteRecalcInterval then print("^3[TAXI DEBUG]^7 Taxi moving too slow, recalculating route") driverData.state.lastRouteRecalculation = currentTime -- Route neu berechnen TaxiDriverRecalculateRoute(driver, vehicle) end end end -- Verhalten basierend auf Umgebung anpassen TaxiDriverAdaptBehavior(driver, vehicle, driverData) lastPos = currentPos end end) return driverData end -- Intelligente Befreiung bei Steckenbleiben function TaxiDriverIntelligentRecovery(driver, vehicle) if not DoesEntityExist(vehicle) or not DoesEntityExist(driver) then return end -- Aktuelle Position und Umgebung analysieren local vehicleCoords = GetEntityCoords(vehicle) local vehicleHeading = GetEntityHeading(vehicle) local vehicleForwardVector = GetEntityForwardVector(vehicle) -- Prüfen ob Hindernisse vorne, hinten, links, rechts local forwardClear = not IsPositionOccupied( vehicleCoords.x + vehicleForwardVector.x * 4.0, vehicleCoords.y + vehicleForwardVector.y * 4.0, vehicleCoords.z, 1.0, false, true, false, false, false, 0, false ) local backwardClear = not IsPositionOccupied( vehicleCoords.x - vehicleForwardVector.x * 4.0, vehicleCoords.y - vehicleForwardVector.y * 4.0, vehicleCoords.z, 1.0, false, true, false, false, false, 0, false ) -- Befreiungsstrategie basierend auf Umgebung ClearPedTasks(driver) if backwardClear then -- Rückwärts fahren wenn hinten frei print("^3[TAXI DEBUG]^7 Recovery: Backing up") TaskVehicleTempAction(driver, vehicle, 8, 2000) -- Reverse Wait(2000) if forwardClear then -- Wenn vorne auch frei, einfach weiterfahren print("^3[TAXI DEBUG]^7 Recovery: Path clear, continuing") TaxiDriverContinueRoute(driver, vehicle) else -- Sonst versuchen zu wenden print("^3[TAXI DEBUG]^7 Recovery: Turning around") TaskVehicleTempAction(driver, vehicle, 7, 2000) -- Turn left Wait(1000) TaskVehicleTempAction(driver, vehicle, 8, 1000) -- Reverse Wait(1000) TaskVehicleTempAction(driver, vehicle, 6, 2000) -- Turn right Wait(1000) TaxiDriverContinueRoute(driver, vehicle) end elseif forwardClear then -- Wenn nur vorne frei, vorwärts fahren print("^3[TAXI DEBUG]^7 Recovery: Moving forward") TaskVehicleTempAction(driver, vehicle, 1, 2000) -- Forward Wait(2000) TaxiDriverContinueRoute(driver, vehicle) else -- Wenn komplett eingeklemmt, versuche zu rütteln print("^3[TAXI DEBUG]^7 Recovery: Trying to wiggle free") TaskVehicleTempAction(driver, vehicle, 7, 1000) -- Turn left Wait(1000) TaskVehicleTempAction(driver, vehicle, 8, 800) -- Reverse Wait(800) TaskVehicleTempAction(driver, vehicle, 6, 1000) -- Turn right Wait(1000) TaskVehicleTempAction(driver, vehicle, 1, 800) -- Forward Wait(800) TaxiDriverContinueRoute(driver, vehicle) end end -- Route neu berechnen function TaxiDriverRecalculateRoute(driver, vehicle) if not DoesEntityExist(vehicle) or not DoesEntityExist(driver) then return end -- Aktuelle Zielposition aus dem Fahrzeug-State ermitteln local destination = Entity(vehicle).state.currentDestination if destination then -- Versuche einen alternativen Weg zu finden print("^3[TAXI DEBUG]^7 Recalculating route to destination") -- Kurz anhalten TaskVehicleTempAction(driver, vehicle, 27, 1000) -- Stop Wait(1000) -- Neue Route mit leicht geändertem Fahrstil local drivingStyle = 786603 -- Normal/Vorsichtig TaskVehicleDriveToCoordLongrange(driver, vehicle, destination.x, destination.y, destination.z, 20.0, drivingStyle, 10.0) else -- Wenn kein Ziel bekannt, einfach weiterfahren TaxiDriverContinueRoute(driver, vehicle) end end -- Normale Fahrt fortsetzen function TaxiDriverContinueRoute(driver, vehicle) if not DoesEntityExist(vehicle) or not DoesEntityExist(driver) then return end -- Ziel aus dem Fahrzeug-State holen local destination = Entity(vehicle).state.currentDestination if destination then -- Zum Ziel fahren mit angepasster Fahrweise local drivingStyle = 786603 -- Normal/Vorsichtig TaskVehicleDriveToCoordLongrange(driver, vehicle, destination.x, destination.y, destination.z, 20.0, drivingStyle, 10.0) else -- Wenn kein Ziel bekannt, einfach geradeaus fahren TaskVehicleDriveWander(driver, vehicle, 15.0, 786603) end end -- Fahrverhalten an Umgebung anpassen function TaxiDriverAdaptBehavior(driver, vehicle, driverData) if not DoesEntityExist(vehicle) or not DoesEntityExist(driver) then return end -- Aktuelle Geschwindigkeit und Position local speed = GetEntitySpeed(vehicle) local vehicleCoords = GetEntityCoords(vehicle) -- Verkehrsdichte in der Umgebung prüfen local vehiclesNearby = 0 local vehicles = GetGamePool('CVehicle') for _, otherVehicle in ipairs(vehicles) do if otherVehicle ~= vehicle then local otherCoords = GetEntityCoords(otherVehicle) local distance = #(vehicleCoords - otherCoords) if distance < 15.0 then vehiclesNearby = vehiclesNearby + 1 end end end -- Verhalten basierend auf Verkehrsdichte anpassen local targetSpeed = driverData.personality.speedPreference if vehiclesNearby > 5 then -- Viel Verkehr: langsamer und vorsichtiger targetSpeed = targetSpeed * 0.7 SetDriverAggressiveness(driver, 0.0) elseif vehiclesNearby > 2 then -- Moderater Verkehr: etwas langsamer targetSpeed = targetSpeed * 0.85 SetDriverAggressiveness(driver, 0.1) else -- Wenig Verkehr: normale Geschwindigkeit SetDriverAggressiveness(driver, 0.2) end -- Geschwindigkeit anpassen wenn nötig if math.abs(speed - targetSpeed) > 5.0 then if speed < targetSpeed then -- Beschleunigen TaskVehicleTempAction(driver, vehicle, 23, 500) -- Gentle forward else -- Abbremsen TaskVehicleTempAction(driver, vehicle, 24, 500) -- Gentle brake end -- Nach der Anpassung normale Fahrt fortsetzen Wait(500) TaxiDriverContinueRoute(driver, vehicle) end end -- Hilfsfunktion zur Normalisierung eines Vektors function norm(vector) local length = math.sqrt(vector.x * vector.x + vector.y * vector.y + vector.z * vector.z) if length == 0 then return vector3(0.0, 0.0, 0.0) end return vector3(vector.x / length, vector.y / length, vector.z / length) end function SpawnTaxiDriver(vehicle) print("^2[TAXI DEBUG]^7 Spawning taxi driver...") -- Bessere Fahrer-Models mit Fallbacks local driverModels = { "A_C_Chimp", -- Taxi Driver (erste Wahl) "a_m_y_business_01", -- Business Male "a_m_m_business_01", -- Business Male 2 "mp_m_freemode_01", -- Male Freemode "a_m_y_downtown_01", -- Downtown Male "a_m_m_farmer_01", -- Farmer "a_m_y_hipster_01", -- Hipster "a_m_y_beach_01" -- Beach Guy } local driver = nil local driverHash = nil -- Versuche verschiedene Models for i, modelName in ipairs(driverModels) do print("^2[TAXI DEBUG]^7 Trying driver model " .. i .. ": " .. modelName) driverHash = GetHashKey(modelName) -- Model laden RequestModel(driverHash) local timeout = GetGameTimer() + 8000 -- Längere Wartezeit local attempts = 0 while not HasModelLoaded(driverHash) and GetGameTimer() < timeout do attempts = attempts + 1 if attempts % 10 == 0 then -- Alle 1 Sekunde loggen print("^3[TAXI DEBUG]^7 Still waiting for model " .. modelName .. " (attempt " .. attempts .. ")") end Wait(100) end if HasModelLoaded(driverHash) then print("^2[TAXI DEBUG]^7 Model " .. modelName .. " loaded successfully after " .. attempts .. " attempts") -- Fahrer erstellen driver = CreatePedInsideVehicle(vehicle, 26, driverHash, -1, true, false) if DoesEntityExist(driver) then print("^2[TAXI DEBUG]^7 Driver created successfully with model: " .. modelName .. " (ID: " .. driver .. ")") break else print("^1[TAXI DEBUG]^7 Failed to create driver with loaded model: " .. modelName) SetModelAsNoLongerNeeded(driverHash) end else print("^1[TAXI DEBUG]^7 Failed to load driver model: " .. modelName) SetModelAsNoLongerNeeded(driverHash) end end -- Wenn immer noch kein Fahrer erstellt wurde if not driver or not DoesEntityExist(driver) then print("^1[TAXI DEBUG]^7 Could not create any driver! Continuing without driver...") return nil end -- Fahrer konfigurieren print("^2[TAXI DEBUG]^7 Configuring driver...") SetEntityAsMissionEntity(driver, true, true) SetBlockingOfNonTemporaryEvents(driver, true) SetPedFleeAttributes(driver, 0, 0) SetPedCombatAttributes(driver, 17, 1) SetPedSeeingRange(driver, 0.0) SetPedHearingRange(driver, 0.0) SetPedAlertness(driver, 0) SetPedKeepTask(driver, true) -- Fortgeschrittene KI-ähnliche Fahrer-Logik initialisieren local driverData = InitializeTaxiDriverAI(driver, vehicle) -- Zufälligen Fahrer-Namen generieren local firstNames = {"Max", "Thomas", "Ali", "Mehmet", "Hans", "Peter", "Klaus", "Michael", "Stefan", "Frank"} local lastNames = {"Müller", "Schmidt", "Schneider", "Fischer", "Weber", "Meyer", "Wagner", "Becker", "Schulz", "Hoffmann"} local driverName = firstNames[math.random(#firstNames)] .. " " .. lastNames[math.random(#lastNames)] -- Fahrer-Name im Fahrzeug-State speichern Entity(vehicle).state.driverName = driverName -- Fahrer-Outfit (nur wenn es ein anpassbarer Ped ist) if driverHash == GetHashKey("mp_m_freemode_01") then print("^2[TAXI DEBUG]^7 Setting driver outfit...") -- Basis-Outfit für Taxi-Fahrer SetPedComponentVariation(driver, 0, 0, 0, 0) -- Face SetPedComponentVariation(driver, 2, 1, 0, 0) -- Hair SetPedComponentVariation(driver, 8, 15, 0, 0) -- Undershirt SetPedComponentVariation(driver, 11, 91, 0, 0) -- Jacket SetPedComponentVariation(driver, 4, 10, 0, 0) -- Pants SetPedComponentVariation(driver, 6, 10, 0, 0) -- Shoes SetPedComponentVariation(driver, 1, 0, 0, 0) -- Mask SetPedComponentVariation(driver, 3, 0, 0, 0) -- Arms SetPedComponentVariation(driver, 5, 0, 0, 0) -- Bag SetPedComponentVariation(driver, 7, 0, 0, 0) -- Tie SetPedComponentVariation(driver, 9, 0, 0, 0) -- Body Armor SetPedComponentVariation(driver, 10, 0, 0, 0) -- Decals -- Zufällige Gesichtsmerkmale SetPedHeadBlendData(driver, math.random(0, 20), math.random(0, 20), 0, math.random(0, 20), math.random(0, 20), 0, 0.5, 0.5, 0.0, false) end -- Model nicht mehr benötigt if driverHash then SetModelAsNoLongerNeeded(driverHash) end print("^2[TAXI DEBUG]^7 Driver spawn completed successfully") return driver end function CreateTaxiBlips(taxi) -- Blip für Taxi erstellen (Entity-Blip) taxiBlip = AddBlipForEntity(taxi) SetBlipSprite(taxiBlip, 198) SetBlipColour(taxiBlip, 5) SetBlipScale(taxiBlip, 0.8) SetBlipDisplay(taxiBlip, 2) -- Zeigt auf Minimap und großer Karte SetBlipShowCone(taxiBlip, true) -- Zeigt Sichtkegel SetBlipAsShortRange(taxiBlip, false) -- Immer sichtbar, egal wie weit entfernt BeginTextCommandSetBlipName("STRING") AddTextComponentString("Dein Taxi") EndTextCommandSetBlipName(taxiBlip) -- Zusätzlicher Blip auf der Karte für bessere Sichtbarkeit local taxiCoords = GetEntityCoords(taxi) mapBlip = AddBlipForCoord(taxiCoords.x, taxiCoords.y, taxiCoords.z) SetBlipSprite(mapBlip, 198) SetBlipColour(mapBlip, 5) SetBlipScale(mapBlip, 1.0) SetBlipDisplay(mapBlip, 4) -- Nur auf großer Karte BeginTextCommandSetBlipName("STRING") AddTextComponentString("Dein Taxi") EndTextCommandSetBlipName(mapBlip) -- Blip aktualisieren während Taxi unterwegs ist CreateThread(function() while DoesEntityExist(taxi) and mapBlip do local taxiCoords = GetEntityCoords(taxi) SetBlipCoords(mapBlip, taxiCoords.x, taxiCoords.y, taxiCoords.z) Wait(1000) end -- Blip entfernen wenn Thread beendet if mapBlip then RemoveBlip(mapBlip) mapBlip = nil end end) end function NavigateToPlayer(driver, taxi, playerCoords) print("^2[TAXI DEBUG]^7 Navigating taxi to player...") -- Ziel im Fahrzeug-State speichern für die KI-Logik Entity(taxi).state.currentDestination = playerCoords -- Versuche einen guten Wegpunkt in der Nähe des Spielers zu finden local success, nodePos = GetClosestVehicleNodeWithHeading(playerCoords.x, playerCoords.y, playerCoords.z, 1, 3.0, 0) if success then print("^2[TAXI DEBUG]^7 Found good vehicle node near player") -- Zum Wegpunkt fahren TaskVehicleDriveToCoordLongrange(driver, taxi, nodePos.x, nodePos.y, nodePos.z, 20.0, 786603, 10.0) else print("^3[TAXI DEBUG]^7 No good vehicle node found, driving directly to player") -- Direkt zum Spieler fahren TaskVehicleDriveToCoordLongrange(driver, taxi, playerCoords.x, playerCoords.y, playerCoords.z, 20.0, 786603, 10.0) end end function MonitorTaxiArrival(taxi, driver, playerCoords) print("^2[TAXI DEBUG]^7 Monitoring taxi arrival...") local arrivalTimeout = GetGameTimer() + (120 * 1000) -- 2 minute timeout CreateThread(function() while DoesEntityExist(taxi) and (not driver or DoesEntityExist(driver)) do local taxiCoords = GetEntityCoords(taxi) local currentPlayerCoords = GetEntityCoords(PlayerPedId()) local distance = #(currentPlayerCoords - taxiCoords) -- Check if taxi is close to player if distance < 15.0 then print("^2[TAXI DEBUG]^7 Taxi arrived!") -- Taxi stoppen if driver and DoesEntityExist(driver) then TaskVehicleTempAction(driver, taxi, 27, 3000) -- Brake Wait(2000) SetVehicleDoorsLocked(taxi, 1) -- Unlock doors end lib.notify({ title = 'Taxi Service', description = 'Dein Taxi ist angekommen! Steige ein.', type = 'success' }) -- qb-target für Einsteigen hinzufügen exports['qb-target']:AddTargetEntity(taxi, { options = { { type = "client", event = "taxi:enterTaxi", icon = "fas fa-car-side", label = "Ins Taxi einsteigen" } }, distance = 3.0 }) break end -- Check for timeout if GetGameTimer() > arrivalTimeout then print("^1[TAXI DEBUG]^7 Taxi arrival timed out!") lib.notify({ title = 'Taxi Service', description = 'Dein Taxi steckt fest. Ein neues wird gerufen!', type = 'warning' }) -- Despawn current taxi and call a new one DespawnTaxi() Wait(1000) CallTaxi() break end Wait(2000) end end) end -- Event für Einsteigen ins Taxi RegisterNetEvent('taxi:enterTaxi', function() print("^2[TAXI DEBUG]^7 Player entering taxi") if not currentTaxi or not DoesEntityExist(currentTaxi) then print("^1[TAXI DEBUG]^7 No taxi exists") return end local playerPed = PlayerPedId() -- Spieler hinten einsteigen lassen local seatIndex = 1 -- Hinten links if not IsVehicleSeatFree(currentTaxi, 1) then seatIndex = 2 -- Hinten rechts end if not IsVehicleSeatFree(currentTaxi, seatIndex) then seatIndex = 0 -- Beifahrer als Fallback end TaskEnterVehicle(playerPed, currentTaxi, 10000, seatIndex, 1.0, 1, 0) -- Warten bis eingestiegen CreateThread(function() local timeout = GetGameTimer() + 10000 local entered = false while GetGameTimer() < timeout and not entered do if IsPedInVehicle(playerPed, currentTaxi, false) then entered = true print("^2[TAXI DEBUG]^7 Player entered taxi successfully") -- qb-target entfernen exports['qb-target']:RemoveTargetEntity(currentTaxi) lib.notify({ title = 'Taxi Service', description = 'Willkommen im Taxi! Wähle dein Ziel.', type = 'success' }) -- Ziel-Menu öffnen Wait(1000) OpenDestinationMenu() end Wait(100) end if not entered then print("^1[TAXI DEBUG]^7 Player failed to enter taxi") lib.notify({ title = 'Taxi Service', description = 'Einsteigen fehlgeschlagen', type = 'error' }) end end) end) function OpenDestinationMenu() print("^2[TAXI DEBUG]^7 Opening destination menu") local options = {} -- Bekannte Ziele hinzufügen for _, destination in pairs(Config.KnownDestinations) do local distance = CalculateDistanceToCoords(destination.coords) / 1000 -- in km local price = math.max(Config.MinFare, math.ceil(distance * Config.PricePerKm)) table.insert(options, { title = destination.name, description = 'Preis: $' .. price .. ' | Entfernung: ' .. math.ceil(distance * 100) / 100 .. 'km', icon = 'map-marker', onSelect = function() StartTaxiRide(destination.coords, price) end }) end -- Waypoint Option table.insert(options, { title = 'Zu meinem Waypoint', description = 'Fahre zu deinem gesetzten Waypoint', icon = 'location-dot', onSelect = function() local waypoint = GetFirstBlipInfoId(8) if DoesBlipExist(waypoint) then local coords = GetBlipInfoIdCoord(waypoint) local distance = CalculateDistanceToCoords(coords) / 1000 local price = math.max(Config.MinFare, math.ceil(distance * Config.PricePerKm)) StartTaxiRide(coords, price) else lib.notify({ title = 'Taxi Service', description = 'Du hast keinen Waypoint gesetzt', type = 'error' }) OpenDestinationMenu() end end }) -- Selbst fahren Option (wenn kein Fahrer) if not currentDriver or not DoesEntityExist(currentDriver) then table.insert(options, { title = '🚗 Selbst fahren', description = 'Du fährst das Taxi selbst', icon = 'car', onSelect = function() SelfDriveTaxi() end }) end -- Aussteigen Option table.insert(options, { title = 'Aussteigen', description = 'Das Taxi verlassen', icon = 'door-open', onSelect = function() ExitTaxi() end }) lib.registerContext({ id = 'taxi_destination_menu', title = 'Taxi - Ziel wählen', options = options }) lib.showContext('taxi_destination_menu') end function StartTaxiRide(destination, price) print("^2[TAXI DEBUG]^7 Starting taxi ride to: " .. tostring(destination.x) .. ", " .. tostring(destination.y) .. ", " .. tostring(destination.z)) if not currentTaxi or not DoesEntityExist(currentTaxi) then print("^1[TAXI DEBUG]^7 No taxi exists for ride") return end -- Wenn kein Fahrer, Spieler selbst fahren lassen if not currentDriver or not DoesEntityExist(currentDriver) then lib.notify({ title = 'Taxi Service', description = 'Kein Fahrer verfügbar. Du musst selbst fahren!', type = 'warning' }) return end lib.notify({ title = 'Taxi Service', description = 'Fahrt gestartet - Preis: $' .. price, type = 'success' }) -- Destination Blip erstellen if destinationBlip then RemoveBlip(destinationBlip) end destinationBlip = AddBlipForCoord(destination.x, destination.y, destination.z) SetBlipSprite(destinationBlip, 1) SetBlipColour(destinationBlip, 2) SetBlipScale(destinationBlip, 0.8) SetBlipRoute(destinationBlip, true) BeginTextCommandSetBlipName("STRING") AddTextComponentString("Taxi Ziel") EndTextCommandSetBlipName(destinationBlip) -- Taximeter starten taxiMeter.isRunning = true taxiMeter.startCoords = GetEntityCoords(currentTaxi) taxiMeter.currentFare = 0 taxiMeter.pricePerKm = Config.PricePerKm -- Ziel im Fahrzeug-State speichern für die KI-Logik Entity(currentTaxi).state.currentDestination = destination -- Zum Ziel fahren mit verbesserter Navigation local drivingStyle = 786603 -- Normal/Vorsichtig TaskVehicleDriveToCoordLongrange(currentDriver, currentTaxi, destination.x, destination.y, destination.z, 20.0, drivingStyle, 10.0) -- Fahrer-Dialog anzeigen local driverName = Entity(currentTaxi).state.driverName or "Taxi-Fahrer" local dialogOptions = { "Ich bringe dich sicher ans Ziel.", "Schönes Wetter heute, oder?", "Ich kenne eine Abkürzung.", "Bist du aus der Gegend?", "Ich fahre schon seit 15 Jahren Taxi.", "Entspann dich und genieße die Fahrt." } -- Zufälligen Dialog auswählen und anzeigen Wait(3000) -- Kurz warten bevor der Fahrer spricht lib.notify({ title = driverName, description = dialogOptions[math.random(#dialogOptions)], type = 'info', icon = 'comment', position = 'top-center', duration = 5000 }) -- Fahrt überwachen MonitorTaxiRide(destination, price) end function MonitorTaxiRide(destination, price) print("^2[TAXI DEBUG]^7 Monitoring taxi ride...") local rideTimeout = GetGameTimer() + (10 * 60 * 1000) -- 10 Minuten Timeout CreateThread(function() while DoesEntityExist(currentTaxi) and DoesEntityExist(currentDriver) do local taxiCoords = GetEntityCoords(currentTaxi) local distance = #(vector3(destination.x, destination.y, destination.z) - taxiCoords) -- Überprüfen ob wir angekommen sind if distance < 10.0 then -- Angekommen TaskVehicleTempAction(currentDriver, currentTaxi, 27, 3000) print("^2[TAXI DEBUG]^7 Arrived at destination") lib.notify({ title = 'Taxi Service', description = 'Du bist angekommen! Preis: $' .. price, type = 'success' }) -- Bezahlung TriggerServerEvent('taxi:payFare', price) -- Blips entfernen if destinationBlip then RemoveBlip(destinationBlip) destinationBlip = nil end -- Fahrer-Dialog anzeigen local driverName = Entity(currentTaxi).state.driverName or "Taxi-Fahrer" local arrivalDialogs = { "Wir sind da! Das macht dann $" .. price .. ".", "Angekommen! $" .. price .. " bitte.", "Hier sind wir. $" .. price .. ", bargeldlos ist auch möglich.", "Ziel erreicht! Das macht $" .. price .. "." } lib.notify({ title = driverName, description = arrivalDialogs[math.random(#arrivalDialogs)], type = 'info', icon = 'comment', position = 'top-center', duration = 5000 }) -- Nach 10 Sekunden Taxi despawnen SetTimeout(10000, function() DespawnTaxi() end) break end -- Überprüfen ob die Fahrt zu lange dauert if GetGameTimer() > rideTimeout then print("^1[TAXI DEBUG]^7 Taxi ride timed out!") -- Berechne verbleibende Distanz local taxiCoords = GetEntityCoords(currentTaxi) local remainingDistance = #(vector3(destination.x, destination.y, destination.z) - taxiCoords) lib.notify({ title = 'Taxi Service', description = 'Die Fahrt dauert zu lange. Noch ' .. math.ceil(remainingDistance) .. 'm bis zum Ziel!', type = 'warning' }) -- Teleportiere Taxi näher ans Ziel (75% des Weges) local direction = vector3( destination.x - taxiCoords.x, destination.y - taxiCoords.y, destination.z - taxiCoords.z ) local normalizedDir = norm(direction) local teleportDistance = remainingDistance * 0.75 local newPos = vector3( taxiCoords.x + normalizedDir.x * teleportDistance, taxiCoords.y + normalizedDir.y * teleportDistance, taxiCoords.z ) -- Finde gültige Z-Koordinate local success, groundZ = GetGroundZFor_3dCoord(newPos.x, newPos.y, newPos.z, true) if success then newPos = vector3(newPos.x, newPos.y, groundZ) end -- Teleportiere Taxi SetEntityCoords(currentTaxi, newPos.x, newPos.y, newPos.z, false, false, false, false) -- Neues Timeout setzen (2 Minuten) rideTimeout = GetGameTimer() + (2 * 60 * 1000) end Wait(2000) end end) end function SelfDriveTaxi() print("^2[TAXI DEBUG]^7 Player driving taxi themselves") if not currentTaxi or not DoesEntityExist(currentTaxi) then return end local playerPed = PlayerPedId() -- Fahrer entfernen falls vorhanden if currentDriver and DoesEntityExist(currentDriver) then DeleteEntity(currentDriver) currentDriver = nil end -- Spieler zum Fahrersitz bewegen TaskShuffleToNextVehicleSeat(playerPed, currentTaxi) lib.notify({ title = 'Taxi Service', description = 'Du fährst das Taxi jetzt selbst. Nutze /stoptaxi um es zu beenden.', type = 'info' }) end function ExitTaxi() print("^2[TAXI DEBUG]^7 Player exiting taxi") if not currentTaxi or not DoesEntityExist(currentTaxi) then return end local playerPed = PlayerPedId() TaskLeaveVehicle(playerPed, currentTaxi, 0) lib.notify({ title = 'Taxi Service', description = 'Du bist ausgestiegen', type = 'info' }) -- Taxi nach 5 Sekunden despawnen SetTimeout(5000, function() DespawnTaxi() end) end function DespawnTaxi() print("^2[TAXI DEBUG]^7 Despawning taxi") if not currentTaxi or not DoesEntityExist(currentTaxi) then return end -- Taxi wegfahren lassen, wenn ein Fahrer existiert if currentDriver and DoesEntityExist(currentDriver) then print("^2[TAXI DEBUG]^7 Making taxi drive away before despawn") -- Zufällige Position in der Nähe finden local taxiCoords = GetEntityCoords(currentTaxi) local angle = math.random() * 2 * math.pi local distance = 150.0 local driveToX = taxiCoords.x + math.cos(angle) * distance local driveToY = taxiCoords.y + math.sin(angle) * distance -- Taxi wegfahren lassen TaskVehicleDriveToCoordLongrange(currentDriver, currentTaxi, driveToX, driveToY, taxiCoords.z, 25.0, 786603, 5.0) -- Blips entfernen if taxiBlip then RemoveBlip(taxiBlip) taxiBlip = nil end if mapBlip then RemoveBlip(mapBlip) mapBlip = nil end if destinationBlip then RemoveBlip(destinationBlip) destinationBlip = nil end -- Nach 10 Sekunden tatsächlich löschen SetTimeout(10000, function() -- Fahrer löschen if currentDriver and DoesEntityExist(currentDriver) then DeleteEntity(currentDriver) currentDriver = nil print("^2[TAXI DEBUG]^7 Driver deleted") end -- Taxi löschen if currentTaxi and DoesEntityExist(currentTaxi) then exports['qb-target']:RemoveTargetEntity(currentTaxi) DeleteEntity(currentTaxi) currentTaxi = nil print("^2[TAXI DEBUG]^7 Taxi deleted") end print("^2[TAXI DEBUG]^7 Taxi despawn completed") end) else -- Sofort löschen wenn kein Fahrer da ist if taxiBlip then RemoveBlip(taxiBlip) taxiBlip = nil end if mapBlip then RemoveBlip(mapBlip) mapBlip = nil end if destinationBlip then RemoveBlip(destinationBlip) destinationBlip = nil end -- Taxi löschen if currentTaxi and DoesEntityExist(currentTaxi) then exports['qb-target']:RemoveTargetEntity(currentTaxi) DeleteEntity(currentTaxi) currentTaxi = nil print("^2[TAXI DEBUG]^7 Taxi deleted") end print("^2[TAXI DEBUG]^7 Taxi despawn completed (no driver)") end end function CalculateDistanceToCoords(coords) local playerCoords = GetEntityCoords(PlayerPedId()) return #(playerCoords - coords) end -- Command um Taxi zu stoppen RegisterCommand('stoptaxi', function() if currentTaxi and DoesEntityExist(currentTaxi) then DespawnTaxi() lib.notify({ title = 'Taxi Service', description = 'Taxi-Service beendet', type = 'info' }) else lib.notify({ title = 'Taxi Service', description = 'Du hast kein aktives Taxi', type = 'error' }) end end) -- Thread zum Überwachen der Tasten im Taxi CreateThread(function() while true do Wait(0) if currentTaxi and DoesEntityExist(currentTaxi) then local playerPed = PlayerPedId() if IsPedInVehicle(playerPed, currentTaxi, false) then -- Zeige Hinweise an local helpText = '[E] - Ziel wählen [F] - Fahrt beenden' lib.showTextUI(helpText, { position = "top-center", icon = 'taxi', style = { borderRadius = 10, backgroundColor = '#48BB78', color = 'white' } }) -- Wenn E gedrückt wird, öffne Menü if IsControlJustReleased(0, 38) then -- E Taste OpenDestinationMenu() end -- Wenn F gedrückt wird, beende Fahrt if IsControlJustReleased(0, 23) then -- F Taste lib.hideTextUI() EndTaxiRide() end else lib.hideTextUI() end else lib.hideTextUI() Wait(1000) -- Längere Wartezeit wenn kein Taxi existiert end end end) -- Funktion zum Beenden der Fahrt function EndTaxiRide() print("^2[TAXI DEBUG]^7 Ending taxi ride") if not currentTaxi or not DoesEntityExist(currentTaxi) then return end local playerPed = PlayerPedId() -- Fahrt beenden Benachrichtigung lib.notify({ title = 'Taxi Service', description = 'Fahrt beendet. Du steigst aus.', type = 'info' }) -- Spieler aussteigen lassen TaskLeaveVehicle(playerPed, currentTaxi, 0) -- Warten bis ausgestiegen CreateThread(function() local timeout = GetGameTimer() + 5000 while GetGameTimer() < timeout do if not IsPedInVehicle(playerPed, currentTaxi, false) then -- Spieler ist ausgestiegen break end Wait(100) end -- Taxi nach 5 Sekunden despawnen SetTimeout(5000, function() DespawnTaxi() end) end) end -- Thread zum Überwachen des Einsteigens ins Taxi (ohne qb-target) CreateThread(function() while true do Wait(1000) if currentTaxi and DoesEntityExist(currentTaxi) and not IsPedInVehicle(PlayerPedId(), currentTaxi, false) then -- Spieler ist nicht im Taxi, aber Taxi existiert local playerPed = PlayerPedId() local playerCoords = GetEntityCoords(playerPed) local taxiCoords = GetEntityCoords(currentTaxi) if #(playerCoords - taxiCoords) < 5.0 then -- Spieler ist in der Nähe des Taxis lib.showTextUI('[E] - Ins Taxi einsteigen', { position = "top-center", icon = 'car-side', style = { borderRadius = 10, backgroundColor = '#4299E1', color = 'white' } }) -- Prüfen ob E gedrückt wird if IsControlJustReleased(0, 38) then -- E Taste -- Spieler will einsteigen lib.hideTextUI() -- Spieler hinten einsteigen lassen local seatIndex = 1 -- Hinten links if not IsVehicleSeatFree(currentTaxi, 1) then seatIndex = 2 -- Hinten rechts end if not IsVehicleSeatFree(currentTaxi, seatIndex) then seatIndex = 0 -- Beifahrer als Fallback end TaskEnterVehicle(playerPed, currentTaxi, 10000, seatIndex, 1.0, 1, 0) -- Warten bis eingestiegen local entryTimeout = GetGameTimer() + 10000 CreateThread(function() while GetGameTimer() < entryTimeout do if IsPedInVehicle(playerPed, currentTaxi, false) then -- Spieler ist eingestiegen Wait(1000) OpenDestinationMenu() break end Wait(100) end end) end else lib.hideTextUI() end end end end) -- Cleanup beim Resource Stop AddEventHandler('onResourceStop', function(resourceName) if GetCurrentResourceName() == resourceName then print("^2[TAXI DEBUG]^7 Cleaning up main script...") -- UI ausblenden lib.hideTextUI() -- Taxi despawnen DespawnTaxi() print("^2[TAXI DEBUG]^7 Main cleanup completed") end end)