forked from Simnation/Main
379 lines
13 KiB
Lua
379 lines
13 KiB
Lua
local QBCore = exports['qb-core']:GetCoreObject()
|
|
local lib = exports.ox_lib
|
|
local PlayerData = {}
|
|
|
|
-- Zug Status
|
|
local currentTrain = nil
|
|
local isRiding = false
|
|
local trainAtStation = {}
|
|
local cinemaCam = nil
|
|
local waitingForTrain = false
|
|
|
|
RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function()
|
|
PlayerData = QBCore.Functions.GetPlayerData()
|
|
CreateStationBlips()
|
|
CreateStationInteractionPoints()
|
|
end)
|
|
|
|
-- Bahnhof Blips erstellen
|
|
function CreateStationBlips()
|
|
for _, station in pairs(Config.TrainStations) do
|
|
local blip = AddBlipForCoord(station.coords.x, station.coords.y, station.coords.z)
|
|
SetBlipSprite(blip, station.blip.sprite)
|
|
SetBlipDisplay(blip, 4)
|
|
SetBlipScale(blip, station.blip.scale)
|
|
SetBlipColour(blip, station.blip.color)
|
|
BeginTextCommandSetBlipName("STRING")
|
|
AddTextComponentString("🚂 " .. station.name)
|
|
EndTextCommandSetBlipName(blip)
|
|
end
|
|
end
|
|
|
|
-- Bahnhof Interaktionspunkte erstellen
|
|
function CreateStationInteractionPoints()
|
|
CreateThread(function()
|
|
while true do
|
|
local sleep = 1000
|
|
local playerPed = PlayerPedId()
|
|
local playerCoords = GetEntityCoords(playerPed)
|
|
|
|
if not isRiding then
|
|
for stationId, station in pairs(Config.TrainStations) do
|
|
local distance = #(playerCoords - station.interactionPoint)
|
|
|
|
if distance <= Config.StationInteractionDistance then
|
|
sleep = 0
|
|
|
|
-- DrawText anzeigen
|
|
DrawText3D(station.interactionPoint.x, station.interactionPoint.y, station.interactionPoint.z + 1.0,
|
|
Config.DrawText.stationText)
|
|
|
|
-- Interaktion
|
|
if IsControlJustPressed(0, 38) then -- E
|
|
if not waitingForTrain then
|
|
OpenStationMenu(station)
|
|
else
|
|
lib:notify({
|
|
title = 'Bitte warten',
|
|
description = 'Ein Zug ist bereits unterwegs',
|
|
type = 'warning'
|
|
})
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Prüfen ob Zug am Bahnhof wartet
|
|
if trainAtStation[station.id] then
|
|
local trainDistance = #(playerCoords - GetEntityCoords(trainAtStation[station.id]))
|
|
if trainDistance <= 8.0 then
|
|
sleep = 0
|
|
DrawText3D(GetEntityCoords(trainAtStation[station.id]), Config.DrawText.boardText)
|
|
|
|
if IsControlJustPressed(0, 38) then -- E
|
|
-- Hier würde das Zielmenü für die Fahrt geöffnet
|
|
OpenDestinationMenu(trainAtStation[station.id], station)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
Wait(sleep)
|
|
end
|
|
end)
|
|
end
|
|
|
|
-- Bahnhof Menü öffnen
|
|
function OpenStationMenu(station)
|
|
local options = {}
|
|
|
|
-- Verfügbare Ziele anzeigen
|
|
for _, destinationId in pairs(station.destinations) do
|
|
local destination = GetStationById(destinationId)
|
|
if destination then
|
|
local price = CalculatePrice(station, destination)
|
|
local icon = GetStationIcon(destination.name)
|
|
|
|
table.insert(options, {
|
|
title = icon .. " " .. destination.name,
|
|
description = destination.description .. " - Preis: $" .. price,
|
|
icon = 'train',
|
|
onSelect = function()
|
|
CallTrainToStation(station, destination, price)
|
|
end,
|
|
metadata = {
|
|
{label = "Preis", value = "$" .. price},
|
|
{label = "Entfernung", value = math.floor(GetDistanceBetweenStations(station, destination)) .. "m"}
|
|
}
|
|
})
|
|
end
|
|
end
|
|
|
|
if #options == 0 then
|
|
table.insert(options, {
|
|
title = "Keine Ziele verfügbar",
|
|
description = "Momentan keine Verbindungen",
|
|
disabled = true
|
|
})
|
|
end
|
|
|
|
table.insert(options, {
|
|
title = "❌ Abbrechen",
|
|
description = "Menü schließen",
|
|
icon = 'xmark'
|
|
})
|
|
|
|
lib:registerContext({
|
|
id = 'station_menu',
|
|
title = "🚉 " .. station.name,
|
|
options = options,
|
|
position = Config.Menu.position
|
|
})
|
|
|
|
lib:showContext('station_menu')
|
|
end
|
|
|
|
-- Zug zum Bahnhof rufen
|
|
function CallTrainToStation(station, destination, price)
|
|
-- Geld prüfen
|
|
QBCore.Functions.TriggerCallback('train:server:canAfford', function(canAfford)
|
|
if canAfford then
|
|
waitingForTrain = true
|
|
|
|
lib:notify({
|
|
title = '🚂 ' .. Config.Menu.texts.trainComing,
|
|
description = 'Der Zug fährt zum Bahnhof',
|
|
type = 'info',
|
|
duration = Config.Notifications.duration.medium
|
|
})
|
|
|
|
-- Zug spawnen und heranfahren lassen
|
|
SpawnAndMoveTrainToStation(station, destination)
|
|
else
|
|
lib:notify({
|
|
title = 'Nicht genug Geld',
|
|
description = "Benötigt: $" .. price,
|
|
type = 'error',
|
|
duration = Config.Notifications.duration.short
|
|
})
|
|
end
|
|
end, price)
|
|
end
|
|
|
|
-- Zug spawnen und zum Bahnhof fahren lassen
|
|
function SpawnAndMoveTrainToStation(station, destination)
|
|
CreateThread(function()
|
|
-- Zug am Spawn-Punkt erstellen
|
|
local train = SpawnTrainAtLocation(station.trainSpawnPoint)
|
|
|
|
if not train then
|
|
waitingForTrain = false
|
|
lib:notify({
|
|
title = 'Fehler',
|
|
description = 'Zug konnte nicht gespawnt werden',
|
|
type = 'error'
|
|
})
|
|
return
|
|
end
|
|
|
|
-- Zug zum Bahnhof fahren lassen
|
|
local targetCoords = vector3(station.coords.x, station.coords.y, station.coords.z)
|
|
local arrived = false
|
|
|
|
-- Zug in Bewegung setzen
|
|
SetTrainSpeed(train, Config.TrainArrival.approachSpeed)
|
|
SetTrainCruiseSpeed(train, Config.TrainArrival.approachSpeed)
|
|
|
|
lib:notify({
|
|
title = '🚂 ' .. Config.Menu.texts.trainArriving,
|
|
description = 'Der Zug nähert sich dem Bahnhof',
|
|
type = 'info',
|
|
duration = Config.Notifications.duration.short
|
|
})
|
|
|
|
-- Warten bis Zug am Bahnhof ankommt
|
|
while not arrived and DoesEntityExist(train) do
|
|
local trainCoords = GetEntityCoords(train)
|
|
local distance = #(trainCoords - targetCoords)
|
|
|
|
if distance < 100 then
|
|
-- Langsamer werden
|
|
SetTrainSpeed(train, Config.TrainArrival.arrivalSpeed)
|
|
SetTrainCruiseSpeed(train, Config.TrainArrival.arrivalSpeed)
|
|
end
|
|
|
|
if distance < 30 then
|
|
-- Ankunft
|
|
SetTrainSpeed(train, 0)
|
|
SetTrainCruiseSpeed(train, 0)
|
|
arrived = true
|
|
|
|
-- Zug am Bahnhof registrieren
|
|
trainAtStation[station.id] = train
|
|
waitingForTrain = false
|
|
|
|
lib:notify({
|
|
title = '🚂 ' .. Config.Menu.texts.trainWaiting,
|
|
description = 'Zug wartet am Bahnhof - [E] zum Einsteigen',
|
|
type = 'success',
|
|
duration = Config.Notifications.duration.long
|
|
})
|
|
|
|
-- Zug nach Wartezeit entfernen wenn niemand einsteigt
|
|
if Config.TrainArrival.despawnAfterWait then
|
|
SetTimeout(Config.TrainArrival.waitTime, function()
|
|
if trainAtStation[station.id] == train and not isRiding then
|
|
lib:notify({
|
|
title = '🚂 Zug fährt ab',
|
|
description = 'Der Zug verlässt den Bahnhof',
|
|
type = 'warning',
|
|
duration = Config.Notifications.duration.short
|
|
})
|
|
|
|
-- Zug wegfahren lassen
|
|
SetTrainSpeed(train, 15.0)
|
|
SetTrainCruiseSpeed(train, 15.0)
|
|
|
|
SetTimeout(10000, function()
|
|
if DoesEntityExist(train) then
|
|
DeleteMissionTrain(train)
|
|
end
|
|
end)
|
|
|
|
trainAtStation[station.id] = nil
|
|
end
|
|
end)
|
|
end
|
|
end
|
|
|
|
Wait(1000)
|
|
end
|
|
end)
|
|
end
|
|
|
|
-- Zielmenü für Fahrt öffnen
|
|
function OpenDestinationMenu(train, currentStation)
|
|
-- Hier das normale Zielmenü wie vorher, aber mit dem wartenden Zug
|
|
local playerPed = PlayerPedId()
|
|
SetPedIntoVehicle(playerPed, train, 1)
|
|
|
|
lib:notify({
|
|
title = '🚂 Willkommen an Bord',
|
|
description = 'Die Fahrt beginnt in Kürze',
|
|
type = 'success',
|
|
duration = Config.Notifications.duration.medium
|
|
})
|
|
|
|
-- Hier würde die normale Zugfahrt-Logik weitergehen
|
|
-- StartTrainJourney(train, destination) etc.
|
|
end
|
|
|
|
-- Hilfsfunktionen
|
|
function SpawnTrainAtLocation(spawnPoint)
|
|
local model = GetHashKey(Config.TrainCars.main)
|
|
|
|
RequestModel(model)
|
|
while not HasModelLoaded(model) do
|
|
Wait(500)
|
|
end
|
|
|
|
local train = CreateMissionTrain(24, spawnPoint.x, spawnPoint.y, spawnPoint.z, true)
|
|
|
|
if DoesEntityExist(train) then
|
|
SetEntityHeading(train, spawnPoint.w)
|
|
SetTrainSpeed(train, 0.0)
|
|
SetTrainCruiseSpeed(train, 0.0)
|
|
|
|
-- Waggons hinzufügen
|
|
Wait(1000)
|
|
for _, carModel in pairs(Config.TrainCars.cars) do
|
|
local carHash = GetHashKey(carModel)
|
|
RequestModel(carHash)
|
|
while not HasModelLoaded(carHash) do
|
|
Wait(500)
|
|
end
|
|
CreateMissionTrainCar(train, carHash, false, false, false)
|
|
end
|
|
|
|
return train
|
|
end
|
|
return nil
|
|
end
|
|
|
|
function GetStationById(id)
|
|
for _, station in pairs(Config.TrainStations) do
|
|
if station.id == id then
|
|
return station
|
|
end
|
|
end
|
|
return nil
|
|
end
|
|
|
|
function CalculatePrice(fromStation, toStation)
|
|
local distance = GetDistanceBetweenStations(fromStation, toStation)
|
|
local price = Config.PriceCalculation.basePrice + (distance * Config.PriceCalculation.pricePerKm / 100)
|
|
|
|
-- Kostenlose Stationen prüfen
|
|
for _, freeStation in pairs(Config.PriceCalculation.freeStations) do
|
|
if fromStation.id == freeStation then
|
|
price = price * 0.5 -- 50% Rabatt
|
|
end
|
|
end
|
|
|
|
return math.min(math.floor(price), Config.PriceCalculation.maxPrice)
|
|
end
|
|
|
|
function GetDistanceBetweenStations(station1, station2)
|
|
local coords1 = vector3(station1.coords.x, station1.coords.y, station1.coords.z)
|
|
local coords2 = vector3(station2.coords.x, station2.coords.y, station2.coords.z)
|
|
return #(coords1 - coords2)
|
|
end
|
|
|
|
function GetStationIcon(stationName)
|
|
if string.find(stationName:lower(), "depot") then
|
|
return Config.Menu.stationIcons.depot
|
|
elseif string.find(stationName:lower(), "island") then
|
|
return Config.Menu.stationIcons.port
|
|
elseif string.find(stationName:lower(), "terminal") then
|
|
return Config.Menu.stationIcons.industrial
|
|
elseif string.find(stationName:lower(), "bay") then
|
|
return Config.Menu.stationIcons.rural
|
|
elseif string.find(stationName:lower(), "hauptbahnhof") then
|
|
return Config.Menu.stationIcons.main
|
|
else
|
|
return Config.Menu.stationIcons.city
|
|
end
|
|
end
|
|
|
|
function DrawText3D(x, y, z, text)
|
|
local onScreen, _x, _y = World3dToScreen2d(x, y, z)
|
|
|
|
if onScreen then
|
|
SetTextScale(Config.DrawText.scale, Config.DrawText.scale)
|
|
SetTextFont(Config.DrawText.font)
|
|
SetTextProportional(1)
|
|
SetTextColour(Config.DrawText.color.r, Config.DrawText.color.g, Config.DrawText.color.b, Config.DrawText.color.a)
|
|
SetTextEntry("STRING")
|
|
SetTextCentre(1)
|
|
AddTextComponentString(text)
|
|
DrawText(_x, _y)
|
|
|
|
local factor = (string.len(text)) / 370
|
|
DrawRect(_x, _y + 0.0125, 0.015 + factor, 0.03,
|
|
Config.DrawText.backgroundColor.r,
|
|
Config.DrawText.backgroundColor.g,
|
|
Config.DrawText.backgroundColor.b,
|
|
Config.DrawText.backgroundColor.a)
|
|
end
|
|
end
|
|
|
|
-- Cleanup
|
|
AddEventHandler('onResourceStop', function(resourceName)
|
|
if GetCurrentResourceName() == resourceName then
|
|
for stationId, train in pairs(trainAtStation) do
|
|
if DoesEntityExist(train) then
|
|
DeleteMissionTrain(train)
|
|
end
|
|
end
|
|
end
|
|
end)
|