local QBCore = exports['qb-core']:GetCoreObject() local stationVehicles = {} local stationBlips = {} function DebugPrint(type, message) if Config.Debug then if type == "error" then print("^1[TAXI STATIONS DEBUG]^7 " .. message) elseif type == "warning" then print("^3[TAXI STATIONS DEBUG]^7 " .. message) else -- success/info print("^2[TAXI STATIONS DEBUG]^7 " .. message) end end end local QBCore = exports['qb-core']:GetCoreObject() local stationVehicles = {} DebugPrint("^2[TAXI STATIONS DEBUG]^7 Stations script loaded") -- Taxi Stationen initialisieren CreateThread(function() Wait(5000) -- Längere Wartezeit, um sicherzustellen, dass alle Ressourcen geladen sind DebugPrint("^2[TAXI STATIONS DEBUG]^7 Initializing taxi stations...") InitializeTaxiStations() -- Regelmäßige Überprüfung und Wiederherstellung der Stationen CreateThread(function() while true do Wait(60000) -- Alle 60 Sekunden prüfen CheckAndRestoreStationVehicles() end end) end) function InitializeTaxiStations() DebugPrint("^2[TAXI STATIONS DEBUG]^7 InitializeTaxiStations started") if not Config.TaxiStations then DebugPrint("^1[TAXI STATIONS DEBUG]^7 Config.TaxiStations not found!") return end DebugPrint("^2[TAXI STATIONS DEBUG]^7 Found " .. #Config.TaxiStations .. " stations") -- Zuerst alle bestehenden Fahrzeuge und Blips entfernen CleanupExistingStations() -- Dann neue erstellen for stationId, station in pairs(Config.TaxiStations) do DebugPrint("^2[TAXI STATIONS DEBUG]^7 Processing station " .. stationId .. ": " .. station.name) -- Blip für Station erstellen local blip = AddBlipForCoord(station.blipCoords.x, station.blipCoords.y, station.blipCoords.z) SetBlipSprite(blip, 198) SetBlipColour(blip, 5) SetBlipScale(blip, 0.8) SetBlipAsShortRange(blip, true) BeginTextCommandSetBlipName("STRING") AddTextComponentString(station.name) EndTextCommandSetBlipName(blip) stationBlips[stationId] = blip DebugPrint("^2[TAXI STATIONS DEBUG]^7 Blip created for station " .. stationId) -- Fahrzeuge an Station spawnen stationVehicles[stationId] = {} -- Verzögertes Spawnen der Fahrzeuge, um Ressourcenkonflikte zu vermeiden CreateThread(function() for vehicleId, vehicleData in pairs(station.vehicles) do -- Kleine Verzögerung zwischen jedem Fahrzeug Wait(500) DebugPrint("^2[TAXI STATIONS DEBUG]^7 Spawning vehicle " .. vehicleId .. " (" .. vehicleData.model .. ") at station " .. stationId) SpawnStationVehicle(stationId, vehicleId, vehicleData) end end) end DebugPrint("^2[TAXI STATIONS DEBUG]^7 All stations initialization started") end function CleanupExistingStations() DebugPrint("^2[TAXI STATIONS DEBUG]^7 Cleaning up existing stations...") -- Alle bestehenden Fahrzeuge löschen for stationId, vehicles in pairs(stationVehicles) do for vehicleId, vehicleInfo in pairs(vehicles) do if vehicleInfo.entity and DoesEntityExist(vehicleInfo.entity) then exports['qb-target']:RemoveTargetEntity(vehicleInfo.entity) DeleteEntity(vehicleInfo.entity) end if vehicleInfo.driver and DoesEntityExist(vehicleInfo.driver) then DeleteEntity(vehicleInfo.driver) end end end -- Alle Blips entfernen for _, blip in pairs(stationBlips) do RemoveBlip(blip) end -- Variablen zurücksetzen stationVehicles = {} stationBlips = {} DebugPrint("^2[TAXI STATIONS DEBUG]^7 Cleanup completed") end function SpawnStationVehicle(stationId, vehicleId, vehicleData) DebugPrint("^2[TAXI STATIONS DEBUG]^7 SpawnStationVehicle: " .. stationId .. "/" .. vehicleId) -- Prüfen ob bereits ein Fahrzeug für diese Position existiert if stationVehicles[stationId] and stationVehicles[stationId][vehicleId] and stationVehicles[stationId][vehicleId].entity and DoesEntityExist(stationVehicles[stationId][vehicleId].entity) then DebugPrint("^3[TAXI STATIONS DEBUG]^7 Vehicle already exists for this position, removing it first") exports['qb-target']:RemoveTargetEntity(stationVehicles[stationId][vehicleId].entity) DeleteEntity(stationVehicles[stationId][vehicleId].entity) end -- Prüfen ob die Position frei ist local clearArea = true local vehicles = GetGamePool('CVehicle') for _, vehicle in ipairs(vehicles) do local vehCoords = GetEntityCoords(vehicle) if #(vector3(vehicleData.coords.x, vehicleData.coords.y, vehicleData.coords.z) - vehCoords) < 3.0 then clearArea = false DebugPrint("^3[TAXI STATIONS DEBUG]^7 Position blocked by another vehicle, will retry later") -- Nach 30 Sekunden erneut versuchen SetTimeout(30000, function() SpawnStationVehicle(stationId, vehicleId, vehicleData) end) return end end CreateThread(function() local vehicleHash = GetHashKey(vehicleData.model) DebugPrint("^2[TAXI STATIONS DEBUG]^7 Vehicle hash: " .. vehicleHash) RequestModel(vehicleHash) local timeout = GetGameTimer() + 10000 while not HasModelLoaded(vehicleHash) and GetGameTimer() < timeout do DebugPrint("^3[TAXI STATIONS DEBUG]^7 Waiting for model " .. vehicleData.model .. " to load...") Wait(100) end if not HasModelLoaded(vehicleHash) then DebugPrint("^1[TAXI STATIONS DEBUG]^7 Failed to load model: " .. vehicleData.model) -- Nach 30 Sekunden erneut versuchen SetTimeout(30000, function() SpawnStationVehicle(stationId, vehicleId, vehicleData) end) return end local vehicle = CreateVehicle( vehicleHash, vehicleData.coords.x, vehicleData.coords.y, vehicleData.coords.z, vehicleData.coords.w, false, false ) if not DoesEntityExist(vehicle) then DebugPrint("^1[TAXI STATIONS DEBUG]^7 Failed to create vehicle!") -- Nach 30 Sekunden erneut versuchen SetTimeout(30000, function() SpawnStationVehicle(stationId, vehicleId, vehicleData) end) return end DebugPrint("^2[TAXI STATIONS DEBUG]^7 Vehicle created: " .. vehicle) -- Fahrzeug konfigurieren SetEntityAsMissionEntity(vehicle, true, true) SetVehicleOnGroundProperly(vehicle) SetVehicleDoorsLocked(vehicle, 2) -- Locked SetVehicleEngineOn(vehicle, false, true, false) -- Verbesserte Persistenz SetEntityInvincible(vehicle, true) SetVehicleCanBeVisiblyDamaged(vehicle, false) SetEntityProofs(vehicle, true, true, true, true, true, true, true, true) SetVehicleExplodesOnHighExplosionDamage(vehicle, false) SetVehicleHasBeenOwnedByPlayer(vehicle, true) SetVehicleIsConsideredByPlayer(vehicle, true) -- Fahrzeug-Info speichern if not stationVehicles[stationId] then stationVehicles[stationId] = {} end stationVehicles[stationId][vehicleId] = { entity = vehicle, data = vehicleData, occupied = false } DebugPrint("^2[TAXI STATIONS DEBUG]^7 Adding qb-target for vehicle " .. vehicle) -- qb-target für Fahrzeug hinzufügen exports['qb-target']:AddTargetEntity(vehicle, { options = { { type = "client", event = "taxi:enterStationVehicle", icon = "fas fa-taxi", label = "Taxi nehmen ($" .. vehicleData.pricePerKm .. "/km)", stationId = stationId, vehicleId = vehicleId } }, distance = 3.0 }) DebugPrint("^2[TAXI STATIONS DEBUG]^7 qb-target added for vehicle " .. vehicle) SetModelAsNoLongerNeeded(vehicleHash) end) end function CheckAndRestoreStationVehicles() DebugPrint("^2[TAXI STATIONS DEBUG]^7 Checking station vehicles...") local restoredCount = 0 for stationId, station in pairs(Config.TaxiStations) do if not stationVehicles[stationId] then stationVehicles[stationId] = {} end for vehicleId, vehicleData in pairs(station.vehicles) do local shouldSpawn = false -- Prüfen ob das Fahrzeug existiert if not stationVehicles[stationId][vehicleId] then DebugPrint("^3[TAXI STATIONS DEBUG]^7 Vehicle data missing for station " .. stationId .. ", vehicle " .. vehicleId) shouldSpawn = true elseif not stationVehicles[stationId][vehicleId].entity then DebugPrint("^3[TAXI STATIONS DEBUG]^7 Vehicle entity missing for station " .. stationId .. ", vehicle " .. vehicleId) shouldSpawn = true elseif not DoesEntityExist(stationVehicles[stationId][vehicleId].entity) then DebugPrint("^3[TAXI STATIONS DEBUG]^7 Vehicle entity doesn't exist for station " .. stationId .. ", vehicle " .. vehicleId) shouldSpawn = true elseif stationVehicles[stationId][vehicleId].occupied then -- Fahrzeug ist besetzt, nicht neu spawnen DebugPrint("^2[TAXI STATIONS DEBUG]^7 Vehicle at station " .. stationId .. ", vehicle " .. vehicleId .. " is occupied") shouldSpawn = false end if shouldSpawn then DebugPrint("^2[TAXI STATIONS DEBUG]^7 Respawning vehicle at station " .. stationId .. ", vehicle " .. vehicleId) SpawnStationVehicle(stationId, vehicleId, vehicleData) restoredCount = restoredCount + 1 -- Kleine Verzögerung zwischen Spawns Wait(500) end end end if restoredCount > 0 then DebugPrint("^2[TAXI STATIONS DEBUG]^7 Restored " .. restoredCount .. " station vehicles") else DebugPrint("^2[TAXI STATIONS DEBUG]^7 All station vehicles are present") end end -- Fortgeschrittenes Taxi-Fahrer-Verhaltenssystem function InitializeTaxiDriverAI(driver, vehicle) if not driver or not DoesEntityExist(driver) then return end DebugPrint("^2[TAXI STATIONS 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 DebugPrint("^3[TAXI STATIONS 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 DebugPrint("^3[TAXI STATIONS 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 DebugPrint("^2[TAXI STATIONS 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 DebugPrint("^3[TAXI STATIONS 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 DebugPrint("^1[TAXI STATIONS 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 DebugPrint("^3[TAXI STATIONS 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 DebugPrint("^3[TAXI STATIONS DEBUG]^7 Recovery: Backing up") TaskVehicleTempAction(driver, vehicle, 8, 2000) -- Reverse Wait(2000) if forwardClear then -- Wenn vorne auch frei, einfach weiterfahren DebugPrint("^3[TAXI STATIONS DEBUG]^7 Recovery: Path clear, continuing") TaxiDriverContinueRoute(driver, vehicle) else -- Sonst versuchen zu wenden DebugPrint("^3[TAXI STATIONS 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 DebugPrint("^3[TAXI STATIONS DEBUG]^7 Recovery: Moving forward") TaskVehicleTempAction(driver, vehicle, 1, 2000) -- Forward Wait(2000) TaxiDriverContinueRoute(driver, vehicle) else -- Wenn komplett eingeklemmt, versuche zu rütteln DebugPrint("^3[TAXI STATIONS 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 -- Da wir die nicht direkt auslesen können, nehmen wir an, dass es das aktuelle Ziel ist local destination = Entity(vehicle).state.currentDestination if destination then -- Versuche einen alternativen Weg zu finden DebugPrint("^3[TAXI STATIONS 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 um Spieler-Sitz zu ermitteln function GetPlayerVehicleSeat(ped, vehicle) if not IsPedInVehicle(ped, vehicle, false) then return nil end -- Alle möglichen Sitze prüfen for seat = -1, 7 do -- -1 = Fahrer, 0 = Beifahrer, 1+ = Hintersitze if GetPedInVehicleSeat(vehicle, seat) == ped then return seat end end return nil end -- Event für Einsteigen in Station-Taxi RegisterNetEvent('taxi:enterStationVehicle', function(data) DebugPrint("^2[TAXI STATIONS DEBUG]^7 Player trying to enter station vehicle") DebugPrint("^2[TAXI STATIONS DEBUG]^7 Data: " .. json.encode(data)) local stationId = data.stationId local vehicleId = data.vehicleId if not stationVehicles[stationId] or not stationVehicles[stationId][vehicleId] then DebugPrint("^1[TAXI STATIONS DEBUG]^7 Vehicle not found in data") lib.notify({ title = 'Taxi Service', description = 'Dieses Taxi ist nicht verfügbar', type = 'error' }) return end local vehicleInfo = stationVehicles[stationId][vehicleId] if vehicleInfo.occupied then DebugPrint("^1[TAXI STATIONS DEBUG]^7 Vehicle already occupied") lib.notify({ title = 'Taxi Service', description = 'Dieses Taxi ist bereits besetzt', type = 'error' }) return end DebugPrint("^2[TAXI STATIONS DEBUG]^7 Entering vehicle...") -- Spieler ins Fahrzeug setzen local playerPed = PlayerPedId() local vehicle = vehicleInfo.entity -- Türen entsperren SetVehicleDoorsLocked(vehicle, 1) -- Info-Text anzeigen während Fahrer geladen wird DebugPrint("^2[TAXI STATIONS DEBUG]^7 Showing driver loading text...") lib.showTextUI('🚕 Warte an der Station - Fahrer wird geladen...', { position = "top-center", icon = 'taxi', style = { borderRadius = 10, backgroundColor = '#48BB78', color = 'white' } }) -- Kurz warten damit der Text sichtbar wird Wait(1000) -- Verschiedene Fahrer-Models versuchen 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 for i, modelName in pairs(driverModels) do DebugPrint("^2[TAXI STATIONS DEBUG]^7 Trying driver model " .. i .. ": " .. modelName) driverHash = GetHashKey(modelName) -- Text während Model-Loading aktualisieren lib.showTextUI('🚕 Lade Fahrer-Model (' .. i .. '/' .. #driverModels .. '): ' .. modelName .. '...', { position = "top-center", icon = 'taxi', style = { borderRadius = 10, backgroundColor = '#48BB78', color = 'white' } }) 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 DebugPrint("^3[TAXI STATIONS DEBUG]^7 Still waiting for model " .. modelName .. " (attempt " .. attempts .. ")") end Wait(100) end if HasModelLoaded(driverHash) then DebugPrint("^2[TAXI STATIONS DEBUG]^7 Driver model " .. modelName .. " loaded successfully") -- Text aktualisieren lib.showTextUI('🚕 Erstelle Fahrer...', { position = "top-center", icon = 'taxi', style = { borderRadius = 10, backgroundColor = '#48BB78', color = 'white' } }) driver = CreatePedInsideVehicle(vehicle, 26, driverHash, -1, true, false) if DoesEntityExist(driver) then DebugPrint("^2[TAXI STATIONS DEBUG]^7 Driver created successfully: " .. driver) break else DebugPrint("^1[TAXI STATIONS DEBUG]^7 Failed to create driver with model: " .. modelName) SetModelAsNoLongerNeeded(driverHash) end else DebugPrint("^1[TAXI STATIONS DEBUG]^7 Failed to load driver model: " .. modelName) SetModelAsNoLongerNeeded(driverHash) end Wait(500) -- Kurze Pause zwischen Versuchen end -- Fallback: Notfall-Fahrer erstellen if not driver or not DoesEntityExist(driver) then DebugPrint("^3[TAXI STATIONS DEBUG]^7 Using emergency fallback driver creation...") lib.showTextUI('🚕 Erstelle Notfall-Fahrer...', { position = "top-center", icon = 'taxi', style = { borderRadius = 10, backgroundColor = '#FFA500', color = 'white' } }) -- Notfall-Fallback mit Hash-Werten local emergencyModels = { `mp_m_freemode_01`, `a_m_y_hipster_01`, `a_m_m_farmer_01`, `a_m_y_beach_01` } for _, hash in pairs(emergencyModels) do RequestModel(hash) local timeout = GetGameTimer() + 5000 while not HasModelLoaded(hash) and GetGameTimer() < timeout do Wait(50) end if HasModelLoaded(hash) then driver = CreatePedInsideVehicle(vehicle, 26, hash, -1, true, false) if DoesEntityExist(driver) then DebugPrint("^2[TAXI STATIONS DEBUG]^7 Emergency driver created") driverHash = hash break end SetModelAsNoLongerNeeded(hash) end end Wait(1000) end -- Wenn immer noch kein Fahrer, ohne Fahrer fortfahren if not driver or not DoesEntityExist(driver) then DebugPrint("^1[TAXI STATIONS DEBUG]^7 Could not create any driver, continuing without driver") lib.showTextUI('❌ Kein Fahrer verfügbar - Du kannst selbst fahren', { position = "top-center", icon = 'exclamation-triangle', style = { borderRadius = 10, backgroundColor = '#FF6B6B', color = 'white' } }) Wait(3000) -- 3 Sekunden anzeigen lib.hideTextUI() driver = nil lib.notify({ title = 'Taxi Service', description = 'Kein Fahrer verfügbar - Du kannst das Taxi selbst fahren', type = 'warning' }) else -- Fahrer erfolgreich erstellt lib.showTextUI('✅ Fahrer bereit - Steige hinten ein!', { position = "top-center", icon = 'check-circle', style = { borderRadius = 10, backgroundColor = '#48BB78', color = 'white' } }) Wait(2000) -- 2 Sekunden anzeigen -- Fahrer konfigurieren SetEntityAsMissionEntity(driver, true, true) SetPedFleeAttributes(driver, 0, 0) SetPedCombatAttributes(driver, 17, 1) SetPedSeeingRange(driver, 0.0) SetPedHearingRange(driver, 0.0) SetPedAlertness(driver, 0) SetPedKeepTask(driver, true) SetBlockingOfNonTemporaryEvents(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 lib.notify({ title = 'Taxi Service', description = 'Dein Fahrer ' .. driverName .. ' ist bereit - Steige hinten ein', type = 'success' }) end -- Spieler HINTEN einsteigen lassen local seatIndex = 1 -- Hinten links als Standard -- Prüfen welche Hintersitze verfügbar sind local availableSeats = {} for i = 1, 3 do -- Sitze 1, 2, 3 (hinten links, hinten mitte, hinten rechts) if IsVehicleSeatFree(vehicle, i) then table.insert(availableSeats, i) end end -- Ersten verfügbaren Hintersitz wählen if #availableSeats > 0 then seatIndex = availableSeats[1] DebugPrint("^2[TAXI STATIONS DEBUG]^7 Using rear seat: " .. seatIndex) else -- Fallback: Beifahrersitz seatIndex = 0 DebugPrint("^3[TAXI STATIONS DEBUG]^7 No rear seats available, using passenger seat") end -- Spieler in den gewählten Sitz einsteigen lassen TaskEnterVehicle(playerPed, vehicle, 10000, seatIndex, 1.0, 1, 0) -- Info-Text während Einsteigen lib.showTextUI('🚕 Steige ins Taxi ein...', { position = "top-center", icon = 'car-side', style = { borderRadius = 10, backgroundColor = '#4299E1', color = 'white' } }) -- Warten bis Spieler eingestiegen ist CreateThread(function() local enterTimeout = GetGameTimer() + 15000 -- Längere Zeit für Einsteigen local hasEntered = false while GetGameTimer() < enterTimeout and not hasEntered do if IsPedInVehicle(playerPed, vehicle, false) then hasEntered = true vehicleInfo.occupied = true vehicleInfo.driver = driver -- Info-Text verstecken lib.hideTextUI() DebugPrint("^2[TAXI STATIONS DEBUG]^7 Player entered successfully") -- Prüfen ob Spieler wirklich hinten sitzt local playerSeat = GetPlayerVehicleSeat(playerPed, vehicle) DebugPrint("^2[TAXI STATIONS DEBUG]^7 Player is in seat: " .. tostring(playerSeat)) if playerSeat == -1 then -- Fahrersitz DebugPrint("^3[TAXI STATIONS DEBUG]^7 Player is in driver seat, moving to passenger area") if driver and DoesEntityExist(driver) then -- Spieler zum nächsten verfügbaren Sitz bewegen Wait(1000) TaskShuffleToNextVehicleSeat(playerPed, vehicle) Wait(2000) end end lib.notify({ title = 'Taxi Service', description = 'Willkommen im Taxi! Wähle dein Ziel.', type = 'success' }) -- Ziel-Menu öffnen Wait(1000) -- Kurz warten damit Einsteigen abgeschlossen ist OpenStationTaxiMenu(stationId, vehicleId, vehicle, driver, vehicleInfo.data.pricePerKm) break end Wait(100) end if not hasEntered then DebugPrint("^1[TAXI STATIONS DEBUG]^7 Player failed to enter vehicle") -- Info-Text verstecken lib.hideTextUI() lib.notify({ title = 'Taxi Service', description = 'Einsteigen fehlgeschlagen', type = 'error' }) -- Cleanup if driver and DoesEntityExist(driver) then DeleteEntity(driver) end SetVehicleDoorsLocked(vehicle, 2) vehicleInfo.occupied = false end end) end) function OpenStationTaxiMenu(stationId, vehicleId, vehicle, driver, pricePerKm) DebugPrint("^2[TAXI STATIONS DEBUG]^7 Opening station taxi menu") local options = {} -- Bekannte Ziele hinzufügen for _, destination in pairs(Config.KnownDestinations) do local customPrice = math.max(Config.MinFare, math.ceil((CalculateDistanceToCoords(destination.coords) / 1000) * pricePerKm)) table.insert(options, { title = destination.name, description = 'Preis: $' .. customPrice .. ' | Entfernung: ' .. math.ceil(CalculateDistanceToCoords(destination.coords) / 1000 * 100) / 100 .. 'km', icon = 'map-marker', onSelect = function() StartStationTaxiRide(stationId, vehicleId, vehicle, driver, destination.coords, customPrice) end }) end -- Andere Taxi-Stationen als Ziele table.insert(options, { title = '📍 Andere Taxi-Stationen', description = 'Fahre zu einer anderen Taxi-Station', icon = 'taxi', onSelect = function() OpenStationSelectionMenu(stationId, vehicleId, vehicle, driver, pricePerKm) 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 * pricePerKm)) StartStationTaxiRide(stationId, vehicleId, vehicle, driver, coords, price) else lib.notify({ title = 'Taxi Service', description = 'Du hast keinen Waypoint gesetzt', type = 'error' }) OpenStationTaxiMenu(stationId, vehicleId, vehicle, driver, pricePerKm) end end }) -- Selbst fahren Option (wenn kein Fahrer) if not driver or not DoesEntityExist(driver) then table.insert(options, { title = '🚗 Selbst fahren', description = 'Du fährst das Taxi selbst (kostenlos)', icon = 'car', onSelect = function() SelfDriveStationTaxi(stationId, vehicleId, vehicle) end }) end -- Aussteigen Option table.insert(options, { title = 'Aussteigen', description = 'Das Taxi verlassen', icon = 'door-open', onSelect = function() ExitStationTaxi(stationId, vehicleId, vehicle, driver) end }) lib.registerContext({ id = 'station_taxi_menu', title = 'Taxi - Ziel wählen (' .. Config.TaxiStations[stationId].name .. ')', options = options }) lib.showContext('station_taxi_menu') end function SelfDriveStationTaxi(stationId, vehicleId, vehicle) DebugPrint("^2[TAXI STATIONS DEBUG]^7 Player driving taxi themselves") local playerPed = PlayerPedId() -- Spieler zum Fahrersitz bewegen TaskShuffleToNextVehicleSeat(playerPed, vehicle) lib.notify({ title = 'Taxi Service', description = 'Du fährst das Taxi jetzt selbst. Bringe es zur Station zurück wenn du fertig bist.', type = 'info' }) -- Überwachung für Rückgabe CreateThread(function() while DoesEntityExist(vehicle) do local playerPed = PlayerPedId() -- Prüfen ob Spieler noch im Fahrzeug ist if not IsPedInVehicle(playerPed, vehicle, false) then DebugPrint("^2[TAXI STATIONS DEBUG]^7 Player left self-drive taxi") -- Nach 30 Sekunden Taxi zurück zur Station SetTimeout(30000, function() ReturnTaxiToStation(stationId, vehicleId, vehicle, nil) end) break end Wait(5000) end end) end function OpenStationSelectionMenu(stationId, vehicleId, vehicle, driver, pricePerKm) DebugPrint("^2[TAXI STATIONS DEBUG]^7 Opening station selection menu") local options = {} for otherStationId, station in pairs(Config.TaxiStations) do if otherStationId ~= stationId then local distance = CalculateDistanceToCoords(station.blipCoords) / 1000 local price = math.max(Config.MinFare, math.ceil(distance * pricePerKm)) table.insert(options, { title = station.name, description = 'Preis: $' .. price .. ' | Entfernung: ' .. math.ceil(distance * 100) / 100 .. 'km', icon = 'building', onSelect = function() StartStationTaxiRide(stationId, vehicleId, vehicle, driver, station.blipCoords, price) end }) end end -- Zurück Option table.insert(options, { title = '← Zurück', description = 'Zurück zum Hauptmenü', icon = 'arrow-left', onSelect = function() OpenStationTaxiMenu(stationId, vehicleId, vehicle, driver, pricePerKm) end }) lib.registerContext({ id = 'station_selection_menu', title = 'Taxi-Stationen', options = options }) lib.showContext('station_selection_menu') end function StartStationTaxiRide(stationId, vehicleId, vehicle, driver, destination, price) DebugPrint("^2[TAXI STATIONS DEBUG]^7 Starting station taxi ride to: " .. tostring(destination.x) .. ", " .. tostring(destination.y) .. ", " .. tostring(destination.z)) -- Wenn kein Fahrer, Spieler selbst fahren lassen if not driver or not DoesEntityExist(driver) then lib.notify({ title = 'Taxi Service', description = 'Kein Fahrer verfügbar. Fahre selbst zum Ziel! (Kostenlos)', type = 'info' }) -- Destination Blip erstellen local destinationBlip = AddBlipForCoord(destination.x, destination.y, destination.z) SetBlipSprite(destinationBlip, 1) SetBlipColour(destinationBlip, 2) SetBlipScale(destinationBlip, 0.8) SetBlipRoute(destinationBlip, true) -- Route zum Ziel anzeigen BeginTextCommandSetBlipName("STRING") AddTextComponentString("Taxi Ziel") EndTextCommandSetBlipName(destinationBlip) -- Route setzen SetNewWaypoint(destination.x, destination.y) return end lib.notify({ title = 'Taxi Service', description = 'Fahrt gestartet - Preis: $' .. price, type = 'success' }) -- Destination Blip erstellen local destinationBlip = AddBlipForCoord(destination.x, destination.y, destination.z) SetBlipSprite(destinationBlip, 1) SetBlipColour(destinationBlip, 2) SetBlipScale(destinationBlip, 0.8) SetBlipRoute(destinationBlip, true) -- Route zum Ziel anzeigen BeginTextCommandSetBlipName("STRING") AddTextComponentString("Taxi Ziel") EndTextCommandSetBlipName(destinationBlip) -- Ziel im Fahrzeug-State speichern für die KI-Logik Entity(vehicle).state.currentDestination = destination -- Zum Ziel fahren mit verbesserter Navigation local drivingStyle = 786603 -- Normal/Vorsichtig TaskVehicleDriveToCoordLongrange(driver, vehicle, destination.x, destination.y, destination.z, 20.0, drivingStyle, 10.0) -- Fahrer-Dialog anzeigen local driverName = Entity(vehicle).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 (vereinfacht, da KI-Logik die meiste Arbeit übernimmt) CreateThread(function() local rideTimeout = GetGameTimer() + (8 * 60 * 1000) -- 8 Minuten Timeout while DoesEntityExist(vehicle) and DoesEntityExist(driver) do local vehicleCoords = GetEntityCoords(vehicle) local distance = #(vector3(destination.x, destination.y, destination.z) - vehicleCoords) -- Überprüfen ob wir angekommen sind if distance < 10.0 then -- Angekommen TaskVehicleTempAction(driver, vehicle, 27, 3000) DebugPrint("^2[TAXI STATIONS DEBUG]^7 Arrived at destination") lib.notify({ title = 'Taxi Service', description = 'Du bist angekommen! Preis: $' .. price, type = 'success' }) -- Bezahlung TriggerServerEvent('taxi:payFare', price) -- Blip entfernen RemoveBlip(destinationBlip) -- Fahrer-Dialog anzeigen local driverName = Entity(vehicle).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 zurück zur Station SetTimeout(10000, function() ReturnTaxiToStation(stationId, vehicleId, vehicle, driver) end) break end -- Überprüfen ob die Fahrt zu lange dauert if GetGameTimer() > rideTimeout then DebugPrint("^1[TAXI STATIONS DEBUG]^7 Taxi ride timed out!") lib.notify({ title = 'Taxi Service', description = 'Die Fahrt dauert zu lange. Wir sind fast da!', type = 'warning' }) -- Teleportiere Taxi in die Nähe des Ziels local offset = vector3( math.random(-20, 20), math.random(-20, 20), 0 ) local nearDestination = vector3(destination.x, destination.y, destination.z) + offset -- Finde gültige Z-Koordinate local success, groundZ = GetGroundZFor_3dCoord(nearDestination.x, nearDestination.y, nearDestination.z, true) if success then nearDestination = vector3(nearDestination.x, nearDestination.y, groundZ) end -- Teleportiere Taxi SetEntityCoords(vehicle, nearDestination.x, nearDestination.y, nearDestination.z, false, false, false, false) -- Neues Timeout setzen (1 Minute) rideTimeout = GetGameTimer() + (60 * 1000) end Wait(2000) end end) end function ExitStationTaxi(stationId, vehicleId, vehicle, driver) DebugPrint("^2[TAXI STATIONS DEBUG]^7 Player exiting station taxi") local playerPed = PlayerPedId() TaskLeaveVehicle(playerPed, vehicle, 0) lib.notify({ title = 'Taxi Service', description = 'Du bist ausgestiegen', type = 'info' }) -- Taxi zurück zur Station nach 5 Sekunden SetTimeout(5000, function() ReturnTaxiToStation(stationId, vehicleId, vehicle, driver) end) end function ReturnTaxiToStation(stationId, vehicleId, vehicle, driver) DebugPrint("^2[TAXI STATIONS DEBUG]^7 Returning taxi to station: " .. stationId .. "/" .. vehicleId) if not stationVehicles[stationId] or not stationVehicles[stationId][vehicleId] then DebugPrint("^1[TAXI STATIONS DEBUG]^7 Station vehicle data not found for return") return end if not DoesEntityExist(vehicle) then DebugPrint("^1[TAXI STATIONS DEBUG]^7 Vehicle doesn't exist anymore") -- Fahrzeug als nicht besetzt markieren stationVehicles[stationId][vehicleId].occupied = false stationVehicles[stationId][vehicleId].driver = nil stationVehicles[stationId][vehicleId].entity = nil -- Nach Respawn-Zeit neues Fahrzeug spawnen DebugPrint("^2[TAXI STATIONS DEBUG]^7 Scheduling respawn in " .. Config.StationTaxiRespawnTime .. " seconds") SetTimeout(Config.StationTaxiRespawnTime * 1000, function() if stationVehicles[stationId] and stationVehicles[stationId][vehicleId] then local vehicleData = stationVehicles[stationId][vehicleId].data DebugPrint("^2[TAXI STATIONS DEBUG]^7 Respawning vehicle at station") SpawnStationVehicle(stationId, vehicleId, vehicleData) end end) return end -- Wenn Fahrer existiert, Taxi zur Station zurückfahren lassen if driver and DoesEntityExist(driver) then DebugPrint("^2[TAXI STATIONS DEBUG]^7 Making taxi drive back to station") -- Zufällige Position in der Nähe der Station finden local stationCoords = Config.TaxiStations[stationId].coords -- Taxi zur Station zurückfahren lassen mit geduldiger Fahrweise local drivingStyle = 786603 -- Normal/Vorsichtig TaskVehicleDriveToCoordLongrange(driver, vehicle, stationCoords.x, stationCoords.y, stationCoords.z, 20.0, drivingStyle, 10.0) -- qb-target entfernen während der Fahrt exports['qb-target']:RemoveTargetEntity(vehicle) -- Nach 10 Sekunden tatsächlich löschen SetTimeout(10000, function() -- Fahrer löschen if driver and DoesEntityExist(driver) then DeleteEntity(driver) DebugPrint("^2[TAXI STATIONS DEBUG]^7 Driver deleted") end -- Fahrzeug löschen if DoesEntityExist(vehicle) then DeleteEntity(vehicle) DebugPrint("^2[TAXI STATIONS DEBUG]^7 Vehicle deleted") end -- Fahrzeug als nicht besetzt markieren stationVehicles[stationId][vehicleId].occupied = false stationVehicles[stationId][vehicleId].driver = nil stationVehicles[stationId][vehicleId].entity = nil -- Nach Respawn-Zeit neues Fahrzeug spawnen DebugPrint("^2[TAXI STATIONS DEBUG]^7 Scheduling respawn in " .. Config.StationTaxiRespawnTime .. " seconds") SetTimeout(Config.StationTaxiRespawnTime * 1000, function() if stationVehicles[stationId] and stationVehicles[stationId][vehicleId] then local vehicleData = stationVehicles[stationId][vehicleId].data DebugPrint("^2[TAXI STATIONS DEBUG]^7 Respawning vehicle at station") SpawnStationVehicle(stationId, vehicleId, vehicleData) end end) end) else -- Sofort löschen wenn kein Fahrer da ist -- qb-target entfernen if DoesEntityExist(vehicle) then exports['qb-target']:RemoveTargetEntity(vehicle) DeleteEntity(vehicle) DebugPrint("^2[TAXI STATIONS DEBUG]^7 Vehicle deleted") end -- Fahrzeug als nicht besetzt markieren stationVehicles[stationId][vehicleId].occupied = false stationVehicles[stationId][vehicleId].driver = nil stationVehicles[stationId][vehicleId].entity = nil -- Nach Respawn-Zeit neues Fahrzeug spawnen DebugPrint("^2[TAXI STATIONS DEBUG]^7 Scheduling respawn in " .. Config.StationTaxiRespawnTime .. " seconds") SetTimeout(Config.StationTaxiRespawnTime * 1000, function() if stationVehicles[stationId] and stationVehicles[stationId][vehicleId] then local vehicleData = stationVehicles[stationId][vehicleId].data DebugPrint("^2[TAXI STATIONS DEBUG]^7 Respawning vehicle at station") SpawnStationVehicle(stationId, vehicleId, vehicleData) end end) end end function CalculateDistanceToCoords(coords) local playerCoords = GetEntityCoords(PlayerPedId()) return #(playerCoords - coords) end -- Command um nächste Taxi-Station zu finden RegisterCommand('nearesttaxi', function() local playerCoords = GetEntityCoords(PlayerPedId()) local nearestStation = nil local nearestDistance = math.huge for stationId, station in pairs(Config.TaxiStations) do local distance = #(playerCoords - station.blipCoords) if distance < nearestDistance then nearestDistance = distance nearestStation = {id = stationId, data = station, distance = distance} end end if nearestStation then lib.notify({ title = 'Taxi Service', description = 'Nächste Station: ' .. nearestStation.data.name .. ' (' .. math.ceil(nearestDistance) .. 'm)', type = 'info' }) -- Waypoint zur nächsten Station setzen SetNewWaypoint(nearestStation.data.blipCoords.x, nearestStation.data.blipCoords.y) else lib.notify({ title = 'Taxi Service', description = 'Keine Taxi-Station gefunden', type = 'error' }) end end) -- Event für Admin Respawn RegisterNetEvent('taxi:respawnAllStations', function() DebugPrint("^2[TAXI STATIONS DEBUG]^7 Respawning all stations...") -- Alle bestehenden Fahrzeuge löschen for stationId, vehicles in pairs(stationVehicles) do for vehicleId, vehicleInfo in pairs(vehicles) do if vehicleInfo.entity and DoesEntityExist(vehicleInfo.entity) then exports['qb-target']:RemoveTargetEntity(vehicleInfo.entity) DeleteEntity(vehicleInfo.entity) end if vehicleInfo.driver and DoesEntityExist(vehicleInfo.driver) then DeleteEntity(vehicleInfo.driver) end end end -- Alle Blips entfernen for _, blip in pairs(stationBlips) do RemoveBlip(blip) end -- Variablen zurücksetzen stationVehicles = {} stationBlips = {} -- Stationen neu initialisieren Wait(1000) InitializeTaxiStations() lib.notify({ title = 'Taxi Service', description = 'Alle Taxi-Stationen wurden neu gespawnt', type = 'success' }) end) -- Thread zum Überwachen der Tasten im Stations-Taxi CreateThread(function() while true do Wait(0) local playerPed = PlayerPedId() local inStationTaxi = false local currentStationTaxi = nil local currentStationId = nil local currentVehicleId = nil local currentDriver = nil local pricePerKm = 0 -- Prüfen ob Spieler in einem Stations-Taxi sitzt for stationId, vehicles in pairs(stationVehicles) do for vehicleId, vehicleInfo in pairs(vehicles) do if vehicleInfo.entity and DoesEntityExist(vehicleInfo.entity) and vehicleInfo.occupied then if IsPedInVehicle(playerPed, vehicleInfo.entity, false) then inStationTaxi = true currentStationTaxi = vehicleInfo.entity currentStationId = stationId currentVehicleId = vehicleId currentDriver = vehicleInfo.driver pricePerKm = vehicleInfo.data.pricePerKm break end end end if inStationTaxi then break end end if inStationTaxi and currentStationTaxi 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 OpenStationTaxiMenu(currentStationId, currentVehicleId, currentStationTaxi, currentDriver, pricePerKm) end -- Wenn F gedrückt wird, beende Fahrt if IsControlJustReleased(0, 23) then -- F Taste lib.hideTextUI() EndStationTaxiRide(currentStationId, currentVehicleId, currentStationTaxi, currentDriver) end else -- Nicht in einem Stations-Taxi lib.hideTextUI() Wait(1000) end end end) -- Funktion zum Beenden der Stations-Taxi Fahrt function EndStationTaxiRide(stationId, vehicleId, vehicle, driver) DebugPrint("^2[TAXI STATIONS DEBUG]^7 Ending station taxi ride") if not vehicle or not DoesEntityExist(vehicle) 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, vehicle, 0) -- Warten bis ausgestiegen CreateThread(function() local timeout = GetGameTimer() + 5000 while GetGameTimer() < timeout do if not IsPedInVehicle(playerPed, vehicle, false) then -- Spieler ist ausgestiegen break end Wait(100) end -- Taxi nach 5 Sekunden zurück zur Station SetTimeout(5000, function() ReturnTaxiToStation(stationId, vehicleId, vehicle, driver) end) end) end -- Cleanup beim Resource Stop AddEventHandler('onResourceStop', function(resourceName) if GetCurrentResourceName() == resourceName then DebugPrint("^2[TAXI STATIONS DEBUG]^7 Cleaning up stations...") -- TextUI verstecken falls noch angezeigt lib.hideTextUI() -- Alle Station-Fahrzeuge löschen for stationId, vehicles in pairs(stationVehicles) do for vehicleId, vehicleInfo in pairs(vehicles) do if vehicleInfo.entity and DoesEntityExist(vehicleInfo.entity) then exports['qb-target']:RemoveTargetEntity(vehicleInfo.entity) DeleteEntity(vehicleInfo.entity) end if vehicleInfo.driver and DoesEntityExist(vehicleInfo.driver) then DeleteEntity(vehicleInfo.driver) end end end -- Alle Blips entfernen for _, blip in pairs(stationBlips) do RemoveBlip(blip) end DebugPrint("^2[TAXI STATIONS DEBUG]^7 Cleanup completed") end end)