diff --git a/resources/[tools]/nordi_taxi/client/main.lua b/resources/[tools]/nordi_taxi/client/main.lua index e8b5edd4d..879ea4db7 100644 --- a/resources/[tools]/nordi_taxi/client/main.lua +++ b/resources/[tools]/nordi_taxi/client/main.lua @@ -86,9 +86,6 @@ function CallTaxi() -- Blip für Taxi erstellen (Entity-Blip) CreateTaxiBlips(taxi) - -- Überwachung des Taxi-Fortschritts - MonitorTaxiProgress(taxi, driver, playerCoords) - -- Überwachung der Ankunft MonitorTaxiArrival(taxi, driver, playerCoords) @@ -260,7 +257,6 @@ function GetImprovedTaxiSpawnPosition(playerCoords) return {x = x, y = y, z = z, w = 0.0} end - function SpawnTaxi(coords) print("^2[TAXI DEBUG]^7 Spawning taxi at: " .. tostring(coords.x) .. ", " .. tostring(coords.y) .. ", " .. tostring(coords.z)) @@ -324,6 +320,14 @@ function SpawnTaxi(coords) 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 @@ -345,12 +349,347 @@ function SpawnTaxi(coords) return taxi end +-- Fortgeschrittenes Taxi-Fahrer-Verhaltenssystem +function InitializeTaxiDriverAI(driver, vehicle) + if not driver or not DoesEntityExist(driver) then return end + + print("^2[TAXI DEBUG]^7 Initializing advanced taxi driver AI") + + -- Fahrer-Persönlichkeit und Fähigkeiten zufällig festlegen + local driverData = { + personality = { + patience = math.random(7, 10) / 10, -- 0.7-1.0: Wie geduldig ist der Fahrer + caution = math.random(6, 10) / 10, -- 0.6-1.0: Wie vorsichtig fährt er + speedPreference = math.random(15, 25), -- 15-25: Bevorzugte Geschwindigkeit + trafficRuleCompliance = math.random(8, 10)/10 -- 0.8-1.0: Wie genau hält er Verkehrsregeln ein + }, + state = { + stuckCounter = 0, + lastStuckRecovery = 0, + lastRouteRecalculation = 0, + currentBehavior = "normal", -- normal, cautious, stuck, recovery + lastSpeedCheck = 0, + speedHistory = {}, + lastPositions = {}, + trafficLightWaitStart = 0, + isWaitingAtTrafficLight = false + }, + settings = { + maxStuckCounter = math.random(15, 25), -- Wie lange warten bis Befreiungsversuch + stuckThreshold = 0.5, -- Bewegungsschwelle für Steckenbleiben + checkInterval = 2000, -- Überprüfungsintervall in ms + positionHistorySize = 5, -- Anzahl der zu speichernden Positionen + minRecoveryInterval = 25000, -- Min. Zeit zwischen Befreiungsversuchen + minRouteRecalcInterval = 30000, -- Min. Zeit zwischen Routenneuberechnungen + trafficLightMaxWait = 45000 -- Max. Wartezeit an Ampeln + } + } + + -- Fahrer-Verhalten basierend auf Persönlichkeit einstellen + SetDriverAbility(driver, driverData.personality.caution) + SetDriverAggressiveness(driver, 1.0 - driverData.personality.caution) + + -- Fahrer-Daten im Entity speichern + Entity(vehicle).state.driverData = driverData + + -- Fahrer-Verhalten-Thread starten + CreateThread(function() + local lastPos = GetEntityCoords(vehicle) + local lastCheck = GetGameTimer() + + while DoesEntityExist(vehicle) and DoesEntityExist(driver) do + Wait(driverData.settings.checkInterval) + + local currentTime = GetGameTimer() + local timeDelta = currentTime - lastCheck + lastCheck = currentTime + + -- Aktuelle Position und Geschwindigkeit + local currentPos = GetEntityCoords(vehicle) + local speed = GetEntitySpeed(vehicle) + local distanceMoved = #(lastPos - currentPos) + + -- Position für Historie speichern + table.insert(driverData.state.lastPositions, 1, currentPos) + if #driverData.state.lastPositions > driverData.settings.positionHistorySize then + table.remove(driverData.state.lastPositions) + end + + -- Geschwindigkeit für Historie speichern + table.insert(driverData.state.speedHistory, 1, speed) + if #driverData.state.speedHistory > 5 then + table.remove(driverData.state.speedHistory) + end + + -- Durchschnittsgeschwindigkeit berechnen + local avgSpeed = 0 + for _, s in ipairs(driverData.state.speedHistory) do + avgSpeed = avgSpeed + s + end + avgSpeed = avgSpeed / #driverData.state.speedHistory + + -- Ampel-Erkennung + local isAtTrafficLight = IsVehicleStoppedAtTrafficLights(vehicle) + + -- Ampel-Wartezustand aktualisieren + if isAtTrafficLight and not driverData.state.isWaitingAtTrafficLight then + -- Gerade an Ampel angekommen + driverData.state.isWaitingAtTrafficLight = true + driverData.state.trafficLightWaitStart = currentTime + print("^3[TAXI DEBUG]^7 Taxi waiting at traffic light") + elseif isAtTrafficLight and driverData.state.isWaitingAtTrafficLight then + -- Immer noch an Ampel + local waitTime = currentTime - driverData.state.trafficLightWaitStart + + -- Wenn zu lange an Ampel, versuche weiterzufahren (Ampel könnte hängen) + if waitTime > driverData.settings.trafficLightMaxWait then + print("^3[TAXI DEBUG]^7 Taxi waited too long at traffic light, trying to continue") + -- Kurz vorwärts fahren um Ampel zu überwinden + TaskVehicleTempAction(driver, vehicle, 1, 2000) -- Forward + Wait(2000) + -- Dann normale Fahrt fortsetzen + TaxiDriverContinueRoute(driver, vehicle) + driverData.state.isWaitingAtTrafficLight = false + end + elseif not isAtTrafficLight and driverData.state.isWaitingAtTrafficLight then + -- Ampel verlassen + driverData.state.isWaitingAtTrafficLight = false + print("^2[TAXI DEBUG]^7 Taxi continued after traffic light") + end + + -- Steckenbleiben-Erkennung (nicht an Ampel und kaum Bewegung) + if not isAtTrafficLight and distanceMoved < driverData.settings.stuckThreshold and speed < 0.5 then + driverData.state.stuckCounter = driverData.state.stuckCounter + 1 + + -- Nur alle 5 Zähler-Erhöhungen loggen + if driverData.state.stuckCounter % 5 == 0 then + print("^3[TAXI DEBUG]^7 Taxi might be stuck: " .. driverData.state.stuckCounter .. "/" .. driverData.settings.maxStuckCounter) + end + + -- Wenn lange genug steckengeblieben und genug Zeit seit letztem Versuch + if driverData.state.stuckCounter >= driverData.settings.maxStuckCounter and + (currentTime - driverData.state.lastStuckRecovery) > driverData.settings.minRecoveryInterval then + + print("^1[TAXI DEBUG]^7 Taxi is stuck, attempting intelligent recovery") + driverData.state.lastStuckRecovery = currentTime + driverData.state.currentBehavior = "recovery" + + -- Intelligente Befreiung basierend auf Umgebung + TaxiDriverIntelligentRecovery(driver, vehicle) + + -- Steckenbleiben-Zähler teilweise zurücksetzen + driverData.state.stuckCounter = math.floor(driverData.settings.maxStuckCounter * 0.4) + end + else + -- Wenn sich das Fahrzeug bewegt oder an einer Ampel steht + if isAtTrafficLight then + -- An Ampel: Zähler langsamer reduzieren + driverData.state.stuckCounter = math.max(0, driverData.state.stuckCounter - 0.2) + else + -- In Bewegung: Zähler reduzieren + driverData.state.stuckCounter = math.max(0, driverData.state.stuckCounter - 1) + + -- Wenn Fahrzeug sich bewegt, aber sehr langsam über längere Zeit + if avgSpeed < 2.0 and driverData.state.stuckCounter > driverData.settings.maxStuckCounter * 0.5 and + (currentTime - driverData.state.lastRouteRecalculation) > driverData.settings.minRouteRecalcInterval then + + print("^3[TAXI DEBUG]^7 Taxi moving too slow, recalculating route") + driverData.state.lastRouteRecalculation = currentTime + + -- Route neu berechnen + TaxiDriverRecalculateRoute(driver, vehicle) + end + end + end + + -- Verhalten basierend auf Umgebung anpassen + TaxiDriverAdaptBehavior(driver, vehicle, driverData) + + lastPos = currentPos + end + end) + + return driverData +end + +-- Intelligente Befreiung bei Steckenbleiben +function TaxiDriverIntelligentRecovery(driver, vehicle) + if not DoesEntityExist(vehicle) or not DoesEntityExist(driver) then return end + + -- Aktuelle Position und Umgebung analysieren + local vehicleCoords = GetEntityCoords(vehicle) + local vehicleHeading = GetEntityHeading(vehicle) + local vehicleForwardVector = GetEntityForwardVector(vehicle) + + -- Prüfen ob Hindernisse vorne, hinten, links, rechts + local forwardClear = not IsPositionOccupied( + vehicleCoords.x + vehicleForwardVector.x * 4.0, + vehicleCoords.y + vehicleForwardVector.y * 4.0, + vehicleCoords.z, + 1.0, false, true, false, false, false, 0, false + ) + + local backwardClear = not IsPositionOccupied( + vehicleCoords.x - vehicleForwardVector.x * 4.0, + vehicleCoords.y - vehicleForwardVector.y * 4.0, + vehicleCoords.z, + 1.0, false, true, false, false, false, 0, false + ) + + -- Befreiungsstrategie basierend auf Umgebung + ClearPedTasks(driver) + + if backwardClear then + -- Rückwärts fahren wenn hinten frei + print("^3[TAXI DEBUG]^7 Recovery: Backing up") + TaskVehicleTempAction(driver, vehicle, 8, 2000) -- Reverse + Wait(2000) + + if forwardClear then + -- Wenn vorne auch frei, einfach weiterfahren + print("^3[TAXI DEBUG]^7 Recovery: Path clear, continuing") + TaxiDriverContinueRoute(driver, vehicle) + else + -- Sonst versuchen zu wenden + print("^3[TAXI DEBUG]^7 Recovery: Turning around") + TaskVehicleTempAction(driver, vehicle, 7, 2000) -- Turn left + Wait(1000) + TaskVehicleTempAction(driver, vehicle, 8, 1000) -- Reverse + Wait(1000) + TaskVehicleTempAction(driver, vehicle, 6, 2000) -- Turn right + Wait(1000) + TaxiDriverContinueRoute(driver, vehicle) + end + elseif forwardClear then + -- Wenn nur vorne frei, vorwärts fahren + print("^3[TAXI DEBUG]^7 Recovery: Moving forward") + TaskVehicleTempAction(driver, vehicle, 1, 2000) -- Forward + Wait(2000) + TaxiDriverContinueRoute(driver, vehicle) + else + -- Wenn komplett eingeklemmt, versuche zu rütteln + print("^3[TAXI DEBUG]^7 Recovery: Trying to wiggle free") + TaskVehicleTempAction(driver, vehicle, 7, 1000) -- Turn left + Wait(1000) + TaskVehicleTempAction(driver, vehicle, 8, 800) -- Reverse + Wait(800) + TaskVehicleTempAction(driver, vehicle, 6, 1000) -- Turn right + Wait(1000) + TaskVehicleTempAction(driver, vehicle, 1, 800) -- Forward + Wait(800) + TaxiDriverContinueRoute(driver, vehicle) + end +end + +-- Route neu berechnen +function TaxiDriverRecalculateRoute(driver, vehicle) + if not DoesEntityExist(vehicle) or not DoesEntityExist(driver) then return end + + -- Aktuelle Zielposition aus dem Fahrzeug-State ermitteln + local destination = Entity(vehicle).state.currentDestination + + if destination then + -- Versuche einen alternativen Weg zu finden + print("^3[TAXI DEBUG]^7 Recalculating route to destination") + + -- Kurz anhalten + TaskVehicleTempAction(driver, vehicle, 27, 1000) -- Stop + Wait(1000) + + -- Neue Route mit leicht geändertem Fahrstil + local drivingStyle = 786603 -- Normal/Vorsichtig + TaskVehicleDriveToCoordLongrange(driver, vehicle, destination.x, destination.y, destination.z, 20.0, drivingStyle, 10.0) + else + -- Wenn kein Ziel bekannt, einfach weiterfahren + TaxiDriverContinueRoute(driver, vehicle) + end +end + +-- Normale Fahrt fortsetzen +function TaxiDriverContinueRoute(driver, vehicle) + if not DoesEntityExist(vehicle) or not DoesEntityExist(driver) then return end + + -- Ziel aus dem Fahrzeug-State holen + local destination = Entity(vehicle).state.currentDestination + + if destination then + -- Zum Ziel fahren mit angepasster Fahrweise + local drivingStyle = 786603 -- Normal/Vorsichtig + TaskVehicleDriveToCoordLongrange(driver, vehicle, destination.x, destination.y, destination.z, 20.0, drivingStyle, 10.0) + else + -- Wenn kein Ziel bekannt, einfach geradeaus fahren + TaskVehicleDriveWander(driver, vehicle, 15.0, 786603) + end +end + +-- Fahrverhalten an Umgebung anpassen +function TaxiDriverAdaptBehavior(driver, vehicle, driverData) + if not DoesEntityExist(vehicle) or not DoesEntityExist(driver) then return end + + -- Aktuelle Geschwindigkeit und Position + local speed = GetEntitySpeed(vehicle) + local vehicleCoords = GetEntityCoords(vehicle) + + -- Verkehrsdichte in der Umgebung prüfen + local vehiclesNearby = 0 + local vehicles = GetGamePool('CVehicle') + for _, otherVehicle in ipairs(vehicles) do + if otherVehicle ~= vehicle then + local otherCoords = GetEntityCoords(otherVehicle) + local distance = #(vehicleCoords - otherCoords) + if distance < 15.0 then + vehiclesNearby = vehiclesNearby + 1 + end + end + end + + -- Verhalten basierend auf Verkehrsdichte anpassen + local targetSpeed = driverData.personality.speedPreference + + if vehiclesNearby > 5 then + -- Viel Verkehr: langsamer und vorsichtiger + targetSpeed = targetSpeed * 0.7 + SetDriverAggressiveness(driver, 0.0) + elseif vehiclesNearby > 2 then + -- Moderater Verkehr: etwas langsamer + targetSpeed = targetSpeed * 0.85 + SetDriverAggressiveness(driver, 0.1) + else + -- Wenig Verkehr: normale Geschwindigkeit + SetDriverAggressiveness(driver, 0.2) + end + + -- Geschwindigkeit anpassen wenn nötig + if math.abs(speed - targetSpeed) > 5.0 then + if speed < targetSpeed then + -- Beschleunigen + TaskVehicleTempAction(driver, vehicle, 23, 500) -- Gentle forward + else + -- Abbremsen + TaskVehicleTempAction(driver, vehicle, 24, 500) -- Gentle brake + end + + -- Nach der Anpassung normale Fahrt fortsetzen + Wait(500) + TaxiDriverContinueRoute(driver, vehicle) + end +end + +-- Hilfsfunktion zur Normalisierung eines Vektors +function norm(vector) + local length = math.sqrt(vector.x * vector.x + vector.y * vector.y + vector.z * vector.z) + if length == 0 then + return vector3(0.0, 0.0, 0.0) + end + return vector3(vector.x / length, vector.y / length, vector.z / length) +end + function SpawnTaxiDriver(vehicle) print("^2[TAXI DEBUG]^7 Spawning taxi driver...") -- Bessere Fahrer-Models mit Fallbacks local driverModels = { - "A_C_Chimp", -- Affe (erste Wahl) + "s_m_y_taxidriver_01", -- 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 @@ -411,8 +750,6 @@ function SpawnTaxiDriver(vehicle) SetEntityAsMissionEntity(driver, true, true) SetBlockingOfNonTemporaryEvents(driver, true) - SetDriverAbility(driver, 1.0) -- Maximale Fahrfähigkeit - SetDriverAggressiveness(driver, 0.0) -- Minimale Aggressivität SetPedFleeAttributes(driver, 0, 0) SetPedCombatAttributes(driver, 17, 1) SetPedSeeingRange(driver, 0.0) @@ -420,6 +757,17 @@ function SpawnTaxiDriver(vehicle) SetPedAlertness(driver, 0) SetPedKeepTask(driver, true) + -- Fortgeschrittene KI-ähnliche Fahrer-Logik initialisieren + local driverData = InitializeTaxiDriverAI(driver, vehicle) + + -- Zufälligen Fahrer-Namen generieren + local firstNames = {"Max", "Thomas", "Ali", "Mehmet", "Hans", "Peter", "Klaus", "Michael", "Stefan", "Frank"} + local lastNames = {"Müller", "Schmidt", "Schneider", "Fischer", "Weber", "Meyer", "Wagner", "Becker", "Schulz", "Hoffmann"} + local driverName = firstNames[math.random(#firstNames)] .. " " .. lastNames[math.random(#lastNames)] + + -- Fahrer-Name im Fahrzeug-State speichern + Entity(vehicle).state.driverName = driverName + -- Fahrer-Outfit (nur wenn es ein anpassbarer Ped ist) if driverHash == GetHashKey("mp_m_freemode_01") then print("^2[TAXI DEBUG]^7 Setting driver outfit...") @@ -494,138 +842,23 @@ end function NavigateToPlayer(driver, taxi, playerCoords) print("^2[TAXI DEBUG]^7 Navigating taxi to player...") + -- Ziel im Fahrzeug-State speichern für die KI-Logik + Entity(taxi).state.currentDestination = playerCoords + -- Versuche einen guten Wegpunkt in der Nähe des Spielers zu finden local success, nodePos = GetClosestVehicleNodeWithHeading(playerCoords.x, playerCoords.y, playerCoords.z, 1, 3.0, 0) if success then print("^2[TAXI DEBUG]^7 Found good vehicle node near player") -- Zum Wegpunkt fahren - TaskVehicleDriveToCoordLongrange(driver, taxi, nodePos.x, nodePos.y, nodePos.z, 25.0, 786603, 5.0) + TaskVehicleDriveToCoordLongrange(driver, taxi, nodePos.x, nodePos.y, nodePos.z, 20.0, 786603, 10.0) else print("^3[TAXI DEBUG]^7 No good vehicle node found, driving directly to player") -- Direkt zum Spieler fahren - TaskVehicleDriveToCoordLongrange(driver, taxi, playerCoords.x, playerCoords.y, playerCoords.z, 25.0, 786603, 5.0) - end - - -- Fahrer-Verhalten verbessern - SetDriverAggressiveness(driver, 0.0) - SetDriverAbility(driver, 1.0) -end - -function MonitorTaxiProgress(taxi, driver, playerCoords) - print("^2[TAXI DEBUG]^7 Monitoring taxi progress...") - - local lastPos = GetEntityCoords(taxi) - local stuckCounter = 0 - local maxStuckCount = 20 - local totalStuckEvents = 3 - local maxTotalStuckEvents = 6 - - CreateThread(function() - while DoesEntityExist(taxi) and DoesEntityExist(driver) do - Wait(3000) - - if not DoesEntityExist(taxi) then - print("^1[TAXI DEBUG]^7 Taxi no longer exists! Taxi ID: " .. tostring(taxi)) - if currentTaxi == taxi then - print("^1[TAXI DEBUG]^7 This was the current active taxi") - else - print("^1[TAXI DEBUG]^7 This was NOT the current active taxi. Current taxi: " .. tostring(currentTaxi)) - end - return - end - - if not DoesEntityExist(driver) then - print("^1[TAXI DEBUG]^7 Driver no longer exists! Driver ID: " .. tostring(driver)) - if currentDriver == driver then - print("^1[TAXI DEBUG]^7 This was the current active driver") - else - print("^1[TAXI DEBUG]^7 This was NOT the current active driver. Current driver: " .. tostring(currentDriver)) - end - return - end - - local currentPos = GetEntityCoords(taxi) - local distanceMoved = #(lastPos - currentPos) - local currentPlayerCoords = GetEntityCoords(PlayerPedId()) - local distanceToPlayer = #(currentPos - currentPlayerCoords) - - -- If taxi is close to player, we're done monitoring progress - if distanceToPlayer < 15.0 then - print("^2[TAXI DEBUG]^7 Taxi arrived near player, stopping progress monitoring") - return - end - - -- Check if taxi is stuck (not moving much) - if distanceMoved < 1.0 then - stuckCounter = stuckCounter + 1 - print("^3[TAXI DEBUG]^7 Taxi might be stuck: " .. stuckCounter .. "/" .. maxStuckCount) - - -- If stuck for too long, try recovery - if stuckCounter >= maxStuckCount then - totalStuckEvents = totalStuckEvents + 1 - print("^1[TAXI DEBUG]^7 Taxi is stuck, attempting recovery #" .. totalStuckEvents) - - if totalStuckEvents >= maxTotalStuckEvents then - print("^1[TAXI DEBUG]^7 Too many stuck events, respawning taxi") - 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() - return - else - -- Try to recover - RecoverStuckTaxi(taxi, driver, currentPlayerCoords) - stuckCounter = 0 - end - end - else - stuckCounter = math.max(0, stuckCounter - 1) -- Gradually reduce counter if moving - end - - lastPos = currentPos - end - end) -end - -function RecoverStuckTaxi(taxi, driver, playerCoords) - print("^2[TAXI DEBUG]^7 Attempting to recover stuck taxi") - - -- Clear current task - ClearPedTasks(driver) - - -- Try to back up a bit first - TaskVehicleTempAction(driver, taxi, 8, 2000) -- Reverse - Wait(2000) - - -- Try to turn around - TaskVehicleTempAction(driver, taxi, 7, 2000) -- Turn left - Wait(1000) - TaskVehicleTempAction(driver, taxi, 8, 1000) -- Reverse - Wait(1000) - TaskVehicleTempAction(driver, taxi, 6, 2000) -- Turn right - Wait(1000) - - -- Try to find a new path - local found, nodePos = GetClosestVehicleNode(playerCoords.x, playerCoords.y, playerCoords.z, 1, 3.0, 0) - - if found then - print("^2[TAXI DEBUG]^7 Found new path for recovery") - TaskVehicleDriveToCoordLongrange(driver, taxi, nodePos.x, nodePos.y, nodePos.z, 25.0, 786603, 5.0) - else - -- Direct approach as fallback - print("^3[TAXI DEBUG]^7 Using direct approach for recovery") - TaskVehicleDriveToCoordLongrange(driver, taxi, playerCoords.x, playerCoords.y, playerCoords.z, 25.0, 786603, 5.0) + TaskVehicleDriveToCoordLongrange(driver, taxi, playerCoords.x, playerCoords.y, playerCoords.z, 20.0, 786603, 10.0) end end - function MonitorTaxiArrival(taxi, driver, playerCoords) print("^2[TAXI DEBUG]^7 Monitoring taxi arrival...") @@ -691,8 +924,6 @@ function MonitorTaxiArrival(taxi, driver, playerCoords) end) end - - -- Event für Einsteigen ins Taxi RegisterNetEvent('taxi:enterTaxi', function() print("^2[TAXI DEBUG]^7 Player entering taxi") @@ -870,48 +1101,48 @@ function StartTaxiRide(destination, price) 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 - NavigateToDestination(currentDriver, currentTaxi, destination) + 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 NavigateToDestination(driver, taxi, destination) - print("^2[TAXI DEBUG]^7 Navigating to destination...") - - -- Versuche einen guten Wegpunkt in der Nähe des Ziels zu finden - local success, nodePos = GetClosestVehicleNodeWithHeading(destination.x, destination.y, destination.z, 1, 3.0, 0) - - if success then - print("^2[TAXI DEBUG]^7 Found good vehicle node near destination") - -- Zum Wegpunkt fahren mit verbesserter Fahrweise - TaskVehicleDriveToCoordLongrange(driver, taxi, nodePos.x, nodePos.y, nodePos.z, 25.0, 786603, 5.0) - else - print("^3[TAXI DEBUG]^7 No good vehicle node found, driving directly to destination") - -- Direkt zum Ziel fahren - TaskVehicleDriveToCoordLongrange(driver, taxi, destination.x, destination.y, destination.z, 25.0, 786603, 5.0) - end - - -- Fahrer-Verhalten verbessern - SetDriverAggressiveness(driver, 0.0) - SetDriverAbility(driver, 1.0) -end - - function MonitorTaxiRide(destination, price) print("^2[TAXI DEBUG]^7 Monitoring taxi ride...") - local lastPos = GetEntityCoords(currentTaxi) - local stuckCounter = 0 - local maxStuckCount = 10 - local rideTimeout = GetGameTimer() + (10 * 60 * 1000) -- 5 Minuten Timeout + 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) - local distanceMoved = #(lastPos - taxiCoords) -- Überprüfen ob wir angekommen sind if distance < 10.0 then @@ -934,6 +1165,24 @@ function MonitorTaxiRide(destination, price) 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() @@ -942,70 +1191,53 @@ function MonitorTaxiRide(destination, price) break end - -- Überprüfen ob das Taxi stecken geblieben ist - if distanceMoved < 1.0 then - stuckCounter = stuckCounter + 1 + -- Überprüfen ob die Fahrt zu lange dauert + if GetGameTimer() > rideTimeout then + print("^1[TAXI DEBUG]^7 Taxi ride timed out!") - if stuckCounter >= maxStuckCount then - print("^1[TAXI DEBUG]^7 Taxi stuck during ride, attempting recovery") - RecoverStuckTaxi(currentTaxi, currentDriver, vector3(destination.x, destination.y, destination.z)) - stuckCounter = 0 + -- 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 - else - stuckCounter = math.max(0, stuckCounter - 1) + + -- 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 --- Überprüfen ob die Fahrt zu lange dauert -if GetGameTimer() > rideTimeout then - print("^1[TAXI DEBUG]^7 Taxi ride timed out!") - - -- Berechne verbleibende Distanz - local taxiCoords = GetEntityCoords(currentTaxi) - local remainingDistance = #(vector3(destination.x, destination.y, destination.z) - taxiCoords) - - lib.notify({ - title = 'Taxi Service', - description = 'Die Fahrt dauert zu lange. Noch ' .. math.ceil(remainingDistance) .. 'm bis zum Ziel!', - type = 'warning' - }) - - -- Teleportiere Taxi näher ans Ziel (75% des Weges) - local direction = vector3( - destination.x - taxiCoords.x, - destination.y - taxiCoords.y, - destination.z - taxiCoords.z - ) - local normalizedDir = norm(direction) - local teleportDistance = remainingDistance * 0.75 - - local newPos = vector3( - taxiCoords.x + normalizedDir.x * teleportDistance, - taxiCoords.y + normalizedDir.y * teleportDistance, - taxiCoords.z - ) - - -- Finde gültige Z-Koordinate - local success, groundZ = GetGroundZFor_3dCoord(newPos.x, newPos.y, newPos.z, true) - if success then - newPos = vector3(newPos.x, newPos.y, groundZ) - end - - -- Teleportiere Taxi - SetEntityCoords(currentTaxi, newPos.x, newPos.y, newPos.z, false, false, false, false) - - -- Neues Timeout setzen (2 Minuten) - rideTimeout = GetGameTimer() + (2 * 60 * 1000) -end - - - lastPos = taxiCoords Wait(2000) end end) end - - function SelfDriveTaxi() print("^2[TAXI DEBUG]^7 Player driving taxi themselves") @@ -1031,7 +1263,6 @@ function SelfDriveTaxi() }) end - function ExitTaxi() print("^2[TAXI DEBUG]^7 Player exiting taxi") @@ -1054,7 +1285,6 @@ function ExitTaxi() end) end - function DespawnTaxi() print("^2[TAXI DEBUG]^7 Despawning taxi") @@ -1144,7 +1374,6 @@ function CalculateDistanceToCoords(coords) return #(playerCoords - coords) end - -- Command um Taxi zu stoppen RegisterCommand('stoptaxi', function() if currentTaxi and DoesEntityExist(currentTaxi) then @@ -1242,7 +1471,6 @@ function EndTaxiRide() end) end - -- Thread zum Überwachen des Einsteigens ins Taxi (ohne qb-target) CreateThread(function() while true do @@ -1270,7 +1498,6 @@ CreateThread(function() 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 @@ -1317,3 +1544,6 @@ AddEventHandler('onResourceStop', function(resourceName) print("^2[TAXI DEBUG]^7 Main cleanup completed") end end) + + + diff --git a/resources/[tools]/nordi_taxi/config.lua b/resources/[tools]/nordi_taxi/config.lua index 609394de7..eb57c1133 100644 --- a/resources/[tools]/nordi_taxi/config.lua +++ b/resources/[tools]/nordi_taxi/config.lua @@ -139,7 +139,7 @@ Config.KnownDestinations = { }, { name = "Paleto Bay", - coords = vector3(-276.0, 6635.0, 7.5), + coords = vector3(-296.31, 6056.98, 31.36), price = 100 }, {