2025-07-29 07:30:32 +02:00
local QBCore = exports [ ' qb-core ' ] : GetCoreObject ( )
local vendingMachines = { }
local robberyInProgress = { }
-- Load vending machines from database
CreateThread ( function ( )
local result = MySQL.Sync . fetchAll ( ' SELECT * FROM vending_machines ' )
if result then
for i = 1 , # result do
local data = result [ i ]
vendingMachines [ data.id ] = {
id = data.id ,
owner = data.owner ,
coords = json.decode ( data.coords ) ,
prop = data.prop ,
money = data.money ,
items = json.decode ( data.items ) or { } ,
prices = json.decode ( data.prices ) or { } ,
stash = ' vending_ ' .. data.id
}
end
2025-07-29 08:42:57 +02:00
print ( " ^2[VENDING]^7 Loaded " .. # result .. " vending machines " )
2025-07-29 07:30:32 +02:00
end
end )
-- Register vending machine (when player buys it)
RegisterNetEvent ( ' vending:server:registerMachine ' , function ( coords , prop )
local src = source
local Player = QBCore.Functions . GetPlayer ( src )
if not Player then return end
-- Check if there's already a machine at these coords
for id , machine in pairs ( vendingMachines ) do
local dist = # ( vector3 ( coords.x , coords.y , coords.z ) - vector3 ( machine.coords . x , machine.coords . y , machine.coords . z ) )
if dist < 2.0 then
TriggerClientEvent ( ' QBCore:Notify ' , src , ' Hier ist bereits ein Automat registriert! ' , ' error ' )
return
end
end
-- Check if player has enough money
if Player.PlayerData . money.cash < Config.VendingMachinePrice then
TriggerClientEvent ( ' QBCore:Notify ' , src , ' Du benötigst $ ' .. Config.VendingMachinePrice .. ' um diesen Automaten zu kaufen! ' , ' error ' )
return
end
-- Remove money
Player.Functions . RemoveMoney ( ' cash ' , Config.VendingMachinePrice )
-- Create machine in database
local machineId = MySQL.insert . await ( ' INSERT INTO vending_machines (owner, coords, prop, money, items, prices) VALUES (?, ?, ?, ?, ?, ?) ' , {
Player.PlayerData . citizenid ,
json.encode ( coords ) ,
prop ,
0 ,
json.encode ( { } ) ,
json.encode ( { } )
} )
-- Add to memory
vendingMachines [ machineId ] = {
id = machineId ,
owner = Player.PlayerData . citizenid ,
coords = coords ,
prop = prop ,
money = 0 ,
items = { } ,
prices = { } ,
stash = ' vending_ ' .. machineId
}
2025-07-29 08:42:57 +02:00
print ( " ^2[VENDING]^7 New vending machine registered: " .. machineId )
2025-07-29 07:30:32 +02:00
TriggerClientEvent ( ' QBCore:Notify ' , src , ' Verkaufsautomat erfolgreich gekauft für $ ' .. Config.VendingMachinePrice .. ' ! ' , ' success ' )
TriggerClientEvent ( ' vending:client:refreshTargets ' , - 1 )
end )
-- Open management menu
RegisterNetEvent ( ' vending:server:openManagement ' , function ( coords )
local src = source
local Player = QBCore.Functions . GetPlayer ( src )
if not Player then return end
local machineId = getMachineIdByCoords ( coords )
if not machineId then return end
local machine = vendingMachines [ machineId ]
if machine.owner ~= Player.PlayerData . citizenid then
TriggerClientEvent ( ' QBCore:Notify ' , src , ' Das ist nicht dein Verkaufsautomat! ' , ' error ' )
return
end
TriggerClientEvent ( ' vending:client:openManagement ' , src , machine )
end )
2025-07-29 08:42:57 +02:00
-- Open stash (korrekt für tgiann-inventory)
2025-07-29 07:30:32 +02:00
RegisterNetEvent ( ' vending:server:openStash ' , function ( coords )
local src = source
local Player = QBCore.Functions . GetPlayer ( src )
if not Player then return end
local machineId = getMachineIdByCoords ( coords )
if not machineId then return end
local machine = vendingMachines [ machineId ]
if machine.owner ~= Player.PlayerData . citizenid then
TriggerClientEvent ( ' QBCore:Notify ' , src , ' Das ist nicht dein Verkaufsautomat! ' , ' error ' )
return
end
2025-07-29 08:42:57 +02:00
-- Öffne das Inventar mit tgiann-inventory
exports [ " tgiann-inventory " ] : OpenInventory ( src , " stash " , machine.stash , {
maxweight = Config.MaxWeight ,
slots = Config.MaxSlots ,
label = ' Vending Machine # ' .. machine.id
} )
2025-07-29 07:30:32 +02:00
end )
-- Set item price
RegisterNetEvent ( ' vending:server:setItemPrice ' , function ( coords , itemName , price )
local src = source
local Player = QBCore.Functions . GetPlayer ( src )
if not Player then return end
local machineId = getMachineIdByCoords ( coords )
if not machineId then return end
local machine = vendingMachines [ machineId ]
if machine.owner ~= Player.PlayerData . citizenid then
TriggerClientEvent ( ' QBCore:Notify ' , src , ' Das ist nicht dein Verkaufsautomat! ' , ' error ' )
return
end
-- Update price
machine.prices [ itemName ] = price
MySQL.update ( ' UPDATE vending_machines SET prices = ? WHERE id = ? ' , { json.encode ( machine.prices ) , machineId } )
2025-07-29 08:25:12 +02:00
TriggerClientEvent ( ' QBCore:Notify ' , src , ' Preis für ' .. ( QBCore.Shared . Items [ itemName ] and QBCore.Shared . Items [ itemName ] . label or itemName ) .. ' auf $ ' .. price .. ' gesetzt! ' , ' success ' )
2025-07-29 07:30:32 +02:00
end )
-- Withdraw money
RegisterNetEvent ( ' vending:server:withdrawMoney ' , function ( coords , amount )
local src = source
local Player = QBCore.Functions . GetPlayer ( src )
if not Player then return end
local machineId = getMachineIdByCoords ( coords )
if not machineId then return end
local machine = vendingMachines [ machineId ]
if machine.owner ~= Player.PlayerData . citizenid then
TriggerClientEvent ( ' QBCore:Notify ' , src , ' Das ist nicht dein Verkaufsautomat! ' , ' error ' )
return
end
if machine.money < amount then
TriggerClientEvent ( ' QBCore:Notify ' , src , ' Nicht genug Geld im Automaten! ' , ' error ' )
return
end
-- Update machine money
machine.money = machine.money - amount
MySQL.update ( ' UPDATE vending_machines SET money = ? WHERE id = ? ' , { machine.money , machineId } )
-- Give money to player
Player.Functions . AddMoney ( ' cash ' , amount )
TriggerClientEvent ( ' QBCore:Notify ' , src , ' Du hast $ ' .. amount .. ' abgehoben! ' , ' success ' )
end )
2025-07-29 08:42:57 +02:00
-- Buy item from vending machine
2025-07-29 07:30:32 +02:00
RegisterNetEvent ( ' vending:server:buyItem ' , function ( coords , itemName )
local src = source
local Player = QBCore.Functions . GetPlayer ( src )
if not Player then return end
local machineId = getMachineIdByCoords ( coords )
if not machineId then return end
local machine = vendingMachines [ machineId ]
local price = machine.prices [ itemName ] or Config.DefaultPrice
-- Check if player has enough money
if Player.PlayerData . money.cash < price then
TriggerClientEvent ( ' QBCore:Notify ' , src , ' Du hast nicht genug Geld! ' , ' error ' )
return
end
2025-07-29 08:42:57 +02:00
-- Get stash items
local stashItems = exports [ " tgiann-inventory " ] : GetSecondaryInventoryItems ( " stash " , machine.stash )
local hasItem = false
if stashItems then
for slot , item in pairs ( stashItems ) do
if item.name == itemName and item.amount > 0 then
hasItem = true
break
end
end
end
if not hasItem then
2025-07-29 08:35:03 +02:00
TriggerClientEvent ( ' QBCore:Notify ' , src , ' Artikel nicht verfügbar! ' , ' error ' )
return
end
-- Remove money from player
Player.Functions . RemoveMoney ( ' cash ' , price )
-- Add money to machine
machine.money = machine.money + price
2025-07-29 08:42:57 +02:00
MySQL.update ( ' UPDATE vending_machines SET money = ? WHERE id = ? ' , { machine.money , machineId } )
2025-07-29 08:35:03 +02:00
2025-07-29 08:42:57 +02:00
-- Remove item from stash and add to player
exports [ " tgiann-inventory " ] : RemoveItemFromSecondaryInventory ( " stash " , machine.stash , itemName , 1 )
2025-07-29 08:39:45 +02:00
Player.Functions . AddItem ( itemName , 1 )
TriggerClientEvent ( ' inventory:client:ItemBox ' , src , QBCore.Shared . Items [ itemName ] , ' add ' )
2025-07-29 08:35:03 +02:00
TriggerClientEvent ( ' QBCore:Notify ' , src , ' Artikel gekauft für $ ' .. price .. ' ! ' , ' success ' )
2025-07-29 07:30:32 +02:00
end )
2025-07-29 08:25:12 +02:00
-- 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 ]
2025-07-29 08:39:45 +02:00
-- Check if player has required item
local hasItem = Player.Functions . GetItemByName ( Config.RobberyItem )
2025-07-29 08:35:03 +02:00
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 )
2025-07-29 08:30:01 +02:00
end
2025-07-29 08:35:03 +02:00
end
TriggerClientEvent ( ' vending:client:startRobbery ' , src , coords )
2025-07-29 08:25:12 +02:00
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
2025-07-29 08:39:45 +02:00
Player.Functions . RemoveItem ( Config.RobberyItem , 1 )
TriggerClientEvent ( ' inventory:client:ItemBox ' , src , QBCore.Shared . Items [ Config.RobberyItem ] , ' remove ' )
2025-07-29 08:25:12 +02:00
TriggerClientEvent ( ' QBCore:Notify ' , src , ' Dein ' .. Config.RobberyItem .. ' ist kaputt gegangen! ' , ' error ' )
end
else
TriggerClientEvent ( ' QBCore:Notify ' , src , ' Aufbruch fehlgeschlagen! ' , ' error ' )
end
end )
2025-07-29 07:30:32 +02:00
-- 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 )
2025-07-29 08:42:57 +02:00
-- Get stash items for vending machine menu
2025-07-29 07:30:32 +02:00
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 ]
2025-07-29 08:42:57 +02:00
-- Get stash items using correct export
local stashItems = exports [ " tgiann-inventory " ] : GetSecondaryInventoryItems ( " stash " , machine.stash )
2025-07-29 08:35:03 +02:00
local items = { }
2025-07-29 08:42:57 +02:00
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 )
2025-07-29 08:25:12 +02:00
end
end
2025-07-29 08:35:03 +02:00
end
cb ( items )
2025-07-29 07:30:32 +02:00
end )
-- Check if player owns machine
QBCore.Functions . CreateCallback ( ' vending:server:isOwner ' , function ( source , cb , coords )
local Player = QBCore.Functions . GetPlayer ( source )
if not Player then
cb ( false )
return
end
local machineId = getMachineIdByCoords ( coords )
if not machineId then
cb ( false )
return
end
local machine = vendingMachines [ machineId ]
cb ( machine.owner == Player.PlayerData . citizenid )
end )
-- Check if machine exists at coords
QBCore.Functions . CreateCallback ( ' vending:server:machineExists ' , function ( source , cb , coords )
local machineId = getMachineIdByCoords ( coords )
cb ( machineId ~= nil )
end )
2025-07-29 08:42:57 +02:00
-- Debug command
QBCore.Commands . Add ( ' vendingdebug ' , ' Debug vending machines (Admin Only) ' , { } , false , function ( source , args )
local Player = QBCore.Functions . GetPlayer ( source )
if Player.PlayerData . permission == " admin " or Player.PlayerData . permission == " god " then
local count = 0
for id , machine in pairs ( vendingMachines ) do
count = count + 1
print ( " ^2[VENDING]^7 Machine # " .. id .. " | Owner: " .. machine.owner .. " | Money: $ " .. machine.money )
end
TriggerClientEvent ( ' QBCore:Notify ' , source , count .. ' Verkaufsautomaten geladen ' , ' success ' )
else
TriggerClientEvent ( ' QBCore:Notify ' , source , ' Keine Berechtigung! ' , ' error ' )
end
end , ' admin ' )