local QBCore = exports['qb-core']:GetCoreObject() local nearbyMachine = nil local currentMachineData = nil local isInteracting = false -- Function to draw 3D text in the world function DrawText3D(x, y, z, text) SetTextScale(0.35, 0.35) SetTextFont(4) SetTextProportional(1) SetTextColour(255, 255, 255, 215) SetTextEntry("STRING") SetTextCentre(1) AddTextComponentString(text) SetDrawOrigin(x, y, z, 0) DrawText(0.0, 0.0) local factor = (string.len(text)) / 370 DrawRect(0.0, 0.0+0.0125, 0.017+ factor, 0.03, 0, 0, 0, 75) ClearDrawOrigin() end -- Function to check if machine is registered (with caching) function isRegisteredMachine(entity) if currentMachineData and currentMachineData.entity == entity then return currentMachineData.isRegistered end local coords = GetEntityCoords(entity) local isRegistered = false QBCore.Functions.TriggerCallback('vending:server:machineExists', function(exists) isRegistered = exists end, coords) -- Wait for callback local timeout = 0 while isRegistered == false and timeout < 100 do Wait(10) timeout = timeout + 1 end if not currentMachineData then currentMachineData = {} end currentMachineData.entity = entity currentMachineData.isRegistered = isRegistered return isRegistered end -- Check if player can manage machine (with caching) function canManageMachine(entity) if currentMachineData and currentMachineData.entity == entity and currentMachineData.canManage ~= nil then return currentMachineData.canManage end local coords = GetEntityCoords(entity) local canManage = false QBCore.Functions.TriggerCallback('vending:server:canManage', function(result) canManage = result end, coords) -- Wait for callback local timeout = 0 while canManage == false and timeout < 100 do Wait(10) timeout = timeout + 1 end if not currentMachineData then currentMachineData = {} end currentMachineData.entity = entity currentMachineData.canManage = canManage return canManage end -- Main thread to detect nearby vending machines CreateThread(function() while true do local playerPed = PlayerPedId() local playerCoords = GetEntityCoords(playerPed) local wait = 1000 local foundMachine = false -- Check for nearby vending machines for _, propName in ipairs(Config.VendingProps) do local hash = GetHashKey(propName) local objects = GetGamePool('CObject') for _, obj in ipairs(objects) do if GetEntityModel(obj) == hash then local objCoords = GetEntityCoords(obj) local dist = #(playerCoords - objCoords) if dist < 2.0 then wait = 0 foundMachine = true nearbyMachine = obj -- Only check status if not already interacting if not isInteracting then local z = objCoords.z + 1.0 local registered = isRegisteredMachine(obj) if registered then local canManage = canManageMachine(obj) if canManage then DrawText3D(objCoords.x, objCoords.y, z, "[E] Kaufen | [G] Verwalten") -- Handle key presses for management if IsControlJustPressed(0, 38) then -- E key isInteracting = true TriggerEvent('vending:client:openBuyMenu', {entity = obj}) Wait(500) -- Prevent multiple triggers isInteracting = false elseif IsControlJustPressed(0, 47) then -- G key isInteracting = true TriggerEvent('vending:client:openOwnerMenu', {entity = obj}) Wait(500) -- Prevent multiple triggers isInteracting = false end else DrawText3D(objCoords.x, objCoords.y, z, "[E] Kaufen | [G] Aufbrechen") -- Handle key presses for buying/robbery if IsControlJustPressed(0, 38) then -- E key isInteracting = true TriggerEvent('vending:client:openBuyMenu', {entity = obj}) Wait(500) -- Prevent multiple triggers isInteracting = false elseif IsControlJustPressed(0, 47) then -- G key isInteracting = true TriggerEvent('vending:client:startRobbery', {entity = obj}) Wait(500) -- Prevent multiple triggers isInteracting = false end end else DrawText3D(objCoords.x, objCoords.y, z, "[E] Automaten kaufen ($" .. Config.VendingMachinePrice .. ")") -- Handle key press for buying machine if IsControlJustPressed(0, 38) then -- E key isInteracting = true TriggerEvent('vending:client:buyMachine', {entity = obj}) Wait(500) -- Prevent multiple triggers isInteracting = false end end end break end end end if foundMachine then break end end if not foundMachine then nearbyMachine = nil currentMachineData = nil end Wait(wait) end end) -- Reset machine data when moving away CreateThread(function() while true do Wait(5000) if not nearbyMachine then currentMachineData = nil end end 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 -- Display confirmation text local startTime = GetGameTimer() local textShown = true CreateThread(function() while textShown do local objCoords = GetEntityCoords(entity) DrawText3D(objCoords.x, objCoords.y, objCoords.z + 1.0, "Automaten für $" .. Config.VendingMachinePrice .. " kaufen?\n[Y] Ja | [N] Nein") Wait(0) end end) -- Wait for key press while GetGameTimer() - startTime < 10000 and textShown do if IsControlJustPressed(0, 246) then -- Y key textShown = false TriggerServerEvent('vending:server:registerMachine', coords, prop) break elseif IsControlJustPressed(0, 249) then -- N key textShown = false break end Wait(0) end textShown = false end) -- Open buy menu with quantity selection 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 -- Simple item selection menu local options = {} local selectedItem = nil 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, { name = item.name, label = itemLabel, price = item.price, amount = item.amount }) end end if #options == 0 then QBCore.Functions.Notify('Keine Artikel verfügbar!', 'error') return end -- Display item selection local currentIndex = 1 local menuActive = true CreateThread(function() while menuActive do local objCoords = GetEntityCoords(entity) local item = options[currentIndex] DrawText3D(objCoords.x, objCoords.y, objCoords.z + 1.0, "Item: " .. item.label .. "\nPreis: $" .. item.price .. " | Verfügbar: " .. item.amount .. "\n[←][→] Navigieren | [ENTER] Auswählen | [ESC] Abbrechen") Wait(0) end end) -- Handle navigation while menuActive do if IsControlJustPressed(0, 174) then -- Left arrow currentIndex = currentIndex - 1 if currentIndex < 1 then currentIndex = #options end Wait(200) elseif IsControlJustPressed(0, 175) then -- Right arrow currentIndex = currentIndex + 1 if currentIndex > #options then currentIndex = 1 end Wait(200) elseif IsControlJustPressed(0, 18) then -- Enter key selectedItem = options[currentIndex] menuActive = false elseif IsControlJustPressed(0, 177) then -- Escape key menuActive = false return end Wait(0) end -- If item selected, ask for quantity if selectedItem then Wait(100) -- Small delay -- Display quantity selection local quantity = 1 local quantityMenu = true CreateThread(function() while quantityMenu do local objCoords = GetEntityCoords(entity) DrawText3D(objCoords.x, objCoords.y, objCoords.z + 1.0, "Item: " .. selectedItem.label .. " | Preis: $" .. (selectedItem.price * quantity) .. "\nMenge: " .. quantity .. "/" .. selectedItem.amount .. "\n[←][→] Ändern | [ENTER] Kaufen | [ESC] Abbrechen") Wait(0) end end) -- Handle quantity selection while quantityMenu do if IsControlJustPressed(0, 174) then -- Left arrow quantity = quantity - 1 if quantity < 1 then quantity = 1 end Wait(100) elseif IsControlJustPressed(0, 175) then -- Right arrow quantity = quantity + 1 if quantity > selectedItem.amount then quantity = selectedItem.amount end Wait(100) elseif IsControlJustPressed(0, 18) then -- Enter key quantityMenu = false TriggerServerEvent('vending:server:buyItem', coords, selectedItem.name, quantity) elseif IsControlJustPressed(0, 177) then -- Escape key quantityMenu = false end Wait(0) end end 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 -- Display owner menu options local options = { {label = "Inventar verwalten", action = "inventory"}, {label = "Preise festlegen", action = "prices"}, {label = "Geld abheben ($" .. machine.money .. ")", action = "withdraw"}, {label = "Statistiken", action = "stats"} } -- Add manager options only for owner if machine.isOwner then table.insert(options, {label = "Verwalter", action = "managers"}) table.insert(options, {label = "Automaten verkaufen", action = "sell"}) end -- Display menu local currentIndex = 1 local menuActive = true CreateThread(function() while menuActive do local objCoords = GetEntityCoords(entity) local menuText = "Verkaufsautomat Verwaltung\n" for i, option in ipairs(options) do if i == currentIndex then menuText = menuText .. "→ " .. option.label .. "\n" else menuText = menuText .. option.label .. "\n" end end menuText = menuText .. "\n[↑][↓] Navigieren | [ENTER] Auswählen | [ESC] Abbrechen" DrawText3D(objCoords.x, objCoords.y, objCoords.z + 1.0, menuText) Wait(0) end end) -- Handle navigation while menuActive do if IsControlJustPressed(0, 172) then -- Up arrow currentIndex = currentIndex - 1 if currentIndex < 1 then currentIndex = #options end Wait(200) elseif IsControlJustPressed(0, 173) then -- Down arrow currentIndex = currentIndex + 1 if currentIndex > #options then currentIndex = 1 end Wait(200) elseif IsControlJustPressed(0, 18) then -- Enter key local selectedOption = options[currentIndex].action menuActive = false -- Handle selected option if selectedOption == "inventory" then TriggerServerEvent('vending:server:openStash', coords) elseif selectedOption == "prices" then openPriceMenu(coords) elseif selectedOption == "withdraw" then openWithdrawMenu(coords, machine.money) elseif selectedOption == "stats" then openStatsMenu(machine) elseif selectedOption == "managers" then openManagersMenu(coords) elseif selectedOption == "sell" then sellVendingMachine(coords, machine.id) end elseif IsControlJustPressed(0, 177) then -- Escape key menuActive = false end Wait(0) end end, coords) end) -- Function to sell the vending machine function sellVendingMachine(coords, machineId) -- Display confirmation text local confirmActive = true CreateThread(function() while confirmActive do DrawText3D(coords.x, coords.y, coords.z + 1.0, "Automaten verkaufen für $" .. math.floor(Config.VendingMachinePrice * Config.SellBackPercentage / 100) .. "?\n" .. "Diese Aktion kann nicht rückgängig gemacht werden!\n" .. "[Y] Bestätigen | [N] Abbrechen") Wait(0) end end) -- Wait for confirmation while confirmActive do if IsControlJustPressed(0, 246) then -- Y key confirmActive = false TriggerServerEvent('vending:server:sellMachine', coords, machineId) elseif IsControlJustPressed(0, 249) then -- N key confirmActive = false end Wait(0) end 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 -- Create options list 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, { name = item.name, label = itemLabel, price = item.price }) end -- Display menu local currentIndex = 1 local menuActive = true CreateThread(function() while menuActive do local menuText = "Preise festlegen\n" for i, option in ipairs(options) do if i == currentIndex then menuText = menuText .. "→ " .. option.label .. " - $" .. option.price .. "\n" else menuText = menuText .. option.label .. " - $" .. option.price .. "\n" end end menuText = menuText .. "\n[↑][↓] Navigieren | [ENTER] Preis ändern | [ESC] Zurück" DrawText3D(coords.x, coords.y, coords.z + 1.0, menuText) Wait(0) end end) -- Handle navigation while menuActive do if IsControlJustPressed(0, 172) then -- Up arrow currentIndex = currentIndex - 1 if currentIndex < 1 then currentIndex = #options end Wait(200) elseif IsControlJustPressed(0, 173) then -- Down arrow currentIndex = currentIndex + 1 if currentIndex > #options then currentIndex = 1 end Wait(200) elseif IsControlJustPressed(0, 18) then -- Enter key local selectedItem = options[currentIndex] menuActive = false setPriceForItem(coords, selectedItem.name, selectedItem.label) elseif IsControlJustPressed(0, 177) then -- Escape key menuActive = false end Wait(0) end end, coords) end -- Set price for specific item function setPriceForItem(coords, itemName, itemLabel) -- Display price input local price = 0 local inputActive = true local inputText = "" CreateThread(function() while inputActive do DrawText3D(coords.x, coords.y, coords.z + 1.0, "Preis für " .. itemLabel .. " festlegen\n" .. "Aktueller Wert: $" .. inputText .. "_\n" .. "Verwende Nummerntasten | [ENTER] Bestätigen | [ESC] Abbrechen") Wait(0) end end) -- Handle input while inputActive do -- Number keys (0-9) for i = 48, 57 do if IsControlJustPressed(0, i) then inputText = inputText .. (i - 48) Wait(200) end end -- Numpad keys (0-9) for i = 96, 105 do if IsControlJustPressed(0, i) then inputText = inputText .. (i - 96) Wait(200) end end -- Backspace if IsControlJustPressed(0, 194) and string.len(inputText) > 0 then inputText = string.sub(inputText, 1, string.len(inputText) - 1) Wait(200) end -- Enter if IsControlJustPressed(0, 18) then inputActive = false price = tonumber(inputText) or 0 if price > 0 then TriggerServerEvent('vending:server:setItemPrice', coords, itemName, price) else QBCore.Functions.Notify('Ungültiger Preis!', 'error') end end -- Escape if IsControlJustPressed(0, 177) then inputActive = false end Wait(0) end end -- Open withdraw menu function openWithdrawMenu(coords, availableMoney) if availableMoney <= 0 then QBCore.Functions.Notify('Kein Geld im Automaten!', 'error') return end -- Display withdraw input local inputActive = true local inputText = "" CreateThread(function() while inputActive do DrawText3D(coords.x, coords.y, coords.z + 1.0, "Geld abheben (Verfügbar: $" .. availableMoney .. ")\n" .. "Betrag: $" .. inputText .. "_\n" .. "Verwende Nummerntasten | [ENTER] Bestätigen | [ESC] Abbrechen") Wait(0) end end) -- Handle input while inputActive do -- Number keys (0-9) for i = 48, 57 do if IsControlJustPressed(0, i) then inputText = inputText .. (i - 48) Wait(200) end end -- Numpad keys (0-9) for i = 96, 105 do if IsControlJustPressed(0, i) then inputText = inputText .. (i - 96) Wait(200) end end -- Backspace if IsControlJustPressed(0, 194) and string.len(inputText) > 0 then inputText = string.sub(inputText, 1, string.len(inputText) - 1) Wait(200) end -- Enter if IsControlJustPressed(0, 18) then inputActive = false local amount = tonumber(inputText) or 0 if amount > 0 and amount <= availableMoney then TriggerServerEvent('vending:server:withdrawMoney', coords, amount) else QBCore.Functions.Notify('Ungültiger Betrag!', 'error') end end -- Escape if IsControlJustPressed(0, 177) then inputActive = false end Wait(0) end end -- Open stats menu function openStatsMenu(machine) -- Display stats local menuActive = true CreateThread(function() while menuActive do DrawText3D(machine.coords.x, machine.coords.y, machine.coords.z + 1.0, "Verkaufsstatistiken\n" .. "Gesamteinnahmen: $" .. machine.money .. "\n" .. "Automat ID: #" .. machine.id .. "\n" .. "Standort: X:" .. math.floor(machine.coords.x) .. " Y:" .. math.floor(machine.coords.y) .. "\n" .. "[ESC] Zurück") Wait(0) end end) -- Wait for escape key while menuActive do if IsControlJustPressed(0, 177) then -- Escape key menuActive = false end Wait(0) end end -- Open managers menu function openManagersMenu(coords) -- Get current managers QBCore.Functions.TriggerCallback('vending:server:getManagers', function(managers) -- Create options list local options = { {label = "Verwalter hinzufügen", action = "add"} } -- Add existing managers if #managers > 0 then for i = 1, #managers do local manager = managers[i] table.insert(options, { label = manager.name .. (manager.online and " (Online)" or " (Offline)"), citizenid = manager.citizenid, action = "manage" }) end else table.insert(options, {label = "Keine Verwalter", action = "none"}) end -- Display menu local currentIndex = 1 local menuActive = true CreateThread(function() while menuActive do local menuText = "Verwalter verwalten\n" for i, option in ipairs(options) do if i == currentIndex then menuText = menuText .. "→ " .. option.label .. "\n" else menuText = menuText .. option.label .. "\n" end end menuText = menuText .. "\n[↑][↓] Navigieren | [ENTER] Auswählen | [ESC] Zurück" DrawText3D(coords.x, coords.y, coords.z + 1.0, menuText) Wait(0) end end) -- Handle navigation while menuActive do if IsControlJustPressed(0, 172) then -- Up arrow currentIndex = currentIndex - 1 if currentIndex < 1 then currentIndex = #options end Wait(200) elseif IsControlJustPressed(0, 173) then -- Down arrow currentIndex = currentIndex + 1 if currentIndex > #options then currentIndex = 1 end Wait(200) elseif IsControlJustPressed(0, 18) then -- Enter key local selectedOption = options[currentIndex] if selectedOption.action == "add" then menuActive = false openAddManagerMenu(coords) elseif selectedOption.action == "manage" then menuActive = false openManagerOptionsMenu(coords, selectedOption.citizenid) end elseif IsControlJustPressed(0, 177) then -- Escape key menuActive = false end Wait(0) end end, coords) end -- Open manager options menu function openManagerOptionsMenu(coords, citizenid) -- Display options local menuActive = true CreateThread(function() while menuActive do DrawText3D(coords.x, coords.y, coords.z + 1.0, "Verwalter Optionen\n" .. "[E] Entfernen\n" .. "[ESC] Zurück") Wait(0) end end) -- Handle input while menuActive do if IsControlJustPressed(0, 38) then -- E key menuActive = false TriggerServerEvent('vending:server:removeManager', coords, citizenid) Wait(500) openManagersMenu(coords) -- Refresh the menu elseif IsControlJustPressed(0, 177) then -- Escape key menuActive = false openManagersMenu(coords) -- Go back to managers menu end Wait(0) end end -- Open add manager menu function openAddManagerMenu(coords) QBCore.Functions.TriggerCallback('vending:server:getOnlinePlayers', function(players) if #players == 0 then QBCore.Functions.Notify('Keine Spieler online!', 'error') openManagersMenu(coords) -- Go back to managers menu return end -- Display player selection local currentIndex = 1 local menuActive = true CreateThread(function() while menuActive do local menuText = "Verwalter hinzufügen\n" for i, player in ipairs(players) do if i == currentIndex then menuText = menuText .. "→ " .. player.name .. " (ID: " .. player.id .. ")\n" else menuText = menuText .. player.name .. " (ID: " .. player.id .. ")\n" end end menuText = menuText .. "\n[↑][↓] Navigieren | [ENTER] Auswählen | [ESC] Zurück" DrawText3D(coords.x, coords.y, coords.z + 1.0, menuText) Wait(0) end end) -- Handle navigation while menuActive do if IsControlJustPressed(0, 172) then -- Up arrow currentIndex = currentIndex - 1 if currentIndex < 1 then currentIndex = #players end Wait(200) elseif IsControlJustPressed(0, 173) then -- Down arrow currentIndex = currentIndex + 1 if currentIndex > #players then currentIndex = 1 end Wait(200) elseif IsControlJustPressed(0, 18) then -- Enter key local selectedPlayer = players[currentIndex] menuActive = false TriggerServerEvent('vending:server:addManager', coords, selectedPlayer.id) Wait(500) openManagersMenu(coords) -- Refresh the menu elseif IsControlJustPressed(0, 177) then -- Escape key menuActive = false openManagersMenu(coords) -- Go back to managers menu end Wait(0) end end) end -- Robbery menu RegisterNetEvent('vending:client:startRobbery', function(data) local entity = data.entity local coords = GetEntityCoords(entity) -- Display robbery confirmation local menuActive = true CreateThread(function() while menuActive do DrawText3D(coords.x, coords.y, coords.z + 1.0, "Verkaufsautomat aufbrechen\n" .. "[E] Aufbrechen\n" .. "[ESC] Abbrechen") Wait(0) end end) -- Handle input while menuActive do if IsControlJustPressed(0, 38) then -- E key menuActive = false TriggerServerEvent('vending:server:startRobbery', coords) elseif IsControlJustPressed(0, 177) then -- Escape key menuActive = false elseif IsControlJustPressed(0, 177) then -- Escape key menuActive = false end Wait(0) end 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 (native implementation) local startTime = GetGameTimer() local endTime = startTime + robberyTime local cancelled = false -- Display progress bar CreateThread(function() while GetGameTimer() < endTime and not cancelled do local timeLeft = endTime - GetGameTimer() local progress = 1.0 - (timeLeft / robberyTime) DrawRect(0.5, 0.95, 0.2, 0.03, 0, 0, 0, 180) DrawRect(0.5 - ((1.0 - progress) * 0.1), 0.95, 0.2 * progress, 0.03, 255, 0, 0, 180) SetTextScale(0.35, 0.35) SetTextFont(4) SetTextProportional(1) SetTextColour(255, 255, 255, 215) SetTextEntry("STRING") SetTextCentre(1) AddTextComponentString("Automat aufbrechen... " .. math.floor(progress * 100) .. "%") DrawText(0.5, 0.94) -- Check for cancel if IsControlJustPressed(0, 177) then -- Escape key cancelled = true end Wait(0) end end) -- Wait for completion while GetGameTimer() < endTime and not cancelled do Wait(100) end ClearPedTasks(playerPed) TriggerServerEvent('vending:server:completeRobbery', coords, not cancelled) end) -- Police alert RegisterNetEvent('vending:client:policeAlert', function(coords, 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) -- Management menu (alternative opening method) RegisterNetEvent('vending:client:openManagement', function(machine) -- Display management menu local options = { {label = "Inventar öffnen", action = "inventory"}, {label = "Geld abheben ($" .. machine.money .. ")", action = "withdraw"} } local currentIndex = 1 local menuActive = true CreateThread(function() while menuActive do local menuText = "Verkaufsautomat #" .. machine.id .. "\n" for i, option in ipairs(options) do if i == currentIndex then menuText = menuText .. "→ " .. option.label .. "\n" else menuText = menuText .. option.label .. "\n" end end menuText = menuText .. "\n[↑][↓] Navigieren | [ENTER] Auswählen | [ESC] Abbrechen" DrawText3D(machine.coords.x, machine.coords.y, machine.coords.z + 1.0, menuText) Wait(0) end end) -- Handle navigation while menuActive do if IsControlJustPressed(0, 172) then -- Up arrow currentIndex = currentIndex - 1 if currentIndex < 1 then currentIndex = #options end Wait(200) elseif IsControlJustPressed(0, 173) then -- Down arrow currentIndex = currentIndex + 1 if currentIndex > #options then currentIndex = 1 end Wait(200) elseif IsControlJustPressed(0, 18) then -- Enter key local selectedOption = options[currentIndex].action menuActive = false if selectedOption == "inventory" then TriggerServerEvent('vending:server:openStash', machine.coords) elseif selectedOption == "withdraw" then openWithdrawMenu(machine.coords, machine.money) end elseif IsControlJustPressed(0, 177) then -- Escape key menuActive = false end Wait(0) end end) -- Debug command to check props RegisterCommand('checkvendingprops', function() local playerPed = PlayerPedId() local playerCoords = GetEntityCoords(playerPed) local foundProps = 0 for _, propName in ipairs(Config.VendingProps) do local hash = GetHashKey(propName) local objects = GetGamePool('CObject') print("Checking for prop: " .. propName .. " (Hash: " .. hash .. ")") for _, obj in ipairs(objects) do if GetEntityModel(obj) == hash then local objCoords = GetEntityCoords(obj) local dist = #(playerCoords - objCoords) if dist < 30.0 then foundProps = foundProps + 1 print("Found " .. propName .. " at distance: " .. dist) -- Add a temporary blip local blip = AddBlipForEntity(obj) SetBlipSprite(blip, 1) SetBlipColour(blip, 2) SetBlipScale(blip, 0.8) BeginTextCommandSetBlipName("STRING") AddTextComponentString(propName) EndTextCommandSetBlipName(blip) -- Remove blip after 10 seconds SetTimeout(10000, function() RemoveBlip(blip) end) end end end end QBCore.Functions.Notify('Found ' .. foundProps .. ' vending machines nearby', 'primary') end, false) -- 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) -- Helper function to display notifications function ShowHelpNotification(text) BeginTextCommandDisplayHelp("STRING") AddTextComponentSubstringPlayerName(text) EndTextCommandDisplayHelp(0, 0, 1, -1) end -- Helper function to get key name function GetKeyName(key) local keyNames = { [38] = "E", [47] = "G", [172] = "↑", [173] = "↓", [174] = "←", [175] = "→", [18] = "ENTER", [177] = "ESC", [246] = "Y", [249] = "N" } return keyNames[key] or "KEY " .. key end -- Helper function to handle text input function HandleTextInput(maxLength) local input = "" local inputActive = true while inputActive do -- Number keys (0-9) for i = 48, 57 do if IsControlJustPressed(0, i) and string.len(input) < maxLength then input = input .. (i - 48) Wait(200) end end -- Numpad keys (0-9) for i = 96, 105 do if IsControlJustPressed(0, i) and string.len(input) < maxLength then input = input .. (i - 96) Wait(200) end end -- Backspace if IsControlJustPressed(0, 194) and string.len(input) > 0 then input = string.sub(input, 1, string.len(input) - 1) Wait(200) end -- Enter if IsControlJustPressed(0, 18) then inputActive = false return input end -- Escape if IsControlJustPressed(0, 177) then inputActive = false return nil end Wait(0) end return nil end -- Event to refresh machine data when a new machine is registered RegisterNetEvent('vending:client:refreshTargets', function() -- Clear cached data currentMachineData = nil end)