1
0
Fork 0
forked from Simnation/Main
Main/resources/[inventory]/nordi_vending/client.lua
2025-07-29 22:55:55 +02:00

735 lines
25 KiB
Lua

local QBCore = exports['qb-core']:GetCoreObject()
local nearbyMachine = nil
local currentMachineData = nil
local isInteracting = false
-- Function to draw 3D text in the world
function DrawText3D(x, y, z, text)
SetTextScale(0.35, 0.35)
SetTextFont(4)
SetTextProportional(1)
SetTextColour(255, 255, 255, 215)
SetTextEntry("STRING")
SetTextCentre(1)
AddTextComponentString(text)
SetDrawOrigin(x, y, z, 0)
DrawText(0.0, 0.0)
local factor = (string.len(text)) / 370
DrawRect(0.0, 0.0+0.0125, 0.017+ factor, 0.03, 0, 0, 0, 75)
ClearDrawOrigin()
end
-- Function to check if machine is registered
function isRegisteredMachine(entity)
local coords = GetEntityCoords(entity)
local isRegistered = false
QBCore.Functions.TriggerCallback('vending:server:machineExists', function(exists)
isRegistered = exists
end, coords)
-- Wait for callback
local timeout = 0
while isRegistered == false and timeout < 100 do
Wait(10)
timeout = timeout + 1
end
return isRegistered
end
-- 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
-- Main thread to detect nearby vending machines
CreateThread(function()
while true do
local playerPed = PlayerPedId()
local playerCoords = GetEntityCoords(playerPed)
local wait = 1000
local foundMachine = false
-- Check for nearby vending machines
for _, propName in ipairs(Config.VendingProps) do
local hash = GetHashKey(propName)
local objects = GetGamePool('CObject')
for _, obj in ipairs(objects) do
if GetEntityModel(obj) == hash then
local objCoords = GetEntityCoords(obj)
local dist = #(playerCoords - objCoords)
if dist < 2.0 then
wait = 0
foundMachine = true
nearbyMachine = obj
-- Only check status if not already interacting
if not isInteracting then
local z = objCoords.z + 1.0
local registered = isRegisteredMachine(obj)
if registered then
local canManage = canManageMachine(obj)
if canManage then
DrawText3D(objCoords.x, objCoords.y, z, "[E] Kaufen | [G] Verwalten")
-- Handle key presses for management
if IsControlJustPressed(0, 38) then -- E key
isInteracting = true
TriggerEvent('vending:client:openBuyMenu', {entity = obj})
Wait(500) -- Prevent multiple triggers
isInteracting = false
elseif IsControlJustPressed(0, 47) then -- G key
isInteracting = true
TriggerEvent('vending:client:openOwnerMenu', {entity = obj})
Wait(500) -- Prevent multiple triggers
isInteracting = false
end
else
DrawText3D(objCoords.x, objCoords.y, z, "[E] Kaufen | [G] Aufbrechen")
-- Handle key presses for buying/robbery
if IsControlJustPressed(0, 38) then -- E key
isInteracting = true
TriggerEvent('vending:client:openBuyMenu', {entity = obj})
Wait(500) -- Prevent multiple triggers
isInteracting = false
elseif IsControlJustPressed(0, 47) then -- G key
isInteracting = true
TriggerEvent('vending:client:startRobbery', {entity = obj})
Wait(500) -- Prevent multiple triggers
isInteracting = false
end
end
else
DrawText3D(objCoords.x, objCoords.y, z, "[E] Automaten kaufen ($" .. Config.VendingMachinePrice .. ")")
-- Handle key press for buying machine
if IsControlJustPressed(0, 38) then -- E key
isInteracting = true
TriggerEvent('vending:client:buyMachine', {entity = obj})
Wait(500) -- Prevent multiple triggers
isInteracting = false
end
end
end
break
end
end
end
if foundMachine then break end
end
if not foundMachine then
nearbyMachine = nil
end
Wait(wait)
end
end)
-- Buy vending machine
RegisterNetEvent('vending:client:buyMachine', function(data)
local entity = data.entity
local coords = GetEntityCoords(entity)
local model = GetEntityModel(entity)
local prop = nil
-- Find prop name
for i = 1, #Config.VendingProps do
if GetHashKey(Config.VendingProps[i]) == model then
prop = Config.VendingProps[i]
break
end
end
if not prop then return end
lib.registerContext({
id = 'vending_buy_confirm',
title = 'Verkaufsautomat kaufen',
options = {
{
title = 'Bestätigen',
description = 'Automaten für $' .. Config.VendingMachinePrice .. ' kaufen',
icon = 'fas fa-check',
onSelect = function()
TriggerServerEvent('vending:server:registerMachine', coords, prop)
end
},
{
title = 'Abbrechen',
description = 'Kauf abbrechen',
icon = 'fas fa-times'
}
}
})
lib.showContext('vending_buy_confirm')
end)
-- Open buy menu with quantity selection
RegisterNetEvent('vending:client:openBuyMenu', function(data)
local entity = data.entity
local coords = GetEntityCoords(entity)
QBCore.Functions.TriggerCallback('vending:server:getStashItems', function(items)
if #items == 0 then
QBCore.Functions.Notify('Dieser Automat ist leer!', 'error')
return
end
local options = {}
for i = 1, #items do
local item = items[i]
if item.amount > 0 then
local itemLabel = QBCore.Shared.Items[item.name] and QBCore.Shared.Items[item.name].label or item.name
table.insert(options, {
title = itemLabel,
description = 'Preis: $' .. item.price .. ' | Verfügbar: ' .. item.amount,
icon = 'fas fa-shopping-cart',
onSelect = function()
openQuantityDialog(coords, item.name, item.price, item.amount, itemLabel)
end
})
end
end
if #options == 0 then
QBCore.Functions.Notify('Keine Artikel verfügbar!', 'error')
return
end
lib.registerContext({
id = 'vending_buy_menu',
title = 'Verkaufsautomat',
options = options
})
lib.showContext('vending_buy_menu')
end, coords)
end)
-- Open 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
-- Open owner menu
RegisterNetEvent('vending:client:openOwnerMenu', function(data)
local entity = data.entity
local coords = GetEntityCoords(entity)
QBCore.Functions.TriggerCallback('vending:server:getMachineByCoords', function(machine)
if not machine then
QBCore.Functions.Notify('Automat nicht gefunden!', 'error')
return
end
local options = {
{
title = 'Inventar verwalten',
description = 'Items hinzufügen/entfernen',
icon = 'fas fa-box',
onSelect = function()
TriggerServerEvent('vending:server:openStash', coords)
end
},
{
title = 'Preise festlegen',
description = 'Verkaufspreise für Items setzen',
icon = 'fas fa-tags',
onSelect = function()
openPriceMenu(coords)
end
},
{
title = 'Geld abheben',
description = 'Verfügbar: $' .. machine.money,
icon = 'fas fa-money-bill',
onSelect = function()
openWithdrawMenu(coords, machine.money)
end
},
{
title = 'Statistiken',
description = 'Verkaufsstatistiken anzeigen',
icon = 'fas fa-chart-bar',
onSelect = function()
openStatsMenu(machine)
end
}
}
-- Add manager options only for owner
if machine.isOwner then
table.insert(options, {
title = 'Verwalter',
description = 'Verwalter hinzufügen/entfernen',
icon = 'fas fa-users-cog',
onSelect = function()
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) .. '$',
icon = 'fas fa-dollar-sign',
onSelect = function()
sellVendingMachine(coords, machine.id)
end
})
end
lib.registerContext({
id = 'vending_owner_menu',
title = 'Verkaufsautomat Verwaltung',
options = options
})
lib.showContext('vending_owner_menu')
end, coords)
end)
-- Function to sell the vending machine
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!',
required = true
}
})
if input and input[1] then
TriggerServerEvent('vending:server:sellMachine', coords, machineId)
end
end
-- Open price menu
function openPriceMenu(coords)
QBCore.Functions.TriggerCallback('vending:server:getStashItems', function(items)
if #items == 0 then
QBCore.Functions.Notify('Keine Items im Automaten!', 'error')
return
end
local options = {}
for i = 1, #items do
local item = items[i]
local itemLabel = QBCore.Shared.Items[item.name] and QBCore.Shared.Items[item.name].label or item.name
table.insert(options, {
title = itemLabel,
description = 'Aktueller Preis: $' .. item.price,
icon = 'fas fa-tag',
onSelect = function()
setPriceForItem(coords, item.name, itemLabel)
end
})
end
lib.registerContext({
id = 'vending_price_menu',
title = 'Preise festlegen',
menu = 'vending_owner_menu',
options = options
})
lib.showContext('vending_price_menu')
end, coords)
end
-- Set price for specific item
function setPriceForItem(coords, itemName, itemLabel)
local input = lib.inputDialog('Preis festlegen', {
{
type = 'number',
label = 'Preis für ' .. itemLabel,
description = 'Neuen Verkaufspreis eingeben',
required = true,
min = 1,
max = 10000
}
})
if input and input[1] then
TriggerServerEvent('vending:server:setItemPrice', coords, itemName, tonumber(input[1]))
end
end
-- Open withdraw menu
function openWithdrawMenu(coords, availableMoney)
if availableMoney <= 0 then
QBCore.Functions.Notify('Kein Geld im Automaten!', 'error')
return
end
local input = lib.inputDialog('Geld abheben', {
{
type = 'number',
label = 'Betrag (Verfügbar: $' .. availableMoney .. ')',
description = 'Wie viel möchtest du abheben?',
required = true,
min = 1,
max = availableMoney
}
})
if input and input[1] then
TriggerServerEvent('vending:server:withdrawMoney', coords, tonumber(input[1]))
end
end
-- Open stats menu
function openStatsMenu(machine)
lib.registerContext({
id = 'vending_stats_menu',
title = 'Verkaufsstatistiken',
menu = 'vending_owner_menu',
options = {
{
title = 'Gesamteinnahmen',
description = '$' .. machine.money,
icon = 'fas fa-dollar-sign'
},
{
title = 'Automat ID',
description = '#' .. machine.id,
icon = 'fas fa-hashtag'
},
{
title = 'Standort',
description = 'X: ' .. math.floor(machine.coords.x) .. ' Y: ' .. math.floor(machine.coords.y),
icon = 'fas fa-map-marker-alt'
}
}
})
lib.showContext('vending_stats_menu')
end
-- Open managers menu
function openManagersMenu(coords)
-- Get current managers
QBCore.Functions.TriggerCallback('vending:server:getManagers', function(managers)
local options = {
{
title = 'Verwalter hinzufügen',
description = 'Neuen Verwalter hinzufügen',
icon = 'fas fa-user-plus',
onSelect = function()
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' or 'Offline',
icon = manager.online and 'fas fa-circle text-success' or 'fas fa-circle text-danger',
onSelect = function()
lib.registerContext({
id = 'manager_options',
title = 'Verwalter: ' .. manager.name,
menu = 'managers_menu',
options = {
{
title = 'Entfernen',
description = 'Verwalter entfernen',
icon = 'fas fa-user-minus',
onSelect = function()
TriggerServerEvent('vending:server:removeManager', coords, manager.citizenid)
Wait(500)
openManagersMenu(coords) -- Refresh the menu
end
}
}
})
lib.showContext('manager_options')
end
})
end
else
table.insert(options, {
title = 'Keine Verwalter',
description = 'Es sind keine Verwalter vorhanden',
icon = 'fas fa-info-circle',
disabled = true
})
end
lib.registerContext({
id = 'managers_menu',
title = 'Verwalter verwalten',
menu = 'vending_owner_menu',
options = options
})
lib.showContext('managers_menu')
end, coords)
end
-- Open add manager menu
function openAddManagerMenu(coords)
QBCore.Functions.TriggerCallback('vending:server:getOnlinePlayers', function(players)
if #players == 0 then
QBCore.Functions.Notify('Keine Spieler online!', 'error')
return
end
local options = {}
for i = 1, #players do
local player = players[i]
table.insert(options, {
title = player.name,
description = 'ID: ' .. player.id,
icon = 'fas fa-user',
onSelect = function()
TriggerServerEvent('vending:server:addManager', coords, player.id)
Wait(500)
openManagersMenu(coords) -- Refresh the menu
end
})
end
lib.registerContext({
id = 'add_manager_menu',
title = 'Verwalter hinzufügen',
menu = 'managers_menu',
options = options
})
lib.showContext('add_manager_menu')
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(coords)
local playerPed = PlayerPedId()
local robberyTime = 10000 -- 10 seconds
-- Animation
RequestAnimDict('anim@heists@fleeca_bank@drilling')
while not HasAnimDictLoaded('anim@heists@fleeca_bank@drilling') do
Wait(100)
end
TaskPlayAnim(playerPed, 'anim@heists@fleeca_bank@drilling', 'drill_straight_idle', 8.0, -8.0, -1, 1, 0, false, false, false)
-- Progress bar
if lib.progressBar then
local success = lib.progressBar({
duration = robberyTime,
label = 'Automat aufbrechen...',
useWhileDead = false,
canCancel = true,
disable = {
car = true,
move = true,
combat = true
}
})
ClearPedTasks(playerPed)
TriggerServerEvent('vending:server:completeRobbery', coords, success)
else
-- Fallback without progress bar
Wait(robberyTime)
ClearPedTasks(playerPed)
TriggerServerEvent('vending:server:completeRobbery', coords, true)
end
end)
-- Police alert
RegisterNetEvent('vending:client:policeAlert', function(coords, streetName)
local alert = {
title = "Verkaufsautomat Aufbruch",
coords = coords,
description = "Ein Verkaufsautomat wird aufgebrochen in " .. streetName
}
-- Add blip
local blip = AddBlipForCoord(coords.x, coords.y, coords.z)
SetBlipSprite(blip, 161)
SetBlipColour(blip, 1)
SetBlipScale(blip, 1.0)
SetBlipAsShortRange(blip, false)
BeginTextCommandSetBlipName("STRING")
AddTextComponentString("Verkaufsautomat Aufbruch")
EndTextCommandSetBlipName(blip)
-- Remove blip after 5 minutes
SetTimeout(300000, function()
RemoveBlip(blip)
end)
QBCore.Functions.Notify('Verkaufsautomat Aufbruch gemeldet: ' .. streetName, 'error', 8000)
end)
-- 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 command to check props
RegisterCommand('checkvendingprops', function()
local playerPed = PlayerPedId()
local playerCoords = GetEntityCoords(playerPed)
local foundProps = 0
for _, propName in ipairs(Config.VendingProps) do
local hash = GetHashKey(propName)
local objects = GetGamePool('CObject')
print("Checking for prop: " .. propName .. " (Hash: " .. hash .. ")")
for _, obj in ipairs(objects) do
if GetEntityModel(obj) == hash then
local objCoords = GetEntityCoords(obj)
local dist = #(playerCoords - objCoords)
if dist < 30.0 then
foundProps = foundProps + 1
print("Found " .. propName .. " at distance: " .. dist)
-- Add a temporary blip
local blip = AddBlipForEntity(obj)
SetBlipSprite(blip, 1)
SetBlipColour(blip, 2)
SetBlipScale(blip, 0.8)
BeginTextCommandSetBlipName("STRING")
AddTextComponentString(propName)
EndTextCommandSetBlipName(blip)
-- Remove blip after 10 seconds
SetTimeout(10000, function()
RemoveBlip(blip)
end)
end
end
end
end
QBCore.Functions.Notify('Found ' .. foundProps .. ' vending machines nearby', 'primary')
end, false)
-- Debug commands
RegisterCommand('vendingdebug', function()
local playerPed = PlayerPedId()
local coords = GetEntityCoords(playerPed)
QBCore.Functions.TriggerCallback('vending:server:getMachineByCoords', function(machine)
if machine then
print('Machine found:', json.encode(machine))
QBCore.Functions.Notify('Machine data logged to console', 'primary')
else
print('No machine found at current location')
QBCore.Functions.Notify('No machine found here', 'error')
end
end, coords)
end, false)
-- Event to refresh machine data when a new machine is registered
RegisterNetEvent('vending:client:refreshTargets', function()
-- Clear cached data
currentMachineData = nil
end)