2025-08-02 13:24:19 +02:00
|
|
|
local QBCore = exports['qb-core']:GetCoreObject()
|
|
|
|
local bowls = {}
|
|
|
|
|
|
|
|
-- Initialize
|
|
|
|
Citizen.CreateThread(function()
|
|
|
|
-- Load all bowls from database
|
|
|
|
LoadBowls()
|
|
|
|
end)
|
|
|
|
|
|
|
|
-- Load bowls from database
|
|
|
|
function LoadBowls()
|
|
|
|
MySQL.query('SELECT * FROM pet_bowls', {}, function(results)
|
|
|
|
if results and #results > 0 then
|
|
|
|
for _, bowl in pairs(results) do
|
|
|
|
bowls[bowl.bowl_id] = {
|
|
|
|
id = bowl.bowl_id,
|
|
|
|
model = bowl.model,
|
|
|
|
type = bowl.type,
|
2025-08-02 14:02:20 +02:00
|
|
|
fill_level = bowl.fill_level,
|
2025-08-02 13:24:19 +02:00
|
|
|
coords = bowl.coords
|
|
|
|
}
|
|
|
|
end
|
|
|
|
print('^2[Pet-Bowls]^7 Loaded ' .. #results .. ' bowls from database')
|
|
|
|
else
|
|
|
|
print('^2[Pet-Bowls]^7 No bowls found in database')
|
|
|
|
end
|
|
|
|
end)
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Client requests all bowls
|
|
|
|
RegisterNetEvent('pet-bowls:server:requestBowls', function()
|
|
|
|
local src = source
|
|
|
|
TriggerClientEvent('pet-bowls:client:loadBowls', src, bowls)
|
|
|
|
end)
|
|
|
|
|
2025-08-02 13:51:31 +02:00
|
|
|
-- Place a new bowl (register an existing prop as a bowl)
|
2025-08-02 13:24:19 +02:00
|
|
|
RegisterNetEvent('pet-bowls:server:placeBowl', function(bowlId, model, bowlType, coords)
|
|
|
|
local src = source
|
|
|
|
local Player = QBCore.Functions.GetPlayer(src)
|
|
|
|
|
|
|
|
if not Player then return end
|
|
|
|
|
|
|
|
-- Save to database
|
|
|
|
local coordsJson = json.encode(coords)
|
|
|
|
MySQL.insert('INSERT INTO pet_bowls (bowl_id, model, type, fill_level, coords) VALUES (?, ?, ?, ?, ?)',
|
|
|
|
{bowlId, model, bowlType, 0, coordsJson},
|
|
|
|
function(id)
|
|
|
|
if id then
|
|
|
|
-- Save to memory
|
|
|
|
bowls[bowlId] = {
|
|
|
|
id = bowlId,
|
|
|
|
model = model,
|
|
|
|
type = bowlType,
|
2025-08-02 14:02:20 +02:00
|
|
|
fill_level = 0,
|
2025-08-02 13:24:19 +02:00
|
|
|
coords = coordsJson
|
|
|
|
}
|
|
|
|
|
|
|
|
-- Notify all clients about the new bowl
|
|
|
|
TriggerClientEvent('pet-bowls:client:updateBowlLevel', -1, bowlId, 0)
|
2025-08-02 14:02:20 +02:00
|
|
|
print('^2[Pet-Bowls]^7 New bowl registered: ' .. bowlId)
|
2025-08-02 13:24:19 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
)
|
|
|
|
end)
|
|
|
|
|
|
|
|
-- Fill a bowl
|
|
|
|
RegisterNetEvent('pet-bowls:server:fillBowl', function(bowlId, itemName, fillAmount)
|
|
|
|
local src = source
|
|
|
|
local Player = QBCore.Functions.GetPlayer(src)
|
|
|
|
|
|
|
|
if not Player then return end
|
|
|
|
|
2025-08-02 13:51:31 +02:00
|
|
|
-- Check if player has the item using standard QBCore function
|
|
|
|
local item = Player.Functions.GetItemByName(itemName)
|
2025-08-02 13:24:19 +02:00
|
|
|
|
2025-08-02 13:51:31 +02:00
|
|
|
if not item or item.amount < 1 then
|
2025-08-02 13:24:19 +02:00
|
|
|
TriggerClientEvent('ox_lib:notify', src, Config.Notifications.noItem)
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
2025-08-02 13:51:31 +02:00
|
|
|
-- Remove the item using standard QBCore function
|
|
|
|
Player.Functions.RemoveItem(itemName, 1)
|
|
|
|
TriggerClientEvent('inventory:client:ItemBox', src, QBCore.Shared.Items[itemName], "remove")
|
2025-08-02 13:24:19 +02:00
|
|
|
|
|
|
|
-- Update bowl fill level
|
|
|
|
local bowl = bowls[bowlId]
|
|
|
|
if bowl then
|
2025-08-02 14:02:20 +02:00
|
|
|
local newLevel = math.min(100, bowl.fill_level + fillAmount)
|
2025-08-02 13:24:19 +02:00
|
|
|
|
|
|
|
-- Update in memory
|
2025-08-02 14:02:20 +02:00
|
|
|
bowl.fill_level = newLevel
|
2025-08-02 13:24:19 +02:00
|
|
|
|
|
|
|
-- Update in database
|
|
|
|
MySQL.update('UPDATE pet_bowls SET fill_level = ?, last_refill = CURRENT_TIMESTAMP WHERE bowl_id = ?',
|
|
|
|
{newLevel, bowlId}
|
|
|
|
)
|
|
|
|
|
|
|
|
-- Update all clients
|
|
|
|
TriggerClientEvent('pet-bowls:client:updateBowlLevel', -1, bowlId, newLevel)
|
|
|
|
TriggerClientEvent('ox_lib:notify', src, Config.Notifications.bowlFilled)
|
2025-08-02 14:02:20 +02:00
|
|
|
|
|
|
|
print('^2[Pet-Bowls]^7 Bowl ' .. bowlId .. ' filled to ' .. newLevel .. '%')
|
2025-08-02 13:24:19 +02:00
|
|
|
end
|
|
|
|
end)
|
|
|
|
|
|
|
|
-- Consume from a bowl
|
|
|
|
RegisterNetEvent('pet-bowls:server:consumeBowl', function(bowlId)
|
|
|
|
local src = source
|
|
|
|
local Player = QBCore.Functions.GetPlayer(src)
|
|
|
|
|
|
|
|
if not Player then return end
|
|
|
|
|
|
|
|
-- Get bowl data
|
|
|
|
local bowl = bowls[bowlId]
|
|
|
|
if not bowl then return end
|
|
|
|
|
|
|
|
-- Find the bowl config
|
|
|
|
local bowlConfig = nil
|
|
|
|
for _, config in pairs(Config.BowlProps) do
|
|
|
|
if config.model == bowl.model then
|
|
|
|
bowlConfig = config
|
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
if not bowlConfig then return end
|
|
|
|
|
|
|
|
-- Check if bowl has content
|
2025-08-02 14:02:20 +02:00
|
|
|
if bowl.fill_level <= 0 then
|
2025-08-02 13:24:19 +02:00
|
|
|
TriggerClientEvent('ox_lib:notify', src, Config.Notifications.bowlEmpty)
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Consume from bowl
|
|
|
|
local consumeAmount = bowlConfig.consumeAmount
|
2025-08-02 14:02:20 +02:00
|
|
|
local newLevel = math.max(0, bowl.fill_level - consumeAmount)
|
2025-08-02 13:24:19 +02:00
|
|
|
|
|
|
|
-- Update in memory
|
2025-08-02 14:02:20 +02:00
|
|
|
bowl.fill_level = newLevel
|
2025-08-02 13:24:19 +02:00
|
|
|
|
|
|
|
-- Update in database
|
|
|
|
MySQL.update('UPDATE pet_bowls SET fill_level = ? WHERE bowl_id = ?',
|
|
|
|
{newLevel, bowlId}
|
|
|
|
)
|
|
|
|
|
2025-08-02 14:37:33 +02:00
|
|
|
-- Apply effects to player - FIXED VERSION FOR DIFFERENT QBCORE VERSIONS
|
2025-08-02 13:24:19 +02:00
|
|
|
local effects = Config.Effects[bowl.type]
|
|
|
|
if effects then
|
2025-08-02 14:32:53 +02:00
|
|
|
-- Get player metadata
|
|
|
|
local metadata = Player.PlayerData.metadata
|
|
|
|
|
2025-08-02 14:37:33 +02:00
|
|
|
-- Apply hunger effect for food bowls
|
2025-08-02 14:32:53 +02:00
|
|
|
if effects.hunger and bowl.type == 'food' then
|
2025-08-02 14:37:33 +02:00
|
|
|
-- Direct HUD update for hunger
|
|
|
|
TriggerClientEvent('hud:client:UpdateHunger', src, effects.hunger, true)
|
|
|
|
print('^2[Pet-Bowls]^7 Updated player hunger by +' .. effects.hunger)
|
2025-08-02 13:24:19 +02:00
|
|
|
end
|
|
|
|
|
2025-08-02 14:37:33 +02:00
|
|
|
-- Apply thirst effect for water bowls
|
2025-08-02 14:32:53 +02:00
|
|
|
if effects.thirst and bowl.type == 'water' then
|
2025-08-02 14:37:33 +02:00
|
|
|
-- Direct HUD update for thirst
|
|
|
|
TriggerClientEvent('hud:client:UpdateThirst', src, effects.thirst, true)
|
|
|
|
print('^2[Pet-Bowls]^7 Updated player thirst by +' .. effects.thirst)
|
2025-08-02 13:24:19 +02:00
|
|
|
end
|
|
|
|
|
2025-08-02 14:32:53 +02:00
|
|
|
-- Apply stress effect (if your server uses this)
|
2025-08-02 13:24:19 +02:00
|
|
|
if effects.stress then
|
2025-08-02 14:37:33 +02:00
|
|
|
-- Try to update stress using common event
|
|
|
|
TriggerClientEvent('hud:client:UpdateStress', src, effects.stress)
|
2025-08-02 13:24:19 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Update all clients
|
|
|
|
TriggerClientEvent('pet-bowls:client:updateBowlLevel', -1, bowlId, newLevel)
|
|
|
|
TriggerClientEvent('ox_lib:notify', src, Config.Notifications.consumed)
|
2025-08-02 14:02:20 +02:00
|
|
|
|
|
|
|
print('^2[Pet-Bowls]^7 Bowl ' .. bowlId .. ' consumed, new level: ' .. newLevel .. '%')
|
2025-08-02 13:24:19 +02:00
|
|
|
end)
|
|
|
|
|
2025-08-02 13:51:31 +02:00
|
|
|
-- Remove a bowl from database (if needed)
|
2025-08-02 13:24:19 +02:00
|
|
|
RegisterNetEvent('pet-bowls:server:removeBowl', function(bowlId)
|
|
|
|
local src = source
|
|
|
|
local Player = QBCore.Functions.GetPlayer(src)
|
|
|
|
|
|
|
|
if not Player then return end
|
|
|
|
|
|
|
|
-- Remove from database
|
|
|
|
MySQL.query('DELETE FROM pet_bowls WHERE bowl_id = ?', {bowlId})
|
|
|
|
|
|
|
|
-- Remove from memory
|
|
|
|
bowls[bowlId] = nil
|
2025-08-02 13:51:31 +02:00
|
|
|
|
|
|
|
-- Notify all clients
|
|
|
|
TriggerClientEvent('pet-bowls:client:bowlRemoved', -1, bowlId)
|
2025-08-02 14:02:20 +02:00
|
|
|
|
|
|
|
print('^2[Pet-Bowls]^7 Bowl removed: ' .. bowlId)
|
|
|
|
end)
|
|
|
|
|
|
|
|
-- Register command to register bowls
|
|
|
|
QBCore.Commands.Add('registerbowl', 'Register a nearby bowl prop', {}, false, function(source, args)
|
|
|
|
TriggerClientEvent('pet-bowls:client:openRegisterBowlMenu', source)
|
2025-08-02 13:24:19 +02:00
|
|
|
end)
|