diff --git a/resources/[inventory]/nordi_vending/client.lua b/resources/[inventory]/nordi_vending/client.lua index 4c9440859..ace50a61c 100644 --- a/resources/[inventory]/nordi_vending/client.lua +++ b/resources/[inventory]/nordi_vending/client.lua @@ -91,14 +91,29 @@ RegisterCommand('refreshvendingtargets', function() QBCore.Functions.Notify('Vending machine targets refreshed', 'success') end, false) +-- Get precise coordinates for entity +function getPreciseCoords(entity) + local coords = GetEntityCoords(entity) + local heading = GetEntityHeading(entity) + local model = GetEntityModel(entity) + + return { + x = coords.x, + y = coords.y, + z = coords.z, + h = heading, + model = model + } +end + -- Check if machine is registered function isRegisteredMachine(entity) - local entityId = NetworkGetNetworkIdFromEntity(entity) + local preciseCoords = getPreciseCoords(entity) local isRegistered = false QBCore.Functions.TriggerCallback('vending:server:machineExists', function(exists) isRegistered = exists - end, entityId) + end, preciseCoords) -- Wait for callback (not ideal but works for canInteract) local timeout = 0 @@ -112,12 +127,12 @@ end -- Check if player can manage machine function canManageMachine(entity) - local entityId = NetworkGetNetworkIdFromEntity(entity) + local preciseCoords = getPreciseCoords(entity) local canManage = false QBCore.Functions.TriggerCallback('vending:server:canManage', function(result) canManage = result - end, entityId) + end, preciseCoords) -- Wait for callback local timeout = 0 @@ -132,13 +147,10 @@ end -- Buy vending machine RegisterNetEvent('vending:client:buyMachine', function(data) local entity = data.entity - local coords = GetEntityCoords(entity) + local preciseCoords = getPreciseCoords(entity) local model = GetEntityModel(entity) - local entityId = NetworkGetNetworkIdFromEntity(entity) local prop = nil - print("[VENDING] Buying machine: Entity ID: " .. entityId) - -- Find prop name for i = 1, #Config.VendingProps do if GetHashKey(Config.VendingProps[i]) == model then @@ -158,7 +170,7 @@ RegisterNetEvent('vending:client:buyMachine', function(data) description = 'Automaten für $' .. Config.VendingMachinePrice .. ' kaufen', icon = 'fas fa-check', onSelect = function() - TriggerServerEvent('vending:server:registerMachine', coords, prop, entityId) + TriggerServerEvent('vending:server:registerMachine', preciseCoords, prop) end }, { @@ -175,9 +187,7 @@ end) -- Open buy menu with quantity selection RegisterNetEvent('vending:client:openBuyMenu', function(data) local entity = data.entity - local entityId = NetworkGetNetworkIdFromEntity(entity) - - print("[VENDING] Opening buy menu: Entity ID: " .. entityId) + local preciseCoords = getPreciseCoords(entity) QBCore.Functions.TriggerCallback('vending:server:getStashItems', function(items) if #items == 0 then @@ -196,7 +206,7 @@ RegisterNetEvent('vending:client:openBuyMenu', function(data) description = 'Preis: $' .. item.price .. ' | Verfügbar: ' .. item.amount, icon = 'fas fa-shopping-cart', onSelect = function() - openQuantityDialog(entityId, item.name, item.price, item.amount, itemLabel) + openQuantityDialog(preciseCoords, item.name, item.price, item.amount, itemLabel) end }) end @@ -214,11 +224,11 @@ RegisterNetEvent('vending:client:openBuyMenu', function(data) }) lib.showContext('vending_buy_menu') - end, entityId) + end, preciseCoords) end) -- Open quantity dialog for buying items -function openQuantityDialog(entityId, itemName, price, maxAmount, itemLabel) +function openQuantityDialog(preciseCoords, itemName, price, maxAmount, itemLabel) local input = lib.inputDialog('Menge auswählen', { { type = 'number', @@ -234,7 +244,7 @@ function openQuantityDialog(entityId, itemName, price, maxAmount, itemLabel) if input and input[1] then local amount = tonumber(input[1]) if amount > 0 and amount <= maxAmount then - TriggerServerEvent('vending:server:buyItem', itemName, amount, entityId) + TriggerServerEvent('vending:server:buyItem', preciseCoords, itemName, amount) else QBCore.Functions.Notify('Ungültige Menge!', 'error') end @@ -244,25 +254,21 @@ end -- Open owner menu RegisterNetEvent('vending:client:openOwnerMenu', function(data) local entity = data.entity - local entityId = NetworkGetNetworkIdFromEntity(entity) + local preciseCoords = getPreciseCoords(entity) - print("[VENDING] Opening owner menu: Entity ID: " .. entityId) - - QBCore.Functions.TriggerCallback('vending:server:getMachineByEntity', function(machine) + QBCore.Functions.TriggerCallback('vending:server:getMachineByCoords', function(machine) if not machine then QBCore.Functions.Notify('Automat nicht gefunden!', 'error') return end - print("[VENDING] Machine data received: ID: " .. machine.id .. ", isOwner: " .. tostring(machine.isOwner)) - local options = { { title = 'Inventar verwalten', description = 'Items hinzufügen/entfernen', icon = 'fas fa-box', onSelect = function() - TriggerServerEvent('vending:server:openStash', entityId) + TriggerServerEvent('vending:server:openStash', preciseCoords) end }, { @@ -270,7 +276,7 @@ RegisterNetEvent('vending:client:openOwnerMenu', function(data) description = 'Verkaufspreise für Items setzen', icon = 'fas fa-tags', onSelect = function() - openPriceMenu(entityId) + openPriceMenu(preciseCoords) end }, { @@ -278,7 +284,7 @@ RegisterNetEvent('vending:client:openOwnerMenu', function(data) description = 'Verfügbar: $' .. machine.money, icon = 'fas fa-money-bill', onSelect = function() - openWithdrawMenu(entityId, machine.money) + openWithdrawMenu(preciseCoords, machine.money) end }, { @@ -293,13 +299,12 @@ RegisterNetEvent('vending:client:openOwnerMenu', function(data) -- Add manager options only for owner if machine.isOwner then - print("[VENDING] Adding manager options for owner") table.insert(options, { title = 'Verwalter', description = 'Verwalter hinzufügen/entfernen', icon = 'fas fa-users-cog', onSelect = function() - openManagersMenu(entityId) + openManagersMenu(preciseCoords) end }) @@ -309,11 +314,9 @@ RegisterNetEvent('vending:client:openOwnerMenu', function(data) description = 'Verkaufe den Automaten für ' .. math.floor(Config.VendingMachinePrice * Config.SellBackPercentage / 100) .. '$', icon = 'fas fa-dollar-sign', onSelect = function() - sellVendingMachine(entityId, machine.id) + sellVendingMachine(preciseCoords, machine.id) end }) - else - print("[VENDING] Not adding manager options - not owner") end lib.registerContext({ @@ -323,11 +326,11 @@ RegisterNetEvent('vending:client:openOwnerMenu', function(data) }) lib.showContext('vending_owner_menu') - end, entityId) + end, preciseCoords) end) -- Funktion zum Verkaufen des Automaten -function sellVendingMachine(entityId, machineId) +function sellVendingMachine(preciseCoords, machineId) local input = lib.inputDialog('Automaten verkaufen', { { type = 'checkbox', @@ -338,12 +341,12 @@ function sellVendingMachine(entityId, machineId) }) if input and input[1] then - TriggerServerEvent('vending:server:sellMachine', machineId, entityId) + TriggerServerEvent('vending:server:sellMachine', preciseCoords, machineId) end end -- Open price menu -function openPriceMenu(entityId) +function openPriceMenu(preciseCoords) QBCore.Functions.TriggerCallback('vending:server:getStashItems', function(items) if #items == 0 then QBCore.Functions.Notify('Keine Items im Automaten!', 'error') @@ -360,7 +363,7 @@ function openPriceMenu(entityId) description = 'Aktueller Preis: $' .. item.price, icon = 'fas fa-tag', onSelect = function() - setPriceForItem(entityId, item.name, itemLabel) + setPriceForItem(preciseCoords, item.name, itemLabel) end }) end @@ -373,11 +376,11 @@ function openPriceMenu(entityId) }) lib.showContext('vending_price_menu') - end, entityId) + end, preciseCoords) end -- Set price for specific item -function setPriceForItem(entityId, itemName, itemLabel) +function setPriceForItem(preciseCoords, itemName, itemLabel) local input = lib.inputDialog('Preis festlegen', { { type = 'number', @@ -390,12 +393,12 @@ function setPriceForItem(entityId, itemName, itemLabel) }) if input and input[1] then - TriggerServerEvent('vending:server:setItemPrice', itemName, tonumber(input[1]), entityId) + TriggerServerEvent('vending:server:setItemPrice', preciseCoords, itemName, tonumber(input[1])) end end -- Open withdraw menu -function openWithdrawMenu(entityId, availableMoney) +function openWithdrawMenu(preciseCoords, availableMoney) if availableMoney <= 0 then QBCore.Functions.Notify('Kein Geld im Automaten!', 'error') return @@ -413,7 +416,7 @@ function openWithdrawMenu(entityId, availableMoney) }) if input and input[1] then - TriggerServerEvent('vending:server:withdrawMoney', tonumber(input[1]), entityId) + TriggerServerEvent('vending:server:withdrawMoney', preciseCoords, tonumber(input[1])) end end @@ -446,7 +449,7 @@ function openStatsMenu(machine) end -- Open managers menu -function openManagersMenu(entityId) +function openManagersMenu(preciseCoords) -- Get current managers QBCore.Functions.TriggerCallback('vending:server:getManagers', function(managers) local options = { @@ -455,7 +458,7 @@ function openManagersMenu(entityId) description = 'Neuen Verwalter hinzufügen', icon = 'fas fa-user-plus', onSelect = function() - openAddManagerMenu(entityId) + openAddManagerMenu(preciseCoords) end } } @@ -479,9 +482,9 @@ function openManagersMenu(entityId) description = 'Verwalter entfernen', icon = 'fas fa-user-minus', onSelect = function() - TriggerServerEvent('vending:server:removeManager', manager.citizenid, entityId) + TriggerServerEvent('vending:server:removeManager', preciseCoords, manager.citizenid) Wait(500) - openManagersMenu(entityId) -- Refresh the menu + openManagersMenu(preciseCoords) -- Refresh the menu end } } @@ -507,11 +510,11 @@ function openManagersMenu(entityId) }) lib.showContext('managers_menu') - end, entityId) + end, preciseCoords) end -- Open add manager menu -function openAddManagerMenu(entityId) +function openAddManagerMenu(preciseCoords) QBCore.Functions.TriggerCallback('vending:server:getOnlinePlayers', function(players) if #players == 0 then QBCore.Functions.Notify('Keine Spieler online!', 'error') @@ -527,9 +530,9 @@ function openAddManagerMenu(entityId) description = 'ID: ' .. player.id, icon = 'fas fa-user', onSelect = function() - TriggerServerEvent('vending:server:addManager', player.id, entityId) + TriggerServerEvent('vending:server:addManager', preciseCoords, player.id) Wait(500) - openManagersMenu(entityId) -- Refresh the menu + openManagersMenu(preciseCoords) -- Refresh the menu end }) end @@ -548,7 +551,7 @@ end -- Robbery menu RegisterNetEvent('vending:client:startRobbery', function(data) local entity = data.entity - local entityId = NetworkGetNetworkIdFromEntity(entity) + local preciseCoords = getPreciseCoords(entity) lib.registerContext({ id = 'vending_robbery_confirm', @@ -559,7 +562,7 @@ RegisterNetEvent('vending:client:startRobbery', function(data) description = 'Versuche den Automaten aufzubrechen', icon = 'fas fa-mask', onSelect = function() - TriggerServerEvent('vending:server:startRobbery', entityId) + TriggerServerEvent('vending:server:startRobbery', preciseCoords) end }, { @@ -574,7 +577,7 @@ RegisterNetEvent('vending:client:startRobbery', function(data) end) -- Start robbery animation and progress -RegisterNetEvent('vending:client:startRobbery', function(entityId) +RegisterNetEvent('vending:client:startRobbery', function(preciseCoords) local playerPed = PlayerPedId() local robberyTime = 10000 -- 10 seconds @@ -601,12 +604,12 @@ RegisterNetEvent('vending:client:startRobbery', function(entityId) }) ClearPedTasks(playerPed) - TriggerServerEvent('vending:server:completeRobbery', entityId, success) + TriggerServerEvent('vending:server:completeRobbery', preciseCoords, success) else -- Fallback without progress bar Wait(robberyTime) ClearPedTasks(playerPed) - TriggerServerEvent('vending:server:completeRobbery', entityId, true) + TriggerServerEvent('vending:server:completeRobbery', preciseCoords, true) end end) @@ -652,7 +655,7 @@ RegisterNetEvent('vending:client:openManagement', function(machine) description = 'Items hinzufügen oder entfernen', icon = 'fas fa-box', onSelect = function() - TriggerServerEvent('vending:server:openStash', machine.entityId) + TriggerServerEvent('vending:server:openStash', machine.coords) end }, { @@ -660,7 +663,7 @@ RegisterNetEvent('vending:client:openManagement', function(machine) description = 'Geld abheben', icon = 'fas fa-money-bill', onSelect = function() - openWithdrawMenu(machine.entityId, machine.money) + openWithdrawMenu(machine.coords, machine.money) end } } @@ -688,8 +691,9 @@ RegisterCommand('checkvendingprops', function() if dist < 30.0 then foundProps = foundProps + 1 - local entityId = NetworkGetNetworkIdFromEntity(obj) - print("Found " .. propName .. " at distance: " .. dist .. " | Entity ID: " .. entityId) + local preciseCoords = getPreciseCoords(obj) + print("Found " .. propName .. " at distance: " .. dist .. " | Coords: " .. + preciseCoords.x .. ", " .. preciseCoords.y .. ", " .. preciseCoords.z) -- Add a temporary blip local blip = AddBlipForEntity(obj) @@ -697,7 +701,7 @@ RegisterCommand('checkvendingprops', function() SetBlipColour(blip, 2) SetBlipScale(blip, 0.8) BeginTextCommandSetBlipName("STRING") - AddTextComponentString(propName .. " | ID: " .. entityId) + AddTextComponentString(propName) EndTextCommandSetBlipName(blip) -- Remove blip after 10 seconds @@ -716,11 +720,10 @@ end, false) RegisterCommand('vendingdebug', function() local playerPed = PlayerPedId() local coords = GetEntityCoords(playerPed) - local entity = nil - local entityId = 0 -- Try to find the closest vending machine local minDist = 3.0 + local closestEntity = nil local objects = GetGamePool('CObject') for _, obj in ipairs(objects) do @@ -731,23 +734,23 @@ RegisterCommand('vendingdebug', function() local dist = #(coords - objCoords) if dist < minDist then minDist = dist - entity = obj - entityId = NetworkGetNetworkIdFromEntity(obj) + closestEntity = obj end end end end - if entity then - QBCore.Functions.TriggerCallback('vending:server:getMachineByEntity', function(machine) + if closestEntity then + local preciseCoords = getPreciseCoords(closestEntity) + QBCore.Functions.TriggerCallback('vending:server:getMachineByCoords', function(machine) if machine then print('Machine found:', json.encode(machine)) - QBCore.Functions.Notify('Machine #' .. machine.id .. ' | Entity ID: ' .. entityId .. ' | Owner: ' .. machine.owner, 'primary') + QBCore.Functions.Notify('Machine #' .. machine.id .. ' | Owner: ' .. machine.owner, 'primary') else - print('No machine found with entity ID:', entityId) - QBCore.Functions.Notify('No machine found with entity ID: ' .. entityId, 'error') + print('No machine found at coords:', json.encode(preciseCoords)) + QBCore.Functions.Notify('No machine found at these coords', 'error') end - end, entityId) + end, preciseCoords) else QBCore.Functions.Notify('No vending machine found nearby', 'error') end diff --git a/resources/[inventory]/nordi_vending/server.lua b/resources/[inventory]/nordi_vending/server.lua index 3c6938332..e69de29bb 100644 --- a/resources/[inventory]/nordi_vending/server.lua +++ b/resources/[inventory]/nordi_vending/server.lua @@ -1,746 +0,0 @@ -local QBCore = exports['qb-core']:GetCoreObject() -local vendingMachines = {} -local robberyInProgress = {} - --- Load vending machines from database -CreateThread(function() - local result = MySQL.Sync.fetchAll('SELECT * FROM vending_machines') - if result then - for i = 1, #result do - local data = result[i] - vendingMachines[data.id] = { - id = data.id, - owner = data.owner, - coords = json.decode(data.coords), - prop = data.prop, - money = data.money, - items = json.decode(data.items) or {}, - prices = json.decode(data.prices) or {}, - managers = json.decode(data.managers) or {}, - stash = 'vending_' .. data.id, - entityId = data.entity_id - } - end - print("^2[VENDING]^7 Loaded " .. #result .. " vending machines") - end -end) - --- Helper function to get machine ID by entity -function getMachineIdByEntity(entityId) - for id, machine in pairs(vendingMachines) do - if machine.entityId == entityId then - print("^2[VENDING]^7 Found machine #" .. id .. " by entity ID: " .. entityId) - return id - end - end - print("^1[VENDING]^7 No machine found with entity ID: " .. entityId) - return nil -end - --- Register vending machine (when player buys it) -RegisterNetEvent('vending:server:registerMachine', function(coords, prop, entityId) - local src = source - local Player = QBCore.Functions.GetPlayer(src) - if not Player then return end - - print("^2[VENDING]^7 Registering machine: Entity ID: " .. entityId .. ", Prop: " .. prop) - - -- Check if there's already a machine with this entity ID - for id, machine in pairs(vendingMachines) do - if machine.entityId == entityId then - TriggerClientEvent('QBCore:Notify', src, 'Dieser Automat ist bereits registriert!', 'error') - return - end - end - - -- Check if player has enough money - if Player.PlayerData.money.cash < Config.VendingMachinePrice then - TriggerClientEvent('QBCore:Notify', src, 'Du benötigst $' .. Config.VendingMachinePrice .. ' um diesen Automaten zu kaufen!', 'error') - return - end - - -- Remove money - Player.Functions.RemoveMoney('cash', Config.VendingMachinePrice) - - -- Create machine in database - local machineId = MySQL.insert.await('INSERT INTO vending_machines (owner, coords, prop, money, items, prices, managers, entity_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?)', { - Player.PlayerData.citizenid, - json.encode(coords), - prop, - 0, - json.encode({}), - json.encode({}), - json.encode({}), - entityId - }) - - -- Add to memory - vendingMachines[machineId] = { - id = machineId, - owner = Player.PlayerData.citizenid, - coords = coords, - prop = prop, - money = 0, - items = {}, - prices = {}, - managers = {}, - stash = 'vending_' .. machineId, - entityId = entityId - } - - print("^2[VENDING]^7 New vending machine registered: #" .. machineId .. " | Entity ID: " .. entityId .. " | Owner: " .. Player.PlayerData.citizenid) - TriggerClientEvent('QBCore:Notify', src, 'Verkaufsautomat erfolgreich gekauft für $' .. Config.VendingMachinePrice .. '!', 'success') - TriggerClientEvent('vending:client:refreshTargets', -1) -end) - --- Sell vending machine -RegisterNetEvent('vending:server:sellMachine', function(machineId, entityId) - local src = source - local Player = QBCore.Functions.GetPlayer(src) - if not Player then return end - - if not machineId then - machineId = getMachineIdByEntity(entityId) - end - - if not machineId then - TriggerClientEvent('QBCore:Notify', src, 'Automat nicht gefunden!', 'error') - return - end - - local machine = vendingMachines[machineId] - - -- Check if player is owner - if machine.owner ~= Player.PlayerData.citizenid then - TriggerClientEvent('QBCore:Notify', src, 'Du bist nicht der Besitzer dieses Automaten!', 'error') - return - end - - -- Calculate sell price - local sellPrice = math.floor(Config.VendingMachinePrice * Config.SellBackPercentage / 100) - - -- Add money from machine to sell price - sellPrice = sellPrice + machine.money - - -- Give money to player - Player.Functions.AddMoney('cash', sellPrice) - - -- Empty stash first - local stashItems = exports["tgiann-inventory"]:GetSecondaryInventoryItems("stash", machine.stash) - if stashItems then - for slot, item in pairs(stashItems) do - if item.amount > 0 then - -- Try to add to player inventory first - if Player.Functions.AddItem(item.name, item.amount) then - exports["tgiann-inventory"]:RemoveItemFromSecondaryInventory("stash", machine.stash, item.name, item.amount, slot) - TriggerClientEvent('inventory:client:ItemBox', src, QBCore.Shared.Items[item.name], 'add', item.amount) - else - -- If player inventory is full, create a drop - exports["tgiann-inventory"]:RemoveItemFromSecondaryInventory("stash", machine.stash, item.name, item.amount, slot) - TriggerClientEvent('QBCore:Notify', src, 'Einige Items wurden auf den Boden fallen gelassen!', 'info') - -- If you have a drop system, you can create a drop here - end - end - end - end - - -- Delete from database - MySQL.Async.execute('DELETE FROM vending_machines WHERE id = ?', {machineId}) - - -- Remove from memory - vendingMachines[machineId] = nil - - TriggerClientEvent('QBCore:Notify', src, 'Automat verkauft für $' .. sellPrice .. '!', 'success') - TriggerClientEvent('vending:client:refreshTargets', -1) -end) - --- Check if player can manage machine -function canManageMachine(playerId, machineId) - local Player = QBCore.Functions.GetPlayer(playerId) - if not Player then - print("^1[VENDING]^7 canManageMachine: Player not found") - return false - end - - local machine = vendingMachines[machineId] - if not machine then - print("^1[VENDING]^7 canManageMachine: Machine not found") - return false - end - - -- Check if player is owner - local isOwner = (machine.owner == Player.PlayerData.citizenid) - print("^2[VENDING]^7 canManageMachine: Player " .. playerId .. " checking machine #" .. machineId) - print("^2[VENDING]^7 canManageMachine: Machine owner: " .. machine.owner) - print("^2[VENDING]^7 canManageMachine: Player citizenid: " .. Player.PlayerData.citizenid) - print("^2[VENDING]^7 canManageMachine: Is owner: " .. tostring(isOwner)) - - if isOwner then - return true - end - - -- Check if player is manager - if machine.managers then - for _, manager in pairs(machine.managers) do - if manager == Player.PlayerData.citizenid then - print("^2[VENDING]^7 canManageMachine: Player is manager") - return true - end - end - end - - print("^1[VENDING]^7 canManageMachine: Player is NOT owner or manager") - return false -end - --- Open management menu -RegisterNetEvent('vending:server:openManagement', function(entityId) - local src = source - local Player = QBCore.Functions.GetPlayer(src) - if not Player then return end - - print("^2[VENDING]^7 Player " .. src .. " trying to manage machine. Entity ID: " .. entityId) - - local machineId = getMachineIdByEntity(entityId) - if not machineId then - TriggerClientEvent('QBCore:Notify', src, 'Automat nicht gefunden!', 'error') - return - end - - local machine = vendingMachines[machineId] - - -- Debug output - print("^2[VENDING]^7 Player " .. src .. " (citizenid: " .. Player.PlayerData.citizenid .. ") trying to manage machine #" .. machineId) - print("^2[VENDING]^7 Machine owner: " .. machine.owner) - print("^2[VENDING]^7 Is owner: " .. tostring(machine.owner == Player.PlayerData.citizenid)) - - -- Check if player can manage - if not canManageMachine(src, machineId) then - TriggerClientEvent('QBCore:Notify', src, 'Du hast keine Berechtigung diesen Automaten zu verwalten!', 'error') - return - end - - -- Add isOwner flag to distinguish between owner and manager - machine.isOwner = (machine.owner == Player.PlayerData.citizenid) - print("^2[VENDING]^7 Setting isOwner flag to: " .. tostring(machine.isOwner)) - - TriggerClientEvent('vending:client:openManagement', src, machine) -end) - --- Open stash -RegisterNetEvent('vending:server:openStash', function(entityId) - local src = source - local Player = QBCore.Functions.GetPlayer(src) - if not Player then return end - - local machineId = getMachineIdByEntity(entityId) - if not machineId then - TriggerClientEvent('QBCore:Notify', src, 'Automat nicht gefunden!', 'error') - return - end - - -- Check if player can manage - if not canManageMachine(src, machineId) then - TriggerClientEvent('QBCore:Notify', src, 'Du hast keine Berechtigung diesen Automaten zu verwalten!', 'error') - return - end - - local machine = vendingMachines[machineId] - - -- Öffne das Inventar mit tgiann-inventory - exports["tgiann-inventory"]:OpenInventory(src, "stash", machine.stash, { - maxweight = Config.MaxWeight, - slots = Config.MaxSlots, - label = 'Vending Machine #' .. machine.id - }) -end) - --- Set item price -RegisterNetEvent('vending:server:setItemPrice', function(itemName, price, entityId) - local src = source - local Player = QBCore.Functions.GetPlayer(src) - if not Player then return end - - local machineId = getMachineIdByEntity(entityId) - if not machineId then - TriggerClientEvent('QBCore:Notify', src, 'Automat nicht gefunden!', 'error') - return - end - - -- Check if player can manage - if not canManageMachine(src, machineId) then - TriggerClientEvent('QBCore:Notify', src, 'Du hast keine Berechtigung diesen Automaten zu verwalten!', 'error') - return - end - - local machine = vendingMachines[machineId] - - -- Update price - machine.prices[itemName] = price - MySQL.update('UPDATE vending_machines SET prices = ? WHERE id = ?', {json.encode(machine.prices), machineId}) - - TriggerClientEvent('QBCore:Notify', src, 'Preis für ' .. (QBCore.Shared.Items[itemName] and QBCore.Shared.Items[itemName].label or itemName) .. ' auf $' .. price .. ' gesetzt!', 'success') -end) - --- Withdraw money -RegisterNetEvent('vending:server:withdrawMoney', function(amount, entityId) - local src = source - local Player = QBCore.Functions.GetPlayer(src) - if not Player then return end - - local machineId = getMachineIdByEntity(entityId) - if not machineId then - TriggerClientEvent('QBCore:Notify', src, 'Automat nicht gefunden!', 'error') - return - end - - -- Check if player can manage - if not canManageMachine(src, machineId) then - TriggerClientEvent('QBCore:Notify', src, 'Du hast keine Berechtigung diesen Automaten zu verwalten!', 'error') - return - end - - local machine = vendingMachines[machineId] - - if machine.money < amount then - TriggerClientEvent('QBCore:Notify', src, 'Nicht genug Geld im Automaten!', 'error') - return - end - - -- Update machine money - machine.money = machine.money - amount - MySQL.update('UPDATE vending_machines SET money = ? WHERE id = ?', {machine.money, machineId}) - - -- Give money to player - Player.Functions.AddMoney('cash', amount) - TriggerClientEvent('QBCore:Notify', src, 'Du hast $' .. amount .. ' abgehoben!', 'success') -end) - --- Buy item from vending machine with quantity selection -RegisterNetEvent('vending:server:buyItem', function(itemName, amount, entityId) - local src = source - local Player = QBCore.Functions.GetPlayer(src) - if not Player then return end - - local machineId = getMachineIdByEntity(entityId) - if not machineId then - TriggerClientEvent('QBCore:Notify', src, 'Automat nicht gefunden!', 'error') - return - end - - local machine = vendingMachines[machineId] - local price = machine.prices[itemName] or Config.DefaultPrice - local totalPrice = price * amount - - -- Check if player has enough money - if Player.PlayerData.money.cash < totalPrice then - TriggerClientEvent('QBCore:Notify', src, 'Du hast nicht genug Geld!', 'error') - return - end - - -- Get stash items - local stashItems = exports["tgiann-inventory"]:GetSecondaryInventoryItems("stash", machine.stash) - local availableAmount = 0 - - if stashItems then - for slot, item in pairs(stashItems) do - if item.name == itemName and item.amount > 0 then - availableAmount = availableAmount + item.amount - end - end - end - - if availableAmount < amount then - TriggerClientEvent('QBCore:Notify', src, 'Nicht genug Artikel verfügbar! Verfügbar: ' .. availableAmount, 'error') - return - end - - -- Check if player can carry the items - if not Player.Functions.AddItem(itemName, amount) then - TriggerClientEvent('QBCore:Notify', src, 'Du kannst nicht so viele Items tragen!', 'error') - return - end - - -- Remove money from player - Player.Functions.RemoveMoney('cash', totalPrice) - - -- Add money to machine - machine.money = machine.money + totalPrice - MySQL.update('UPDATE vending_machines SET money = ? WHERE id = ?', {machine.money, machineId}) - - -- Remove items from stash - local remainingToRemove = amount - for slot, item in pairs(stashItems) do - if item.name == itemName and item.amount > 0 then - local removeAmount = math.min(remainingToRemove, item.amount) - exports["tgiann-inventory"]:RemoveItemFromSecondaryInventory("stash", machine.stash, itemName, removeAmount, slot) - remainingToRemove = remainingToRemove - removeAmount - - if remainingToRemove <= 0 then - break - end - end - end - - -- Show item box - TriggerClientEvent('inventory:client:ItemBox', src, QBCore.Shared.Items[itemName], 'add', amount) - - TriggerClientEvent('QBCore:Notify', src, amount .. 'x ' .. (QBCore.Shared.Items[itemName] and QBCore.Shared.Items[itemName].label or itemName) .. ' gekauft für $' .. totalPrice .. '!', 'success') -end) - --- Add manager to vending machine -RegisterNetEvent('vending:server:addManager', function(targetId, entityId) - local src = source - local Player = QBCore.Functions.GetPlayer(src) - if not Player then return end - - local machineId = getMachineIdByEntity(entityId) - if not machineId then - TriggerClientEvent('QBCore:Notify', src, 'Automat nicht gefunden!', 'error') - return - end - - local machine = vendingMachines[machineId] - - -- Only owner can add managers - if machine.owner ~= Player.PlayerData.citizenid then - TriggerClientEvent('QBCore:Notify', src, 'Nur der Besitzer kann Verwalter hinzufügen!', 'error') - return - end - - -- Get target player - local Target = QBCore.Functions.GetPlayer(tonumber(targetId)) - if not Target then - TriggerClientEvent('QBCore:Notify', src, 'Spieler nicht gefunden!', 'error') - return - end - - -- Check if already a manager - if machine.managers then - for _, manager in pairs(machine.managers) do - if manager == Target.PlayerData.citizenid then - TriggerClientEvent('QBCore:Notify', src, 'Diese Person ist bereits ein Verwalter!', 'error') - return - end - end - else - machine.managers = {} - end - - -- Add to managers - table.insert(machine.managers, Target.PlayerData.citizenid) - MySQL.update('UPDATE vending_machines SET managers = ? WHERE id = ?', {json.encode(machine.managers), machineId}) - - TriggerClientEvent('QBCore:Notify', src, Target.PlayerData.charinfo.firstname .. ' ' .. Target.PlayerData.charinfo.lastname .. ' als Verwalter hinzugefügt!', 'success') - TriggerClientEvent('QBCore:Notify', Target.PlayerData.source, 'Du wurdest als Verwalter für einen Verkaufsautomaten hinzugefügt!', 'success') -end) - --- Remove manager from vending machine -RegisterNetEvent('vending:server:removeManager', function(citizenid, entityId) - local src = source - local Player = QBCore.Functions.GetPlayer(src) - if not Player then return end - - local machineId = getMachineIdByEntity(entityId) - if not machineId then - TriggerClientEvent('QBCore:Notify', src, 'Automat nicht gefunden!', 'error') - return - end - - local machine = vendingMachines[machineId] - - -- Only owner can remove managers - if machine.owner ~= Player.PlayerData.citizenid then - TriggerClientEvent('QBCore:Notify', src, 'Nur der Besitzer kann Verwalter entfernen!', 'error') - return - end - - -- Check if manager exists - local found = false - local newManagers = {} - - if machine.managers then - for _, manager in pairs(machine.managers) do - if manager ~= citizenid then - table.insert(newManagers, manager) - else - found = true - end - end - end - - if not found then - TriggerClientEvent('QBCore:Notify', src, 'Diese Person ist kein Verwalter!', 'error') - return - end - - -- Update managers - machine.managers = newManagers - MySQL.update('UPDATE vending_machines SET managers = ? WHERE id = ?', {json.encode(machine.managers), machineId}) - - TriggerClientEvent('QBCore:Notify', src, 'Verwalter entfernt!', 'success') - - -- Notify the removed manager if online - local players = QBCore.Functions.GetPlayers() - for _, playerId in ipairs(players) do - local targetPlayer = QBCore.Functions.GetPlayer(playerId) - if targetPlayer and targetPlayer.PlayerData.citizenid == citizenid then - TriggerClientEvent('QBCore:Notify', targetPlayer.PlayerData.source, 'Du wurdest als Verwalter eines Verkaufsautomaten entfernt!', 'error') - break - end - end -end) - --- Start robbery -RegisterNetEvent('vending:server:startRobbery', function(entityId) - local src = source - local Player = QBCore.Functions.GetPlayer(src) - if not Player then return end - - local machineId = getMachineIdByEntity(entityId) - if not machineId then - TriggerClientEvent('QBCore:Notify', src, 'Automat nicht gefunden!', 'error') - return - end - - local machine = vendingMachines[machineId] - - -- Check if player has required item - local hasItem = Player.Functions.GetItemByName(Config.RobberyItem) - if not hasItem or hasItem.amount < 1 then - TriggerClientEvent('QBCore:Notify', src, 'Du benötigst einen ' .. Config.RobberyItem, 'error') - return - end - - -- Check if already being robbed - if robberyInProgress[machineId] then - TriggerClientEvent('QBCore:Notify', src, 'Dieser Automat wird bereits aufgebrochen!', 'error') - return - end - - -- Check if machine has money - if machine.money < Config.MinRobberyAmount then - TriggerClientEvent('QBCore:Notify', src, 'Nicht genug Geld im Automaten!', 'error') - return - end - - robberyInProgress[machineId] = true - - -- Alert police - local streetHash = GetStreetNameAtCoord(machine.coords.x, machine.coords.y, machine.coords.z) - local streetName = GetStreetNameFromHashKey(streetHash) - - local players = QBCore.Functions.GetQBPlayers() - for k, v in pairs(players) do - if v.PlayerData.job.name == 'police' and v.PlayerData.job.onduty then - TriggerClientEvent('vending:client:policeAlert', v.PlayerData.source, machine.coords, streetName) - end - end - - -- Alert owner and managers - for _, playerId in ipairs(QBCore.Functions.GetPlayers()) do - local targetPlayer = QBCore.Functions.GetPlayer(playerId) - if targetPlayer then - if targetPlayer.PlayerData.citizenid == machine.owner then - TriggerClientEvent('QBCore:Notify', targetPlayer.PlayerData.source, 'Dein Verkaufsautomat wird gerade aufgebrochen! Standort: ' .. streetName, 'error', 10000) - elseif machine.managers then - for _, manager in pairs(machine.managers) do - if targetPlayer.PlayerData.citizenid == manager then - TriggerClientEvent('QBCore:Notify', targetPlayer.PlayerData.source, 'Ein Verkaufsautomat, den du verwaltest, wird gerade aufgebrochen! Standort: ' .. streetName, 'error', 10000) - break - end - end - end - end - end - - TriggerClientEvent('vending:client:startRobbery', src, entityId) -end) - --- Complete robbery -RegisterNetEvent('vending:server:completeRobbery', function(entityId, success) - local src = source - local Player = QBCore.Functions.GetPlayer(src) - if not Player then return end - - local machineId = getMachineIdByEntity(entityId) - if not machineId then - TriggerClientEvent('QBCore:Notify', src, 'Automat nicht gefunden!', 'error') - return - end - - local machine = vendingMachines[machineId] - robberyInProgress[machineId] = false - - if success then - local stolenAmount = math.random(Config.MinRobberyAmount, math.min(machine.money, Config.MaxRobberyAmount)) - - -- Remove money from machine - machine.money = machine.money - stolenAmount - MySQL.update('UPDATE vending_machines SET money = ? WHERE id = ?', {machine.money, machineId}) - - -- Give money to player - Player.Functions.AddMoney('cash', stolenAmount) - TriggerClientEvent('QBCore:Notify', src, 'Du hast $' .. stolenAmount .. ' gestohlen!', 'success') - - -- Remove robbery item with chance - if math.random(1, 100) <= Config.RobberyItemBreakChance then - Player.Functions.RemoveItem(Config.RobberyItem, 1) - TriggerClientEvent('inventory:client:ItemBox', src, QBCore.Shared.Items[Config.RobberyItem], 'remove') - TriggerClientEvent('QBCore:Notify', src, 'Dein ' .. Config.RobberyItem .. ' ist kaputt gegangen!', 'error') - end - else - TriggerClientEvent('QBCore:Notify', src, 'Aufbruch fehlgeschlagen!', 'error') - end -end) - --- Get machine data by entity -QBCore.Functions.CreateCallback('vending:server:getMachineByEntity', function(source, cb, entityId) - local machineId = getMachineIdByEntity(entityId) - if machineId then - cb(vendingMachines[machineId]) - else - cb(nil) - end -end) - --- Get stash items for vending machine menu -QBCore.Functions.CreateCallback('vending:server:getStashItems', function(source, cb, entityId) - local machineId = getMachineIdByEntity(entityId) - if not machineId then - cb({}) - return - end - - local machine = vendingMachines[machineId] - - -- Get stash items using correct export - local stashItems = exports["tgiann-inventory"]:GetSecondaryInventoryItems("stash", machine.stash) - local items = {} - - if stashItems then - for slot, item in pairs(stashItems) do - if item.amount > 0 then - item.price = machine.prices[item.name] or Config.DefaultPrice - table.insert(items, item) - end - end - end - - cb(items) -end) - --- Get managers list -QBCore.Functions.CreateCallback('vending:server:getManagers', function(source, cb, entityId) - local machineId = getMachineIdByEntity(entityId) - if not machineId then - cb({}) - return - end - - local machine = vendingMachines[machineId] - local managersList = {} - - if machine.managers and #machine.managers > 0 then - for _, citizenid in pairs(machine.managers) do - -- Try to get online player info - local found = false - local players = QBCore.Functions.GetPlayers() - - for _, playerId in ipairs(players) do - local targetPlayer = QBCore.Functions.GetPlayer(playerId) - if targetPlayer and targetPlayer.PlayerData.citizenid == citizenid then - table.insert(managersList, { - citizenid = citizenid, - name = targetPlayer.PlayerData.charinfo.firstname .. ' ' .. targetPlayer.PlayerData.charinfo.lastname, - online = true - }) - found = true - break - end - end - - -- If not online, get from database - if not found then - local result = MySQL.Sync.fetchAll('SELECT charinfo FROM players WHERE citizenid = ?', {citizenid}) - if result and result[1] then - local charinfo = json.decode(result[1].charinfo) - table.insert(managersList, { - citizenid = citizenid, - name = charinfo.firstname .. ' ' .. charinfo.lastname, - online = false - }) - else - table.insert(managersList, { - citizenid = citizenid, - name = "Unbekannt", - online = false - }) - end - end - end - end - - cb(managersList) -end) - --- Check if machine exists -QBCore.Functions.CreateCallback('vending:server:machineExists', function(source, cb, entityId) - local machineId = getMachineIdByEntity(entityId) - cb(machineId ~= nil) -end) - --- Check if player can manage machine -QBCore.Functions.CreateCallback('vending:server:canManage', function(source, cb, entityId) - local machineId = getMachineIdByEntity(entityId) - if not machineId then - cb(false) - return - end - - cb(canManageMachine(source, machineId)) -end) - --- Get online players for manager selection -QBCore.Functions.CreateCallback('vending:server:getOnlinePlayers', function(source, cb) - local src = source - local Player = QBCore.Functions.GetPlayer(src) - if not Player then - cb({}) - return - end - - local players = {} - local onlinePlayers = QBCore.Functions.GetPlayers() - - for _, playerId in ipairs(onlinePlayers) do - local targetPlayer = QBCore.Functions.GetPlayer(playerId) - if targetPlayer and targetPlayer.PlayerData.source ~= src then - table.insert(players, { - id = targetPlayer.PlayerData.source, - name = targetPlayer.PlayerData.charinfo.firstname .. ' ' .. targetPlayer.PlayerData.charinfo.lastname, - citizenid = targetPlayer.PlayerData.citizenid - }) - end - end - - cb(players) -end) - --- Debug command -QBCore.Commands.Add('vendingdebug', 'Debug vending machines (Admin Only)', {}, false, function(source, args) - local Player = QBCore.Functions.GetPlayer(source) - if Player.PlayerData.permission == "admin" or Player.PlayerData.permission == "god" then - local count = 0 - for id, machine in pairs(vendingMachines) do - count = count + 1 - print("^2[VENDING]^7 Machine #" .. id .. " | Owner: " .. machine.owner .. " | Money: $" .. machine.money .. " | Entity ID: " .. (machine.entityId or "none")) - end - - TriggerClientEvent('QBCore:Notify', source, count .. ' Verkaufsautomaten geladen', 'success') - else - TriggerClientEvent('QBCore:Notify', source, 'Keine Berechtigung!', 'error') - end -end, 'admin') - -