2025-03-01 12:58:43 +00:00
local CraftLock = false
--- Opens a crafting menu based on the provided data.
---
--- This function checks job requirements, prepares the menu options, and opens the crafting menu.
--- It handles item availability, crafting recipes, and displays appropriate icons and labels.
---
---@param data table A table containing crafting menu data.
--- - **craftable** (`table`): The crafting options and settings.
--- - **Header** (`string`): The header/title of the crafting menu.
--- - **Recipes** (`table`): A list of crafting recipes.
--- - **coords** (`vector3`): The coordinates where the crafting menu is being opened.
--- - **stashTable** (`string` or `table`, optional): The stash name(s) to check for item availability.
--- - **stashName** (`string` or `table`, optional): Alias for `stashTable`.
--- - **job** (`string` or `table`, optional): Job(s) required to access the crafting menu.
--- - **gang** (`string` or `table`, optional): Gang(s) required to access the crafting menu.
--- - **onBack** (`function`, optional): Function to call when returning from the menu.
---
---@usage
--- ```lua
--- craftingMenu({
--- craftable = {
--- Header = "Weapon Crafting",
--- Recipes = {
--- [1] = {
--- ["weapon_pistol"] = { ["steel"] = 5, ["plastic"] = 2 },
--- amount = 1,
--- },
--- -- More recipes...
--- },
--- Anims = {
--- animDict = "amb@prop_human_parking_meter@male@idle_a",
--- anim = "idle_a",
--- },
--- },
--- coords = vector3(100.0, 200.0, 300.0),
--- stashTable = "crafting_stash",
--- job = "mechanic", -- Optional
--- onBack = function() print("Returning to previous menu") end,
--- })
--- ```
function craftingMenu ( data )
2025-03-06 23:49:07 +00:00
-- Prevent opening the menu if crafting is locked.
2025-03-01 12:58:43 +00:00
if CraftLock then return end
2025-03-06 23:49:07 +00:00
-- If a job or gang restriction exists and the player doesn't pass the job check, exit early.
2025-03-01 12:58:43 +00:00
if ( data.job or data.gang ) and not jobCheck ( data.job or data.gang ) then return end
2025-03-06 23:49:07 +00:00
-- Display a temporary "thinking" notification/menu depending on the configured system.
2025-03-01 12:58:43 +00:00
if Config.System . Menu == " jim " then
triggerNotify ( nil , " Thinking " , " info " )
else
openMenu ( { { header = " Thinking... " , icon = " fas fa-hourglass-end " , isMenuHeader = true } } , { header = " Crafting Menu " } )
end
2025-03-06 23:49:07 +00:00
-- Normalize stash name: if stashTable is provided, assign it to stashName.
2025-03-07 13:30:17 +00:00
data.stashName = data.stashTable or data.stashName
2025-03-06 23:49:07 +00:00
-- Initialize an empty menu table and a flag for job verification.
2025-03-01 12:58:43 +00:00
local Menu , hasjob = { } , false
2025-03-06 23:49:07 +00:00
-- Get the list of recipes from the provided data.
2025-03-01 12:58:43 +00:00
local Recipes = data.craftable . Recipes
2025-03-07 13:30:17 +00:00
local craftedItems = { }
2025-03-06 23:49:07 +00:00
-- Create a temporary table to collect required item amounts for each recipe.
2025-03-01 12:58:43 +00:00
local tempCarryTable = { }
for i = 1 , # Recipes do
2025-03-06 23:49:07 +00:00
-- Iterate over each key in the current recipe.
2025-03-01 12:58:43 +00:00
for k in pairs ( Recipes [ i ] ) do
2025-03-07 13:30:17 +00:00
if k == " hasCrafted " and not data.craftable . craftedItems then
craftedItems = GetMetadata ( nil , " craftedItems " ) or { }
data.craftable . craftedItems = craftedItems
end
2025-03-06 23:49:07 +00:00
-- Ignore meta keys: "amount", "metadata", "job", and "gang".
2025-03-01 12:58:43 +00:00
if k ~= " amount " and k ~= " metadata " and k ~= " job " and k ~= " gang " then
2025-03-06 23:49:07 +00:00
-- Record the required amount for this ingredient (default to 1 if not specified).
2025-03-01 12:58:43 +00:00
tempCarryTable [ k ] = Recipes [ i ] . amount or 1
end
end
end
2025-03-06 23:49:07 +00:00
-- Trigger a server callback to check if the player can carry the required items.
2025-03-01 12:58:43 +00:00
local canCarryTable = triggerCallback ( getScript ( ) .. ' :server:canCarry ' , tempCarryTable )
2025-03-06 23:49:07 +00:00
-- Process each recipe to build the menu entries.
2025-03-01 12:58:43 +00:00
for i = 1 , # Recipes do
2025-03-06 23:49:07 +00:00
-- Ensure the recipe has an "amount" field; default to 1 if missing.
2025-03-01 12:58:43 +00:00
if not Recipes [ i ] [ " amount " ] then Recipes [ i ] [ " amount " ] = 1 end
2025-03-06 23:49:07 +00:00
-- Loop through each key-value pair in the recipe.
2025-03-01 12:58:43 +00:00
for k , v in pairs ( Recipes [ i ] ) do
2025-03-06 23:49:07 +00:00
-- Skip meta keys that are not ingredients.
local excludeKeys = {
amount = true ,
metadata = true ,
description = true ,
info = true ,
job = true ,
gang = true ,
oneUse = true ,
slot = true ,
blueprintRef = true ,
craftingLevel = true ,
craftedItems = true ,
hasCrafted = true ,
2025-03-07 13:30:17 +00:00
exp = true ,
2025-03-06 23:49:07 +00:00
}
if not excludeKeys [ k ] then
-- Check job requirements if specified for the recipe.
2025-03-01 12:58:43 +00:00
if Recipes [ i ] . job then
for l , b in pairs ( Recipes [ i ] . job ) do
2025-03-06 23:49:07 +00:00
-- hasJob returns true if the player meets the job criteria.
2025-03-01 12:58:43 +00:00
hasjob = hasJob ( l , nil , b )
if hasjob == true then break end
end
2025-03-06 23:49:07 +00:00
else
hasjob = true
end
-- Initialize variables for menu display text, disable flag, and any metadata.
local setheader , settext , disable , metadata = " " , " " , false , ( Recipes [ i ] [ " metadata " ] or Recipes [ i ] [ " info " ] or nil )
2025-03-01 12:58:43 +00:00
if hasjob then
2025-03-06 23:49:07 +00:00
-- Build tables for ingredient details.
2025-03-01 12:58:43 +00:00
local itemTable = { }
local metaTable = { }
2025-03-06 23:49:07 +00:00
-- Iterate over the ingredients for the current key.
2025-03-01 12:58:43 +00:00
for l , b in pairs ( Recipes [ i ] [ tostring ( k ) ] ) do
2025-03-06 23:49:07 +00:00
-- Append item label and quantity to the settext string.
-- Use a line break (br) if settext is not empty.
2025-03-01 12:58:43 +00:00
settext = settext .. ( settext ~= " " and br or " " ) .. ( Items [ l ] and Items [ l ] . label or " error - " .. l ) .. ( b > 1 and " x " .. b or " " )
2025-03-06 23:49:07 +00:00
-- Populate the metaTable with item labels and their amounts.
2025-03-01 12:58:43 +00:00
metaTable [ Items [ l ] and Items [ l ] . label or " error - " .. l ] = b
2025-03-06 23:49:07 +00:00
-- Build a simple table of items required.
2025-03-01 12:58:43 +00:00
itemTable [ l ] = b
2025-03-06 23:49:07 +00:00
Wait ( 0 ) -- Yield to avoid freezing the game.
2025-03-01 12:58:43 +00:00
end
2025-03-06 23:49:07 +00:00
-- Wait until the server callback (canCarryTable) has returned.
2025-03-01 12:58:43 +00:00
while not canCarryTable do Wait ( 0 ) end
2025-03-06 23:49:07 +00:00
-- Determine if the recipe should be disabled by checking if the player has the required items.
2025-03-01 12:58:43 +00:00
disable = not checkHasItem ( data.stashName , itemTable )
2025-03-06 23:49:07 +00:00
-- Construct the header text for this menu item using metadata or default item label.
setheader = ( ( metadata and metadata.label ) or ( Items [ tostring ( k ) ] and Items [ tostring ( k ) ] . label ) or " error - " .. tostring ( k ) )
.. ( Recipes [ i ] [ " amount " ] > 1 and " x " .. Recipes [ i ] [ " amount " ] or " " )
-- Append an emoji to indicate carry status:
-- If not disabled and the player cannot carry the item, append 📦,
-- otherwise append ✔️ if they can carry it.
-- if jim-crafting and its a blueprint item that has/hasnt been crafting prefix with ✨ to represent its a new item
2025-03-01 12:58:43 +00:00
if not disable then
2025-03-06 23:49:07 +00:00
if not canCarryTable [ k ] then
setheader = setheader .. " 📦 "
else
setheader = setheader .. " ✔️ "
end
elseif not canCarryTable [ k ] then
setheader = setheader .. " 📦 "
end
if Recipes [ i ] [ " hasCrafted " ] ~= nil then
if craftedItems [ k ] == nil then
setheader = " ✨ " .. setheader
end
end
-- Add the constructed menu item into the Menu table.
2025-03-01 12:58:43 +00:00
Menu [ # Menu + 1 ] = {
2025-03-06 23:49:07 +00:00
-- Show an arrow if the item is enabled and can be carried.
2025-03-01 12:58:43 +00:00
arrow = not disable and canCarryTable [ k ] ,
2025-03-06 23:49:07 +00:00
-- Disable the menu item based on the state of QBMenuExport and carry-check.
isMenuHeader = disable or not canCarryTable [ k ] ,
-- Set icon and image for the menu item (using metadata image if available).
2025-03-01 12:58:43 +00:00
icon = invImg ( ( metadata and metadata.image ) or tostring ( k ) ) ,
image = invImg ( ( metadata and metadata.image ) or tostring ( k ) ) ,
2025-03-06 23:49:07 +00:00
-- Final header text, appending ❌ if disabled or cannot be carried.
2025-03-01 12:58:43 +00:00
header = setheader .. ( ( disable or not canCarryTable [ k ] ) and " ❌ " or " " ) ,
2025-03-06 23:49:07 +00:00
-- Set description text if QBMenuExport is started.
txt = ( isStarted ( QBMenuExport ) or disable ) and settext or nil ,
-- Attach the metadata table containing ingredient details.
2025-03-01 12:58:43 +00:00
metadata = metaTable ,
2025-03-06 23:49:07 +00:00
-- Define the onSelect function to trigger crafting actions if the item is selectable.
2025-03-01 12:58:43 +00:00
onSelect = ( ( not disable and canCarryTable [ k ] ) and ( function ( )
2025-03-06 23:49:07 +00:00
-- Build transaction data with details needed for crafting.
local transdata = {
item = k ,
craft = data.craftable . Recipes [ i ] ,
craftable = data.craftable ,
coords = data.coords ,
stashName = data.stashName ,
onBack = data.onBack ,
metadata = metadata
}
-- Call multiCraft or makeItem based on configuration.
if Config.Crafting . MultiCraft then
multiCraft ( transdata )
else
makeItem ( transdata )
end
2025-03-01 12:58:43 +00:00
end ) or nil ) ,
}
end
end
2025-03-06 23:49:07 +00:00
Wait ( 0 ) -- Yield within the loop to maintain responsiveness.
2025-03-01 12:58:43 +00:00
end
end
2025-03-06 23:49:07 +00:00
-- Open the final crafting menu with the built Menu table and provided header/onBack configuration.
openMenu ( Menu , {
header = data.craftable . Header ,
headertxt = data.craftable . Headertxt ,
onBack = data.onBack or nil ,
canClose = true ,
onExit = function ( ) end ,
} )
-- Trigger an action (likely camera or player focus) to look at the specified coordinates.
2025-03-01 12:58:43 +00:00
lookEnt ( data.coords )
end
2025-03-06 23:49:07 +00:00
2025-03-01 12:58:43 +00:00
--- Opens a menu for selecting the quantity to craft.
---
--- This function presents the player with options to craft multiple quantities of an item, based on `Config.Crafting.MultiCraftAmounts`.
---
---@param data table A table containing crafting data.
--- - **item** (`string`): The item to craft.
--- - **craft** (`table`): The crafting recipe for the item.
--- - **craftable** (`table`): The crafting options and settings.
--- - **coords** (`vector3`): The coordinates where the crafting is taking place.
--- - **stashName** (`string` or `table`, optional): The stash name(s) to check for item availability.
--- - **onBack** (`function`, optional): Function to call when returning from the menu.
--- - **metadata** (`table`, optional): Metadata for the crafted item.
---
---@usage
--- ```lua
--- multiCraft({
--- item = "weapon_pistol",
--- craft = { ["weapon_pistol"] = { ["steel"] = 5, ["plastic"] = 2 }, amount = 1 },
--- craftable = craftingOptions,
--- coords = vector3(100.0, 200.0, 300.0),
--- stashName = "crafting_stash",
--- onBack = function() craftingMenu(data) end,
--- metadata = { label = "Custom Pistol", image = "custom_pistol.png" },
--- })
--- ```
function multiCraft ( data )
local Menu = { }
local success = Config.Crafting . MultiCraftAmounts
local metadata = data.metadata or nil
Menu [ # Menu + 1 ] = {
isMenuHeader = true ,
icon = invImg ( metadata and metadata.image or data.item ) ,
header = metadata and metadata.label or Items [ data.item ] . label ,
}
for k in pairsByKeys ( success ) do
local settext = " "
local itemTable = { }
for l , b in pairs ( data.craft [ data.item ] ) do
itemTable [ l ] = ( b * k )
settext = settext .. ( settext ~= " " and br or " " ) .. Items [ l ] . label .. ( b * k > 1 and " - x " .. b * k or " " )
Wait ( 0 )
end
local disable , stashname = checkHasItem ( data.stashName , itemTable )
Menu [ # Menu + 1 ] = {
isMenuHeader = not disable ,
arrow = disable ,
header = " Craft - x " .. k * data.craft . amount ,
txt = settext ,
onSelect = function ( )
2025-03-06 23:49:07 +00:00
makeItem ( {
item = data.item ,
craft = data.craft ,
craftable = data.craftable ,
amount = k ,
coords = data.coords ,
stashName = stashname ,
stashTable = data.stashName ,
onBack = data.onBack ,
metadata = data.metadata
} )
2025-03-01 12:58:43 +00:00
end ,
}
end
openMenu ( Menu , { header = data.craftable . Header , onBack = function ( ) craftingMenu ( data ) end , } )
end
--- Initiates the crafting process for a specified item.
---
--- This function handles the crafting animation, progress bar, item removal, and item creation.
---
---@param data table A table containing crafting data.
--- - **item** (`string`): The item to craft.
--- - **craft** (`table`): The crafting recipe for the item.
--- - **craftable** (`table`): The crafting options and settings.
--- - **amount** (`number`, optional): The quantity to craft. Default is `1`.
--- - **coords** (`vector3`): The coordinates where the crafting is taking place.
--- - **stashName** (`string` or `table`, optional): The stash name(s) to remove items from.
--- - **stashTable** (`string` or `table`, optional): Alias for `stashName`.
--- - **onBack** (`function`, optional): Function to call when returning from the menu.
--- - **metadata** (`table`, optional): Metadata for the crafted item.
---
---@usage
--- ```lua
--- makeItem({
--- item = "weapon_pistol",
--- craft = { ["weapon_pistol"] = { ["steel"] = 5, ["plastic"] = 2 }, amount = 1 },
--- craftable = craftingOptions,
--- amount = 2,
--- coords = vector3(100.0, 200.0, 300.0),
--- stashName = "crafting_stash",
--- onBack = function() craftingMenu(data) end,
--- metadata = { label = "Custom Pistol", image = "custom_pistol.png" },
--- })
--- ```
function makeItem ( data )
if CraftLock then return end
CraftLock = true
if data.stashTable then data.stashName = data.stashTable end
local bartime = data.craftable . progressBar and data.craftable . progressBar.time or 5000
2025-03-06 23:49:07 +00:00
local bartext = ( data.craftable . progressBar and data.craftable . progressBar.label ) or ( Loc [ Config.Lan ] . progressbar and Loc [ Config.Lan ] . progressbar [ " progress_make " ] ) or " Making "
2025-03-01 12:58:43 +00:00
local animDict = data.craftable . Anims and data.craftable . Anims.animDict or " amb@prop_human_parking_meter@male@idle_a "
local anim = data.craftable . Anims and data.craftable . Anims.anim or " idle_a "
local amount = data.amount and ( data.amount ~= 1 ) and data.amount or 1
local metadata = data.metadata or nil
local prop = data.craftable . Anims and data.craftable . Anims.prop or nil
2025-03-06 23:49:07 +00:00
local canReturn = true
2025-03-01 12:58:43 +00:00
local crafted , crafting = true , true
local cam = createTempCam ( PlayerPedId ( ) , data.coords )
startTempCam ( cam )
for i = 1 , amount do
2025-03-06 23:49:07 +00:00
countTable ( data.craft )
2025-03-01 12:58:43 +00:00
for k , v in pairs ( data.craft ) do
2025-03-06 23:49:07 +00:00
local excludeKeys = {
amount = true ,
info = true ,
metadata = true ,
description = true ,
job = true ,
gang = true ,
oneUse = true ,
slot = true ,
blueprintRef = true ,
craftingLevel = true ,
craftedItems = true ,
hasCrafted = true ,
2025-03-07 13:30:17 +00:00
exp = true ,
2025-03-06 23:49:07 +00:00
}
if not excludeKeys [ k ] then
2025-03-01 12:58:43 +00:00
if type ( v ) == " table " then
for l , b in pairs ( v ) do
if crafting and progressBar ( {
label = " Using " .. b .. " " .. Items [ l ] . label ,
time = 1000 ,
cancel = true ,
dict = ' pickup_object ' ,
anim = " putdown_low " ,
flag = 48 ,
icon = l ,
} ) then
TriggerEvent ( ( isStarted ( QBInv ) and QBInvNew and " qb- " or " " ) .. " inventory:client:ItemBox " , Items [ l ] , " use " , b ) -- Show item box for each item
else
crafted , crafting = false , false
break
end
Wait ( 200 )
end
if crafted then
local craftProp = nil
if prop then
local model , pos , rot , bone = prop.model , prop.pos , prop.rot , prop.bone
craftProp = makeProp ( { prop = model , coords = vec4 ( 0 , 0 , 0 , 0 ) , true , true } )
AttachEntityToEntity ( craftProp , PlayerPedId ( ) , GetPedBoneIndex ( PlayerPedId ( ) , bone ) , pos.x , pos.y , pos.z , rot.x , rot.y , rot.z , true , true , false , true , 1 , true )
end
if crafting and progressBar ( {
label = bartext .. ( ( metadata and metadata.label ) or Items [ data.item ] . label ) ,
time = bartime ,
cancel = true ,
dict = animDict ,
anim = anim ,
flag = 49 ,
icon = data.item ,
} ) then
TriggerServerEvent ( getScript ( ) .. " :Crafting:GetItem " , data.item , data.craft , data.stashName , metadata )
2025-03-07 13:30:17 +00:00
CreateThread ( function ( )
if data.craft [ " hasCrafted " ] ~= nil then
debugPrint ( " hasCrafted Found, marking ' " .. data.item .. " ' as crafted for player " )
2025-03-06 23:49:07 +00:00
2025-03-07 13:30:17 +00:00
data.craftable . craftedItems [ data.item ] = true
triggerCallback ( getScript ( ) .. " :server:SetMetadata " , " craftedItems " , data.craftable . craftedItems )
end
Wait ( 100 )
if data.craft [ " exp " ] ~= nil then
craftingLevel += data.craft [ " exp " ] . give
jsonPrint ( data.craft [ " exp " ] )
debugPrint ( " exp Found, giving exp for ' " .. data.item .. " ' " )
triggerCallback ( getScript ( ) .. " :server:SetMetadata " , " craftingLevel " , craftingLevel )
end
end )
2025-03-06 23:49:07 +00:00
if data.craftable . Recipes [ 1 ] . oneUse == true then
removeItem ( " craftrecipe " , 1 , nil , data.craftable . Recipes [ 1 ] . slot )
local breakId = GetSoundId ( )
PlaySoundFromEntity ( breakId , " Drill_Pin_Break " , PlayerPedId ( ) , " DLC_HEIST_FLEECA_SOUNDSET " , 1 , 0 )
canReturn = false
-- If recipe is removed it doesn't try to open menu again, it was causing blank menus for some reason
end
2025-03-01 12:58:43 +00:00
else
crafting = false
break
end
if craftProp then destroyProp ( craftProp ) end
end
end
end
end
Wait ( 500 )
end
stopTempCam ( )
CraftLock = false
lockInv ( false )
2025-03-06 23:49:07 +00:00
if canReturn then craftingMenu ( data ) end
2025-03-01 12:58:43 +00:00
ClearPedTasks ( PlayerPedId ( ) )
end
--- Server event handler for giving the crafted item to the player.
---
--- This event is triggered when the crafting process is completed successfully.
---
--- @param ItemMake string The item being crafted.
--- @param craftable table The crafting recipe and details.
--- @param stashName string|table The stash name(s) to remove items from.
--- @param metadata table (optional) Metadata for the crafted item.
RegisterNetEvent ( getScript ( ) .. " :Crafting:GetItem " , function ( ItemMake , craftable , stashName , metadata )
local src , amount , stashItems = source , craftable and craftable.amount or 1 , nil
if stashName then
local itemRemove = { }
if type ( stashName ) == " table " then
for _ , name in pairs ( stashName ) do
stashItems = getStash ( name )
for k , v in pairs ( craftable [ ItemMake ] or { } ) do
for _ , b in pairs ( stashItems or { } ) do
if k == b.name then itemRemove [ k ] = v end
end
end
end
else
stashItems = getStash ( stashName )
for k , v in pairs ( craftable [ ItemMake ] or { } ) do
for _ , b in pairs ( stashItems or { } ) do
if k == b.name then itemRemove [ k ] = v end
end
end
end
stashRemoveItem ( stashItems , stashName , itemRemove )
else
if craftable then
for k , v in pairs ( craftable [ ItemMake ] or { } ) do
2025-03-06 23:49:07 +00:00
removeItem ( tostring ( k ) , v , src )
2025-03-01 12:58:43 +00:00
end
end
end
2025-03-06 23:49:07 +00:00
addItem ( ItemMake , amount , metadata , src )
2025-03-01 12:58:43 +00:00
--if isStarted("core_skills") then exports["core_skills"]:AddExperience(src, 2) end
end )
--- Opens a selling menu based on the provided data.
---
--- This function checks available items to sell, prepares the menu options, and opens the selling menu.
---
---@param data table A table containing selling menu data.
--- - **sellTable** (`table`): The selling options and settings.
--- - **Items** (`table`): A list of items that can be sold with their prices.
--- - **Header** (`string`, optional): The header/title of the selling menu.
--- - **ped** (`number`, optional): The ped entity involved in the selling interaction.
--- - **onBack** (`function`, optional): Function to call when returning from the menu.
---
---@usage
--- ```lua
--- sellMenu({
--- sellTable = {
--- Header = "Sell Items",
--- Items = {
--- ["gold_ring"] = 100,
--- ["diamond"] = 500,
--- },
--- },
--- ped = pedEntity,
--- onBack = function() print("Returning to previous menu") end,
--- })
--- ```
function sellMenu ( data )
local origData = data
local Menu = { }
if data.sellTable . Items then
local itemList = { }
for k , v in pairs ( data.sellTable . Items ) do itemList [ k ] = 1 end
local _ , hasTable = hasItem ( itemList )
for k , v in pairsByKeys ( data.sellTable . Items ) do
Menu [ # Menu + 1 ] = {
isMenuHeader = not hasTable [ k ] . hasItem ,
icon = invImg ( k ) ,
header = Items [ k ] . label .. ( hasTable [ k ] . hasItem and " 💰 (x " .. hasTable [ k ] . count .. " ) " or " " ) ,
txt = Loc [ Config.Lan ] . info [ " sell_all " ] .. v .. " " .. Loc [ Config.Lan ] . info [ " sell_each " ] ,
onSelect = function ( )
sellAnim ( { item = k , price = v , ped = data.ped , onBack = function ( ) sellMenu ( data ) end } )
end ,
}
end
else
for k , v in pairsByKeys ( data.sellTable ) do
if type ( v ) == " table " then
Menu [ # Menu + 1 ] = {
arrow = true ,
header = k ,
txt = " Amount of items: " .. countTable ( v.Items ) ,
onSelect = function ( )
v.onBack = function ( ) sellMenu ( origData ) end
v.sellTable = data.sellTable [ k ]
sellMenu ( v )
end ,
}
end
end
end
openMenu ( Menu , { header = data.sellTable . Header or " Amount of items: " .. countTable ( data.sellTable . Items ) , headertxt = data.sellTable . Header and " Amount of items: " .. countTable ( data.sellTable . Items ) or " " , canClose = true , onBack = data.onBack } )
end
--- Handles the selling animation and item transaction.
---
--- This function plays the selling animation, removes the item from the player's inventory, and gives the player money.
---
---@param data table A table containing selling data.
--- - **item** (`string`): The item to sell.
--- - **price** (`number`): The price per item.
--- - **ped** (`number`, optional): The ped entity involved in the selling interaction.
--- - **onBack** (`function`, optional): Function to call when returning from the menu.
---
---@usage
--- ```lua
--- sellAnim({
--- item = "gold_ring",
--- price = 100,
--- ped = pedEntity,
--- onBack = function() sellMenu(data) end,
--- })
--- ```
function sellAnim ( data )
if not hasItem ( data.item , 1 ) then
triggerNotify ( nil , Loc [ Config.Lan ] . error [ " dont_have " ] .. " " .. Items [ data.item ] . label , " error " )
return
end
for k , v in pairs ( GetGamePool ( ' CObject ' ) ) do
for _ , model in pairs ( { ` p_cs_clipboard ` } ) do
if GetEntityModel ( v ) == model then
if IsEntityAttachedToEntity ( data.ped , v ) then
DeleteObject ( v ) DetachEntity ( v , 0 , 0 ) SetEntityAsMissionEntity ( v , true , true )
Wait ( 100 ) DeleteEntity ( v )
end
end
end
end
TriggerServerEvent ( getScript ( ) .. " Sellitems " , data )
lookEnt ( data.ped )
local dict = " mp_common "
playAnim ( dict , " givetake2_a " , 0.3 , 2 )
playAnim ( dict , " givetake2_b " , 0.3 , 2 , data.ped )
Wait ( 2000 )
StopAnimTask ( PlayerPedId ( ) , dict , " givetake2_a " , 0.5 )
StopAnimTask ( data.ped , dict , " givetake2_b " , 0.5 )
if data.onBack then data.onBack ( ) end
end
--- Server event handler for processing the item sale.
---
--- This event removes the sold item from the player's inventory and adds money to their account.
---
---@param data table The data containing item and price information.
RegisterNetEvent ( getScript ( ) .. " Sellitems " , function ( data )
local src = source
local hasItems , hasTable = hasItem ( data.item , 1 , src )
if hasItems then
2025-03-06 23:49:07 +00:00
removeItem ( data.item , hasTable [ data.item ] . count , src )
2025-03-01 12:58:43 +00:00
TriggerEvent ( getScript ( ) .. " :server:FundPlayer " , ( hasTable [ data.item ] . count * data.price ) , " cash " , src )
else
triggerNotify ( nil , Loc [ Config.Lan ] . error [ " dont_have " ] .. " " .. Items [ data.item ] . label , " error " , src )
end
end )
--- Opens a shop interface for the player.
---
--- This function checks job requirements and opens the shop using the appropriate inventory system.
---
---@param data table A table containing shop data.
--- - **shop** (`string`): The shop identifier.
--- - **items** (`table`): The items available in the shop.
--- - **coords** (`vector3`): The coordinates where the shop interaction is happening.
--- - **job** (`string` or `table`, optional): Job(s) required to access the shop.
--- - **gang** (`string` or `table`, optional): Gang(s) required to access the shop.
---
---@usage
--- ```lua
--- openShop({
--- shop = "weapon_shop",
--- items = weaponShopItems,
--- coords = vector3(100.0, 200.0, 300.0),
--- job = "police",
--- })
--- ```
function openShop ( data )
if ( data.job or data.gang ) and not jobCheck ( data.job or data.gang ) then return end
if isStarted ( OXInv ) then
exports [ OXInv ] : openInventory ( ' shop ' , { type = data.shop } )
elseif isStarted ( QBInv ) then
if QBInvNew then
TriggerServerEvent ( getScript ( ) .. ' :server:OpenShopNewQB ' , data.shop ) -- i hate qb-inv
else
TriggerServerEvent ( Config.General . JimShops and " jim-shops:ShopOpen " or " inventory:server:OpenInventory " , " shop " , data.items . label , data.items )
end
else
TriggerServerEvent ( Config.General . JimShops and " jim-shops:ShopOpen " or " inventory:server:OpenInventory " , " shop " , data.items . label , data.items )
end
lookEnt ( data.coords )
end
--- Server event handler for opening a new QB inventory shop.
---
--- This event is triggered when using the new QB inventory system.
---
---@param data table The shop data to open.
RegisterNetEvent ( getScript ( ) .. ' :server:OpenShopNewQB ' , function ( data )
exports [ QBInv ] : OpenShop ( source , data )
end )
--- Server-side callback registration for checking if the player can carry items.
if isServer ( ) then
createCallback ( getScript ( ) .. ' :server:canCarry ' , function ( source , itemTable ) local result = canCarry ( itemTable , source ) return result end )
2025-02-21 13:47:15 +00:00
end