From ee396ec359dbc8cebde6b51fafa19683aef0d90f Mon Sep 17 00:00:00 2001 From: Nordi98 Date: Tue, 12 Aug 2025 17:11:44 +0200 Subject: [PATCH] ed --- resources/[tools]/nordi_taxi/client/main.lua | 1595 ----------------- .../[tools]/nordi_taxi/client/stations.lua | 1594 ---------------- resources/[tools]/nordi_taxi/config.lua | 180 -- resources/[tools]/nordi_taxi/fxmanifest.lua | 26 - resources/[tools]/nordi_taxi/server/main.lua | 62 - 5 files changed, 3457 deletions(-) delete mode 100644 resources/[tools]/nordi_taxi/client/main.lua delete mode 100644 resources/[tools]/nordi_taxi/client/stations.lua delete mode 100644 resources/[tools]/nordi_taxi/config.lua delete mode 100644 resources/[tools]/nordi_taxi/fxmanifest.lua delete mode 100644 resources/[tools]/nordi_taxi/server/main.lua diff --git a/resources/[tools]/nordi_taxi/client/main.lua b/resources/[tools]/nordi_taxi/client/main.lua deleted file mode 100644 index be3c0ad4c..000000000 --- a/resources/[tools]/nordi_taxi/client/main.lua +++ /dev/null @@ -1,1595 +0,0 @@ - -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 -} - - -function DebugPrint(type, message) - if Config.Debug then - if type == "error" then - print("^1[TAXI DEBUG]^7 " .. message) - elseif type == "warning" then - print("^3[TAXI DEBUG]^7 " .. message) - else -- success/info - print("^2[TAXI DEBUG]^7 " .. message) - end - end -end - -local QBCore = exports['qb-core']:GetCoreObject() -local currentTaxi = nil - -DebugPrint("^2[TAXI DEBUG]^7 Main script loaded") - --- Taxi rufen Command -RegisterCommand('taxi', function() - DebugPrint("^2[TAXI DEBUG]^7 Taxi command executed") - - if currentTaxi and DoesEntityExist(currentTaxi) then - DebugPrint("^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() - DebugPrint("^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) - - DebugPrint("^2[TAXI DEBUG]^7 Player coords: " .. tostring(playerCoords)) - - -- Verbesserte Spawn-Position für Taxi finden - local spawnCoords = GetImprovedTaxiSpawnPosition(playerCoords) - if not spawnCoords then - DebugPrint("^1[TAXI DEBUG]^7 No spawn position found") - lib.notify({ - title = 'Taxi Service', - description = 'Kein geeigneter Spawn-Punkt gefunden', - type = 'error' - }) - return - end - - DebugPrint("^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 - DebugPrint("^1[TAXI DEBUG]^7 Failed to spawn taxi") - lib.notify({ - title = 'Taxi Service', - description = 'Taxi konnte nicht gespawnt werden', - type = 'error' - }) - return - end - - DebugPrint("^2[TAXI DEBUG]^7 Taxi spawned: " .. taxi) - currentTaxi = taxi - - -- Fahrer spawnen - local driver = SpawnTaxiDriver(taxi) - if driver then - currentDriver = driver - DebugPrint("^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 - DebugPrint("^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) - DebugPrint("^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 - DebugPrint("^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 - DebugPrint("^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 - DebugPrint("^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 - DebugPrint("^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 - DebugPrint("^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 - DebugPrint("^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 - DebugPrint("^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 - - DebugPrint("^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) - DebugPrint("^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 - - DebugPrint("^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 - DebugPrint("^3[TAXI DEBUG]^7 Waiting for taxi model to load...") - Wait(100) - end - end - - if not modelLoaded then - DebugPrint("^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 - DebugPrint("^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 - DebugPrint("^1[TAXI DEBUG]^7 Failed to create taxi vehicle!") - return nil - end - - DebugPrint("^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 - DebugPrint("^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 - - DebugPrint("^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, 60), -- 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 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 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 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 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 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 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 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 DEBUG]^7 Recovery: Path clear, continuing") - TaxiDriverContinueRoute(driver, vehicle) - else - -- Sonst versuchen zu wenden - DebugPrint("^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 - DebugPrint("^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 - DebugPrint("^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 - DebugPrint("^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) - DebugPrint("^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 - DebugPrint("^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 - DebugPrint("^3[TAXI DEBUG]^7 Still waiting for model " .. modelName .. " (attempt " .. attempts .. ")") - end - Wait(100) - end - - if HasModelLoaded(driverHash) then - DebugPrint("^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 - DebugPrint("^2[TAXI DEBUG]^7 Driver created successfully with model: " .. modelName .. " (ID: " .. driver .. ")") - break - else - DebugPrint("^1[TAXI DEBUG]^7 Failed to create driver with loaded model: " .. modelName) - SetModelAsNoLongerNeeded(driverHash) - end - else - DebugPrint("^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 - DebugPrint("^1[TAXI DEBUG]^7 Could not create any driver! Continuing without driver...") - return nil - end - - -- Fahrer konfigurieren - DebugPrint("^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 - DebugPrint("^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 - - DebugPrint("^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) - DebugPrint("^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 - DebugPrint("^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 - DebugPrint("^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) - DebugPrint("^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 - DebugPrint("^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 - DebugPrint("^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() - DebugPrint("^2[TAXI DEBUG]^7 Player entering taxi") - - if not currentTaxi or not DoesEntityExist(currentTaxi) then - DebugPrint("^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 - DebugPrint("^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 - DebugPrint("^1[TAXI DEBUG]^7 Player failed to enter taxi") - lib.notify({ - title = 'Taxi Service', - description = 'Einsteigen fehlgeschlagen', - type = 'error' - }) - end - end) -end) - -function OpenDestinationMenu() - DebugPrint("^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) - DebugPrint("^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 - DebugPrint("^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) - DebugPrint("^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) - - DebugPrint("^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 - DebugPrint("^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() - DebugPrint("^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() - DebugPrint("^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() - DebugPrint("^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 - DebugPrint("^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 - DebugPrint("^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 - DebugPrint("^2[TAXI DEBUG]^7 Taxi deleted") - end - DebugPrint("^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 - DebugPrint("^2[TAXI DEBUG]^7 Taxi deleted") - end - - DebugPrint("^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() - DebugPrint("^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 - DebugPrint("^2[TAXI DEBUG]^7 Cleaning up main script...") - - -- UI ausblenden - lib.hideTextUI() - - -- Taxi despawnen - DespawnTaxi() - - DebugPrint("^2[TAXI DEBUG]^7 Main cleanup completed") - end -end) - - - - diff --git a/resources/[tools]/nordi_taxi/client/stations.lua b/resources/[tools]/nordi_taxi/client/stations.lua deleted file mode 100644 index 1c5008d13..000000000 --- a/resources/[tools]/nordi_taxi/client/stations.lua +++ /dev/null @@ -1,1594 +0,0 @@ -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) - - - - - diff --git a/resources/[tools]/nordi_taxi/config.lua b/resources/[tools]/nordi_taxi/config.lua deleted file mode 100644 index d5cb749ad..000000000 --- a/resources/[tools]/nordi_taxi/config.lua +++ /dev/null @@ -1,180 +0,0 @@ -Config = {} - -Config.Debug = false -- Set to true to enable debug prints, false to disable - - --- Taxi Fahrzeuge und Preise -Config.TaxiVehicles = { - { - model = 'taxi', - label = 'Standard Taxi', - pricePerKm = 5, - spawnChance = 80 - }, - { - model = 'vstretch', - label = 'Luxus Limousine', - pricePerKm = 15, - spawnChance = 10 - }, - { - model = 'elegyrh7', - label = 'JDM Taxi', - pricePerKm = 15, - spawnChance = 10 - }, - - -} - --- Taxi Stationen mit festen Fahrzeugen -Config.TaxiStations = { - { - name = "Los Santos Airport Taxi", - coords = vector4(-1051.28, -2712.83, 13.68, 243.31), - blipCoords = vector3(-1051.28, -2712.83, 13.68), - vehicles = { - { - model = 'taxi', - coords = vector4(-1051.28, -2712.83, 13.68, 243.31), - pricePerKm = 5 - }, - { - model = 'taxi', - coords = vector4(-1041.38, -2718.65, 13.67, 239.73), - pricePerKm = 5 - } - } - }, - { - name = "Downtown Taxi Stand", - coords = vector4(913.97, -160.64, 74.72, 200.67), - blipCoords = vector3(913.97, -160.64, 74.72), - vehicles = { - { - model = 'taxi', - coords = vector4(913.97, -160.64, 74.72, 200.67), - pricePerKm = 5 - }, - { - model = 'taxi', - coords = vector4(899.74, -180.99, 73.86, 247.36), - pricePerKm = 5 - } - } - }, - { - name = "Paleto Bay Taxi", - coords = vector4(-339.14, 6072.48, 31.31, 225.76), - blipCoords = vector3(-339.14, 6072.48, 31.31), - vehicles = { - { - model = 'taxi', - coords = vector4(-339.14, 6072.48, 31.31, 225.76), - pricePerKm = 6 - }, - - } - }, - { - name = "Stadtpark Taxi", - coords = vector4(204.9, -846.9, 30.5, 254.69), - blipCoords = vector3(204.9, -846.9, 30.5), - vehicles = { - { - model = 'taxi', - coords = vector4(204.9, -846.9, 30.5, 254.69), - pricePerKm = 6 - }, - { - model = 'taxi', - coords = vector4(213.61, -849.66, 30.28, 248.6), - pricePerKm = 6 - } - - - - } - }, - { - name = "Vespucci Beach Taxi", - coords = vector4(-1614.7, -857.81, 10.02, 140.47), - blipCoords = vector3(-1609.67, -862.78, 10.01), - vehicles = { - { - model = 'taxi', - coords = vector4(-1614.7, -857.81, 10.02, 140.47), - pricePerKm = 5 - }, - { - model = 'vstretch', - coords = vector4(-1609.67, -862.78, 10.01, 230.02), - pricePerKm = 15 - } - } - } -} - --- Spawn Locations für /taxi Command (mobile Taxis) -Config.MobileTaxiSpawns = { - vector4(-1013.96, -2734.56, 13.67, 246.68), - vector4(902.33, -143.8, 76.62, 327.11), - vector4(-1277.46, -810.35, 17.13, 133.23), - vector4(1705.39, 4803.73, 41.79, 91.83), - vector4(-383.43, 6064.31, 31.5, 135.49), - vector4(136.64, 6369.87, 31.37, 28.48), -- Paleto - -} - --- Bekannte Ziele mit festen Preisen -Config.KnownDestinations = { - { - name = "Los Santos International Airport", - coords = vector3(-1037.0, -2674.0, 13.8), - price = 50 - }, - { - name = "Vinewood Hills", - coords = vector3(120.0, 564.0, 184.0), - price = 35 - }, - { - name = "Del Perro Pier", - coords = vector3(-1850.0, -1230.0, 13.0), - price = 25 - }, - { - name = "Sandy Shores", - coords = vector3(1815.27, 3649.01, 34.25), - price = 75 - }, - { - name = "Paleto Bay", - coords = vector3(-296.31, 6056.98, 31.36), - price = 100 - }, - { - name = "Mount Chiliad", - coords = vector3(501.0, 5604.0, 797.0), - price = 120 - }, - { - name = "Maze Bank Tower", - coords = vector3(-46.24, -787.47, 44.14), - price = 40 - }, - { - name = "Vespucci Beach", - coords = vector3(-1686.28, -934.24, 7.69), - price = 30 - } -} - --- Allgemeine Einstellungen -Config.MaxWaitTime = 120 -- Sekunden bis Taxi spawnt -Config.TaxiCallCooldown = 30 -- Sekunden zwischen Taxi-Rufen -Config.MinFare = 10 -- Mindestpreis -Config.PricePerKm = 5 -- Standardpreis pro Kilometer -Config.WaitingFee = 2 -- Preis pro Minute warten -Config.StationTaxiRespawnTime = 300 -- 5 Minuten bis Taxi an Station respawnt - diff --git a/resources/[tools]/nordi_taxi/fxmanifest.lua b/resources/[tools]/nordi_taxi/fxmanifest.lua deleted file mode 100644 index b7e740a2c..000000000 --- a/resources/[tools]/nordi_taxi/fxmanifest.lua +++ /dev/null @@ -1,26 +0,0 @@ -fx_version 'cerulean' -game 'gta5' - -author 'YourName' -description 'Taxi System with ox_lib and qb-target' -version '1.0.0' - -shared_scripts { - '@ox_lib/init.lua', - 'config.lua' -} - -client_scripts { - 'client/main.lua', - 'client/stations.lua' -} - -server_scripts { - 'server/main.lua' -} - -dependencies { - 'qb-core', - 'ox_lib', - 'qb-target' -} diff --git a/resources/[tools]/nordi_taxi/server/main.lua b/resources/[tools]/nordi_taxi/server/main.lua deleted file mode 100644 index 8231a2081..000000000 --- a/resources/[tools]/nordi_taxi/server/main.lua +++ /dev/null @@ -1,62 +0,0 @@ - -function DebugPrint(type, message) - if Config.Debug then - if type == "error" then - print('^1[TAXI]^7 ' .. message) - elseif type == "warning" then - print('^3[TAXI]^7 ' .. message) - else -- success/info - print('^2[TAXI]^7 ' .. message) - end - end -end - -local QBCore = exports['qb-core']:GetCoreObject() - - -RegisterNetEvent('taxi:payFare', function(amount) - local src = source - local Player = QBCore.Functions.GetPlayer(src) - - if not Player then return end - - local playerMoney = Player.PlayerData.money.cash - - if playerMoney >= amount then - Player.Functions.RemoveMoney('cash', amount, 'taxi-fare') - TriggerClientEvent('QBCore:Notify', src, 'Du hast $' .. amount .. ' für die Taxifahrt bezahlt', 'success') - - -- Log für Admin - DebugPrint('^2[TAXI]^7 ' .. Player.PlayerData.name .. ' (' .. src .. ') hat $' .. amount .. ' für eine Taxifahrt bezahlt') - else - local bankMoney = Player.PlayerData.money.bank - if bankMoney >= amount then - Player.Functions.RemoveMoney('bank', amount, 'taxi-fare') - TriggerClientEvent('QBCore:Notify', src, 'Du hast $' .. amount .. ' per Karte für die Taxifahrt bezahlt', 'success') - - -- Log für Admin - DebugPrint('^2[TAXI]^7 ' .. Player.PlayerData.name .. ' (' .. src .. ') hat $' .. amount .. ' per Karte für eine Taxifahrt bezahlt') - else - TriggerClientEvent('QBCore:Notify', src, 'Du hast nicht genug Geld für die Taxifahrt!', 'error') - - -- Log für Admin - DebugPrint('^1[TAXI]^7 ' .. Player.PlayerData.name .. ' (' .. src .. ') konnte $' .. amount .. ' für eine Taxifahrt nicht bezahlen') - end - end -end) - --- Admin Command zum Respawnen aller Taxi-Stationen -QBCore.Commands.Add('respawntaxis', 'Respawne alle Taxi-Stationen (Admin Only)', {}, false, function(source, args) - local Player = QBCore.Functions.GetPlayer(source) - if Player.PlayerData.job.name == 'admin' or QBCore.Functions.HasPermission(source, 'admin') then - TriggerClientEvent('taxi:respawnAllStations', -1) - TriggerClientEvent('QBCore:Notify', source, 'Alle Taxi-Stationen wurden respawnt', 'success') - else - TriggerClientEvent('QBCore:Notify', source, 'Du hast keine Berechtigung für diesen Befehl', 'error') - end -end, 'admin') - --- Event für das Respawnen der Stationen -RegisterNetEvent('taxi:respawnAllStations', function() - -- Wird an alle Clients gesendet -end)