2025-07-29 07:30:32 +02:00
|
|
|
local QBCore = exports['qb-core']:GetCoreObject()
|
2025-07-29 22:35:35 +02:00
|
|
|
local nearbyMachine = nil
|
2025-07-29 22:47:43 +02:00
|
|
|
local currentMachineData = nil
|
|
|
|
local isInteracting = false
|
2025-07-29 07:30:32 +02:00
|
|
|
|
2025-07-29 22:35:35 +02:00
|
|
|
-- Function to draw 3D text in the world
|
|
|
|
function DrawText3D(x, y, z, text)
|
2025-07-29 22:47:43 +02:00
|
|
|
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()
|
2025-07-29 22:35:35 +02:00
|
|
|
end
|
2025-07-29 09:48:16 +02:00
|
|
|
|
2025-07-29 22:47:43 +02:00
|
|
|
-- Function to check if machine is registered (with caching)
|
2025-07-29 10:53:08 +02:00
|
|
|
function isRegisteredMachine(entity)
|
2025-07-29 22:47:43 +02:00
|
|
|
if currentMachineData and currentMachineData.entity == entity then
|
|
|
|
return currentMachineData.isRegistered
|
|
|
|
end
|
|
|
|
|
2025-07-29 10:23:04 +02:00
|
|
|
local coords = GetEntityCoords(entity)
|
2025-07-29 10:53:08 +02:00
|
|
|
local isRegistered = false
|
2025-07-29 10:23:04 +02:00
|
|
|
|
2025-07-29 10:53:08 +02:00
|
|
|
QBCore.Functions.TriggerCallback('vending:server:machineExists', function(exists)
|
|
|
|
isRegistered = exists
|
|
|
|
end, coords)
|
|
|
|
|
2025-07-29 22:47:43 +02:00
|
|
|
-- Wait for callback
|
2025-07-29 10:53:08 +02:00
|
|
|
local timeout = 0
|
|
|
|
while isRegistered == false and timeout < 100 do
|
|
|
|
Wait(10)
|
|
|
|
timeout = timeout + 1
|
|
|
|
end
|
|
|
|
|
2025-07-29 22:47:43 +02:00
|
|
|
if not currentMachineData then currentMachineData = {} end
|
|
|
|
currentMachineData.entity = entity
|
|
|
|
currentMachineData.isRegistered = isRegistered
|
|
|
|
|
2025-07-29 10:53:08 +02:00
|
|
|
return isRegistered
|
2025-07-29 10:23:04 +02:00
|
|
|
end
|
|
|
|
|
2025-07-29 22:47:43 +02:00
|
|
|
-- Check if player can manage machine (with caching)
|
2025-07-29 10:53:08 +02:00
|
|
|
function canManageMachine(entity)
|
2025-07-29 22:47:43 +02:00
|
|
|
if currentMachineData and currentMachineData.entity == entity and currentMachineData.canManage ~= nil then
|
|
|
|
return currentMachineData.canManage
|
|
|
|
end
|
|
|
|
|
2025-07-29 10:53:08 +02:00
|
|
|
local coords = GetEntityCoords(entity)
|
|
|
|
local canManage = false
|
2025-07-29 08:25:12 +02:00
|
|
|
|
2025-07-29 10:53:08 +02:00
|
|
|
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
|
|
|
|
|
2025-07-29 22:47:43 +02:00
|
|
|
if not currentMachineData then currentMachineData = {} end
|
|
|
|
currentMachineData.entity = entity
|
|
|
|
currentMachineData.canManage = canManage
|
|
|
|
|
2025-07-29 10:53:08 +02:00
|
|
|
return canManage
|
2025-07-29 08:25:12 +02:00
|
|
|
end
|
|
|
|
|
2025-07-29 22:35:35 +02:00
|
|
|
-- Main thread to detect nearby vending machines
|
|
|
|
CreateThread(function()
|
|
|
|
while true do
|
|
|
|
local playerPed = PlayerPedId()
|
|
|
|
local playerCoords = GetEntityCoords(playerPed)
|
|
|
|
local wait = 1000
|
2025-07-29 22:47:43 +02:00
|
|
|
local foundMachine = false
|
2025-07-29 22:35:35 +02:00
|
|
|
|
|
|
|
-- 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
|
2025-07-29 22:47:43 +02:00
|
|
|
foundMachine = true
|
2025-07-29 22:35:35 +02:00
|
|
|
nearbyMachine = obj
|
|
|
|
|
2025-07-29 22:47:43 +02:00
|
|
|
-- 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")
|
2025-07-29 22:35:35 +02:00
|
|
|
|
2025-07-29 22:47:43 +02:00
|
|
|
-- 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
|
2025-07-29 22:35:35 +02:00
|
|
|
end
|
|
|
|
end
|
2025-07-29 22:47:43 +02:00
|
|
|
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
|
2025-07-29 22:35:35 +02:00
|
|
|
end
|
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2025-07-29 22:47:43 +02:00
|
|
|
if foundMachine then break end
|
|
|
|
end
|
|
|
|
|
|
|
|
if not foundMachine then
|
|
|
|
nearbyMachine = nil
|
|
|
|
currentMachineData = nil
|
2025-07-29 22:35:35 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
Wait(wait)
|
|
|
|
end
|
|
|
|
end)
|
|
|
|
|
2025-07-29 22:47:43 +02:00
|
|
|
-- Reset machine data when moving away
|
|
|
|
CreateThread(function()
|
|
|
|
while true do
|
|
|
|
Wait(5000)
|
|
|
|
if not nearbyMachine then
|
|
|
|
currentMachineData = nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end)
|
|
|
|
|
2025-07-29 10:53:08 +02:00
|
|
|
-- Buy vending machine
|
|
|
|
RegisterNetEvent('vending:client:buyMachine', function(data)
|
|
|
|
local entity = data.entity
|
|
|
|
local coords = GetEntityCoords(entity)
|
2025-07-29 07:30:32 +02:00
|
|
|
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
|
|
|
|
|
2025-07-29 10:53:08 +02:00
|
|
|
if not prop then return end
|
2025-07-29 07:30:32 +02:00
|
|
|
|
2025-07-29 22:47:43 +02:00
|
|
|
-- Display confirmation text
|
|
|
|
local startTime = GetGameTimer()
|
|
|
|
local textShown = true
|
2025-07-29 07:30:32 +02:00
|
|
|
|
2025-07-29 22:47:43 +02:00
|
|
|
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
|
2025-07-29 10:53:08 +02:00
|
|
|
end)
|
2025-07-29 07:30:32 +02:00
|
|
|
|
2025-07-29 10:53:08 +02:00
|
|
|
-- Open buy menu with quantity selection
|
|
|
|
RegisterNetEvent('vending:client:openBuyMenu', function(data)
|
|
|
|
local entity = data.entity
|
|
|
|
local coords = GetEntityCoords(entity)
|
|
|
|
|
2025-07-29 07:30:32 +02:00
|
|
|
QBCore.Functions.TriggerCallback('vending:server:getStashItems', function(items)
|
|
|
|
if #items == 0 then
|
|
|
|
QBCore.Functions.Notify('Dieser Automat ist leer!', 'error')
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
2025-07-29 22:47:43 +02:00
|
|
|
-- Simple item selection menu
|
2025-07-29 07:30:32 +02:00
|
|
|
local options = {}
|
2025-07-29 22:47:43 +02:00
|
|
|
local selectedItem = nil
|
2025-07-29 07:30:32 +02:00
|
|
|
|
|
|
|
for i = 1, #items do
|
|
|
|
local item = items[i]
|
|
|
|
if item.amount > 0 then
|
2025-07-29 07:51:42 +02:00
|
|
|
local itemLabel = QBCore.Shared.Items[item.name] and QBCore.Shared.Items[item.name].label or item.name
|
2025-07-29 07:30:32 +02:00
|
|
|
table.insert(options, {
|
2025-07-29 22:47:43 +02:00
|
|
|
name = item.name,
|
|
|
|
label = itemLabel,
|
|
|
|
price = item.price,
|
|
|
|
amount = item.amount
|
2025-07-29 07:30:32 +02:00
|
|
|
})
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2025-07-29 10:53:08 +02:00
|
|
|
if #options == 0 then
|
2025-07-29 08:25:12 +02:00
|
|
|
QBCore.Functions.Notify('Keine Artikel verfügbar!', 'error')
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
2025-07-29 22:47:43 +02:00
|
|
|
-- Display item selection
|
|
|
|
local currentIndex = 1
|
|
|
|
local menuActive = true
|
2025-07-29 07:30:32 +02:00
|
|
|
|
2025-07-29 22:47:43 +02:00
|
|
|
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
|
2025-07-29 10:53:08 +02:00
|
|
|
end, coords)
|
|
|
|
end)
|
|
|
|
|
|
|
|
-- Open owner menu
|
|
|
|
RegisterNetEvent('vending:client:openOwnerMenu', function(data)
|
|
|
|
local entity = data.entity
|
|
|
|
local coords = GetEntityCoords(entity)
|
|
|
|
|
2025-07-29 10:23:04 +02:00
|
|
|
QBCore.Functions.TriggerCallback('vending:server:getMachineByCoords', function(machine)
|
2025-07-29 08:25:12 +02:00
|
|
|
if not machine then
|
|
|
|
QBCore.Functions.Notify('Automat nicht gefunden!', 'error')
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
2025-07-29 22:47:43 +02:00
|
|
|
-- Display owner menu options
|
2025-07-29 09:02:52 +02:00
|
|
|
local options = {
|
2025-07-29 22:47:43 +02:00
|
|
|
{label = "Inventar verwalten", action = "inventory"},
|
|
|
|
{label = "Preise festlegen", action = "prices"},
|
|
|
|
{label = "Geld abheben ($" .. machine.money .. ")", action = "withdraw"},
|
|
|
|
{label = "Statistiken", action = "stats"}
|
2025-07-29 09:02:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
-- Add manager options only for owner
|
|
|
|
if machine.isOwner then
|
2025-07-29 22:47:43 +02:00
|
|
|
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
|
2025-07-29 09:02:52 +02:00
|
|
|
end
|
2025-07-29 22:47:43 +02:00
|
|
|
|
|
|
|
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
|
2025-07-29 10:53:08 +02:00
|
|
|
sellVendingMachine(coords, machine.id)
|
2025-07-29 09:20:46 +02:00
|
|
|
end
|
2025-07-29 22:47:43 +02:00
|
|
|
elseif IsControlJustPressed(0, 177) then -- Escape key
|
|
|
|
menuActive = false
|
|
|
|
end
|
|
|
|
Wait(0)
|
2025-07-29 09:02:52 +02:00
|
|
|
end
|
2025-07-29 10:53:08 +02:00
|
|
|
end, coords)
|
|
|
|
end)
|
2025-07-29 08:25:12 +02:00
|
|
|
|
2025-07-29 22:35:35 +02:00
|
|
|
-- Function to sell the vending machine
|
2025-07-29 10:53:08 +02:00
|
|
|
function sellVendingMachine(coords, machineId)
|
2025-07-29 22:47:43 +02:00
|
|
|
-- Display confirmation text
|
|
|
|
local confirmActive = true
|
2025-07-29 09:20:46 +02:00
|
|
|
|
2025-07-29 22:47:43 +02:00
|
|
|
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)
|
2025-07-29 09:20:46 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2025-07-29 08:25:12 +02:00
|
|
|
-- Open price menu
|
2025-07-29 10:53:08 +02:00
|
|
|
function openPriceMenu(coords)
|
2025-07-29 08:25:12 +02:00
|
|
|
QBCore.Functions.TriggerCallback('vending:server:getStashItems', function(items)
|
|
|
|
if #items == 0 then
|
|
|
|
QBCore.Functions.Notify('Keine Items im Automaten!', 'error')
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
2025-07-29 22:47:43 +02:00
|
|
|
-- Create options list
|
2025-07-29 08:25:12 +02:00
|
|
|
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, {
|
2025-07-29 22:47:43 +02:00
|
|
|
name = item.name,
|
|
|
|
label = itemLabel,
|
|
|
|
price = item.price
|
2025-07-29 08:25:12 +02:00
|
|
|
})
|
|
|
|
end
|
|
|
|
|
2025-07-29 22:47:43 +02:00
|
|
|
-- Display menu
|
|
|
|
local currentIndex = 1
|
|
|
|
local menuActive = true
|
2025-07-29 08:25:12 +02:00
|
|
|
|
2025-07-29 22:47:43 +02:00
|
|
|
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
|
2025-07-29 10:53:08 +02:00
|
|
|
end, coords)
|
2025-07-29 08:25:12 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
-- Set price for specific item
|
2025-07-29 10:53:08 +02:00
|
|
|
function setPriceForItem(coords, itemName, itemLabel)
|
2025-07-29 22:47:43 +02:00
|
|
|
-- Display price input
|
|
|
|
local price = 0
|
|
|
|
local inputActive = true
|
|
|
|
local inputText = ""
|
2025-07-29 08:25:12 +02:00
|
|
|
|
2025-07-29 22:47:43 +02:00
|
|
|
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)
|
2025-07-29 08:25:12 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Open withdraw menu
|
2025-07-29 10:53:08 +02:00
|
|
|
function openWithdrawMenu(coords, availableMoney)
|
2025-07-29 08:25:12 +02:00
|
|
|
if availableMoney <= 0 then
|
|
|
|
QBCore.Functions.Notify('Kein Geld im Automaten!', 'error')
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
2025-07-29 22:47:43 +02:00
|
|
|
-- 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)
|
2025-07-29 08:25:12 +02:00
|
|
|
|
2025-07-29 22:47:43 +02:00
|
|
|
-- 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)
|
2025-07-29 08:25:12 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Open stats menu
|
|
|
|
function openStatsMenu(machine)
|
2025-07-29 22:47:43 +02:00
|
|
|
-- Display stats
|
|
|
|
local menuActive = true
|
2025-07-29 08:25:12 +02:00
|
|
|
|
2025-07-29 22:47:43 +02:00
|
|
|
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
|
2025-07-29 08:25:12 +02:00
|
|
|
end
|
|
|
|
|
2025-07-29 09:02:52 +02:00
|
|
|
-- Open managers menu
|
2025-07-29 10:53:08 +02:00
|
|
|
function openManagersMenu(coords)
|
|
|
|
-- Get current managers
|
2025-07-29 09:02:52 +02:00
|
|
|
QBCore.Functions.TriggerCallback('vending:server:getManagers', function(managers)
|
2025-07-29 22:47:43 +02:00
|
|
|
-- Create options list
|
2025-07-29 09:02:52 +02:00
|
|
|
local options = {
|
2025-07-29 22:47:43 +02:00
|
|
|
{label = "Verwalter hinzufügen", action = "add"}
|
2025-07-29 09:02:52 +02:00
|
|
|
}
|
|
|
|
|
2025-07-29 22:47:43 +02:00
|
|
|
-- Add existing managers
|
2025-07-29 09:02:52 +02:00
|
|
|
if #managers > 0 then
|
|
|
|
for i = 1, #managers do
|
|
|
|
local manager = managers[i]
|
|
|
|
table.insert(options, {
|
2025-07-29 22:47:43 +02:00
|
|
|
label = manager.name .. (manager.online and " (Online)" or " (Offline)"),
|
|
|
|
citizenid = manager.citizenid,
|
|
|
|
action = "manage"
|
2025-07-29 09:02:52 +02:00
|
|
|
})
|
|
|
|
end
|
|
|
|
else
|
2025-07-29 22:47:43 +02:00
|
|
|
table.insert(options, {label = "Keine Verwalter", action = "none"})
|
2025-07-29 09:02:52 +02:00
|
|
|
end
|
|
|
|
|
2025-07-29 22:47:43 +02:00
|
|
|
-- Display menu
|
|
|
|
local currentIndex = 1
|
|
|
|
local menuActive = true
|
2025-07-29 09:02:52 +02:00
|
|
|
|
2025-07-29 22:47:43 +02:00
|
|
|
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
|
2025-07-29 10:53:08 +02:00
|
|
|
end, coords)
|
2025-07-29 09:02:52 +02:00
|
|
|
end
|
|
|
|
|
2025-07-29 22:47:43 +02:00
|
|
|
-- 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
|
|
|
|
|
2025-07-29 09:02:52 +02:00
|
|
|
-- Open add manager menu
|
2025-07-29 10:53:08 +02:00
|
|
|
function openAddManagerMenu(coords)
|
2025-07-29 09:02:52 +02:00
|
|
|
QBCore.Functions.TriggerCallback('vending:server:getOnlinePlayers', function(players)
|
|
|
|
if #players == 0 then
|
|
|
|
QBCore.Functions.Notify('Keine Spieler online!', 'error')
|
2025-07-29 22:47:43 +02:00
|
|
|
openManagersMenu(coords) -- Go back to managers menu
|
2025-07-29 09:02:52 +02:00
|
|
|
return
|
|
|
|
end
|
|
|
|
|
2025-07-29 22:47:43 +02:00
|
|
|
-- Display player selection
|
|
|
|
local currentIndex = 1
|
|
|
|
local menuActive = true
|
2025-07-29 09:02:52 +02:00
|
|
|
|
2025-07-29 22:47:43 +02:00
|
|
|
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
|
2025-07-29 09:02:52 +02:00
|
|
|
end
|
2025-07-29 22:47:43 +02:00
|
|
|
|
|
|
|
menuText = menuText .. "\n[↑][↓] Navigieren | [ENTER] Auswählen | [ESC] Zurück"
|
|
|
|
|
|
|
|
DrawText3D(coords.x, coords.y, coords.z + 1.0, menuText)
|
|
|
|
Wait(0)
|
|
|
|
end
|
|
|
|
end)
|
2025-07-29 09:02:52 +02:00
|
|
|
|
2025-07-29 22:47:43 +02:00
|
|
|
-- 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
|
2025-07-29 09:02:52 +02:00
|
|
|
end)
|
|
|
|
end
|
|
|
|
|
2025-07-29 10:53:08 +02:00
|
|
|
-- Robbery menu
|
|
|
|
RegisterNetEvent('vending:client:startRobbery', function(data)
|
|
|
|
local entity = data.entity
|
|
|
|
local coords = GetEntityCoords(entity)
|
|
|
|
|
2025-07-29 22:47:43 +02:00
|
|
|
-- 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)
|
2025-07-29 10:53:08 +02:00
|
|
|
|
2025-07-29 22:47:43 +02:00
|
|
|
-- 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
|
2025-07-29 10:53:08 +02:00
|
|
|
end)
|
|
|
|
|
2025-07-29 08:25:12 +02:00
|
|
|
-- Start robbery animation and progress
|
2025-07-29 10:53:08 +02:00
|
|
|
RegisterNetEvent('vending:client:startRobbery', function(coords)
|
2025-07-29 08:25:12 +02:00
|
|
|
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)
|
|
|
|
|
2025-07-29 22:47:43 +02:00
|
|
|
-- 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)
|
2025-07-29 08:25:12 +02:00
|
|
|
end
|
2025-07-29 22:47:43 +02:00
|
|
|
|
|
|
|
ClearPedTasks(playerPed)
|
|
|
|
TriggerServerEvent('vending:server:completeRobbery', coords, not cancelled)
|
2025-07-29 08:25:12 +02:00
|
|
|
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)
|
|
|
|
|
2025-07-29 10:53:08 +02:00
|
|
|
-- Management menu (alternative opening method)
|
|
|
|
RegisterNetEvent('vending:client:openManagement', function(machine)
|
2025-07-29 22:47:43 +02:00
|
|
|
-- 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"
|
2025-07-29 10:53:08 +02:00
|
|
|
end
|
2025-07-29 22:47:43 +02:00
|
|
|
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)
|
2025-07-29 10:53:08 +02:00
|
|
|
|
2025-07-29 22:47:43 +02:00
|
|
|
-- 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
|
2025-07-29 07:30:32 +02:00
|
|
|
end)
|
|
|
|
|
2025-07-29 10:53:08 +02:00
|
|
|
-- Debug command to check props
|
2025-07-29 09:39:15 +02:00
|
|
|
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
|
2025-07-29 10:53:08 +02:00
|
|
|
print("Found " .. propName .. " at distance: " .. dist)
|
2025-07-29 09:39:15 +02:00
|
|
|
|
|
|
|
-- Add a temporary blip
|
|
|
|
local blip = AddBlipForEntity(obj)
|
|
|
|
SetBlipSprite(blip, 1)
|
|
|
|
SetBlipColour(blip, 2)
|
|
|
|
SetBlipScale(blip, 0.8)
|
|
|
|
BeginTextCommandSetBlipName("STRING")
|
2025-07-29 10:23:04 +02:00
|
|
|
AddTextComponentString(propName)
|
2025-07-29 09:39:15 +02:00
|
|
|
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)
|
2025-07-29 09:41:19 +02:00
|
|
|
|
2025-07-29 10:53:08 +02:00
|
|
|
-- Debug commands
|
2025-07-29 09:48:16 +02:00
|
|
|
RegisterCommand('vendingdebug', function()
|
|
|
|
local playerPed = PlayerPedId()
|
|
|
|
local coords = GetEntityCoords(playerPed)
|
2025-07-29 09:41:19 +02:00
|
|
|
|
2025-07-29 10:53:08 +02:00
|
|
|
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')
|
2025-07-29 09:48:16 +02:00
|
|
|
end
|
2025-07-29 10:53:08 +02:00
|
|
|
end, coords)
|
2025-07-29 09:41:19 +02:00
|
|
|
end, false)
|
2025-07-29 22:47:43 +02:00
|
|
|
|
|
|
|
-- 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)
|
|
|
|
|