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 {}, stash = 'vending_' .. data.id } end end end) -- Register vending machine (when player buys it) RegisterNetEvent('vending:server:registerMachine', function(coords, prop) local src = source local Player = QBCore.Functions.GetPlayer(src) if not Player then return end -- Check if there's already a machine at these coords for id, machine in pairs(vendingMachines) do local dist = #(vector3(coords.x, coords.y, coords.z) - vector3(machine.coords.x, machine.coords.y, machine.coords.z)) if dist < 2.0 then TriggerClientEvent('QBCore:Notify', src, 'Hier ist bereits ein Automat 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) VALUES (?, ?, ?, ?, ?, ?)', { Player.PlayerData.citizenid, json.encode(coords), prop, 0, json.encode({}), json.encode({}) }) -- Add to memory vendingMachines[machineId] = { id = machineId, owner = Player.PlayerData.citizenid, coords = coords, prop = prop, money = 0, items = {}, prices = {}, stash = 'vending_' .. machineId } TriggerClientEvent('QBCore:Notify', src, 'Verkaufsautomat erfolgreich gekauft für $' .. Config.VendingMachinePrice .. '!', 'success') TriggerClientEvent('vending:client:refreshTargets', -1) end) -- Open management menu RegisterNetEvent('vending:server:openManagement', function(coords) local src = source local Player = QBCore.Functions.GetPlayer(src) if not Player then return end local machineId = getMachineIdByCoords(coords) if not machineId then return end local machine = vendingMachines[machineId] if machine.owner ~= Player.PlayerData.citizenid then TriggerClientEvent('QBCore:Notify', src, 'Das ist nicht dein Verkaufsautomat!', 'error') return end TriggerClientEvent('vending:client:openManagement', src, machine) end) -- Open stash (mit mehreren Methoden versuchen) RegisterNetEvent('vending:server:openStash', function(coords) local src = source local Player = QBCore.Functions.GetPlayer(src) if not Player then return end local machineId = getMachineIdByCoords(coords) if not machineId then return end local machine = vendingMachines[machineId] if machine.owner ~= Player.PlayerData.citizenid then TriggerClientEvent('QBCore:Notify', src, 'Das ist nicht dein Verkaufsautomat!', 'error') return end -- Versuche verschiedene Methoden für tgiann-inventory local success = false -- Methode 1: TriggerClientEvent if not success then local clientSuccess = pcall(function() TriggerClientEvent('tgiann-inventory:client:openStash', src, { stashId = machine.stash, stashLabel = 'Vending Machine #' .. machine.id, maxweight = Config.MaxWeight, slots = Config.MaxSlots }) end) if clientSuccess then success = true print('[Vending] Opened stash via client event') end end -- Methode 2: Server Event if not success then local eventSuccess = pcall(function() TriggerEvent('tgiann-inventory:server:openStash', src, machine.stash, { maxweight = Config.MaxWeight, slots = Config.MaxSlots, label = 'Vending Machine #' .. machine.id }) end) if eventSuccess then success = true print('[Vending] Opened stash via server event') end end -- Methode 3: Fallback - eigenes Stash-System if not success then TriggerClientEvent('vending:client:openCustomStash', src, machine) print('[Vending] Opened custom stash fallback') end end) -- Set item price RegisterNetEvent('vending:server:setItemPrice', function(coords, itemName, price) local src = source local Player = QBCore.Functions.GetPlayer(src) if not Player then return end local machineId = getMachineIdByCoords(coords) if not machineId then return end local machine = vendingMachines[machineId] if machine.owner ~= Player.PlayerData.citizenid then TriggerClientEvent('QBCore:Notify', src, 'Das ist nicht dein Verkaufsautomat!', 'error') return end -- 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(coords, amount) local src = source local Player = QBCore.Functions.GetPlayer(src) if not Player then return end local machineId = getMachineIdByCoords(coords) if not machineId then return end local machine = vendingMachines[machineId] if machine.owner ~= Player.PlayerData.citizenid then TriggerClientEvent('QBCore:Notify', src, 'Das ist nicht dein Verkaufsautomat!', 'error') return end 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 (mit Fallback-System) RegisterNetEvent('vending:server:buyItem', function(coords, itemName) local src = source local Player = QBCore.Functions.GetPlayer(src) if not Player then return end local machineId = getMachineIdByCoords(coords) if not machineId then return end local machine = vendingMachines[machineId] local price = machine.prices[itemName] or Config.DefaultPrice -- Check if player has enough money if Player.PlayerData.money.cash < price then TriggerClientEvent('QBCore:Notify', src, 'Du hast nicht genug Geld!', 'error') return end -- Check if item is available in our database if not machine.items[itemName] or machine.items[itemName] <= 0 then TriggerClientEvent('QBCore:Notify', src, 'Artikel nicht verfügbar!', 'error') return end -- Remove money from player Player.Functions.RemoveMoney('cash', price) -- Add money to machine machine.money = machine.money + price -- Remove item from machine machine.items[itemName] = machine.items[itemName] - 1 -- Update database MySQL.update('UPDATE vending_machines SET money = ?, items = ? WHERE id = ?', { machine.money, json.encode(machine.items), machineId }) -- Add item to player using QBCore Player.Functions.AddItem(itemName, 1) TriggerClientEvent('inventory:client:ItemBox', src, QBCore.Shared.Items[itemName], 'add') TriggerClientEvent('QBCore:Notify', src, 'Artikel gekauft für $' .. price .. '!', 'success') end) -- Add item to vending machine (for stocking) RegisterNetEvent('vending:server:addItem', function(coords, itemName, amount) local src = source local Player = QBCore.Functions.GetPlayer(src) if not Player then return end local machineId = getMachineIdByCoords(coords) if not machineId then return end local machine = vendingMachines[machineId] if machine.owner ~= Player.PlayerData.citizenid then TriggerClientEvent('QBCore:Notify', src, 'Das ist nicht dein Verkaufsautomat!', 'error') return end -- Check if player has the item local item = Player.Functions.GetItemByName(itemName) if not item or item.amount < amount then TriggerClientEvent('QBCore:Notify', src, 'Du hast nicht genug von diesem Item!', 'error') return end -- Remove item from player Player.Functions.RemoveItem(itemName, amount) TriggerClientEvent('inventory:client:ItemBox', src, QBCore.Shared.Items[itemName], 'remove') -- Add item to machine if not machine.items[itemName] then machine.items[itemName] = 0 end machine.items[itemName] = machine.items[itemName] + amount -- Update database MySQL.update('UPDATE vending_machines SET items = ? WHERE id = ?', {json.encode(machine.items), machineId}) TriggerClientEvent('QBCore:Notify', src, amount .. 'x ' .. (QBCore.Shared.Items[itemName] and QBCore.Shared.Items[itemName].label or itemName) .. ' zum Automaten hinzugefügt!', 'success') end) -- Remove item from vending machine RegisterNetEvent('vending:server:removeItem', function(coords, itemName, amount) local src = source local Player = QBCore.Functions.GetPlayer(src) if not Player then return end local machineId = getMachineIdByCoords(coords) if not machineId then return end local machine = vendingMachines[machineId] if machine.owner ~= Player.PlayerData.citizenid then TriggerClientEvent('QBCore:Notify', src, 'Das ist nicht dein Verkaufsautomat!', 'error') return end -- Check if machine has the item if not machine.items[itemName] or machine.items[itemName] < amount then TriggerClientEvent('QBCore:Notify', src, 'Nicht genug Items im Automaten!', 'error') return end -- Remove item from machine machine.items[itemName] = machine.items[itemName] - amount -- Add item to player Player.Functions.AddItem(itemName, amount) TriggerClientEvent('inventory:client:ItemBox', src, QBCore.Shared.Items[itemName], 'add') -- Update database MySQL.update('UPDATE vending_machines SET items = ? WHERE id = ?', {json.encode(machine.items), machineId}) TriggerClientEvent('QBCore:Notify', src, amount .. 'x ' .. (QBCore.Shared.Items[itemName] and QBCore.Shared.Items[itemName].label or itemName) .. ' aus dem Automaten entfernt!', 'success') end) -- Start robbery RegisterNetEvent('vending:server:startRobbery', function(coords) local src = source local Player = QBCore.Functions.GetPlayer(src) if not Player then return end local machineId = getMachineIdByCoords(coords) if not machineId then 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(coords.x, coords.y, 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, coords, streetName) end end TriggerClientEvent('vending:client:startRobbery', src, coords) end) -- Complete robbery RegisterNetEvent('vending:server:completeRobbery', function(coords, success) local src = source local Player = QBCore.Functions.GetPlayer(src) if not Player then return end local machineId = getMachineIdByCoords(coords) if not machineId then 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) -- Helper function to get machine ID by coordinates function getMachineIdByCoords(coords) for id, machine in pairs(vendingMachines) do local dist = #(vector3(coords.x, coords.y, coords.z) - vector3(machine.coords.x, machine.coords.y, machine.coords.z)) if dist < 2.0 then return id end end return nil end -- Get machine data by coordinates QBCore.Functions.CreateCallback('vending:server:getMachineByCoords', function(source, cb, coords) local machineId = getMachineIdByCoords(coords) if machineId then cb(vendingMachines[machineId]) else cb(nil) end end) -- Get stash items for vending machine menu (using our database) QBCore.Functions.CreateCallback('vending:server:getStashItems', function(source, cb, coords) local machineId = getMachineIdByCoords(coords) if not machineId then cb({}) return end local machine = vendingMachines[machineId] local items = {} for itemName, amount in pairs(machine.items) do if amount > 0 then local itemData = QBCore.Shared.Items[itemName] if itemData then table.insert(items, { name = itemName, label = itemData.label, amount = amount, price = machine.prices[itemName] or Config.DefaultPrice, image = itemData.image }) end end end cb(items) end) -- Check if player owns machine QBCore.Functions.CreateCallback('vending:server:isOwner', function(source, cb, coords) local Player = QBCore.Functions.GetPlayer(source) if not Player then cb(false) return end local machineId = getMachineIdByCoords(coords) if not machineId then cb(false) return end local machine = vendingMachines[machineId] cb(machine.owner == Player.PlayerData.citizenid) end) -- Check if machine exists at coords QBCore.Functions.CreateCallback('vending:server:machineExists', function(source, cb, coords) local machineId = getMachineIdByCoords(coords) cb(machineId ~= nil) end)