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)