1
0
Fork 0
forked from Simnation/Main
This commit is contained in:
Nordi98 2025-07-29 10:53:08 +02:00
parent e73fc734a3
commit 8110c00382
2 changed files with 497 additions and 582 deletions

View file

@ -1,108 +1,138 @@
local QBCore = exports['qb-core']:GetCoreObject()
local nearbyMachines = {}
local currentMachine = nil
local showingMenu = false
-- Kontinuierlicher Check für Verkaufsautomaten
-- Function to initialize targets
function InitializeTargets()
-- Remove existing targets first to avoid duplicates
exports['qb-target']:RemoveTargetModel(Config.VendingProps)
Wait(100)
-- Add targets
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)
return not isRegisteredMachine(entity)
end
},
{
type = "client",
event = "vending:client:openBuyMenu",
icon = "fas fa-shopping-cart",
label = "Kaufen",
canInteract = function(entity)
return isRegisteredMachine(entity)
end
},
{
type = "client",
event = "vending:client:openOwnerMenu",
icon = "fas fa-cog",
label = "Verwalten",
canInteract = function(entity)
return canManageMachine(entity)
end
},
{
type = "client",
event = "vending:client:startRobbery",
icon = "fas fa-mask",
label = "Aufbrechen",
canInteract = function(entity)
return isRegisteredMachine(entity) and not canManageMachine(entity)
end
}
},
distance = 2.0
})
print("^2[VENDING]^7 Added targets to " .. #Config.VendingProps .. " vending machine props")
end
-- Add targets to all vending machine props with multiple attempts (Option 1)
CreateThread(function()
while true do
local playerPed = PlayerPedId()
local playerCoords = GetEntityCoords(playerPed)
local sleep = 1000
-- First attempt
Wait(2000)
InitializeTargets()
-- Reset current machine
currentMachine = nil
-- Second attempt after a delay
Wait(5000)
InitializeTargets()
-- Check for nearby vending machines
local objects = GetGamePool('CObject')
for _, obj in ipairs(objects) do
local model = GetEntityModel(obj)
for _, propName in ipairs(Config.VendingProps) do
if model == GetHashKey(propName) then
local objCoords = GetEntityCoords(obj)
local dist = #(playerCoords - objCoords)
-- Third attempt after server is fully loaded
Wait(10000)
InitializeTargets()
end)
if dist < 2.0 then
currentMachine = obj
sleep = 0
-- Event-based initialization (Option 2)
RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function()
Wait(1000)
InitializeTargets()
end)
-- Show help text
if not showingMenu then
DrawText3D(objCoords.x, objCoords.y, objCoords.z + 1.5, "[E] Verkaufsautomat")
RegisterNetEvent('QBCore:Client:OnPlayerUnload', function()
-- Nothing to do here, but good to have for completeness
end)
if IsControlJustPressed(0, 38) then -- E key
handleMachineInteraction(obj)
end
end
break
end
end
end
if currentMachine then break end
end
Wait(sleep)
-- Listen for resource start/stop events
AddEventHandler('onResourceStart', function(resourceName)
if resourceName == 'qb-target' or resourceName == GetCurrentResourceName() then
Wait(1000)
InitializeTargets()
end
end)
-- 3D Text function
function DrawText3D(x, y, z, text)
local onScreen, _x, _y = World3dToScreen2d(x, y, z)
local px, py, pz = table.unpack(GetGameplayCamCoords())
-- Command to manually refresh targets
RegisterCommand('refreshvendingtargets', function()
InitializeTargets()
QBCore.Functions.Notify('Vending machine targets refreshed', 'success')
end, false)
if onScreen then
SetTextScale(0.35, 0.35)
SetTextFont(4)
SetTextProportional(1)
SetTextColour(255, 255, 255, 215)
SetTextEntry("STRING")
SetTextCentre(1)
AddTextComponentString(text)
DrawText(_x, _y)
local factor = (string.len(text)) / 370
DrawRect(_x, _y + 0.0125, 0.015 + factor, 0.03, 41, 11, 41, 68)
end
end
-- Get precise coordinates for entity
function getPreciseCoords(entity)
-- Check if machine is registered
function isRegisteredMachine(entity)
local coords = GetEntityCoords(entity)
local heading = GetEntityHeading(entity)
local model = GetEntityModel(entity)
local isRegistered = false
return {
x = coords.x,
y = coords.y,
z = coords.z,
h = heading,
model = model
}
end
-- Handle machine interaction
function handleMachineInteraction(entity)
showingMenu = true
local preciseCoords = getPreciseCoords(entity)
-- Check if machine is registered
QBCore.Functions.TriggerCallback('vending:server:machineExists', function(exists)
if exists then
-- Check if player can manage
QBCore.Functions.TriggerCallback('vending:server:canManage', function(canManage)
if canManage then
showOwnerMenu(entity, preciseCoords)
else
showBuyMenu(entity, preciseCoords)
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
end, preciseCoords)
else
showPurchaseMenu(entity, preciseCoords)
end
end, preciseCoords)
return isRegistered
end
-- Show purchase menu (buy the machine)
function showPurchaseMenu(entity, preciseCoords)
-- Check if player can manage machine
function canManageMachine(entity)
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
return canManage
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
@ -114,67 +144,39 @@ function showPurchaseMenu(entity, preciseCoords)
end
end
if not prop then
showingMenu = false
return
end
if not prop then return end
lib.registerContext({
id = 'vending_purchase',
title = 'Verkaufsautomat',
options = {
{
title = 'Automaten kaufen',
description = 'Kaufe diesen Automaten für $' .. Config.VendingMachinePrice,
icon = 'fas fa-dollar-sign',
onSelect = function()
lib.registerContext({
id = 'vending_purchase_confirm',
title = 'Kauf bestätigen',
menu = 'vending_purchase',
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', preciseCoords, prop)
showingMenu = false
TriggerServerEvent('vending:server:registerMachine', coords, prop)
end
},
{
title = 'Abbrechen',
description = 'Kauf abbrechen',
icon = 'fas fa-times',
onSelect = function()
showingMenu = false
end
}
}
})
lib.showContext('vending_purchase_confirm')
end
},
{
title = 'Schließen',
description = 'Menü schließen',
icon = 'fas fa-times',
onSelect = function()
showingMenu = false
end
icon = 'fas fa-times'
}
}
})
lib.showContext('vending_purchase')
end
lib.showContext('vending_buy_confirm')
end)
-- Open buy menu with quantity selection
RegisterNetEvent('vending:client:openBuyMenu', function(data)
local entity = data.entity
local coords = GetEntityCoords(entity)
-- Show buy menu (buy items from machine)
function showBuyMenu(entity, preciseCoords)
QBCore.Functions.TriggerCallback('vending:server:getStashItems', function(items)
if #items == 0 then
QBCore.Functions.Notify('Dieser Automat ist leer!', 'error')
showingMenu = false
return
end
@ -189,58 +191,14 @@ function showBuyMenu(entity, preciseCoords)
description = 'Preis: $' .. item.price .. ' | Verfügbar: ' .. item.amount,
icon = 'fas fa-shopping-cart',
onSelect = function()
openQuantityDialog(preciseCoords, item.name, item.price, item.amount, itemLabel)
openQuantityDialog(coords, item.name, item.price, item.amount, itemLabel)
end
})
end
end
-- Add robbery option
table.insert(options, {
title = 'Aufbrechen',
description = 'Versuche den Automaten aufzubrechen',
icon = 'fas fa-mask',
onSelect = function()
lib.registerContext({
id = 'vending_robbery_confirm',
title = 'Verkaufsautomat aufbrechen',
menu = 'vending_buy_menu',
options = {
{
title = 'Aufbrechen',
description = 'Versuche den Automaten aufzubrechen (benötigt ' .. Config.RobberyItem .. ')',
icon = 'fas fa-mask',
onSelect = function()
TriggerServerEvent('vending:server:startRobbery', preciseCoords)
showingMenu = false
end
},
{
title = 'Abbrechen',
description = 'Aufbruch abbrechen',
icon = 'fas fa-times',
onSelect = function()
showingMenu = false
end
}
}
})
lib.showContext('vending_robbery_confirm')
end
})
table.insert(options, {
title = 'Schließen',
description = 'Menü schließen',
icon = 'fas fa-times',
onSelect = function()
showingMenu = false
end
})
if #options == 1 then -- Only close option
if #options == 0 then
QBCore.Functions.Notify('Keine Artikel verfügbar!', 'error')
showingMenu = false
return
end
@ -251,15 +209,41 @@ function showBuyMenu(entity, preciseCoords)
})
lib.showContext('vending_buy_menu')
end, preciseCoords)
end, coords)
end)
-- Open quantity dialog for buying items
function openQuantityDialog(coords, itemName, price, maxAmount, itemLabel)
local input = lib.inputDialog('Menge auswählen', {
{
type = 'number',
label = itemLabel .. ' - $' .. price .. ' pro Stück',
description = 'Wie viele möchtest du kaufen? (Max: ' .. maxAmount .. ')',
required = true,
min = 1,
max = maxAmount,
default = 1
}
})
if input and input[1] then
local amount = tonumber(input[1])
if amount > 0 and amount <= maxAmount then
TriggerServerEvent('vending:server:buyItem', coords, itemName, amount)
else
QBCore.Functions.Notify('Ungültige Menge!', 'error')
end
end
end
-- Show owner menu
function showOwnerMenu(entity, preciseCoords)
-- 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')
showingMenu = false
return
end
@ -269,8 +253,7 @@ function showOwnerMenu(entity, preciseCoords)
description = 'Items hinzufügen/entfernen',
icon = 'fas fa-box',
onSelect = function()
TriggerServerEvent('vending:server:openStash', preciseCoords)
showingMenu = false
TriggerServerEvent('vending:server:openStash', coords)
end
},
{
@ -278,7 +261,7 @@ function showOwnerMenu(entity, preciseCoords)
description = 'Verkaufspreise für Items setzen',
icon = 'fas fa-tags',
onSelect = function()
openPriceMenu(preciseCoords)
openPriceMenu(coords)
end
},
{
@ -286,7 +269,7 @@ function showOwnerMenu(entity, preciseCoords)
description = 'Verfügbar: $' .. machine.money,
icon = 'fas fa-money-bill',
onSelect = function()
openWithdrawMenu(preciseCoords, machine.money)
openWithdrawMenu(coords, machine.money)
end
},
{
@ -306,30 +289,21 @@ function showOwnerMenu(entity, preciseCoords)
description = 'Verwalter hinzufügen/entfernen',
icon = 'fas fa-users-cog',
onSelect = function()
openManagersMenu(preciseCoords)
openManagersMenu(coords)
end
})
-- Add sell option only for owner
table.insert(options, {
title = 'Automaten verkaufen',
description = 'Verkaufe den Automaten für $' .. math.floor(Config.VendingMachinePrice * Config.SellBackPercentage / 100),
description = 'Verkaufe den Automaten für ' .. math.floor(Config.VendingMachinePrice * Config.SellBackPercentage / 100) .. '$',
icon = 'fas fa-dollar-sign',
onSelect = function()
sellVendingMachine(preciseCoords, machine.id)
sellVendingMachine(coords, machine.id)
end
})
end
table.insert(options, {
title = 'Schließen',
description = 'Menü schließen',
icon = 'fas fa-times',
onSelect = function()
showingMenu = false
end
})
lib.registerContext({
id = 'vending_owner_menu',
title = 'Verkaufsautomat Verwaltung',
@ -337,59 +311,30 @@ function showOwnerMenu(entity, preciseCoords)
})
lib.showContext('vending_owner_menu')
end, preciseCoords)
end
-- Open quantity dialog for buying items
function openQuantityDialog(preciseCoords, itemName, price, maxAmount, itemLabel)
local input = lib.inputDialog('Menge auswählen', {
{
type = 'number',
label = itemLabel .. ' - $' .. price .. ' pro Stück',
description = 'Wie viele möchtest du kaufen? (Max: ' .. maxAmount .. ')',
required = true,
min = 1,
max = maxAmount,
default = 1
}
})
if input and input[1] then
local amount = tonumber(input[1])
if amount > 0 and amount <= maxAmount then
TriggerServerEvent('vending:server:buyItem', preciseCoords, itemName, amount)
else
QBCore.Functions.Notify('Ungültige Menge!', 'error')
end
end
showingMenu = false
end
end, coords)
end)
-- Funktion zum Verkaufen des Automaten
function sellVendingMachine(preciseCoords, machineId)
function sellVendingMachine(coords, machineId)
local input = lib.inputDialog('Automaten verkaufen', {
{
type = 'checkbox',
label = 'Bestätigen',
description = 'Du erhältst $' .. math.floor(Config.VendingMachinePrice * Config.SellBackPercentage / 100) .. ' zurück. Diese Aktion kann nicht rückgängig gemacht werden!',
description = 'Du erhältst ' .. math.floor(Config.VendingMachinePrice * Config.SellBackPercentage / 100) .. '$ zurück. Diese Aktion kann nicht rückgängig gemacht werden!',
required = true
}
})
if input and input[1] then
TriggerServerEvent('vending:server:sellMachine', preciseCoords, machineId)
TriggerServerEvent('vending:server:sellMachine', coords, machineId)
end
showingMenu = false
end
-- Open price menu
function openPriceMenu(preciseCoords)
function openPriceMenu(coords)
QBCore.Functions.TriggerCallback('vending:server:getStashItems', function(items)
if #items == 0 then
QBCore.Functions.Notify('Keine Items im Automaten!', 'error')
showingMenu = false
return
end
@ -403,32 +348,24 @@ function openPriceMenu(preciseCoords)
description = 'Aktueller Preis: $' .. item.price,
icon = 'fas fa-tag',
onSelect = function()
setPriceForItem(preciseCoords, item.name, itemLabel)
setPriceForItem(coords, item.name, itemLabel)
end
})
end
table.insert(options, {
title = 'Zurück',
description = 'Zurück zum Hauptmenü',
icon = 'fas fa-arrow-left',
onSelect = function()
showOwnerMenu(currentMachine, preciseCoords)
end
})
lib.registerContext({
id = 'vending_price_menu',
title = 'Preise festlegen',
menu = 'vending_owner_menu',
options = options
})
lib.showContext('vending_price_menu')
end, preciseCoords)
end, coords)
end
-- Set price for specific item
function setPriceForItem(preciseCoords, itemName, itemLabel)
function setPriceForItem(coords, itemName, itemLabel)
local input = lib.inputDialog('Preis festlegen', {
{
type = 'number',
@ -441,17 +378,14 @@ function setPriceForItem(preciseCoords, itemName, itemLabel)
})
if input and input[1] then
TriggerServerEvent('vending:server:setItemPrice', preciseCoords, itemName, tonumber(input[1]))
TriggerServerEvent('vending:server:setItemPrice', coords, itemName, tonumber(input[1]))
end
showingMenu = false
end
-- Open withdraw menu
function openWithdrawMenu(preciseCoords, availableMoney)
function openWithdrawMenu(coords, availableMoney)
if availableMoney <= 0 then
QBCore.Functions.Notify('Kein Geld im Automaten!', 'error')
showingMenu = false
return
end
@ -467,10 +401,8 @@ function openWithdrawMenu(preciseCoords, availableMoney)
})
if input and input[1] then
TriggerServerEvent('vending:server:withdrawMoney', preciseCoords, tonumber(input[1]))
TriggerServerEvent('vending:server:withdrawMoney', coords, tonumber(input[1]))
end
showingMenu = false
end
-- Open stats menu
@ -478,6 +410,7 @@ function openStatsMenu(machine)
lib.registerContext({
id = 'vending_stats_menu',
title = 'Verkaufsstatistiken',
menu = 'vending_owner_menu',
options = {
{
title = 'Gesamteinnahmen',
@ -493,14 +426,6 @@ function openStatsMenu(machine)
title = 'Standort',
description = 'X: ' .. math.floor(machine.coords.x) .. ' Y: ' .. math.floor(machine.coords.y),
icon = 'fas fa-map-marker-alt'
},
{
title = 'Zurück',
description = 'Zurück zum Hauptmenü',
icon = 'fas fa-arrow-left',
onSelect = function()
showOwnerMenu(currentMachine, machine.coords)
end
}
}
})
@ -509,7 +434,8 @@ function openStatsMenu(machine)
end
-- Open managers menu
function openManagersMenu(preciseCoords)
function openManagersMenu(coords)
-- Get current managers
QBCore.Functions.TriggerCallback('vending:server:getManagers', function(managers)
local options = {
{
@ -517,43 +443,38 @@ function openManagersMenu(preciseCoords)
description = 'Neuen Verwalter hinzufügen',
icon = 'fas fa-user-plus',
onSelect = function()
openAddManagerMenu(preciseCoords)
openAddManagerMenu(coords)
end
}
}
-- Add existing managers with remove option
if #managers > 0 then
for i = 1, #managers do
local manager = managers[i]
table.insert(options, {
title = manager.name,
description = manager.online and 'Online - Klicken zum Entfernen' or 'Offline - Klicken zum Entfernen',
description = manager.online and 'Online' or 'Offline',
icon = manager.online and 'fas fa-circle text-success' or 'fas fa-circle text-danger',
onSelect = function()
lib.registerContext({
id = 'manager_confirm_remove',
title = 'Verwalter entfernen',
id = 'manager_options',
title = 'Verwalter: ' .. manager.name,
menu = 'managers_menu',
options = {
{
title = 'Bestätigen',
description = manager.name .. ' als Verwalter entfernen',
icon = 'fas fa-check',
title = 'Entfernen',
description = 'Verwalter entfernen',
icon = 'fas fa-user-minus',
onSelect = function()
TriggerServerEvent('vending:server:removeManager', preciseCoords, manager.citizenid)
showingMenu = false
end
},
{
title = 'Abbrechen',
description = 'Zurück zur Verwalterliste',
icon = 'fas fa-times',
onSelect = function()
openManagersMenu(preciseCoords)
TriggerServerEvent('vending:server:removeManager', coords, manager.citizenid)
Wait(500)
openManagersMenu(coords) -- Refresh the menu
end
}
}
})
lib.showContext('manager_confirm_remove')
lib.showContext('manager_options')
end
})
end
@ -566,31 +487,22 @@ function openManagersMenu(preciseCoords)
})
end
table.insert(options, {
title = 'Zurück',
description = 'Zurück zum Hauptmenü',
icon = 'fas fa-arrow-left',
onSelect = function()
showOwnerMenu(currentMachine, preciseCoords)
end
})
lib.registerContext({
id = 'managers_menu',
title = 'Verwalter verwalten',
menu = 'vending_owner_menu',
options = options
})
lib.showContext('managers_menu')
end, preciseCoords)
end, coords)
end
-- Open add manager menu
function openAddManagerMenu(preciseCoords)
function openAddManagerMenu(coords)
QBCore.Functions.TriggerCallback('vending:server:getOnlinePlayers', function(players)
if #players == 0 then
QBCore.Functions.Notify('Keine Spieler online!', 'error')
showingMenu = false
return
end
@ -603,24 +515,17 @@ function openAddManagerMenu(preciseCoords)
description = 'ID: ' .. player.id,
icon = 'fas fa-user',
onSelect = function()
TriggerServerEvent('vending:server:addManager', preciseCoords, player.id)
showingMenu = false
TriggerServerEvent('vending:server:addManager', coords, player.id)
Wait(500)
openManagersMenu(coords) -- Refresh the menu
end
})
end
table.insert(options, {
title = 'Zurück',
description = 'Zurück zur Verwalterliste',
icon = 'fas fa-arrow-left',
onSelect = function()
openManagersMenu(preciseCoords)
end
})
lib.registerContext({
id = 'add_manager_menu',
title = 'Verwalter hinzufügen',
menu = 'managers_menu',
options = options
})
@ -628,8 +533,36 @@ function openAddManagerMenu(preciseCoords)
end)
end
-- Robbery menu
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(preciseCoords)
RegisterNetEvent('vending:client:startRobbery', function(coords)
local playerPed = PlayerPedId()
local robberyTime = 10000 -- 10 seconds
@ -656,17 +589,23 @@ RegisterNetEvent('vending:client:startRobbery', function(preciseCoords)
})
ClearPedTasks(playerPed)
TriggerServerEvent('vending:server:completeRobbery', preciseCoords, success)
TriggerServerEvent('vending:server:completeRobbery', coords, success)
else
-- Fallback without progress bar
Wait(robberyTime)
ClearPedTasks(playerPed)
TriggerServerEvent('vending:server:completeRobbery', preciseCoords, true)
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)
@ -685,17 +624,40 @@ RegisterNetEvent('vending:client:policeAlert', function(coords, streetName)
QBCore.Functions.Notify('Verkaufsautomat Aufbruch gemeldet: ' .. streetName, 'error', 8000)
end)
-- Event handlers for menu closing
RegisterNetEvent('vending:client:closeMenu', function()
showingMenu = false
-- Refresh targets (called when new machine is registered)
RegisterNetEvent('vending:client:refreshTargets', function()
InitializeTargets()
end)
-- Close menu when inventory is opened
AddEventHandler('inventory:client:OpenInventory', function()
showingMenu = false
-- 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
-- Debug command to check props
RegisterCommand('checkvendingprops', function()
local playerPed = PlayerPedId()
local playerCoords = GetEntityCoords(playerPed)
@ -714,9 +676,7 @@ RegisterCommand('checkvendingprops', function()
if dist < 30.0 then
foundProps = foundProps + 1
local preciseCoords = getPreciseCoords(obj)
print("Found " .. propName .. " at distance: " .. dist .. " | Coords: " ..
preciseCoords.x .. ", " .. preciseCoords.y .. ", " .. preciseCoords.z)
print("Found " .. propName .. " at distance: " .. dist)
-- Add a temporary blip
local blip = AddBlipForEntity(obj)
@ -739,41 +699,18 @@ RegisterCommand('checkvendingprops', function()
QBCore.Functions.Notify('Found ' .. foundProps .. ' vending machines nearby', 'primary')
end, false)
-- Debug commands
RegisterCommand('vendingdebug', function()
local playerPed = PlayerPedId()
local coords = GetEntityCoords(playerPed)
-- Try to find the closest vending machine
local minDist = 3.0
local closestEntity = nil
local objects = GetGamePool('CObject')
for _, obj in ipairs(objects) do
local model = GetEntityModel(obj)
for _, propName in ipairs(Config.VendingProps) do
if model == GetHashKey(propName) then
local objCoords = GetEntityCoords(obj)
local dist = #(coords - objCoords)
if dist < minDist then
minDist = dist
closestEntity = obj
end
end
end
end
if closestEntity then
local preciseCoords = getPreciseCoords(closestEntity)
QBCore.Functions.TriggerCallback('vending:server:getMachineByCoords', function(machine)
if machine then
print('Machine found:', json.encode(machine))
QBCore.Functions.Notify('Machine #' .. machine.id .. ' | Owner: ' .. machine.owner, 'primary')
QBCore.Functions.Notify('Machine data logged to console', 'primary')
else
print('No machine found at coords:', json.encode(preciseCoords))
QBCore.Functions.Notify('No machine found at these coords', 'error')
end
end, preciseCoords)
else
QBCore.Functions.Notify('No vending machine found nearby', 'error')
print('No machine found at current location')
QBCore.Functions.Notify('No machine found here', 'error')
end
end, coords)
end, false)

View file

@ -24,46 +24,16 @@ CreateThread(function()
end
end)
-- Helper function to get machine ID by precise coordinates
function getMachineIdByCoords(preciseCoords)
-- First try to find an exact match
for id, machine in pairs(vendingMachines) do
if machine.coords.x == preciseCoords.x and
machine.coords.y == preciseCoords.y and
machine.coords.z == preciseCoords.z and
machine.coords.model == preciseCoords.model then
return id
end
end
-- If no exact match, try with a small tolerance
local closestId = nil
local closestDist = 0.1 -- Very small tolerance
for id, machine in pairs(vendingMachines) do
if machine.coords.model == preciseCoords.model then
local dist = #(vector3(preciseCoords.x, preciseCoords.y, preciseCoords.z) - vector3(machine.coords.x, machine.coords.y, machine.coords.z))
if dist < closestDist then
closestDist = dist
closestId = id
end
end
end
return closestId
end
-- Register vending machine (when player buys it)
RegisterNetEvent('vending:server:registerMachine', function(preciseCoords, prop)
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
if machine.coords.x == preciseCoords.x and
machine.coords.y == preciseCoords.y and
machine.coords.z == preciseCoords.z then
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
@ -81,7 +51,7 @@ RegisterNetEvent('vending:server:registerMachine', function(preciseCoords, prop)
-- Create machine in database
local machineId = MySQL.insert.await('INSERT INTO vending_machines (owner, coords, prop, money, items, prices, managers) VALUES (?, ?, ?, ?, ?, ?, ?)', {
Player.PlayerData.citizenid,
json.encode(preciseCoords),
json.encode(coords),
prop,
0,
json.encode({}),
@ -93,7 +63,7 @@ RegisterNetEvent('vending:server:registerMachine', function(preciseCoords, prop)
vendingMachines[machineId] = {
id = machineId,
owner = Player.PlayerData.citizenid,
coords = preciseCoords,
coords = coords,
prop = prop,
money = 0,
items = {},
@ -102,19 +72,19 @@ RegisterNetEvent('vending:server:registerMachine', function(preciseCoords, prop)
stash = 'vending_' .. machineId
}
print("^2[VENDING]^7 New vending machine registered: #" .. machineId)
print("^2[VENDING]^7 New vending machine registered: " .. machineId)
TriggerClientEvent('QBCore:Notify', src, 'Verkaufsautomat erfolgreich gekauft für $' .. Config.VendingMachinePrice .. '!', 'success')
TriggerClientEvent('vending:client:refreshTargets', -1)
end)
-- Sell vending machine
RegisterNetEvent('vending:server:sellMachine', function(preciseCoords, machineId)
RegisterNetEvent('vending:server:sellMachine', function(coords, machineId)
local src = source
local Player = QBCore.Functions.GetPlayer(src)
if not Player then return end
if not machineId then
machineId = getMachineIdByCoords(preciseCoords)
machineId = getMachineIdByCoords(coords)
end
if not machineId then
@ -194,16 +164,13 @@ function canManageMachine(playerId, machineId)
end
-- Open management menu
RegisterNetEvent('vending:server:openManagement', function(preciseCoords)
RegisterNetEvent('vending:server:openManagement', function(coords)
local src = source
local Player = QBCore.Functions.GetPlayer(src)
if not Player then return end
local machineId = getMachineIdByCoords(preciseCoords)
if not machineId then
TriggerClientEvent('QBCore:Notify', src, 'Automat nicht gefunden!', 'error')
return
end
local machineId = getMachineIdByCoords(coords)
if not machineId then return end
local machine = vendingMachines[machineId]
@ -220,16 +187,13 @@ RegisterNetEvent('vending:server:openManagement', function(preciseCoords)
end)
-- Open stash
RegisterNetEvent('vending:server:openStash', function(preciseCoords)
RegisterNetEvent('vending:server:openStash', function(coords)
local src = source
local Player = QBCore.Functions.GetPlayer(src)
if not Player then return end
local machineId = getMachineIdByCoords(preciseCoords)
if not machineId then
TriggerClientEvent('QBCore:Notify', src, 'Automat nicht gefunden!', 'error')
return
end
local machineId = getMachineIdByCoords(coords)
if not machineId then return end
-- Check if player can manage
if not canManageMachine(src, machineId) then
@ -246,18 +210,14 @@ RegisterNetEvent('vending:server:openStash', function(preciseCoords)
label = 'Vending Machine #' .. machine.id
})
end)
-- Set item price
RegisterNetEvent('vending:server:setItemPrice', function(preciseCoords, itemName, 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(preciseCoords)
if not machineId then
TriggerClientEvent('QBCore:Notify', src, 'Automat nicht gefunden!', 'error')
return
end
local machineId = getMachineIdByCoords(coords)
if not machineId then return end
-- Check if player can manage
if not canManageMachine(src, machineId) then
@ -275,16 +235,13 @@ RegisterNetEvent('vending:server:setItemPrice', function(preciseCoords, itemName
end)
-- Withdraw money
RegisterNetEvent('vending:server:withdrawMoney', function(preciseCoords, amount)
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(preciseCoords)
if not machineId then
TriggerClientEvent('QBCore:Notify', src, 'Automat nicht gefunden!', 'error')
return
end
local machineId = getMachineIdByCoords(coords)
if not machineId then return end
-- Check if player can manage
if not canManageMachine(src, machineId) then
@ -309,16 +266,13 @@ RegisterNetEvent('vending:server:withdrawMoney', function(preciseCoords, amount)
end)
-- Buy item from vending machine with quantity selection
RegisterNetEvent('vending:server:buyItem', function(preciseCoords, itemName, amount)
RegisterNetEvent('vending:server:buyItem', function(coords, itemName, amount)
local src = source
local Player = QBCore.Functions.GetPlayer(src)
if not Player then return end
local machineId = getMachineIdByCoords(preciseCoords)
if not machineId then
TriggerClientEvent('QBCore:Notify', src, 'Automat nicht gefunden!', 'error')
return
end
local machineId = getMachineIdByCoords(coords)
if not machineId then return end
local machine = vendingMachines[machineId]
local price = machine.prices[itemName] or Config.DefaultPrice
@ -381,16 +335,13 @@ RegisterNetEvent('vending:server:buyItem', function(preciseCoords, itemName, amo
end)
-- Add manager to vending machine
RegisterNetEvent('vending:server:addManager', function(preciseCoords, targetId)
RegisterNetEvent('vending:server:addManager', function(coords, targetId)
local src = source
local Player = QBCore.Functions.GetPlayer(src)
if not Player then return end
local machineId = getMachineIdByCoords(preciseCoords)
if not machineId then
TriggerClientEvent('QBCore:Notify', src, 'Automat nicht gefunden!', 'error')
return
end
local machineId = getMachineIdByCoords(coords)
if not machineId then return end
local machine = vendingMachines[machineId]
@ -428,16 +379,13 @@ RegisterNetEvent('vending:server:addManager', function(preciseCoords, targetId)
end)
-- Remove manager from vending machine
RegisterNetEvent('vending:server:removeManager', function(preciseCoords, citizenid)
RegisterNetEvent('vending:server:removeManager', function(coords, citizenid)
local src = source
local Player = QBCore.Functions.GetPlayer(src)
if not Player then return end
local machineId = getMachineIdByCoords(preciseCoords)
if not machineId then
TriggerClientEvent('QBCore:Notify', src, 'Automat nicht gefunden!', 'error')
return
end
local machineId = getMachineIdByCoords(coords)
if not machineId then return end
local machine = vendingMachines[machineId]
@ -483,148 +431,9 @@ RegisterNetEvent('vending:server:removeManager', function(preciseCoords, citizen
end
end)
-- Start robbery
RegisterNetEvent('vending:server:startRobbery', function(preciseCoords)
local src = source
local Player = QBCore.Functions.GetPlayer(src)
if not Player then return end
local machineId = getMachineIdByCoords(preciseCoords)
if not machineId then
TriggerClientEvent('QBCore:Notify', src, 'Automat nicht gefunden!', 'error')
return
end
local machine = vendingMachines[machineId]
-- Check if player has required item
local hasItem = Player.Functions.GetItemByName(Config.RobberyItem)
if not hasItem or hasItem.amount < 1 then
TriggerClientEvent('QBCore:Notify', src, 'Du benötigst einen ' .. Config.RobberyItem, 'error')
return
end
-- Check if already being robbed
if robberyInProgress[machineId] then
TriggerClientEvent('QBCore:Notify', src, 'Dieser Automat wird bereits aufgebrochen!', 'error')
return
end
-- Check if machine has money
if machine.money < Config.MinRobberyAmount then
TriggerClientEvent('QBCore:Notify', src, 'Nicht genug Geld im Automaten!', 'error')
return
end
robberyInProgress[machineId] = true
-- Alert police
local streetHash = GetStreetNameAtCoord(machine.coords.x, machine.coords.y, machine.coords.z)
local streetName = GetStreetNameFromHashKey(streetHash)
local players = QBCore.Functions.GetQBPlayers()
for k, v in pairs(players) do
if v.PlayerData.job.name == 'police' and v.PlayerData.job.onduty then
TriggerClientEvent('vending:client:policeAlert', v.PlayerData.source, machine.coords, streetName)
end
end
-- Alert owner and managers
for _, playerId in ipairs(QBCore.Functions.GetPlayers()) do
local targetPlayer = QBCore.Functions.GetPlayer(playerId)
if targetPlayer then
if targetPlayer.PlayerData.citizenid == machine.owner then
TriggerClientEvent('QBCore:Notify', targetPlayer.PlayerData.source, 'Dein Verkaufsautomat wird gerade aufgebrochen! Standort: ' .. streetName, 'error', 10000)
elseif machine.managers then
for _, manager in pairs(machine.managers) do
if targetPlayer.PlayerData.citizenid == manager then
TriggerClientEvent('QBCore:Notify', targetPlayer.PlayerData.source, 'Ein Verkaufsautomat, den du verwaltest, wird gerade aufgebrochen! Standort: ' .. streetName, 'error', 10000)
break
end
end
end
end
end
TriggerClientEvent('vending:client:startRobbery', src, preciseCoords)
end)
-- Complete robbery
RegisterNetEvent('vending:server:completeRobbery', function(preciseCoords, success)
local src = source
local Player = QBCore.Functions.GetPlayer(src)
if not Player then return end
local machineId = getMachineIdByCoords(preciseCoords)
if not machineId then
TriggerClientEvent('QBCore:Notify', src, 'Automat nicht gefunden!', 'error')
return
end
local machine = vendingMachines[machineId]
robberyInProgress[machineId] = false
if success then
local stolenAmount = math.random(Config.MinRobberyAmount, math.min(machine.money, Config.MaxRobberyAmount))
-- Remove money from machine
machine.money = machine.money - stolenAmount
MySQL.update('UPDATE vending_machines SET money = ? WHERE id = ?', {machine.money, machineId})
-- Give money to player
Player.Functions.AddMoney('cash', stolenAmount)
TriggerClientEvent('QBCore:Notify', src, 'Du hast $' .. stolenAmount .. ' gestohlen!', 'success')
-- Remove robbery item with chance
if math.random(1, 100) <= Config.RobberyItemBreakChance then
Player.Functions.RemoveItem(Config.RobberyItem, 1)
TriggerClientEvent('inventory:client:ItemBox', src, QBCore.Shared.Items[Config.RobberyItem], 'remove')
TriggerClientEvent('QBCore:Notify', src, 'Dein ' .. Config.RobberyItem .. ' ist kaputt gegangen!', 'error')
end
else
TriggerClientEvent('QBCore:Notify', src, 'Aufbruch fehlgeschlagen!', 'error')
end
end)
-- Get machine data by coordinates
QBCore.Functions.CreateCallback('vending:server:getMachineByCoords', function(source, cb, preciseCoords)
local machineId = getMachineIdByCoords(preciseCoords)
if machineId then
cb(vendingMachines[machineId])
else
cb(nil)
end
end)
-- Get stash items for vending machine menu
QBCore.Functions.CreateCallback('vending:server:getStashItems', function(source, cb, preciseCoords)
local machineId = getMachineIdByCoords(preciseCoords)
if not machineId then
cb({})
return
end
local machine = vendingMachines[machineId]
-- Get stash items using correct export
local stashItems = exports["tgiann-inventory"]:GetSecondaryInventoryItems("stash", machine.stash)
local items = {}
if stashItems then
for slot, item in pairs(stashItems) do
if item.amount > 0 then
item.price = machine.prices[item.name] or Config.DefaultPrice
table.insert(items, item)
end
end
end
cb(items)
end)
-- Get managers list
QBCore.Functions.CreateCallback('vending:server:getManagers', function(source, cb, preciseCoords)
local machineId = getMachineIdByCoords(preciseCoords)
QBCore.Functions.CreateCallback('vending:server:getManagers', function(source, cb, coords)
local machineId = getMachineIdByCoords(coords)
if not machineId then
cb({})
return
@ -676,15 +485,177 @@ QBCore.Functions.CreateCallback('vending:server:getManagers', function(source, c
cb(managersList)
end)
-- Check if machine exists
QBCore.Functions.CreateCallback('vending:server:machineExists', function(source, cb, preciseCoords)
local machineId = getMachineIdByCoords(preciseCoords)
cb(machineId ~= nil)
-- 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
-- Alert owner and managers
for _, playerId in ipairs(QBCore.Functions.GetPlayers()) do
local targetPlayer = QBCore.Functions.GetPlayer(playerId)
if targetPlayer then
if targetPlayer.PlayerData.citizenid == machine.owner then
TriggerClientEvent('QBCore:Notify', targetPlayer.PlayerData.source, 'Dein Verkaufsautomat wird gerade aufgebrochen! Standort: ' .. streetName, 'error', 10000)
elseif machine.managers then
for _, manager in pairs(machine.managers) do
if targetPlayer.PlayerData.citizenid == manager then
TriggerClientEvent('QBCore:Notify', targetPlayer.PlayerData.source, 'Ein Verkaufsautomat, den du verwaltest, wird gerade aufgebrochen! Standort: ' .. streetName, 'error', 10000)
break
end
end
end
end
end
TriggerClientEvent('vending:client:startRobbery', src, 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
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]
-- Get stash items using correct export
local stashItems = exports["tgiann-inventory"]:GetSecondaryInventoryItems("stash", machine.stash)
local items = {}
if stashItems then
for slot, item in pairs(stashItems) do
if item.amount > 0 then
item.price = machine.prices[item.name] or Config.DefaultPrice
table.insert(items, item)
end
end
end
cb(items)
end)
-- 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 player can manage machine
QBCore.Functions.CreateCallback('vending:server:canManage', function(source, cb, preciseCoords)
local machineId = getMachineIdByCoords(preciseCoords)
QBCore.Functions.CreateCallback('vending:server:canManage', 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
@ -693,6 +664,12 @@ QBCore.Functions.CreateCallback('vending:server:canManage', function(source, cb,
cb(canManageMachine(source, machineId))
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)
-- Get online players for manager selection
QBCore.Functions.CreateCallback('vending:server:getOnlinePlayers', function(source, cb)
local src = source
@ -735,3 +712,4 @@ QBCore.Commands.Add('vendingdebug', 'Debug vending machines (Admin Only)', {}, f
end
end, 'admin')