diff --git a/resources/[tools]/nordi_taxi/client/main.lua b/resources/[tools]/nordi_taxi/client/main.lua index bf7e9fc2d..01f1588af 100644 --- a/resources/[tools]/nordi_taxi/client/main.lua +++ b/resources/[tools]/nordi_taxi/client/main.lua @@ -45,8 +45,8 @@ function CallTaxi() print("^2[TAXI DEBUG]^7 Player coords: " .. tostring(playerCoords)) - -- Spawn-Position für Taxi finden - Direkt aus Config - local spawnCoords = GetTaxiSpawnPosition(playerCoords) + -- Verbesserte Spawn-Position für Taxi finden + local spawnCoords = GetImprovedTaxiSpawnPosition(playerCoords) if not spawnCoords then print("^1[TAXI DEBUG]^7 No spawn position found") lib.notify({ @@ -57,7 +57,7 @@ function CallTaxi() return end - print("^2[TAXI DEBUG]^7 Spawn coords found: " .. tostring(spawnCoords)) + print("^2[TAXI DEBUG]^7 Spawn coords found: " .. tostring(spawnCoords.x) .. ", " .. tostring(spawnCoords.y) .. ", " .. tostring(spawnCoords.z)) -- Taxi spawnen local taxi = SpawnTaxi(spawnCoords) @@ -80,55 +80,23 @@ function CallTaxi() currentDriver = driver print("^2[TAXI DEBUG]^7 Driver spawned: " .. driver) - -- Zum Spieler fahren - TaskVehicleDriveToCoord(driver, taxi, playerCoords.x, playerCoords.y, playerCoords.z, 25.0, 0, GetEntityModel(taxi), 786603, 1.0, true) + -- Verbesserte Navigation zum Spieler + NavigateToPlayer(driver, taxi, playerCoords) -- 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) + CreateTaxiBlips(taxi) - -- 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) + -- Überwachung des Taxi-Fortschritts + MonitorTaxiProgress(taxi, driver, playerCoords) - -- 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) + -- Ü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' }) - - -- Überwachung der Ankunft - MonitorTaxiArrival(taxi, driver, playerCoords) else print("^1[TAXI DEBUG]^7 Failed to spawn driver") lib.notify({ @@ -140,87 +108,151 @@ function CallTaxi() end) end -function GetTaxiSpawnPosition(playerCoords) - print("^2[TAXI DEBUG]^7 Finding spawn position...") +function GetImprovedTaxiSpawnPosition(playerCoords) + print("^2[TAXI DEBUG]^7 Finding improved spawn position...") - -- Prüfen ob Config.MobileTaxiSpawns existiert und nicht leer ist - if not Config.MobileTaxiSpawns or #Config.MobileTaxiSpawns == 0 then - print("^1[TAXI DEBUG]^7 Config.MobileTaxiSpawns is missing or empty") - return nil + -- 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 + foundNode, nodePos = GetClosestVehicleNode(playerCoords.x, playerCoords.y, playerCoords.z, 1, 3.0, 0) + + if foundNode then + local nodeDistance = #(playerCoords - nodePos) + if nodeDistance > 50.0 and nodeDistance < 150.0 then + roadPosition = nodePos + print("^2[TAXI DEBUG]^7 Found road node for spawn at distance: " .. nodeDistance) + return {x = roadPosition.x, y = roadPosition.y, z = roadPosition.z, w = 0.0} + end end - -- 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)) - table.insert(sortedSpawns, { - coords = spawnPos, - distance = distance - }) + -- 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 > 40.0 and nodeDistance < 200.0 then + roadPosition = nodePos + print("^2[TAXI DEBUG]^7 Found major road node for spawn at distance: " .. nodeDistance) + return {x = roadPosition.x, y = roadPosition.y, z = roadPosition.z, w = 0.0} + end end - -- Nach Entfernung sortieren (nächste zuerst) - table.sort(sortedSpawns, function(a, b) - return a.distance < b.distance - end) - - -- Prüfen ob die nächsten Positionen frei sind - for i, spawn in ipairs(sortedSpawns) do - local spawnCoords = spawn.coords + -- 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)) + table.insert(sortedSpawns, { + coords = spawnPos, + distance = distance + }) + end - -- Prüfen ob Position frei ist - local clearArea = true - local vehicles = GetGamePool('CVehicle') + -- Nach Entfernung sortieren (nächste zuerst) + table.sort(sortedSpawns, function(a, b) + return a.distance < b.distance + end) - -- 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 + -- Prüfen ob die nächsten Positionen frei sind + for i, spawn in ipairs(sortedSpawns) do + local spawnCoords = spawn.coords + + -- Prüfen ob Position frei ist + local clearArea = true + local vehicles = GetGamePool('CVehicle') + + -- Prüfen ob andere Fahrzeuge in der Nähe sind + for _, vehicle in ipairs(vehicles) do + local vehCoords = GetEntityCoords(vehicle) + if #(vector3(spawnCoords.x, spawnCoords.y, spawnCoords.z) - vehCoords) < 5.0 then + clearArea = false + break + end + end + + -- Wenn Position frei ist, verwenden + if clearArea then + print("^2[TAXI DEBUG]^7 Using spawn position from config: " .. tostring(spawnCoords.x) .. ", " .. tostring(spawnCoords.y) .. ", " .. tostring(spawnCoords.z) .. " (Distance: " .. spawn.distance .. "m)") + return spawnCoords end end - -- Wenn Position frei ist, verwenden - if clearArea then - print("^2[TAXI DEBUG]^7 Using spawn position from config: " .. tostring(spawnCoords) .. " (Distance: " .. spawn.distance .. "m)") - return spawnCoords - end + -- Wenn keine freie Position gefunden wurde, die am weitesten entfernte verwenden + local fallbackSpawn = sortedSpawns[#sortedSpawns].coords + print("^3[TAXI DEBUG]^7 No clear spawn position found, using fallback: " .. tostring(fallbackSpawn.x) .. ", " .. tostring(fallbackSpawn.y) .. ", " .. tostring(fallbackSpawn.z)) + return fallbackSpawn end - -- Wenn keine freie Position gefunden wurde, die am weitesten entfernte verwenden - local fallbackSpawn = sortedSpawns[#sortedSpawns].coords - print("^3[TAXI DEBUG]^7 No clear spawn position found, using fallback: " .. tostring(fallbackSpawn)) - return fallbackSpawn + -- Absolute Notfall-Fallback: Zufällige Position um Spieler herum + local angle = math.random() * 2 * math.pi + local distance = math.random(80, 120) + local x = playerCoords.x + math.cos(angle) * distance + local y = playerCoords.y + math.sin(angle) * distance + local z = playerCoords.z + + -- Versuche eine gültige Z-Koordinate zu bekommen + local success, groundZ = GetGroundZFor_3dCoord(x, y, z, true) + if success then + z = groundZ + end + + print("^3[TAXI DEBUG]^7 Using emergency random spawn position") + return {x = x, y = y, z = z, w = 0.0} end function SpawnTaxi(coords) - print("^2[TAXI DEBUG]^7 Spawning taxi at: " .. tostring(coords)) + print("^2[TAXI DEBUG]^7 Spawning taxi at: " .. tostring(coords.x) .. ", " .. tostring(coords.y) .. ", " .. tostring(coords.z)) -- Sicherstellen dass wir ein gültiges Taxi-Model haben local taxiModel = nil if Config.TaxiVehicles and #Config.TaxiVehicles > 0 then - taxiModel = GetHashKey(Config.TaxiVehicles[1].model) + -- Zufälliges Taxi-Model aus Config wählen + local randomIndex = math.random(1, #Config.TaxiVehicles) + taxiModel = GetHashKey(Config.TaxiVehicles[randomIndex].model) else taxiModel = GetHashKey("taxi") -- Fallback end print("^2[TAXI DEBUG]^7 Taxi model hash: " .. taxiModel) + -- Model laden mit Timeout RequestModel(taxiModel) + local modelLoaded = false local timeout = GetGameTimer() + 10000 - while not HasModelLoaded(taxiModel) and GetGameTimer() < timeout do - print("^3[TAXI DEBUG]^7 Waiting for taxi model to load...") - Wait(100) + + while not modelLoaded and GetGameTimer() < timeout do + modelLoaded = HasModelLoaded(taxiModel) + if not modelLoaded then + print("^3[TAXI DEBUG]^7 Waiting for taxi model to load...") + Wait(100) + end end - if not HasModelLoaded(taxiModel) then - print("^1[TAXI DEBUG]^7 Failed to load taxi model!") - return nil + if not modelLoaded then + print("^1[TAXI DEBUG]^7 Failed to load taxi model! Trying default model.") + SetModelAsNoLongerNeeded(taxiModel) + + -- Versuche Standard-Taxi als Fallback + taxiModel = GetHashKey("taxi") + RequestModel(taxiModel) + + timeout = GetGameTimer() + 5000 + while not HasModelLoaded(taxiModel) and GetGameTimer() < timeout do + Wait(100) + end + + if not HasModelLoaded(taxiModel) then + print("^1[TAXI DEBUG]^7 Failed to load default taxi model!") + return nil + end end - -- Direkt die Koordinaten aus der Config verwenden - local taxi = CreateVehicle(taxiModel, coords.x, coords.y, coords.z, coords.w, true, false) + -- Fahrzeug erstellen + local taxi = CreateVehicle(taxiModel, coords.x, coords.y, coords.z, coords.w or 0.0, true, false) if not DoesEntityExist(taxi) then print("^1[TAXI DEBUG]^7 Failed to create taxi vehicle!") @@ -229,6 +261,7 @@ function SpawnTaxi(coords) print("^2[TAXI DEBUG]^7 Taxi created successfully: " .. taxi) + -- Fahrzeug konfigurieren SetEntityAsMissionEntity(taxi, true, true) SetVehicleOnGroundProperly(taxi) SetVehicleEngineOn(taxi, true, true, false) @@ -241,32 +274,40 @@ function SpawnTaxi(coords) print("^2[TAXI DEBUG]^7 Taxi livery set") end + -- Fahrzeug-Extras aktivieren falls vorhanden + for i = 1, 14 do + if DoesExtraExist(taxi, i) then + SetVehicleExtra(taxi, i, false) -- Extra aktivieren + end + end + + -- Fahrzeug-Farbe setzen (Gelb für Taxis) + SetVehicleColours(taxi, 88, 88) -- Taxi Yellow + SetModelAsNoLongerNeeded(taxiModel) return taxi end - - function SpawnTaxiDriver(vehicle) print("^2[TAXI DEBUG]^7 Spawning taxi driver...") -- Bessere Fahrer-Models mit Fallbacks local driverModels = { - "A_C_Chimp", -- Standard Male (sollte immer verfügbar sein) - "U_M_M_Jesus_01", -- Standard Female - "a_m_y_business_01", -- Business Male - "a_f_y_business_01", -- Business Female - "a_m_m_business_01", -- Business Male 2 - "a_m_y_downtown_01", -- Downtown Male - "A_M_M_SouCent_02", -- Pilot - "IG_Tonya" -- Dealer + "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 + "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 pairs(driverModels) do + for i, modelName in ipairs(driverModels) do print("^2[TAXI DEBUG]^7 Trying driver model " .. i .. ": " .. modelName) driverHash = GetHashKey(modelName) @@ -303,37 +344,6 @@ function SpawnTaxiDriver(vehicle) end -- Wenn immer noch kein Fahrer erstellt wurde - if not driver or not DoesEntityExist(driver) then - print("^1[TAXI DEBUG]^7 All driver models failed, trying emergency fallback...") - - -- Notfall-Fallback: Versuche den einfachsten Ped zu erstellen - 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 - print("^2[TAXI DEBUG]^7 Emergency driver created with hash: " .. hash) - driverHash = hash - break - end - SetModelAsNoLongerNeeded(hash) - end - end - end - - -- Wenn immer noch kein Fahrer if not driver or not DoesEntityExist(driver) then print("^1[TAXI DEBUG]^7 Could not create any driver! Continuing without driver...") return nil @@ -343,29 +353,33 @@ function SpawnTaxiDriver(vehicle) print("^2[TAXI DEBUG]^7 Configuring driver...") 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) SetPedHearingRange(driver, 0.0) SetPedAlertness(driver, 0) SetPedKeepTask(driver, true) - SetBlockingOfNonTemporaryEvents(driver, true) -- Fahrer-Outfit (nur wenn es ein anpassbarer Ped ist) - if driverHash == GetHashKey("mp_m_freemode_01") or driverHash == GetHashKey("mp_f_freemode_01") then + if driverHash == GetHashKey("mp_m_freemode_01") then print("^2[TAXI DEBUG]^7 Setting driver outfit...") -- Basis-Outfit für Taxi-Fahrer - SetPedComponentVariation(driver, 8, 15, 0, 0) -- Undershirt - SetPedComponentVariation(driver, 11, 28, 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 + 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) @@ -380,14 +394,178 @@ function SpawnTaxiDriver(vehicle) return driver end +function CreateTaxiBlips(taxi) + -- Blip für Taxi erstellen (Entity-Blip) + taxiBlip = AddBlipForEntity(taxi) + SetBlipSprite(taxiBlip, 198) + SetBlipColour(taxiBlip, 5) + SetBlipScale(taxiBlip, 0.8) + SetBlipDisplay(taxiBlip, 2) -- Zeigt auf Minimap und großer Karte + SetBlipShowCone(taxiBlip, true) -- Zeigt Sichtkegel + SetBlipAsShortRange(taxiBlip, false) -- Immer sichtbar, egal wie weit entfernt + BeginTextCommandSetBlipName("STRING") + AddTextComponentString("Dein Taxi") + EndTextCommandSetBlipName(taxiBlip) + + -- Zusätzlicher Blip auf der Karte für bessere Sichtbarkeit + local taxiCoords = GetEntityCoords(taxi) + mapBlip = AddBlipForCoord(taxiCoords.x, taxiCoords.y, taxiCoords.z) + SetBlipSprite(mapBlip, 198) + SetBlipColour(mapBlip, 5) + SetBlipScale(mapBlip, 1.0) + SetBlipDisplay(mapBlip, 4) -- Nur auf großer Karte + BeginTextCommandSetBlipName("STRING") + AddTextComponentString("Dein Taxi") + EndTextCommandSetBlipName(mapBlip) + + -- Blip aktualisieren während Taxi unterwegs ist + CreateThread(function() + while DoesEntityExist(taxi) and mapBlip do + local taxiCoords = GetEntityCoords(taxi) + SetBlipCoords(mapBlip, taxiCoords.x, taxiCoords.y, taxiCoords.z) + Wait(1000) + end + + -- Blip entfernen wenn Thread beendet + if mapBlip then + RemoveBlip(mapBlip) + mapBlip = nil + end + end) +end + +function NavigateToPlayer(driver, taxi, playerCoords) + print("^2[TAXI DEBUG]^7 Navigating taxi to player...") + + -- 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) + 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) +} + +function MonitorTaxiProgress(taxi, driver, playerCoords) + print("^2[TAXI DEBUG]^7 Monitoring taxi progress...") + + local lastPos = GetEntityCoords(taxi) + local stuckCounter = 0 + local maxStuckCount = 5 + local totalStuckEvents = 0 + local maxTotalStuckEvents = 3 + + CreateThread(function() + while DoesEntityExist(taxi) and DoesEntityExist(driver) do + Wait(3000) + + -- Check if taxi exists and is moving + if not DoesEntityExist(taxi) or not DoesEntityExist(driver) then + print("^1[TAXI DEBUG]^7 Taxi or driver no longer exists") + 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) + end +} + function MonitorTaxiArrival(taxi, driver, playerCoords) print("^2[TAXI DEBUG]^7 Monitoring taxi arrival...") + local arrivalTimeout = GetGameTimer() + (120 * 1000) -- 2 minute timeout + CreateThread(function() while DoesEntityExist(taxi) and (not driver or DoesEntityExist(driver)) do local taxiCoords = GetEntityCoords(taxi) - local distance = #(playerCoords - taxiCoords) + local currentPlayerCoords = GetEntityCoords(PlayerPedId()) + local distance = #(currentPlayerCoords - taxiCoords) + -- Check if taxi is close to player if distance < 15.0 then print("^2[TAXI DEBUG]^7 Taxi arrived!") @@ -420,10 +598,26 @@ function MonitorTaxiArrival(taxi, driver, playerCoords) break end + -- Check for timeout + if GetGameTimer() > arrivalTimeout then + print("^1[TAXI DEBUG]^7 Taxi arrival timed out!") + lib.notify({ + title = 'Taxi Service', + description = 'Dein Taxi steckt fest. Ein neues wird gerufen!', + type = 'warning' + }) + + -- Despawn current taxi and call a new one + DespawnTaxi() + Wait(1000) + CallTaxi() + break + end + Wait(2000) end end) -end +} -- Event für Einsteigen ins Taxi RegisterNetEvent('taxi:enterTaxi', function() @@ -484,7 +678,6 @@ RegisterNetEvent('taxi:enterTaxi', function() end) end) - function OpenDestinationMenu() print("^2[TAXI DEBUG]^7 Opening destination menu") @@ -560,7 +753,7 @@ function OpenDestinationMenu() end function StartTaxiRide(destination, price) - print("^2[TAXI DEBUG]^7 Starting taxi ride to: " .. tostring(destination)) + print("^2[TAXI DEBUG]^7 Starting taxi ride to: " .. tostring(destination.x) .. ", " .. tostring(destination.y) .. ", " .. tostring(destination.z)) if not currentTaxi or not DoesEntityExist(currentTaxi) then print("^1[TAXI DEBUG]^7 No taxi exists for ride") @@ -584,29 +777,68 @@ function StartTaxiRide(destination, price) }) -- 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) - -- Zum Ziel fahren - TaskVehicleDriveToCoord(currentDriver, currentTaxi, destination.x, destination.y, destination.z, 25.0, 0, GetEntityModel(currentTaxi), 786603, 1.0, true) + -- Taximeter starten + taxiMeter.isRunning = true + taxiMeter.startCoords = GetEntityCoords(currentTaxi) + taxiMeter.currentFare = 0 + taxiMeter.pricePerKm = Config.PricePerKm + + -- Zum Ziel fahren mit verbesserter Navigation + NavigateToDestination(currentDriver, currentTaxi, destination) -- 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) +} + function MonitorTaxiRide(destination, price) print("^2[TAXI DEBUG]^7 Monitoring taxi ride...") + local lastPos = GetEntityCoords(currentTaxi) + local stuckCounter = 0 + local maxStuckCount = 5 + local rideTimeout = GetGameTimer() + (5 * 60 * 1000) -- 5 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 -- Angekommen TaskVehicleTempAction(currentDriver, currentTaxi, 27, 3000) @@ -635,10 +867,54 @@ function MonitorTaxiRide(destination, price) break end + -- Überprüfen ob das Taxi stecken geblieben ist + if distanceMoved < 1.0 then + stuckCounter = stuckCounter + 1 + + 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 + end + else + stuckCounter = math.max(0, stuckCounter - 1) + end + + -- Überprüfen ob die Fahrt zu lange dauert + if GetGameTimer() > rideTimeout then + print("^1[TAXI 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(currentTaxi, nearDestination.x, nearDestination.y, nearDestination.z, false, false, false, false) + + -- Neues Timeout setzen (1 Minute) + rideTimeout = GetGameTimer() + (60 * 1000) + } + + lastPos = taxiCoords Wait(2000) end end) -end +} function SelfDriveTaxi() print("^2[TAXI DEBUG]^7 Player driving taxi themselves") @@ -663,7 +939,7 @@ function SelfDriveTaxi() description = 'Du fährst das Taxi jetzt selbst. Nutze /stoptaxi um es zu beenden.', type = 'info' }) -end +} function ExitTaxi() print("^2[TAXI DEBUG]^7 Player exiting taxi") @@ -685,7 +961,7 @@ function ExitTaxi() SetTimeout(5000, function() DespawnTaxi() end) -end +} function DespawnTaxi() print("^2[TAXI DEBUG]^7 Despawning taxi") @@ -706,7 +982,7 @@ function DespawnTaxi() local driveToY = taxiCoords.y + math.sin(angle) * distance -- Taxi wegfahren lassen - TaskVehicleDriveToCoord(currentDriver, currentTaxi, driveToX, driveToY, taxiCoords.z, 25.0, 0, GetEntityModel(currentTaxi), 786603, 1.0, true) + TaskVehicleDriveToCoordLongrange(currentDriver, currentTaxi, driveToX, driveToY, taxiCoords.z, 25.0, 786603, 5.0) -- Blips entfernen if taxiBlip then @@ -769,12 +1045,12 @@ function DespawnTaxi() print("^2[TAXI DEBUG]^7 Taxi despawn completed (no driver)") end -end +} function CalculateDistanceToCoords(coords) local playerCoords = GetEntityCoords(PlayerPedId()) return #(playerCoords - coords) -end +} -- Command um Taxi zu stoppen RegisterCommand('stoptaxi', function() @@ -794,7 +1070,6 @@ RegisterCommand('stoptaxi', function() end end) - -- Thread zum Überwachen der Tasten im Taxi CreateThread(function() while true do @@ -872,9 +1147,7 @@ function EndTaxiRide() DespawnTaxi() end) end) -end - - +} -- Thread zum Überwachen des Einsteigens ins Taxi (ohne qb-target) CreateThread(function() @@ -899,6 +1172,7 @@ CreateThread(function() } }) + -- Prüfen ob E gedrückt wird if IsControlJustReleased(0, 38) then -- E Taste -- Spieler will einsteigen lib.hideTextUI() @@ -916,15 +1190,17 @@ CreateThread(function() -- Warten bis eingestiegen local entryTimeout = GetGameTimer() + 10000 - while GetGameTimer() < entryTimeout do - if IsPedInVehicle(playerPed, currentTaxi, false) then - -- Spieler ist eingestiegen - Wait(1000) - OpenDestinationMenu() - break + CreateThread(function() + while GetGameTimer() < entryTimeout do + if IsPedInVehicle(playerPed, currentTaxi, false) then + -- Spieler ist eingestiegen + Wait(1000) + OpenDestinationMenu() + break + end + Wait(100) end - Wait(100) - end + end) end else lib.hideTextUI() @@ -933,14 +1209,17 @@ CreateThread(function() end end) - - -- Cleanup beim Resource Stop AddEventHandler('onResourceStop', function(resourceName) if GetCurrentResourceName() == resourceName then print("^2[TAXI DEBUG]^7 Cleaning up main script...") + + -- UI ausblenden + lib.hideTextUI() + + -- Taxi despawnen DespawnTaxi() + print("^2[TAXI DEBUG]^7 Main cleanup completed") end end) - diff --git a/resources/[tools]/nordi_taxi/config.lua b/resources/[tools]/nordi_taxi/config.lua index 26e9e8576..e00e15838 100644 --- a/resources/[tools]/nordi_taxi/config.lua +++ b/resources/[tools]/nordi_taxi/config.lua @@ -123,7 +123,7 @@ Config.KnownDestinations = { }, { name = "Sandy Shores", - coords = vector3(1836.0, 3672.0, 34.0), + coords = vector3(1815.27, 3649.01, 34.25), price = 75 }, {