1
0
Fork 0
forked from Simnation/Main
This commit is contained in:
Nordi98 2025-07-01 14:06:41 +02:00
parent ff77f014da
commit 6c5b470e91
7 changed files with 19 additions and 659 deletions

View file

@ -6,7 +6,10 @@ Config.GrillProps = {
"prop_bbq_2", "prop_bbq_2",
"prop_bbq_3", "prop_bbq_3",
"prop_bbq_4", "prop_bbq_4",
"prop_bbq_5" "prop_bbq_5",
"smallbbqtrailer",
"bigbbqtrailer"
} }
-- Zeit zum Grillen (in ms) -- Zeit zum Grillen (in ms)
@ -22,7 +25,18 @@ Config.GrillRecipes = {
requires = { requires = {
{item = "rawmeat", amount = 1} {item = "rawmeat", amount = 1}
} }
},
{
label = "Fisch",
description = "Ein perfekt gegrilltes Fischfilet",
item = "grilled_fish",
icon = "fas fa-drumstick-bite",
requires = {
{item = "fish_fillet", amount = 1}
}
} }
-- Hier kannst du weitere Rezepte hinzufügen -- Hier kannst du weitere Rezepte hinzufügen
} }

View file

@ -1,238 +0,0 @@
local QBCore = exports['qb-core']:GetCoreObject()
local inZone = false
local currentMachine = nil
local PlayerData = {}
local function SetupTarget()
if not Config.UseQBTarget then return end
-- Default 24/7 machines
for modelHash, machineData in pairs(Config.DefaultMachines.Models) do
exports['qb-target']:AddTargetModel(modelHash, {
options = {
{
type = 'client',
event = 'vendingmachines:client:openMenu',
icon = 'fas fa-cash-register',
label = 'Use Vending Machine',
machineModel = modelHash,
isPlayerOwned = false
},
Config.EnableRobbery and {
type = 'client',
event = 'vendingmachines:client:startRobbery',
icon = 'fas fa-lock',
label = 'Rob Machine',
item = Config.RobberyItem,
machineModel = modelHash,
isPlayerOwned = false
} or nil
},
distance = Config.TargetOptions.distance
})
end
-- Player owned machines will be added dynamically as they're loaded
end
local function RefreshPlayerMachines()
local playerMachines = QBCore.Functions.TriggerRpc('vendingmachines:server:getPlayerMachines', PlayerData.citizenid)
for _, machine in pairs(playerMachines) do
exports['qb-target']:AddBoxZone('vending_' .. machine.id, json.decode(machine.location), 0.5, 0.5, {
name = 'vending_' .. machine.id,
heading = 0,
debugPoly = false,
minZ = json.decode(machine.location).z - 0.5,
maxZ = json.decode(machine.location).z + 0.5
}, {
options = {
{
type = 'client',
event = 'vendingmachines:client:openMenu',
icon = 'fas fa-cash-register',
label = 'Use Vending Machine',
machineId = machine.id,
isPlayerOwned = true,
machineModel = machine.model_hash
},
Config.EnableRobbery and {
type = 'client',
event = 'vendingmachines:client:startRobbery',
icon = 'fas fa-lock',
label = 'Rob Machine',
item = Config.RobberyItem,
machineId = machine.id,
isPlayerOwned = true
} or nil,
table.contains(Config.PlayerOwnedMachines.AllowedJobs, PlayerData.job.name) and {
type = 'client',
event = 'vendingmachines:client:restockMenu',
icon = 'fas fa-boxes',
label = 'Restock Machine',
machineId = machine.id
} or nil,
table.contains(Config.PlayerOwnedMachines.AllowedJobs, PlayerData.job.name) and {
type = 'client',
event = 'vendingmachines:client:collectEarnings',
icon = 'fas fa-money-bill-wave',
label = 'Collect Earnings',
machineId = machine.id
} or nil
},
distance = Config.TargetOptions.distance
})
end
end
local function OpenVendingMenu(machineInfo)
local menu = {
header = 'Vending Machine',
items = {}
}
if machineInfo.isPlayerOwned then
menu.header = 'Player Vending Machine'
menu.items[#menu.items + 1] = {
title = 'Stock: ' .. (currentMachine and currentMachine.stock or '?'),
description = 'Available items for purchase',
disabled = true
}
else
menu.header = '24/7 Vending Machine'
end
local items = Config.DefaultMachines.Models[machineInfo.machineModel].items
for _, item in pairs(items) do
menu.items[#menu.items + 1] = {
title = item.label,
description = 'Price: $' .. item.price,
onSelect = function()
local input = lib.inputDialog('Purchase Amount', {
{ type = 'number', label = 'Amount', min = 1, max = 10, default = 1 }
})
if input and input[1] then
TriggerServerEvent('vendingmachines:server:processPurchase',
machineInfo.isPlayerOwned,
machineInfo.isPlayerOwned and machineInfo.machineId or machineInfo.machineModel,
item.name,
input[1])
end
end
}
end
lib.registerContext(menu)
lib.showContext('vending_menu')
end
local function StartRobbery(machineInfo)
QBCore.Functions.TriggerCallback('vendingmachines:server:hasItem', function(hasItem)
if hasItem then
local success = lib.skillCheck({ 'easy', 'easy', { areaSize = 60, speedMultiplier = 1 } }, { 'w', 'a', 's', 'd' })
if success then
QBCore.Functions.Progressbar('robbing_machine', 'Robbing vending machine...',
Config.RobberyTime * 1000, false, true, {
disableMovement = true,
disableCarMovement = true,
disableMouse = false,
disableCombat = true,
}, {
animDict = 'mini@safe_cracking',
anim = 'idle_base',
flags = 16,
}, {}, {}, function()
TriggerServerEvent('vendingmachines:server:completeRobbery',
machineInfo.isPlayerOwned,
machineInfo.isPlayerOwned and machineInfo.machineId or nil)
end, function()
TriggerServerEvent('vendingmachines:server:robberyFailed',
machineInfo.isPlayerOwned,
machineInfo.isPlayerOwned and machineInfo.machineId or nil)
end)
else
QBCore.Functions.Notify('Robbery failed', 'error')
end
else
QBCore.Functions.Notify('You don\'t have the required item', 'error')
end
end, Config.RobberyItem)
end
-- Events
RegisterNetEvent('vendingmachines:client:openMenu', function(data)
OpenVendingMenu(data)
end)
RegisterNetEvent('vendingmachines:client:registerMachine', function()
local playerPed = PlayerPedId()
local coords = GetEntityCoords(playerPed)
local obj = GetClosestObjectOfType(coords, 3.0, GetHashKey('prop_vend_soda_01'), false, false, false)
if DoesEntityExist(obj) then
local modelHash = GetEntityModel(obj)
local validModel = false
for _, model in pairs(Config.PlayerOwnedMachines.Models) do
if model == modelHash then
validModel = true
break
end
end
if not validModel then
QBCore.Functions.Notify('This vending machine cannot be owned', 'error')
return
end
local objCoords = GetEntityCoords(obj)
TriggerServerEvent('vendingmachines:server:registerMachine', modelHash, objCoords)
else
QBCore.Functions.Notify('No vending machine nearby', 'error')
end
end)
RegisterNetEvent('vendingmachines:client:startRobbery', function(data)
StartRobbery(data)
end)
RegisterNetEvent('vendingmachines:client:refreshPlayerMachines', function()
RefreshPlayerMachines()
end)
RegisterNetEvent('vendingmachines:client:restockMenu', function(data)
local input = lib.inputDialog('Restock Amount', {
{ type = 'number', label = 'Amount', min = 1, default = 1 }
})
if input and input[1] then
TriggerServerEvent('vendingmachines:server:restockMachine', data.machineId)
end
end)
RegisterNetEvent('vendingmachines:client:collectEarnings', function(data)
TriggerServerEvent('vendingmachines:server:collectEarnings', data.machineId)
end)
-- Initialization
AddEventHandler('QBCore:Client:OnPlayerLoaded', function()
PlayerData = QBCore.Functions.GetPlayerData()
SetupTarget()
RefreshPlayerMachines()
end)
AddEventHandler('QBCore:Client:OnJobUpdate', function(job)
PlayerData.job = job
end)
AddEventHandler('onResourceStart', function(resource)
if GetCurrentResourceName() == resource then
PlayerData = QBCore.Functions.GetPlayerData()
SetupTarget()
Citizen.SetTimeout(5000, function()
RefreshPlayerMachines()
end)
end
end)

View file

@ -1,30 +0,0 @@
fx_version 'cerulean'
game 'gta5'
name 'QB-VendingMachines'
author 'Nordi'
description 'Advanced Vending Machine System for QB-Core'
version '1.0.0'
shared_scripts {
'shared/config.lua',
'@qb-core/shared/locale.lua',
'locales/en.lua' -- add other locales as needed
}
client_scripts {
'@qb-target/client.lua',
'client/main.lua'
}
server_scripts {
'@oxmysql/lib/MySQL.lua',
'server/main.lua'
}
dependencies {
'qb-core',
'qb-target',
'qs-inventory',
'ox_lib' -- or 'ox_lib' if using newer version
}

View file

@ -1,316 +0,0 @@
local QBCore = exports['qb-core']:GetCoreObject()
local Config = require 'config'
-- SQL Setup
local function SetupDatabase()
local query = [[
CREATE TABLE IF NOT EXISTS player_vending_machines (
id INT AUTO_INCREMENT PRIMARY KEY,
owner VARCHAR(50) NOT NULL,
model_hash BIGINT NOT NULL,
location LONGTEXT NOT NULL,
stock INT DEFAULT 0,
earnings DECIMAL(10,2) DEFAULT 0,
last_collected BIGINT DEFAULT 0,
UNIQUE KEY unique_machine (owner, model_hash, location(255))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
]]
MySQL.ready(function()
MySQL.query(query, {}, function(result)
print('^2[Vending Machines]^7 Database table initialized')
end)
end)
end
-- Global state for 24/7 machine robberies
local robberyCooldown = {}
-- Register usable items
QBCore.Functions.CreateUseableItem(Config.RobberyItem, function(source)
TriggerClientEvent('vendingmachines:client:startRobbery', source)
end)
if Config.PlayerOwnedMachines.RestockItem then
QBCore.Functions.CreateUseableItem(Config.PlayerOwnedMachines.RestockItem, function(source)
TriggerClientEvent('vendingmachines:client:startRestock', source)
end)
end
-- Player-owned machine management
local function GetPlayerMachines(citizenid)
local result = MySQL.query.await('SELECT * FROM player_vending_machines WHERE owner = ?', { citizenid })
return result
end
local function GetMachineById(id)
local result = MySQL.query.await('SELECT * FROM player_vending_machines WHERE id = ?', { id })
return result[1]
end
local function RegisterPlayerMachine(source, modelHash, coords)
local Player = QBCore.Functions.GetPlayer(source)
if not Player then return false end
local location = json.encode({
x = coords.x,
y = coords.y,
z = coords.z
})
local result = MySQL.insert.await([[
INSERT INTO player_vending_machines (owner, model_hash, location)
VALUES (?, ?, ?)
]], { Player.PlayerData.citizenid, modelHash, location })
if result then
TriggerClientEvent('vendingmachines:client:refreshPlayerMachines', -1)
return true
end
return false
end
local function RestockMachine(machineId, amount)
local machine = GetMachineById(machineId)
if not machine then return false end
local newStock = math.min(machine.stock + amount, Config.PlayerOwnedMachines.MaxStock)
MySQL.update.await('UPDATE player_vending_machines SET stock = ? WHERE id = ?', { newStock, machineId })
return true
end
local function CollectEarnings(machineId)
local machine = GetMachineById(machineId)
if not machine or machine.earnings <= 0 then return 0 end
local amount = machine.earnings
MySQL.update.await('UPDATE player_vending_machines SET earnings = 0, last_collected = ? WHERE id = ?',
{ os.time(), machineId })
return amount
end
-- Handle vending machine purchases
local function ProcessPurchase(source, isPlayerOwned, machineId, itemName, amount)
local Player = QBCore.Functions.GetPlayer(source)
if not Player then return false end
if isPlayerOwned then
-- Player-owned machine purchase
local machine = GetMachineById(machineId)
if not machine or machine.stock < amount then return false end
local itemData = nil
for _, item in pairs(Config.DefaultMachines.Models[machine.model_hash].items) do
if item.name == itemName then
itemData = item
break
end
end
if not itemData then return false end
local totalPrice = itemData.price * amount
if Player.Functions.RemoveMoney('cash', totalPrice) then
local earnings = totalPrice
local ownerCut = math.floor(earnings * Config.PlayerOwnedMachines.OwnerCut)
local businessCut = earnings - ownerCut
MySQL.update.await('UPDATE player_vending_machines SET stock = stock - ?, earnings = earnings + ? WHERE id = ?',
{ amount, businessCut, machineId })
-- Give item to player
Player.Functions.AddItem(itemName, amount)
return true
end
else
-- 24/7 machine purchase
local modelHash = tonumber(machineId)
local machineItems = Config.DefaultMachines.Models[modelHash]
if not machineItems then return false end
local itemData = nil
for _, item in pairs(machineItems.items) do
if item.name == itemName then
itemData = item
break
end
end
if not itemData then return false end
local totalPrice = itemData.price * amount
if Player.Functions.RemoveMoney('cash', totalPrice) then
Player.Functions.AddItem(itemName, amount)
return true
end
end
end
-- Robbery functions
local function AlertPolice(machineCoords)
if Config.Dispatch == 'ps-dispatch' then
exports['ps-dispatch']:VendingMachineRobbery(machineCoords)
elseif Config.Dispatch == 'qb-dispatch' then
TriggerEvent('qb-dispatch:officerDistress', {
dispatchCode = '10-31',
firstStreet = GetStreetAndZone(machineCoords),
priority = 2,
origin = {
x = machineCoords.x,
y = machineCoords.y,
z = machineCoords.z
},
blip = {
sprite = 52,
scale = 1.5,
color = 1,
flashes = true,
text = 'Vending Machine Robbery',
time = 5
}
})
end
end
local function CompleteRobbery(source, isPlayerOwned, machineId)
local Player = QBCore.Functions.GetPlayer(source)
if not Player then return false end
if robberyCooldown[source] and os.time() - robberyCooldown[source] < 300 then
TriggerClientEvent('QBCore:Notify', source, 'You need to wait before robbing again', 'error')
return false
end
if Player.Functions.RemoveItem(Config.RobberyItem, 1) then
local reward = math.random(Config.MinRobberyCash, Config.MaxRobberyCash)
Player.Functions.AddMoney('cash', reward)
if math.random(1, 100) <= Config.RobberyAlertChance then
local coords = GetEntityCoords(GetPlayerPed(source))
AlertPolice(coords)
end
robberyCooldown[source] = os.time()
if isPlayerOwned then
local machine = GetMachineById(machineId)
if machine then
MySQL.update.await('UPDATE player_vending_machines SET stock = GREATEST(0, stock - ?) WHERE id = ?',
{ math.random(5, 15), machineId })
end
end
return true
end
return false
end
-- Server Events
RegisterNetEvent('vendingmachines:server:registerMachine', function(modelHash, coords)
local src = source
if RegisterPlayerMachine(src, modelHash, coords) then
TriggerClientEvent('QBCore:Notify', src, 'Vending machine registered successfully', 'success')
else
TriggerClientEvent('QBCore:Notify', src, 'Failed to register vending machine', 'error')
end
end)
RegisterNetEvent('vendingmachines:server:processPurchase', function(isPlayerOwned, machineId, itemName, amount)
local src = source
if ProcessPurchase(src, isPlayerOwned, machineId, itemName, amount) then
TriggerClientEvent('QBCore:Notify', src, 'Purchase successful', 'success')
else
TriggerClientEvent('QBCore:Notify', src, 'Purchase failed', 'error')
end
end)
RegisterNetEvent('vendingmachines:server:restockMachine', function(machineId)
local src = source
local Player = QBCore.Functions.GetPlayer(src)
if not Player then return end
local jobName = Player.PlayerData.job.name
local allowed = false
for _, job in pairs(Config.PlayerOwnedMachines.AllowedJobs) do
if job == jobName then
allowed = true
break
end
end
if not allowed then
TriggerClientEvent('QBCore:Notify', src, 'You are not authorized to restock machines', 'error')
return
end
if Player.Functions.RemoveItem(Config.PlayerOwnedMachines.RestockItem, 1) then
if RestockMachine(machineId, Config.PlayerOwnedMachines.StockAmount) then
TriggerClientEvent('QBCore:Notify', src, 'Machine restocked successfully', 'success')
else
Player.Functions.AddItem(Config.PlayerOwnedMachines.RestockItem, 1)
TriggerClientEvent('QBCore:Notify', src, 'Failed to restock machine', 'error')
end
else
TriggerClientEvent('QBCore:Notify', src, 'You don\'t have the restock item', 'error')
end
end)
RegisterNetEvent('vendingmachines:server:collectEarnings', function(machineId)
local src = source
local Player = QBCore.Functions.GetPlayer(src)
if not Player then return end
local jobName = Player.PlayerData.job.name
local allowed = false
for _, job in pairs(Config.PlayerOwnedMachines.AllowedJobs) do
if job == jobName then
allowed = true
break
end
end
if not allowed then
TriggerClientEvent('QBCore:Notify', src, 'You are not authorized to collect earnings', 'error')
return
end
local amount = CollectEarnings(machineId)
if amount > 0 then
Player.Functions.AddMoney('cash', amount)
TriggerClientEvent('QBCore:Notify', src, string.format('Collected $%d from the machine', amount), 'success')
else
TriggerClientEvent('QBCore:Notify', src, 'No earnings to collect', 'error')
end
end)
RegisterNetEvent('vendingmachines:server:completeRobbery', function(isPlayerOwned, machineId)
local src = source
if CompleteRobbery(src, isPlayerOwned, machineId) then
TriggerClientEvent('QBCore:Notify', src, 'Robbery successful', 'success')
else
TriggerClientEvent('QBCore:Notify', src, 'Robbery failed', 'error')
end
end)
-- Commands
QBCore.Commands.Add('registermachine', 'Register a player-owned vending machine', {}, false, function(source)
TriggerClientEvent('vendingmachines:client:registerMachine', source)
end, 'admin')
QBCore.Commands.Add('mymachines', 'View your owned vending machines', {}, false, function(source)
local Player = QBCore.Functions.GetPlayer(source)
if not Player then return end
local machines = GetPlayerMachines(Player.PlayerData.citizenid)
if #machines > 0 then
local msg = "Your machines:\n"
for _, machine in pairs(machines) do
msg = msg .. string.format("ID: %d | Stock: %d | Earnings: $%.2f\n", machine.id, machine.stock, machine.earnings)
end
TriggerClientEvent('chat:addMessage', source, { args = { 'SYSTEM', msg } })
else
TriggerClientEvent('QBCore:Notify', source, 'You don\'t own any machines', 'error')
end
end)
-- Initialize
SetupDatabase()

View file

@ -1,70 +0,0 @@
Config = {}
-- General Settings
Config.UseQBTarget = true
Config.UseOxLib = true
Config.Inventory = 'qs-inventory' -- or 'qb-inventory'
-- Robbery Settings
Config.EnableRobbery = true
Config.RobberyItem = 'lockpick' -- item needed to rob
Config.MinRobberyCash = 50
Config.MaxRobberyCash = 250
Config.RobberyTime = 15 -- seconds
Config.PoliceJob = 'police'
Config.Dispatch = 'ps-dispatch' -- or 'qb-dispatch'
Config.RobberyAlertChance = 70 -- percentage chance police get alerted
-- Player-owned Vending Machines
Config.PlayerOwnedMachines = {
AllowedJobs = { -- jobs that can restock/collect money
'vending',
'delivery'
},
Models = {
`prop_vend_soda_01`,
`prop_vend_soda_02`,
`prop_vend_water_01`
},
RestockItem = 'sodasyrup', -- item needed to restock
StockAmount = 10, -- how much stock restock item provides
PricePerItem = 10, -- how much player earns per sale
MaxStock = 50,
OwnerCut = 0.7 -- percentage owner gets (30% goes to business)
}
-- 24/7 Vending Machines
Config.DefaultMachines = {
Models = {
[`prop_vend_soda_01`] = {
items = {
{ name = 'water_bottle', price = 5, label = 'Water' },
{ name = 'kurkakola', price = 7, label = 'Cola' },
{ name = 'sprunk', price = 7, label = 'Sprunk' }
}
},
[`prop_vend_soda_02`] = {
items = {
{ name = 'water_bottle', price = 5, label = 'Water' },
{ name = 'ecola', price = 8, label = 'eCola' }
}
},
[`prop_vend_coffe_01`] = {
items = {
{ name = 'coffee', price = 10, label = 'Coffee' }
}
}
}
}
-- Target Options
Config.TargetOptions = {
useZones = true, -- create target zones for machines
distance = 2.0
}
-- Notification Settings
Config.Notify = 'qb' -- or 'ox', 'okok', 'esx'
Config.Locale = 'en' -- if using locale files
return Config

View file

@ -123,8 +123,8 @@ Config.fish = {
-- Add prices for processed items -- Add prices for processed items
Config.processedItems = { Config.processedItems = {
{ item = 'fish_fillet', label = 'Fish Fillet', price = {50, 100} }, { item = 'fish_fillet', label = 'Fish Fillet', price = {10, 40} },
{ item = 'caviar', label = 'Caviar', price = {300, 500} }, { item = 'caviar', label = 'Caviar', price = {60, 100} },
} }
RegisterNetEvent('wasabi_fishing:notify') RegisterNetEvent('wasabi_fishing:notify')

View file

@ -18,7 +18,7 @@ Strings = {
fish_success = 'Fisch im Kasten das Abendessen ist gesichert.', fish_success = 'Fisch im Kasten das Abendessen ist gesichert.',
fish_success_desc = 'Du hast eine/n %s!', fish_success_desc = 'Du hast eine/n %s!',
sell_shop_blip = 'Fish Market', sell_shop_blip = 'Fish Market',
sell_fish = '[E] - Fisch verkaufen.', sell_fish = '[E] - Fisch verkaufen',
kicked = 'Du kannsts versuchen, aber das klappt hier nicht.', kicked = 'Du kannsts versuchen, aber das klappt hier nicht.',
sold_for = 'Fisch verkauft.', sold_for = 'Fisch verkauft.',
sold_for_desc = 'Du hast %sx %s für $%s verkauft.', sold_for_desc = 'Du hast %sx %s für $%s verkauft.',
@ -28,7 +28,7 @@ Strings = {
waiting_bite_desc = 'Ein bisschen Geduld der Fisch ist gleich da.', waiting_bite_desc = 'Ein bisschen Geduld der Fisch ist gleich da.',
cannot_carry = 'Kein Platz!', cannot_carry = 'Kein Platz!',
cannot_carry_desc = 'Du schleppst schon genug mehr passt nicht rein!', cannot_carry_desc = 'Du schleppst schon genug mehr passt nicht rein!',
no_knife = 'Kein Messer.', no_knife = 'Kein Messer',
no_knife_desc = 'Ohne Messer ist der Fisch nur Deko.', no_knife_desc = 'Ohne Messer ist der Fisch nur Deko.',
processing_success = 'Fang verarbeitet nächster Schritt: Grill an!', processing_success = 'Fang verarbeitet nächster Schritt: Grill an!',
processing_success_desc = '%d %s frisch aus der Fischverarbeitung!', processing_success_desc = '%d %s frisch aus der Fischverarbeitung!',