forked from Simnation/Main
ed
This commit is contained in:
parent
bfca08b472
commit
e3b92cca6f
5 changed files with 921 additions and 0 deletions
363
resources/[tools]/nordi_taxi/client/main.lua
Normal file
363
resources/[tools]/nordi_taxi/client/main.lua
Normal file
|
@ -0,0 +1,363 @@
|
||||||
|
local QBCore = exports['qb-core']:GetCoreObject()
|
||||||
|
local currentTaxi = nil
|
||||||
|
local taxiDriver = nil
|
||||||
|
local inTaxi = false
|
||||||
|
local taxiBlip = nil
|
||||||
|
local destinationBlip = nil
|
||||||
|
local meterRunning = false
|
||||||
|
local currentFare = 0
|
||||||
|
local lastTaxiCall = 0
|
||||||
|
|
||||||
|
-- Taxi rufen Command (Mobile Taxi)
|
||||||
|
RegisterCommand('taxi', function()
|
||||||
|
local currentTime = GetGameTimer()
|
||||||
|
if currentTime - lastTaxiCall < (Config.TaxiCallCooldown * 1000) then
|
||||||
|
local remainingTime = math.ceil((Config.TaxiCallCooldown * 1000 - (currentTime - lastTaxiCall)) / 1000)
|
||||||
|
lib.notify({
|
||||||
|
title = 'Taxi Service',
|
||||||
|
description = 'Du musst noch ' .. remainingTime .. ' Sekunden warten',
|
||||||
|
type = 'error'
|
||||||
|
})
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if currentTaxi then
|
||||||
|
lib.notify({
|
||||||
|
title = 'Taxi Service',
|
||||||
|
description = 'Du hast bereits ein Taxi gerufen',
|
||||||
|
type = 'error'
|
||||||
|
})
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
CallMobileTaxi()
|
||||||
|
end)
|
||||||
|
|
||||||
|
function CallMobileTaxi()
|
||||||
|
lastTaxiCall = GetGameTimer()
|
||||||
|
|
||||||
|
lib.notify({
|
||||||
|
title = 'Taxi Service',
|
||||||
|
description = 'Ein Taxi wurde gerufen und ist auf dem Weg zu dir',
|
||||||
|
type = 'success'
|
||||||
|
})
|
||||||
|
|
||||||
|
CreateThread(function()
|
||||||
|
local playerPed = PlayerPedId()
|
||||||
|
local playerCoords = GetEntityCoords(playerPed)
|
||||||
|
|
||||||
|
-- Zufällige Spawn-Location wählen
|
||||||
|
local spawnLocation = Config.MobileTaxiSpawns[math.random(#Config.MobileTaxiSpawns)]
|
||||||
|
|
||||||
|
-- Zufälliges Taxi-Fahrzeug wählen
|
||||||
|
local selectedVehicle = SelectRandomTaxi()
|
||||||
|
|
||||||
|
-- Fahrzeug spawnen
|
||||||
|
local vehicleHash = GetHashKey(selectedVehicle.model)
|
||||||
|
RequestModel(vehicleHash)
|
||||||
|
while not HasModelLoaded(vehicleHash) do
|
||||||
|
Wait(100)
|
||||||
|
end
|
||||||
|
|
||||||
|
currentTaxi = CreateVehicle(vehicleHash, spawnLocation.x, spawnLocation.y, spawnLocation.z, spawnLocation.w, true, false)
|
||||||
|
SetEntityAsMissionEntity(currentTaxi, true, true)
|
||||||
|
SetVehicleOnGroundProperly(currentTaxi)
|
||||||
|
|
||||||
|
-- Fahrer spawnen
|
||||||
|
local driverHash = GetHashKey("a_m_m_taxi_01")
|
||||||
|
RequestModel(driverHash)
|
||||||
|
while not HasModelLoaded(driverHash) do
|
||||||
|
Wait(100)
|
||||||
|
end
|
||||||
|
|
||||||
|
taxiDriver = CreatePedInsideVehicle(currentTaxi, 26, driverHash, -1, true, false)
|
||||||
|
SetEntityAsMissionEntity(taxiDriver, true, true)
|
||||||
|
SetPedFleeAttributes(taxiDriver, 0, 0)
|
||||||
|
SetPedCombatAttributes(taxiDriver, 17, 1)
|
||||||
|
SetPedSeeingRange(taxiDriver, 0.0)
|
||||||
|
SetPedHearingRange(taxiDriver, 0.0)
|
||||||
|
SetPedAlertness(taxiDriver, 0)
|
||||||
|
SetPedKeepTask(taxiDriver, true)
|
||||||
|
|
||||||
|
-- Blip erstellen
|
||||||
|
taxiBlip = AddBlipForEntity(currentTaxi)
|
||||||
|
SetBlipSprite(taxiBlip, 198)
|
||||||
|
SetBlipColour(taxiBlip, 5)
|
||||||
|
SetBlipScale(taxiBlip, 0.8)
|
||||||
|
BeginTextCommandSetBlipName("STRING")
|
||||||
|
AddTextComponentString("Taxi")
|
||||||
|
EndTextCommandSetBlipName(taxiBlip)
|
||||||
|
|
||||||
|
-- Zum Spieler fahren
|
||||||
|
TaskVehicleDriveToCoord(taxiDriver, currentTaxi, playerCoords.x, playerCoords.y, playerCoords.z, 20.0, 0, vehicleHash, 786603, 1.0, true)
|
||||||
|
|
||||||
|
-- Warten bis Taxi ankommt
|
||||||
|
local arrived = false
|
||||||
|
local timeout = GetGameTimer() + (Config.MaxWaitTime * 1000)
|
||||||
|
|
||||||
|
while not arrived and GetGameTimer() < timeout do
|
||||||
|
local taxiCoords = GetEntityCoords(currentTaxi)
|
||||||
|
local distance = #(playerCoords - taxiCoords)
|
||||||
|
|
||||||
|
if distance < 10.0 then
|
||||||
|
arrived = true
|
||||||
|
TaskVehicleTempAction(taxiDriver, currentTaxi, 27, 3000)
|
||||||
|
|
||||||
|
lib.notify({
|
||||||
|
title = 'Taxi Service',
|
||||||
|
description = 'Dein Taxi ist angekommen! Steige ein.',
|
||||||
|
type = 'success'
|
||||||
|
})
|
||||||
|
|
||||||
|
WaitForPlayerToEnter(selectedVehicle.pricePerKm)
|
||||||
|
end
|
||||||
|
Wait(1000)
|
||||||
|
end
|
||||||
|
|
||||||
|
if not arrived then
|
||||||
|
lib.notify({
|
||||||
|
title = 'Taxi Service',
|
||||||
|
description = 'Das Taxi konnte dich nicht erreichen',
|
||||||
|
type = 'error'
|
||||||
|
})
|
||||||
|
CleanupMobileTaxi()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
function SelectRandomTaxi()
|
||||||
|
local totalChance = 0
|
||||||
|
for _, vehicle in pairs(Config.TaxiVehicles) do
|
||||||
|
totalChance = totalChance + vehicle.spawnChance
|
||||||
|
end
|
||||||
|
|
||||||
|
local randomValue = math.random(1, totalChance)
|
||||||
|
local currentChance = 0
|
||||||
|
|
||||||
|
for _, vehicle in pairs(Config.TaxiVehicles) do
|
||||||
|
currentChance = currentChance + vehicle.spawnChance
|
||||||
|
if randomValue <= currentChance then
|
||||||
|
return vehicle
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return Config.TaxiVehicles[1]
|
||||||
|
end
|
||||||
|
|
||||||
|
function WaitForPlayerToEnter(pricePerKm)
|
||||||
|
CreateThread(function()
|
||||||
|
local timeout = GetGameTimer() + 60000
|
||||||
|
|
||||||
|
while currentTaxi and GetGameTimer() < timeout do
|
||||||
|
local playerPed = PlayerPedId()
|
||||||
|
|
||||||
|
if IsPedInVehicle(playerPed, currentTaxi, false) then
|
||||||
|
inTaxi = true
|
||||||
|
OpenMobileTaxiMenu(pricePerKm)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
|
||||||
|
Wait(1000)
|
||||||
|
end
|
||||||
|
|
||||||
|
if not inTaxi then
|
||||||
|
lib.notify({
|
||||||
|
title = 'Taxi Service',
|
||||||
|
description = 'Das Taxi ist weggefahren',
|
||||||
|
type = 'error'
|
||||||
|
})
|
||||||
|
CleanupMobileTaxi()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
function OpenMobileTaxiMenu(pricePerKm)
|
||||||
|
local options = {}
|
||||||
|
|
||||||
|
-- Bekannte Ziele hinzufügen
|
||||||
|
for _, destination in pairs(Config.KnownDestinations) do
|
||||||
|
local customPrice = math.max(Config.MinFare, math.ceil((CalculateDistance(destination.coords) / 1000) * pricePerKm))
|
||||||
|
table.insert(options, {
|
||||||
|
title = destination.name,
|
||||||
|
description = 'Preis: $' .. customPrice,
|
||||||
|
icon = 'map-marker',
|
||||||
|
onSelect = function()
|
||||||
|
StartMobileTaxiRide(destination.coords, customPrice)
|
||||||
|
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 = CalculateDistance(coords) / 1000
|
||||||
|
local price = math.max(Config.MinFare, math.ceil(distance * pricePerKm))
|
||||||
|
StartMobileTaxiRide(coords, price)
|
||||||
|
else
|
||||||
|
lib.notify({
|
||||||
|
title = 'Taxi Service',
|
||||||
|
description = 'Du hast keinen Waypoint gesetzt',
|
||||||
|
type = 'error'
|
||||||
|
})
|
||||||
|
OpenMobileTaxiMenu(pricePerKm)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
})
|
||||||
|
|
||||||
|
-- Aussteigen Option
|
||||||
|
table.insert(options, {
|
||||||
|
title = 'Aussteigen',
|
||||||
|
description = 'Das Taxi verlassen',
|
||||||
|
icon = 'door-open',
|
||||||
|
onSelect = function()
|
||||||
|
ExitMobileTaxi()
|
||||||
|
end
|
||||||
|
})
|
||||||
|
|
||||||
|
lib.registerContext({
|
||||||
|
id = 'mobile_taxi_menu',
|
||||||
|
title = 'Taxi - Ziel wählen',
|
||||||
|
options = options
|
||||||
|
})
|
||||||
|
|
||||||
|
lib.showContext('mobile_taxi_menu')
|
||||||
|
end
|
||||||
|
|
||||||
|
function StartMobileTaxiRide(destination, price)
|
||||||
|
if not currentTaxi or not taxiDriver then return end
|
||||||
|
|
||||||
|
currentFare = price
|
||||||
|
meterRunning = true
|
||||||
|
|
||||||
|
-- Destination Blip erstellen
|
||||||
|
destinationBlip = AddBlipForCoord(destination.x, destination.y, destination.z)
|
||||||
|
SetBlipSprite(destinationBlip, 1)
|
||||||
|
SetBlipColour(destinationBlip, 2)
|
||||||
|
SetBlipScale(destinationBlip, 0.8)
|
||||||
|
BeginTextCommandSetBlipName("STRING")
|
||||||
|
AddTextComponentString("Taxi Ziel")
|
||||||
|
EndTextCommandSetBlipName(destinationBlip)
|
||||||
|
|
||||||
|
lib.notify({
|
||||||
|
title = 'Taxi Service',
|
||||||
|
description = 'Fahrt gestartet - Preis: $' .. price,
|
||||||
|
type = 'success'
|
||||||
|
})
|
||||||
|
|
||||||
|
-- Zum Ziel fahren
|
||||||
|
TaskVehicleDriveToCoord(taxiDriver, currentTaxi, destination.x, destination.y, destination.z, 25.0, 0, GetEntityModel(currentTaxi), 786603, 1.0, true)
|
||||||
|
|
||||||
|
-- Überwachen der Fahrt
|
||||||
|
CreateThread(function()
|
||||||
|
while meterRunning and currentTaxi do
|
||||||
|
local taxiCoords = GetEntityCoords(currentTaxi)
|
||||||
|
local distance = #(vector3(destination.x, destination.y, destination.z) - taxiCoords)
|
||||||
|
|
||||||
|
if distance < 10.0 then
|
||||||
|
TaskVehicleTempAction(taxiDriver, currentTaxi, 27, 3000)
|
||||||
|
|
||||||
|
lib.notify({
|
||||||
|
title = 'Taxi Service',
|
||||||
|
description = 'Du bist angekommen! Preis: $' .. currentFare,
|
||||||
|
type = 'success'
|
||||||
|
})
|
||||||
|
|
||||||
|
TriggerServerEvent('taxi:payFare', currentFare)
|
||||||
|
|
||||||
|
SetTimeout(10000, function()
|
||||||
|
CleanupMobileTaxi()
|
||||||
|
end)
|
||||||
|
|
||||||
|
break
|
||||||
|
end
|
||||||
|
|
||||||
|
Wait(2000)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
function CalculateDistance(coords)
|
||||||
|
local playerCoords = GetEntityCoords(PlayerPedId())
|
||||||
|
return #(playerCoords - coords)
|
||||||
|
end
|
||||||
|
|
||||||
|
function ExitMobileTaxi()
|
||||||
|
local playerPed = PlayerPedId()
|
||||||
|
TaskLeaveVehicle(playerPed, currentTaxi, 0)
|
||||||
|
|
||||||
|
lib.notify({
|
||||||
|
title = 'Taxi Service',
|
||||||
|
description = 'Du bist ausgestiegen',
|
||||||
|
type = 'info'
|
||||||
|
})
|
||||||
|
|
||||||
|
SetTimeout(5000, function()
|
||||||
|
CleanupMobileTaxi()
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
function CleanupMobileTaxi()
|
||||||
|
meterRunning = false
|
||||||
|
inTaxi = false
|
||||||
|
|
||||||
|
if taxiBlip then
|
||||||
|
RemoveBlip(taxiBlip)
|
||||||
|
taxiBlip = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
if destinationBlip then
|
||||||
|
RemoveBlip(destinationBlip)
|
||||||
|
destinationBlip = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
if currentTaxi then
|
||||||
|
if taxiDriver then
|
||||||
|
DeleteEntity(taxiDriver)
|
||||||
|
taxiDriver = nil
|
||||||
|
end
|
||||||
|
DeleteEntity(currentTaxi)
|
||||||
|
currentTaxi = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Menu erneut öffnen wenn im Mobile Taxi
|
||||||
|
CreateThread(function()
|
||||||
|
while true do
|
||||||
|
if inTaxi and currentTaxi and not meterRunning then
|
||||||
|
if IsControlJustPressed(0, 38) then -- E Taste
|
||||||
|
local selectedVehicle = nil
|
||||||
|
local vehicleModel = GetEntityModel(currentTaxi)
|
||||||
|
|
||||||
|
for _, vehicle in pairs(Config.TaxiVehicles) do
|
||||||
|
if GetHashKey(vehicle.model) == vehicleModel then
|
||||||
|
selectedVehicle = vehicle
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if selectedVehicle then
|
||||||
|
OpenMobileTaxiMenu(selectedVehicle.pricePerKm)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
lib.showTextUI('[E] - Ziel wählen')
|
||||||
|
else
|
||||||
|
lib.hideTextUI()
|
||||||
|
end
|
||||||
|
|
||||||
|
Wait(0)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- Cleanup beim Disconnect
|
||||||
|
AddEventHandler('onResourceStop', function(resourceName)
|
||||||
|
if GetCurrentResourceName() == resourceName then
|
||||||
|
CleanupMobileTaxi()
|
||||||
|
end
|
||||||
|
end)
|
332
resources/[tools]/nordi_taxi/client/stations.lua
Normal file
332
resources/[tools]/nordi_taxi/client/stations.lua
Normal file
|
@ -0,0 +1,332 @@
|
||||||
|
local QBCore = exports['qb-core']:GetCoreObject()
|
||||||
|
local stationVehicles = {}
|
||||||
|
local stationBlips = {}
|
||||||
|
|
||||||
|
-- Taxi Stationen initialisieren
|
||||||
|
CreateThread(function()
|
||||||
|
Wait(1000)
|
||||||
|
InitializeTaxiStations()
|
||||||
|
end)
|
||||||
|
|
||||||
|
function InitializeTaxiStations()
|
||||||
|
for stationId, station in pairs(Config.TaxiStations) do
|
||||||
|
-- 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
|
||||||
|
|
||||||
|
-- Fahrzeuge an Station spawnen
|
||||||
|
stationVehicles[stationId] = {}
|
||||||
|
for vehicleId, vehicleData in pairs(station.vehicles) do
|
||||||
|
SpawnStationVehicle(stationId, vehicleId, vehicleData)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function SpawnStationVehicle(stationId, vehicleId, vehicleData)
|
||||||
|
CreateThread(function()
|
||||||
|
local vehicleHash = GetHashKey(vehicleData.model)
|
||||||
|
RequestModel(vehicleHash)
|
||||||
|
while not HasModelLoaded(vehicleHash) do
|
||||||
|
Wait(100)
|
||||||
|
end
|
||||||
|
|
||||||
|
local vehicle = CreateVehicle(
|
||||||
|
vehicleHash,
|
||||||
|
vehicleData.coords.x,
|
||||||
|
vehicleData.coords.y,
|
||||||
|
vehicleData.coords.z,
|
||||||
|
vehicleData.coords.w,
|
||||||
|
false,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
|
||||||
|
SetEntityAsMissionEntity(vehicle, true, true)
|
||||||
|
SetVehicleOnGroundProperly(vehicle)
|
||||||
|
SetVehicleDoorsLocked(vehicle, 2) -- Locked
|
||||||
|
SetVehicleEngineOn(vehicle, false, true, false)
|
||||||
|
|
||||||
|
-- Fahrzeug-Info speichern
|
||||||
|
stationVehicles[stationId][vehicleId] = {
|
||||||
|
entity = vehicle,
|
||||||
|
data = vehicleData,
|
||||||
|
occupied = false
|
||||||
|
}
|
||||||
|
|
||||||
|
-- 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
|
||||||
|
})
|
||||||
|
|
||||||
|
SetModelAsNoLongerNeeded(vehicleHash)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Event für Einsteigen in Station-Taxi
|
||||||
|
RegisterNetEvent('taxi:enterStationVehicle', function(data)
|
||||||
|
local stationId = data.stationId
|
||||||
|
local vehicleId = data.vehicleId
|
||||||
|
|
||||||
|
if not stationVehicles[stationId] or not stationVehicles[stationId][vehicleId] then
|
||||||
|
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
|
||||||
|
lib.notify({
|
||||||
|
title = 'Taxi Service',
|
||||||
|
description = 'Dieses Taxi ist bereits besetzt',
|
||||||
|
type = 'error'
|
||||||
|
})
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Spieler ins Fahrzeug setzen
|
||||||
|
local playerPed = PlayerPedId()
|
||||||
|
local vehicle = vehicleInfo.entity
|
||||||
|
|
||||||
|
-- Türen entsperren
|
||||||
|
SetVehicleDoorsLocked(vehicle, 1)
|
||||||
|
|
||||||
|
-- Fahrer spawnen
|
||||||
|
local driverHash = GetHashKey("a_m_m_taxi_01")
|
||||||
|
RequestModel(driverHash)
|
||||||
|
while not HasModelLoaded(driverHash) do
|
||||||
|
Wait(100)
|
||||||
|
end
|
||||||
|
|
||||||
|
local driver = CreatePedInsideVehicle(vehicle, 26, driverHash, -1, true, false)
|
||||||
|
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)
|
||||||
|
|
||||||
|
-- Spieler einsteigen lassen
|
||||||
|
TaskEnterVehicle(playerPed, vehicle, 10000, 0, 1.0, 1, 0)
|
||||||
|
|
||||||
|
-- Warten bis Spieler eingestiegen ist
|
||||||
|
CreateThread(function()
|
||||||
|
local timeout = GetGameTimer() + 10000
|
||||||
|
while GetGameTimer() < timeout do
|
||||||
|
if IsPedInVehicle(playerPed, vehicle, false) then
|
||||||
|
vehicleInfo.occupied = true
|
||||||
|
vehicleInfo.driver = driver
|
||||||
|
|
||||||
|
-- Ziel-Menu öffnen
|
||||||
|
OpenStationTaxiMenu(stationId, vehicleId, vehicle, driver, vehicleInfo.data.pricePerKm)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
Wait(100)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
function OpenStationTaxiMenu(stationId, vehicleId, vehicle, driver, pricePerKm)
|
||||||
|
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,
|
||||||
|
icon = 'map-marker',
|
||||||
|
onSelect = function()
|
||||||
|
StartStationTaxiRide(stationId, vehicleId, vehicle, driver, destination.coords, customPrice)
|
||||||
|
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 * 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
|
||||||
|
})
|
||||||
|
|
||||||
|
-- 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',
|
||||||
|
options = options
|
||||||
|
})
|
||||||
|
|
||||||
|
lib.showContext('station_taxi_menu')
|
||||||
|
end
|
||||||
|
|
||||||
|
function StartStationTaxiRide(stationId, vehicleId, vehicle, driver, destination, price)
|
||||||
|
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)
|
||||||
|
BeginTextCommandSetBlipName("STRING")
|
||||||
|
AddTextComponentString("Taxi Ziel")
|
||||||
|
EndTextCommandSetBlipName(destinationBlip)
|
||||||
|
|
||||||
|
-- Zum Ziel fahren
|
||||||
|
TaskVehicleDriveToCoord(driver, vehicle, destination.x, destination.y, destination.z, 25.0, 0, GetEntityModel(vehicle), 786603, 1.0, true)
|
||||||
|
|
||||||
|
-- Fahrt überwachen
|
||||||
|
CreateThread(function()
|
||||||
|
while DoesEntityExist(vehicle) and DoesEntityExist(driver) do
|
||||||
|
local vehicleCoords = GetEntityCoords(vehicle)
|
||||||
|
local distance = #(vector3(destination.x, destination.y, destination.z) - vehicleCoords)
|
||||||
|
|
||||||
|
if distance < 10.0 then
|
||||||
|
-- Angekommen
|
||||||
|
TaskVehicleTempAction(driver, vehicle, 27, 3000)
|
||||||
|
|
||||||
|
lib.notify({
|
||||||
|
title = 'Taxi Service',
|
||||||
|
description = 'Du bist angekommen! Preis: $' .. price,
|
||||||
|
type = 'success'
|
||||||
|
})
|
||||||
|
|
||||||
|
-- Bezahlung
|
||||||
|
TriggerServerEvent('taxi:payFare', price)
|
||||||
|
|
||||||
|
-- Blip entfernen
|
||||||
|
RemoveBlip(destinationBlip)
|
||||||
|
|
||||||
|
-- Nach 10 Sekunden Taxi zurück zur Station
|
||||||
|
SetTimeout(10000, function()
|
||||||
|
ReturnTaxiToStation(stationId, vehicleId, vehicle, driver)
|
||||||
|
end)
|
||||||
|
|
||||||
|
break
|
||||||
|
end
|
||||||
|
|
||||||
|
Wait(2000)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
function ExitStationTaxi(stationId, vehicleId, vehicle, driver)
|
||||||
|
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)
|
||||||
|
if not stationVehicles[stationId] or not stationVehicles[stationId][vehicleId] then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Fahrer löschen
|
||||||
|
if DoesEntityExist(driver) then
|
||||||
|
DeleteEntity(driver)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Fahrzeug löschen
|
||||||
|
if DoesEntityExist(vehicle) then
|
||||||
|
exports['qb-target']:RemoveTargetEntity(vehicle)
|
||||||
|
DeleteEntity(vehicle)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Fahrzeug als nicht besetzt markieren
|
||||||
|
stationVehicles[stationId][vehicleId].occupied = false
|
||||||
|
stationVehicles[stationId][vehicleId].driver = nil
|
||||||
|
|
||||||
|
-- Nach Respawn-Zeit neues Fahrzeug spawnen
|
||||||
|
SetTimeout(Config.StationTaxiRespawnTime * 1000, function()
|
||||||
|
if stationVehicles[stationId] and stationVehicles[stationId][vehicleId] then
|
||||||
|
local vehicleData = stationVehicles[stationId][vehicleId].data
|
||||||
|
SpawnStationVehicle(stationId, vehicleId, vehicleData)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
function CalculateDistanceToCoords(coords)
|
||||||
|
local playerCoords = GetEntityCoords(PlayerPedId())
|
||||||
|
return #(playerCoords - coords)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Cleanup beim Resource Stop
|
||||||
|
AddEventHandler('onResourceStop', function(resourceName)
|
||||||
|
if GetCurrentResourceName() == resourceName then
|
||||||
|
-- Alle Station-Fahrzeuge löschen
|
||||||
|
for stationId, vehicles in pairs(stationVehicles) do
|
||||||
|
for vehicleId, vehicleInfo in pairs(vehicles) do
|
||||||
|
if 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
|
||||||
|
end
|
||||||
|
end)
|
178
resources/[tools]/nordi_taxi/config.lua
Normal file
178
resources/[tools]/nordi_taxi/config.lua
Normal file
|
@ -0,0 +1,178 @@
|
||||||
|
Config = {}
|
||||||
|
|
||||||
|
-- Taxi Fahrzeuge und Preise
|
||||||
|
Config.TaxiVehicles = {
|
||||||
|
{
|
||||||
|
model = 'taxi',
|
||||||
|
label = 'Standard Taxi',
|
||||||
|
pricePerKm = 5,
|
||||||
|
spawnChance = 70
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model = 'stretch',
|
||||||
|
label = 'Luxus Limousine',
|
||||||
|
pricePerKm = 15,
|
||||||
|
spawnChance = 20
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model = 'superd',
|
||||||
|
label = 'Premium Taxi',
|
||||||
|
pricePerKm = 10,
|
||||||
|
spawnChance = 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Taxi Stationen mit festen Fahrzeugen
|
||||||
|
Config.TaxiStations = {
|
||||||
|
{
|
||||||
|
name = "Los Santos Airport Taxi",
|
||||||
|
coords = vector4(-1041.51, -2730.2, 20.17, 240.0),
|
||||||
|
blipCoords = vector3(-1041.51, -2730.2, 20.17),
|
||||||
|
vehicles = {
|
||||||
|
{
|
||||||
|
model = 'taxi',
|
||||||
|
coords = vector4(-1041.51, -2730.2, 20.17, 240.0),
|
||||||
|
pricePerKm = 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model = 'stretch',
|
||||||
|
coords = vector4(-1045.0, -2732.0, 20.17, 240.0),
|
||||||
|
pricePerKm = 15
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name = "Downtown Taxi Stand",
|
||||||
|
coords = vector4(895.46, -179.28, 74.7, 240.0),
|
||||||
|
blipCoords = vector3(895.46, -179.28, 74.7),
|
||||||
|
vehicles = {
|
||||||
|
{
|
||||||
|
model = 'taxi',
|
||||||
|
coords = vector4(895.46, -179.28, 74.7, 240.0),
|
||||||
|
pricePerKm = 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model = 'superd',
|
||||||
|
coords = vector4(892.0, -181.0, 74.7, 240.0),
|
||||||
|
pricePerKm = 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name = "Mirror Park Taxi",
|
||||||
|
coords = vector4(1696.62, 4785.41, 42.02, 90.0),
|
||||||
|
blipCoords = vector3(1696.62, 4785.41, 42.02),
|
||||||
|
vehicles = {
|
||||||
|
{
|
||||||
|
model = 'taxi',
|
||||||
|
coords = vector4(1696.62, 4785.41, 42.02, 90.0),
|
||||||
|
pricePerKm = 5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name = "Paleto Bay Taxi",
|
||||||
|
coords = vector4(-348.88, 6063.5, 31.5, 225.0),
|
||||||
|
blipCoords = vector3(-348.88, 6063.5, 31.5),
|
||||||
|
vehicles = {
|
||||||
|
{
|
||||||
|
model = 'taxi',
|
||||||
|
coords = vector4(-348.88, 6063.5, 31.5, 225.0),
|
||||||
|
pricePerKm = 6
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name = "Stadtpark Taxi",
|
||||||
|
coords = vector4(218.13, -917.98, 29.6, 343.32),
|
||||||
|
blipCoords = vector3(218.13, -917.98, 29.6),
|
||||||
|
vehicles = {
|
||||||
|
{
|
||||||
|
model = 'taxi',
|
||||||
|
coords = vector4(218.13, -917.98, 29.6, 343.32),
|
||||||
|
pricePerKm = 6
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
name = "Vespucci Beach Taxi",
|
||||||
|
coords = vector4(-1266.53, -833.8, 17.11, 37.5),
|
||||||
|
blipCoords = vector3(-1266.53, -833.8, 17.11),
|
||||||
|
vehicles = {
|
||||||
|
{
|
||||||
|
model = 'taxi',
|
||||||
|
coords = vector4(-1266.53, -833.8, 17.11, 37.5),
|
||||||
|
pricePerKm = 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model = 'stretch',
|
||||||
|
coords = vector4(-1270.0, -830.0, 17.11, 37.5),
|
||||||
|
pricePerKm = 15
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Spawn Locations für /taxi Command (mobile Taxis)
|
||||||
|
Config.MobileTaxiSpawns = {
|
||||||
|
vector4(-1041.51, -2730.2, 20.17, 240.0),
|
||||||
|
vector4(895.46, -179.28, 74.7, 240.0),
|
||||||
|
vector4(-1266.53, -833.8, 17.11, 37.5),
|
||||||
|
vector4(1696.62, 4785.41, 42.02, 90.0),
|
||||||
|
vector4(-348.88, 6063.5, 31.5, 225.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
-- 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(1836.0, 3672.0, 34.0),
|
||||||
|
price = 75
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name = "Paleto Bay",
|
||||||
|
coords = vector3(-276.0, 6635.0, 7.5),
|
||||||
|
price = 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name = "Mount Chiliad",
|
||||||
|
coords = vector3(501.0, 5604.0, 797.0),
|
||||||
|
price = 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name = "Maze Bank Tower",
|
||||||
|
coords = vector3(-75.0, -818.0, 326.0),
|
||||||
|
price = 40
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name = "Vespucci Beach",
|
||||||
|
coords = vector3(-1266.0, -833.0, 17.0),
|
||||||
|
price = 30
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Allgemeine Einstellungen
|
||||||
|
Config.MaxWaitTime = 120 -- Sekunden bis Taxi spawnt
|
||||||
|
Config.TaxiCallCooldown = 30 -- Sekunden zwischen Taxi-Rufen
|
||||||
|
Config.MinFare = 10 -- Mindestpreis
|
||||||
|
Config.WaitingFee = 2 -- Preis pro Minute warten
|
||||||
|
Config.StationTaxiRespawnTime = 300 -- 5 Minuten bis Taxi an Station respawnt
|
0
resources/[tools]/nordi_taxi/fxmanifest.lua
Normal file
0
resources/[tools]/nordi_taxi/fxmanifest.lua
Normal file
48
resources/[tools]/nordi_taxi/server/main.lua
Normal file
48
resources/[tools]/nordi_taxi/server/main.lua
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
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
|
||||||
|
print('^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
|
||||||
|
print('^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
|
||||||
|
print('^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)
|
Loading…
Add table
Add a link
Reference in a new issue