2026-04-14 15:54:53 +02:00

287 lines
8.6 KiB
Lua

ESX = exports['es_extended']:getSharedObject()
local isNuiOpen = false
local playerLoaded = false
local isTestDriving = false
local testDriveVehicle = nil
-- PlayerData laden
Citizen.CreateThread(function()
local pd = ESX.GetPlayerData()
if pd and pd.job and pd.job.name then
ESX.PlayerData = pd
playerLoaded = true
end
end)
RegisterNetEvent('esx:playerLoaded')
AddEventHandler('esx:playerLoaded', function(xPlayer)
ESX.PlayerData = xPlayer
playerLoaded = true
end)
RegisterNetEvent('esx:setJob')
AddEventHandler('esx:setJob', function(job)
ESX.PlayerData.job = job
playerLoaded = true
end)
-- =====================
-- KEYBIND
-- =====================
RegisterCommand('openCoinshop', function()
if isNuiOpen then return end
OpenCoinshop()
end, false)
RegisterKeyMapping('openCoinshop', Config.KeyBind.description, 'keyboard', Config.KeyBind.key)
-- =====================
-- NUI MANAGEMENT
-- =====================
function OpenCoinshop()
if isNuiOpen then return end
ESX.TriggerServerCallback('mercy-coinshop:getShopData', function(data)
if not data then return end
isNuiOpen = true
SetNuiFocus(true, true)
SendNUIMessage({
type = 'open',
coins = data.coins,
categories = data.categories,
theme = Config.Theme,
locale = Config.Locale,
confirmPopup = Config.ConfirmPopup,
isAdmin = data.isAdmin,
shopName = Config.ShopName,
logoURL = Config.LogoURL,
playtimeBonus = data.playtimeBonus,
tebexEnabled = data.tebexEnabled,
tebexStoreUrl = Config.Tebex.storeUrl or '',
testDriveEnabled = Config.TestDrive and Config.TestDrive.enabled or false,
})
end)
end
function CloseMenu()
if not isNuiOpen then return end
isNuiOpen = false
SetNuiFocus(false, false)
SendNUIMessage({ type = 'close' })
end
-- =====================
-- NUI CALLBACKS
-- =====================
RegisterNUICallback('close', function(_, cb)
CloseMenu()
cb('ok')
end)
RegisterNUICallback('buyVehicle', function(data, cb)
TriggerServerEvent('mercy-coinshop:buyVehicle', data.model, data.isWeekly or false)
cb('ok')
end)
RegisterNUICallback('buyItem', function(data, cb)
TriggerServerEvent('mercy-coinshop:buyItem', data.categoryId, data.itemIndex)
cb('ok')
end)
RegisterNUICallback('buyPack', function(data, cb)
TriggerServerEvent('mercy-coinshop:buyPack', data.categoryId, data.itemIndex)
cb('ok')
end)
RegisterNUICallback('buyPlate', function(data, cb)
TriggerServerEvent('mercy-coinshop:buyPlate', data.vehiclePlate, data.newPlate)
cb('ok')
end)
RegisterNUICallback('redeemCode', function(data, cb)
ESX.TriggerServerCallback('mercy-coinshop:redeemCode', function(result)
SendNUIMessage({
type = 'redeemResult',
success = result.success,
message = result.message,
coins = result.coins,
})
end, data.code)
cb('ok')
end)
RegisterNUICallback('getHistory', function(_, cb)
ESX.TriggerServerCallback('mercy-coinshop:getHistory', function(history)
SendNUIMessage({ type = 'updateHistory', history = history })
end)
cb('ok')
end)
-- Testfahrt beenden (wiederverwendbar)
local function EndTestDrive()
if not isTestDriving then return end
isTestDriving = false
end
RegisterNUICallback('testDrive', function(data, cb)
cb('ok')
if not Config.TestDrive or not Config.TestDrive.enabled then return end
if isTestDriving then
TriggerEvent(Config.Notification.event, Config.Notification.title, Config.Locale.testDriveAlready or 'Du bist bereits auf einer Testfahrt!', 'error', Config.Notification.duration)
return
end
local model = data.model
if not model then return end
CloseMenu()
isTestDriving = true
Citizen.CreateThread(function()
-- Spieler-Position merken
local playerPed = PlayerPedId()
local returnCoords = GetEntityCoords(playerPed)
local returnHeading = GetEntityHeading(playerPed)
-- Model laden
local modelHash = GetHashKey(model)
RequestModel(modelHash)
while not HasModelLoaded(modelHash) do
Wait(100)
end
-- Spawn-Position
local spawnCoords = Config.TestDrive.spawnCoords
local spawnX, spawnY, spawnZ, spawnH = spawnCoords.x, spawnCoords.y, spawnCoords.z, spawnCoords.w
-- Spieler teleportieren
SetEntityCoords(playerPed, spawnX, spawnY, spawnZ, false, false, false, true)
Wait(1000)
-- Fahrzeug spawnen
local vehicle = CreateVehicle(modelHash, spawnX, spawnY, spawnZ, spawnH, true, false)
SetModelAsNoLongerNeeded(modelHash)
testDriveVehicle = vehicle
-- Spieler ins Fahrzeug setzen
TaskWarpPedIntoVehicle(playerPed, vehicle, -1)
-- Kennzeichen setzen
local plate = "TEST" .. tostring(math.random(1000, 9999))
SetVehicleNumberPlateText(vehicle, plate)
-- Keys geben
TriggerServerEvent("vehicles_keys:selfGiveVehicleKeys", plate)
-- Fahrzeug-Extras
SetVehicleEngineOn(vehicle, true, true, false)
SetVehicleOnGroundProperly(vehicle)
-- Kurz warten damit ESC vom NUI-Schliessen nicht sofort die Testfahrt beendet
Wait(2000)
-- Countdown mit Aussteig- und ESC-Erkennung
local duration = Config.TestDrive.duration or 60
local remaining = duration
local lastSecond = GetGameTimer()
while remaining > 0 and isTestDriving do
local ped = PlayerPedId()
-- Aussteigen erkennen
if not IsPedInAnyVehicle(ped, false) then
break
end
-- ESC (Backspace/200) erkennen
if IsControlJustPressed(0, 200) then
break
end
-- HUD-Text anzeigen
local helpText = string.format("~b~Testfahrt~s~ | ~y~%ds~s~ | ~r~ESC~s~ = Beenden | ~r~Aussteigen~s~ = Beenden", remaining)
SetTextComponentFormat("STRING")
AddTextComponentString(helpText)
DisplayHelpTextFromStringLabel(0, false, true, -1)
-- Jede Sekunde runterzaehlen
if GetGameTimer() - lastSecond >= 1000 then
remaining = remaining - 1
lastSecond = GetGameTimer()
end
Wait(0)
end
-- Testfahrt beenden
isTestDriving = false
-- Keys entfernen
TriggerServerEvent("vehicles_keys:selfRemoveKeys", plate)
-- Spieler aus Fahrzeug holen
local ped = PlayerPedId()
if IsPedInVehicle(ped, vehicle, false) then
TaskLeaveVehicle(ped, vehicle, 16)
Wait(1500)
end
-- Fahrzeug löschen
if DoesEntityExist(vehicle) then
DeleteEntity(vehicle)
end
testDriveVehicle = nil
-- Zurück teleportieren
Wait(500)
ped = PlayerPedId()
SetEntityCoords(ped, returnCoords.x, returnCoords.y, returnCoords.z, false, false, false, true)
SetEntityHeading(ped, returnHeading)
TriggerEvent(Config.Notification.event, Config.Notification.title, Config.Locale.testDriveEnd or 'Testfahrt beendet!', 'info', Config.Notification.duration)
end)
end)
RegisterNUICallback('getPlayerVehicles', function(_, cb)
ESX.TriggerServerCallback('mercy-coinshop:getPlayerVehicles', function(vehicles)
SendNUIMessage({ type = 'updatePlayerVehicles', vehicles = vehicles })
end)
cb('ok')
end)
-- =====================
-- SERVER EVENT HANDLERS
-- =====================
RegisterNetEvent('mercy-coinshop:notify')
AddEventHandler('mercy-coinshop:notify', function(message, nType)
TriggerEvent(Config.Notification.event, Config.Notification.title, message, nType or 'info', Config.Notification.duration)
end)
RegisterNetEvent('mercy-coinshop:updateCoins')
AddEventHandler('mercy-coinshop:updateCoins', function(coins)
if isNuiOpen then
SendNUIMessage({ type = 'updateCoins', coins = coins })
end
end)
RegisterNetEvent('mercy-coinshop:purchaseSuccess')
AddEventHandler('mercy-coinshop:purchaseSuccess', function(model)
if isNuiOpen then
SendNUIMessage({ type = 'purchaseSuccess', model = model })
end
end)
RegisterNetEvent('mercy-coinshop:playtimeReset')
AddEventHandler('mercy-coinshop:playtimeReset', function()
if isNuiOpen then
SendNUIMessage({ type = 'playtimeReset' })
end
end)
RegisterNetEvent('mercy-coinshop:forceClose')
AddEventHandler('mercy-coinshop:forceClose', function()
CloseMenu()
end)