local QBCore = exports['qb-core']:GetCoreObject() -- Add targets to all vending machine props CreateThread(function() Wait(2000) exports['qb-target']:AddTargetModel(Config.VendingProps, { options = { { type = "client", event = "vending:client:buyMachine", icon = "fas fa-dollar-sign", label = "Automaten kaufen ($" .. Config.VendingMachinePrice .. ")", canInteract = function(entity, distance, data) return not isRegisteredMachine(entity) end }, { type = "client", event = "vending:client:openBuyMenu", icon = "fas fa-shopping-cart", label = "Kaufen", canInteract = function(entity, distance, data) return isRegisteredMachine(entity) end }, { type = "client", event = "vending:client:openOwnerMenu", icon = "fas fa-cog", label = "Verwalten", canInteract = function(entity, distance, data) return isOwnerOfMachine(entity) end }, { type = "client", event = "vending:client:startRobbery", icon = "fas fa-mask", label = "Aufbrechen", canInteract = function(entity, distance, data) return isRegisteredMachine(entity) and not isOwnerOfMachine(entity) end } }, distance = 2.0 }) end) -- Check if machine is registered function isRegisteredMachine(entity) local coords = GetEntityCoords(entity) local isRegistered = false QBCore.Functions.TriggerCallback('vending:server:machineExists', function(exists) isRegistered = exists end, coords) -- Wait for callback (not ideal but works for canInteract) local timeout = 0 while isRegistered == false and timeout < 100 do Wait(10) timeout = timeout + 1 end return isRegistered end -- Check if player owns machine function isOwnerOfMachine(entity) local coords = GetEntityCoords(entity) local isOwner = false QBCore.Functions.TriggerCallback('vending:server:isOwner', function(owner) isOwner = owner end, coords) -- Wait for callback local timeout = 0 while isOwner == false and timeout < 100 do Wait(10) timeout = timeout + 1 end return isOwner end -- Buy vending machine RegisterNetEvent('vending:client:buyMachine', function(data) local entity = data.entity local coords = GetEntityCoords(entity) local model = GetEntityModel(entity) local prop = nil -- Find prop name for i = 1, #Config.VendingProps do if GetHashKey(Config.VendingProps[i]) == model then prop = Config.VendingProps[i] break end end if not prop then return end lib.registerContext({ id = 'vending_buy_confirm', title = 'Verkaufsautomat kaufen', options = { { title = 'Bestätigen', description = 'Automaten für $' .. Config.VendingMachinePrice .. ' kaufen', icon = 'fas fa-check', onSelect = function() TriggerServerEvent('vending:server:registerMachine', coords, prop) end }, { title = 'Abbrechen', description = 'Kauf abbrechen', icon = 'fas fa-times' } } }) lib.showContext('vending_buy_confirm') end) -- Open buy menu RegisterNetEvent('vending:client:openBuyMenu', function(data) local entity = data.entity local coords = GetEntityCoords(entity) QBCore.Functions.TriggerCallback('vending:server:getStashItems', function(items) if #items == 0 then QBCore.Functions.Notify('Dieser Automat ist leer!', 'error') return end local options = {} for i = 1, #items do local item = items[i] if item.amount > 0 then local itemLabel = QBCore.Shared.Items[item.name] and QBCore.Shared.Items[item.name].label or item.name table.insert(options, { title = itemLabel, description = 'Preis: $' .. item.price .. ' | Verfügbar: ' .. item.amount, icon = 'fas fa-shopping-cart', onSelect = function() TriggerServerEvent('vending:server:buyItem', coords, item.name) end }) end end if #options == 0 then QBCore.Functions.Notify('Keine Artikel verfügbar!', 'error') return end lib.registerContext({ id = 'vending_buy_menu', title = 'Verkaufsautomat', options = options }) lib.showContext('vending_buy_menu') end, coords) end) -- Open owner menu RegisterNetEvent('vending:client:openOwnerMenu', function(data) local entity = data.entity local coords = GetEntityCoords(entity) QBCore.Functions.TriggerCallback('vending:server:getMachineByCoords', function(machine) if not machine then QBCore.Functions.Notify('Automat nicht gefunden!', 'error') return end lib.registerContext({ id = 'vending_owner_menu', title = 'Verkaufsautomat Verwaltung', options = { { title = 'Inventar verwalten', description = 'Items hinzufügen/entfernen', icon = 'fas fa-box', onSelect = function() TriggerServerEvent('vending:server:openStash', coords) end }, { title = 'Preise festlegen', description = 'Verkaufspreise für Items setzen', icon = 'fas fa-tags', onSelect = function() openPriceMenu(coords) end }, { title = 'Geld abheben', description = 'Verfügbar: $' .. machine.money, icon = 'fas fa-money-bill', onSelect = function() openWithdrawMenu(coords, machine.money) end }, { title = 'Statistiken', description = 'Verkaufsstatistiken anzeigen', icon = 'fas fa-chart-bar', onSelect = function() openStatsMenu(machine) end } } }) lib.showContext('vending_owner_menu') end, coords) end) -- Open price menu function openPriceMenu(coords) QBCore.Functions.TriggerCallback('vending:server:getStashItems', function(items) if #items == 0 then QBCore.Functions.Notify('Keine Items im Automaten!', 'error') return end local options = {} for i = 1, #items do local item = items[i] local itemLabel = QBCore.Shared.Items[item.name] and QBCore.Shared.Items[item.name].label or item.name table.insert(options, { title = itemLabel, description = 'Aktueller Preis: $' .. item.price, icon = 'fas fa-tag', onSelect = function() setPriceForItem(coords, item.name, itemLabel) end }) end lib.registerContext({ id = 'vending_price_menu', title = 'Preise festlegen', menu = 'vending_owner_menu', options = options }) lib.showContext('vending_price_menu') end, coords) end -- Set price for specific item function setPriceForItem(coords, itemName, itemLabel) local input = lib.inputDialog('Preis festlegen', { { type = 'number', label = 'Preis für ' .. itemLabel, description = 'Neuen Verkaufspreis eingeben', required = true, min = 1, max = 10000 } }) if input and input[1] then TriggerServerEvent('vending:server:setItemPrice', coords, itemName, tonumber(input[1])) end end -- Open withdraw menu function openWithdrawMenu(coords, availableMoney) if availableMoney <= 0 then QBCore.Functions.Notify('Kein Geld im Automaten!', 'error') return end local input = lib.inputDialog('Geld abheben', { { type = 'number', label = 'Betrag (Verfügbar: $' .. availableMoney .. ')', description = 'Wie viel möchtest du abheben?', required = true, min = 1, max = availableMoney } }) if input and input[1] then TriggerServerEvent('vending:server:withdrawMoney', coords, tonumber(input[1])) end end -- Open stats menu function openStatsMenu(machine) lib.registerContext({ id = 'vending_stats_menu', title = 'Verkaufsstatistiken', menu = 'vending_owner_menu', options = { { title = 'Gesamteinnahmen', description = '$' .. machine.money, icon = 'fas fa-dollar-sign' }, { title = 'Automat ID', description = '#' .. machine.id, icon = 'fas fa-hashtag' }, { title = 'Standort', description = 'X: ' .. math.floor(machine.coords.x) .. ' Y: ' .. math.floor(machine.coords.y), icon = 'fas fa-map-marker-alt' } } }) lib.showContext('vending_stats_menu') end -- Start robbery RegisterNetEvent('vending:client:startRobbery', function(data) local entity = data.entity local coords = GetEntityCoords(entity) lib.registerContext({ id = 'vending_robbery_confirm', title = 'Verkaufsautomat aufbrechen', options = { { title = 'Aufbrechen', description = 'Versuche den Automaten aufzubrechen', icon = 'fas fa-mask', onSelect = function() TriggerServerEvent('vending:server:startRobbery', coords) end }, { title = 'Abbrechen', description = 'Aufbruch abbrechen', icon = 'fas fa-times' } } }) lib.showContext('vending_robbery_confirm') end) -- Start robbery animation and progress RegisterNetEvent('vending:client:startRobbery', function(coords) local playerPed = PlayerPedId() local robberyTime = 10000 -- 10 seconds -- Animation RequestAnimDict('anim@heists@fleeca_bank@drilling') while not HasAnimDictLoaded('anim@heists@fleeca_bank@drilling') do Wait(100) end TaskPlayAnim(playerPed, 'anim@heists@fleeca_bank@drilling', 'drill_straight_idle', 8.0, -8.0, -1, 1, 0, false, false, false) -- Progress bar if lib.progressBar then local success = lib.progressBar({ duration = robberyTime, label = 'Automat aufbrechen...', useWhileDead = false, canCancel = true, disable = { car = true, move = true, combat = true } }) ClearPedTasks(playerPed) TriggerServerEvent('vending:server:completeRobbery', coords, success) else -- Fallback without progress bar Wait(robberyTime) ClearPedTasks(playerPed) TriggerServerEvent('vending:server:completeRobbery', coords, true) end end) -- Police alert RegisterNetEvent('vending:client:policeAlert', function(coords, streetName) local alert = { title = "Verkaufsautomat Aufbruch", coords = coords, description = "Ein Verkaufsautomat wird aufgebrochen in " .. streetName } -- Add blip local blip = AddBlipForCoord(coords.x, coords.y, coords.z) SetBlipSprite(blip, 161) SetBlipColour(blip, 1) SetBlipScale(blip, 1.0) SetBlipAsShortRange(blip, false) BeginTextCommandSetBlipName("STRING") AddTextComponentString("Verkaufsautomat Aufbruch") EndTextCommandSetBlipName(blip) -- Remove blip after 5 minutes SetTimeout(300000, function() RemoveBlip(blip) end) QBCore.Functions.Notify('Verkaufsautomat Aufbruch gemeldet: ' .. streetName, 'error', 8000) end) -- Refresh targets (called when new machine is registered) RegisterNetEvent('vending:client:refreshTargets', function() -- Targets are automatically updated by qb-target -- This event can be used for additional refresh logic if needed end) -- Management menu (alternative opening method) RegisterNetEvent('vending:client:openManagement', function(machine) lib.registerContext({ id = 'vending_management', title = 'Verkaufsautomat #' .. machine.id, options = { { title = 'Inventar öffnen', description = 'Items hinzufügen oder entfernen', icon = 'fas fa-box', onSelect = function() TriggerServerEvent('vending:server:openStash', machine.coords) end }, { title = 'Einnahmen: $' .. machine.money, description = 'Geld abheben', icon = 'fas fa-money-bill', onSelect = function() openWithdrawMenu(machine.coords, machine.money) end } } }) lib.showContext('vending_management') end) -- Debug commands RegisterCommand('vendingdebug', function() local playerPed = PlayerPedId() local coords = GetEntityCoords(playerPed) QBCore.Functions.TriggerCallback('vending:server:getMachineByCoords', function(machine) if machine then print('Machine found:', json.encode(machine)) QBCore.Functions.Notify('Machine data logged to console', 'primary') else print('No machine found at current location') QBCore.Functions.Notify('No machine found here', 'error') end end, coords) end, false)