fix(qb-core): post-update recovery + centralizare notify 17mov_Hud

Restaurat jobs.lua din git (Quasar fork a suprascris joburile 17mov). Adăugat item map în items.lua (lipsea, rupt rv-maphold). Setat licences.driver = false în config.lua. Override QBCore.Functions.Notify + QBCore:Notify event → 17mov_Hud:ShowNotification (toate notificările merg automat prin 17mov_Hud).
This commit is contained in:
2026-04-03 02:47:59 +03:00
parent 06414ed181
commit e756e29294
1539 changed files with 51926 additions and 39806 deletions
@@ -0,0 +1,93 @@
--[[
Hi dear customer or developer, here you can fully configure your server's
framework or you could even duplicate this file to create your own framework.
If you do not have much experience, we recommend you download the base version
of the framework that you use in its latest version and it will work perfectly.
]]
if Config.Framework ~= 'esx' then
return
end
ESX = exports['es_extended']:getSharedObject()
function GetPlayerData()
return ESX.GetPlayerData()
end
local first = true
RegisterNetEvent('esx:playerLoaded', function()
if first then
first = false
CreateThread(function()
Wait(1000)
GetPlayerData(function(PlayerData)
PlayerJob = PlayerData.job
SetPedArmour(PlayerPedId(), PlayerData.metadata['armor'])
currentarmor = PlayerData.metadata['armor']
startedsync = true
Wait(100)
if Config.VestTexture then
local ped = PlayerPedId()
local PlayerData = GetPlayerData()
local GetArmor = GetPedArmour(ped)
currentVest = GetPedDrawableVariation(ped, 9)
currentVestTexture = GetPedTextureVariation(ped, 9)
if GetArmor >= 1 then
SetVest()
elseif GetArmor >= 51 then
SetHeavyVest()
end
end
end)
end)
end
end)
function SendTextMessage(msg, type)
if type == 'inform' then
lib.notify({
title = 'Inventory',
description = msg,
type = 'inform'
})
end
if type == 'error' then
lib.notify({
title = 'Inventory',
description = msg,
type = 'error'
})
end
if type == 'success' then
lib.notify({
title = 'Inventory',
description = msg,
type = 'success'
})
end
end
function ProgressBar(name, label, duration, useWhileDead, canCancel, disableControls, animation, prop, propTwo, onFinish, onCancel)
if lib.progressCircle({
duration = duration,
label = label,
position = 'bottom',
useWhileDead = useWhileDead,
canCancel = canCancel,
disable = disableControls,
anim = {
dict = animation.animDict,
clip = animation.anim,
flag = animation?.flags
},
prop = prop
}) then
onFinish()
else
if onCancel then
onCancel()
end
end
end
@@ -0,0 +1,112 @@
--[[
Hi dear customer or developer, here you can fully configure your server's
framework or you could even duplicate this file to create your own framework.
If you do not have much experience, we recommend you download the base version
of the framework that you use in its latest version and it will work perfectly.
]]
if Config.Framework ~= 'qb' then
return
end
QBCore = exports['qb-core']:GetCoreObject()
function GetPlayerData()
return QBCore.Functions.GetPlayers()
end
local first = true
RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function()
if first then
first = false
CreateThread(function()
Wait(1000)
GetPlayerData(function(PlayerData)
PlayerJob = PlayerData.job
SetPedArmour(PlayerPedId(), PlayerData.metadata['armor'])
currentarmor = PlayerData.metadata['armor']
startedsync = true
Wait(100)
if Config.VestTexture then
local ped = PlayerPedId()
local PlayerData = QS.GetPlayerData()
local GetArmor = GetPedArmour(ped)
currentVest = GetPedDrawableVariation(ped, 9)
currentVestTexture = GetPedTextureVariation(ped, 9)
if GetArmor >= 1 then
SetVest()
elseif GetArmor >= 51 then
SetHeavyVest()
end
end
end)
end)
end
end)
function SendTextMessage(msg, type)
if type == 'inform' then
lib.notify({
title = 'Inventory',
description = msg,
type = 'inform'
})
end
if type == 'error' then
lib.notify({
title = 'Inventory',
description = msg,
type = 'error'
})
end
if type == 'success' then
lib.notify({
title = 'Inventory',
description = msg,
type = 'success'
})
end
end
function ShowHelpNotification(msg)
BeginTextCommandDisplayHelp('STRING')
AddTextComponentSubstringPlayerName(msg)
EndTextCommandDisplayHelp(0, 0, false, -1)
end
function DrawText3D(x, y, z, text)
SetTextScale(0.4, 0.4)
SetTextFont(4)
SetTextProportional(1)
SetTextColour(255, 255, 255, 215)
SetTextEntry('STRING')
SetTextCentre(true)
AddTextComponentString(text)
SetDrawOrigin(x, y, z, 0)
DrawText(0.0, 0.0)
ClearDrawOrigin()
end
function ProgressBar(name, label, duration, useWhileDead, canCancel, disableControls, animation, prop, propTwo, onFinish, onCancel)
if lib.progressCircle({
duration = duration,
label = label,
position = 'bottom',
useWhileDead = useWhileDead,
canCancel = canCancel,
disable = disableControls,
anim = {
dict = animation.animDict,
clip = animation.anim,
flag = animation?.flags
},
prop = prop
}) then
onFinish()
else
if onCancel then
onCancel()
end
end
end
@@ -0,0 +1,33 @@
fx_version 'adamant'
game 'gta5'
lua54 'yes'
shared_scripts {
'@ox_lib/init.lua',
'shared/*.lua',
'locales/*.lua',
}
server_scripts {
'server/**/**/**.lua'
}
client_scripts {
'client/**/**/**.lua'
}
escrow_ignore {
'shared/config.lua',
'locales/*.lua',
'client/custom/framework/*.lua',
'server/custom/framework/*.lua',
}
dependencies {
'qs-inventory', -- Required.
'/server:4752', -- ⚠️PLEASE READ⚠️ This requires at least server build 4700 or higher
}
dependency '/assetpacks'
@@ -0,0 +1,8 @@
Locales['de'] = {
["ARMOR_NOTIFICATION_ALREADY_HAVE"] = "Du hast schon eine Weste an",
["ARMOR_NOTIFICATION_DONT_HAVE"] = "Du hast keine Weste!",
["ARMOR_PROGRESS_USE_ARMOR"] = "Kugelsichere Weste Anziehen ...",
["ARMOR_PROGRESS_USE_HEAVYARMOR"] = "Schwere Weste Anziehen ...",
["ARMOR_PROGRESS_REMOVE_ARMOR"] = "Weste ausziehen ...",
}
@@ -0,0 +1,8 @@
Locales['en'] = {
["ARMOR_NOTIFICATION_ALREADY_HAVE"] = "You already have a bulletproof vest",
["ARMOR_NOTIFICATION_DONT_HAVE"] = "You don't have a bulletproof vest",
["ARMOR_PROGRESS_USE_ARMOR"] = "Placing Armor ...",
["ARMOR_PROGRESS_USE_HEAVYARMOR"] = "Placing Heavy Armor ...",
["ARMOR_PROGRESS_REMOVE_ARMOR"] = "Removing Armor ...",
}
@@ -0,0 +1,8 @@
Locales['es'] = {
["ARMOR_NOTIFICATION_ALREADY_HAVE"] = "Ya tienes un chaleco antibalas",
["ARMOR_NOTIFICATION_DONT_HAVE"] = "No tienes un chaleco antibalas",
["ARMOR_PROGRESS_USE_ARMOR"] = "Colocando Armor...",
["ARMOR_PROGRESS_USE_HEAVYARMOR"] = "Colocando Heavy Armor...",
["ARMOR_PROGRESS_REMOVE_ARMOR"] = "Quitando Armor...",
}
@@ -0,0 +1,8 @@
Locales['it'] = {
["ARMOR_NOTIFICATION_ALREADY_HAVE"] = "Hai già un giubbotto anti-proiettile",
["ARMOR_NOTIFICATION_DONT_HAVE"] = "Non hai un giubbotto anti-proiettile",
["ARMOR_PROGRESS_USE_ARMOR"] = "Indossando giubbotto anti-proiettile...",
["ARMOR_PROGRESS_USE_HEAVYARMOR"] = "Indossando giubbotto anti-proiettile pesante...",
["ARMOR_PROGRESS_REMOVE_ARMOR"] = "Togliendo armatura...",
}
@@ -0,0 +1,34 @@
--[[
Hi dear customer or developer, here you can fully configure your server's
framework or you could even duplicate this file to create your own framework.
If you do not have much experience, we recommend you download the base version
of the framework that you use in its latest version and it will work perfectly.
]]
if Config.Framework ~= 'esx' then
return
end
ESX = exports['es_extended']:getSharedObject()
function RegisterUsableItem(name, cb)
exports['qs-inventory']:CreateUsableItem(name, cb)
end
function GetPlayerFromId(source)
return ESX.GetPlayerFromId(source)
end
function GetIdentifier(source)
return ESX.GetPlayerFromId(source).identifier
end
function AddItem(source, item, count, slot)
exports['qs-inventory']:AddItem(source, item, count, slot)
end
function RemoveItem(source, item, count)
local xPlayer = GetPlayerFromId(source)
xPlayer.removeInventoryItem(item, count)
end
@@ -0,0 +1,34 @@
--[[
Hi dear customer or developer, here you can fully configure your server's
framework or you could even duplicate this file to create your own framework.
If you do not have much experience, we recommend you download the base version
of the framework that you use in its latest version and it will work perfectly.
]]
if Config.Framework ~= 'qb' then
return
end
QBCore = exports['qb-core']:GetCoreObject()
function RegisterUsableItem(name, cb)
exports['qs-inventory']:CreateUsableItem(name, cb)
end
function GetPlayerFromId(player)
return QBCore.Functions.GetPlayer(player)
end
function GetIdentifier(player)
return QBCore.Functions.GetPlayer(player).PlayerData.citizenid
end
function AddItem(source, item, count, slot)
exports['qs-inventory']:AddItem(source, item, count, slot)
end
function RemoveItem(source, item, count)
local xPlayer = GetPlayerFromId(source)
xPlayer.Functions.RemoveItem(item, count)
end
@@ -0,0 +1,103 @@
Config = {}
Locales = {}
local esxHas = GetResourceState('es_extended') == 'started'
local qbHas = GetResourceState('qb-core') == 'started'
local qbxHas = GetResourceState('qbx_core') == 'started'
Config.Framework = esxHas and 'esx' or qbHas and 'qb' or qbxHas and 'qb' or 'esx'
--[[
Set the primary language for the resource.
Choose one of the default languages located in locales/*.
If your desired language is not listed, feel free to create your own!
]]
Config.Language = 'en'
--[[
General configuration settings for the resource.
Customize each option as needed.
]]
Config.Progressbar = { -- Timer durations for progress bars (in milliseconds).
UseArmor = 5000, -- Duration for applying regular armor.
UseHeavyArmor = 5000, -- Duration for applying heavy armor.
ResetArmor = 2500 -- Duration for removing the armor.
}
Config.SetPedArmour = { -- Amount of armor applied to the player.
UseArmor = 50, -- Armor value for regular armor.
UseHeavyArmor = 100, -- Armor value for heavy armor.
ResetArmor = 0 -- Armor value when the vest is removed.
}
--[[
Command used to remove the player's vest.
]]
Config.ResetArmor = 'resetarmor' -- Command to reset/remove your vest.
--[[
Configuration to check if a player has a vest equipped.
]]
Config.VestTexture = true -- Should vest textures be used? (true = Yes, false = No)
Config.CheckVest = {
check = false, -- Enable automatic vest checks? (true = Yes, false = No)
time = 30000 -- Frequency of checks (in milliseconds). Ignored if check = false.
}
--[[
Vest configuration based on player gender.
Customize the vest components for both male and female characters.
]]
Config.Vest = {
male = {
['bproof_1'] = 6, -- Main vest component ID for males.
['bproof_2'] = 1 -- Secondary vest texture ID for males.
},
female = {
['bproof_1'] = 0, -- Main vest component ID for females.
['bproof_2'] = 0 -- Secondary vest texture ID for females.
},
maleHeavy = {
['bproof_1'] = 27, -- Main heavy vest component ID for males.
['bproof_2'] = 2 -- Secondary heavy vest texture ID for males.
},
femaleHeavy = {
['bproof_1'] = 6, -- Main heavy vest component ID for females.
['bproof_2'] = 0 -- Secondary heavy vest texture ID for females.
}
}
--[[
Editable functions to handle vest application or removal.
These functions are only executed if VestTexture is set to true.
]]
function SetVest() -- Function to apply the regular vest texture.
local isMale = GetEntityModel(PlayerPedId()) == joaat('mp_m_freemode_01')
local vest = isMale and Config.Vest.male or Config.Vest.female
SetPedComponentVariation(PlayerPedId(), 9, vest['bproof_1'], vest['bproof_2'], 0)
end
function SetHeavyVest() -- Function to apply the heavy vest texture.
local isMale = GetEntityModel(PlayerPedId()) == joaat('mp_m_freemode_01')
local vest = isMale and Config.Vest.maleHeavy or Config.Vest.femaleHeavy
SetPedComponentVariation(PlayerPedId(), 9, vest['bproof_1'], vest['bproof_2'], 0)
end
function RemoveVest() -- Function to remove the vest texture.
SetPedComponentVariation(PlayerPedId(), 9, 0, 1, 0)
end
--[[
Debug mode configuration.
When enabled, detailed debug prints/logs are displayed for development purposes.
Use this only during development/testing phases.
]]
Config.Debug = false
@@ -0,0 +1,90 @@
--[[
Hi dear customer or developer, here you can fully configure your server's
framework or you could even duplicate this file to create your own framework.
If you do not have much experience, we recommend you download the base version
of the framework that you use in its latest version and it will work perfectly.
]]
if Config.Framework ~= 'esx' then
return
end
ESX = exports['es_extended']:getSharedObject()
RegisterNetEvent('esx:playerLoaded')
AddEventHandler('esx:playerLoaded', function(xPlayer)
Wait(10000)
StartThread()
end)
AddEventHandler('onClientResourceStart', function(resourceName)
if (GetCurrentResourceName() == resourceName) then
ESX = exports['es_extended']:getSharedObject()
Wait(10000)
StartThread()
end
end)
function getSex()
local promise = promise.new()
ESX.TriggerServerCallback('esx_skin:getPlayerSkin', function(skin, jobSkin)
promise:resolve(skin.sex)
end)
return Citizen.Await(promise)
end
function OpenStash(metadata)
local other = {}
other.maxweight = metadata.weight
other.slots = metadata.slots
TriggerServerEvent('inventory:server:OpenInventory', 'stash', 'Backpack_' .. metadata.ID, other)
TriggerEvent('inventory:client:SetCurrentStash', 'Backpack_' .. metadata.ID)
repeat Wait(1000) until IsNuiFocused() == false
TriggerEvent('backpacks:client:close', metadata.ID)
end
function SendTextMessage(msg, type)
if type == 'inform' then
lib.notify({
title = 'Inventory',
description = msg,
type = 'inform'
})
end
if type == 'error' then
lib.notify({
title = 'Inventory',
description = msg,
type = 'error'
})
end
if type == 'success' then
lib.notify({
title = 'Inventory',
description = msg,
type = 'success'
})
end
end
function Progressbar(name, label, duration, useWhileDead, canCancel, disableControls, animation, prop, propTwo, onFinish, onCancel)
if lib.progressCircle({
duration = duration,
label = label,
position = 'bottom',
useWhileDead = useWhileDead,
canCancel = canCancel,
disable = disableControls,
anim = {
dict = animation.animDict,
clip = animation.anim,
flag = animation?.flags
},
prop = prop
}) then
onFinish()
else
onCancel()
end
end
@@ -0,0 +1,85 @@
--[[
Hi dear customer or developer, here you can fully configure your server's
framework or you could even duplicate this file to create your own framework.
If you do not have much experience, we recommend you download the base version
of the framework that you use in its latest version and it will work perfectly.
]]
if Config.Framework ~= 'qb' then
return
end
QBCore = exports['qb-core']:GetCoreObject()
RegisterNetEvent('QBCore:Client:OnPlayerLoaded')
AddEventHandler('QBCore:Client:OnPlayerLoaded', function(xPlayer)
Wait(10000)
StartThread()
end)
AddEventHandler('onClientResourceStart', function(resourceName)
if (GetCurrentResourceName() == resourceName) then
QBCore = exports['qb-core']:GetCoreObject()
Wait(10000)
StartThread()
end
end)
function getSex()
return QBCore.Functions.GetPlayerData()?.charinfo?.gender
end
function OpenStash(metadata)
local other = {}
other.maxweight = metadata.weight
other.slots = metadata.slots
TriggerServerEvent('inventory:server:OpenInventory', 'stash', 'Backpack_' .. metadata.ID, other)
TriggerEvent('inventory:client:SetCurrentStash', 'Backpack_' .. metadata.ID)
repeat Wait(1000) until IsNuiFocused() == false
TriggerEvent('backpacks:client:close', metadata.ID)
end
function SendTextMessage(msg, type)
if type == 'inform' then
lib.notify({
title = 'Inventory',
description = msg,
type = 'inform'
})
end
if type == 'error' then
lib.notify({
title = 'Inventory',
description = msg,
type = 'error'
})
end
if type == 'success' then
lib.notify({
title = 'Inventory',
description = msg,
type = 'success'
})
end
end
function Progressbar(name, label, duration, useWhileDead, canCancel, disableControls, animation, prop, propTwo, onFinish, onCancel)
if lib.progressCircle({
duration = duration,
label = label,
position = 'bottom',
useWhileDead = useWhileDead,
canCancel = canCancel,
disable = disableControls,
anim = {
dict = animation.animDict,
clip = animation.anim,
flag = animation?.flags
},
prop = prop
}) then
onFinish()
else
onCancel()
end
end
@@ -0,0 +1,47 @@
if Config.Menu ~= 'esx_menu_default' then
return
end
function CreateBackpack(ID)
ESX.UI.Menu.Open('dialog', GetCurrentResourceName(), 'create_password',
{
title = Lang('CREATE_PASSWORD'),
}, function(data, menu)
local length = string.len(data.value)
if length <= 0 then
SendTextMessage(Lang('BAD_PASSWORD'), 'error')
elseif length < Config.PasswordLength.min then
SendTextMessage(Lang('MORE_PASSWORD'), 'error')
elseif length > Config.PasswordLength.max then
SendTextMessage(Lang('LESS_PASSWORD'), 'error')
else
SendTextMessage(Lang('ADDED_PASSWORD'), 'success')
TriggerServerEvent('backpacks:server:add_password', { ID = ID, password = data.value })
menu.close()
end
end, function(data, menu)
menu.close()
end)
end
function CheckMeta(backpack_metadata)
if backpack_metadata.locked then
ESX.UI.Menu.Open('dialog', GetCurrentResourceName(), 'enter_password',
{
title = Lang('INTRODUCE_PASSWORD'),
}, function(data, menu)
if backpack_metadata.password == data.value then
menu.close()
backpack_metadata.trypassword = data.value
OpenBackpack(backpack_metadata)
else
SendTextMessage(Lang('BAD_PASSWORD'), 'error')
menu.close()
end
end, function(data, menu)
menu.close()
end)
else
OpenBackpack(backpack_metadata)
end
end
@@ -0,0 +1,48 @@
if Config.Menu ~= 'ox_lib' then
return
end
function CreateBackpack(ID)
if not lib then
print('You need to uncomment the ox_lib export on line 10 of qs-backpacks/fxmanifest.lua')
return
end
local keyboard1 = lib.inputDialog(Lang('CREATE_PASSWORD') .. ' Min ' .. Config.PasswordLength.min .. ' Max ' .. Config.PasswordLength.max, { Lang('INTRODUCE_PASSWORD_2') })
if not keyboard1 then return end
local pass = tostring(keyboard1[1])
local length = string.len(pass)
if length <= 0 then
SendTextMessage(Lang('BAD_PASSWORD'), 'error')
return
end
if length < Config.PasswordLength.min then
SendTextMessage(Lang('MORE_PASSWORD'), 'error')
return
end
if length > Config.PasswordLength.max then
SendTextMessage(Lang('LESS_PASSWORD'), 'error')
return
end
SendTextMessage(Lang('ADDED_PASSWORD'), 'success')
TriggerServerEvent('backpacks:server:add_password', { ID = ID, password = pass })
end
function CheckMeta(backpack_metadata)
if backpack_metadata.locked then
if not lib then
print('You need to uncomment the ox_lib export on line 10 of qs-backpacks/fxmanifest.lua')
return
end
local data = lib.inputDialog(Lang('INTRODUCE_PASSWORD'), { Lang('INTRODUCE_PASSWORD_2') })
if not data then
SendTextMessage(Lang('BAD_PASSWORD'), 'error')
return
end
backpack_metadata.trypassword = data[1]
OpenBackpack(backpack_metadata)
else
OpenBackpack(backpack_metadata)
end
end
@@ -0,0 +1,64 @@
if Config.Menu ~= 'qb-menu' then
return
end
function CreateBackpack(ID)
local inputData = exports['qb-input']:ShowInput({
header = Lang('CREATE_PASSWORD') .. ' Min ' .. Config.PasswordLength.min .. ' Max ' .. Config.PasswordLength.max,
inputs = {
{
type = 'password',
isRequired = true,
name = 'pass', -- name of the input should be unique otherwise it might override
type = 'password', -- type of the input
text = Lang('INTRODUCE_PASSWORD_2'),
},
}
})
if inputData then
if not inputData.pass then return end
local length = string.len(inputData.pass)
if length <= 0 then
SendTextMessage(Lang('BAD_PASSWORD'), 'error')
return
end
if length < Config.PasswordLength.min then
SendTextMessage(Lang('MORE_PASSWORD'), 'error')
return
end
if length > Config.PasswordLength.max then
SendTextMessage(Lang('LESS_PASSWORD'), 'error')
return
end
SendTextMessage(Lang('ADDED_PASSWORD'), 'success')
TriggerServerEvent('backpacks:server:add_password', { ID = ID, password = inputData.pass })
end
end
function CheckMeta(backpack_metadata)
if backpack_metadata.locked then
local inputData = exports['qb-input']:ShowInput({
header = Lang('INTRODUCE_PASSWORD'),
inputs = {
{
type = 'password',
isRequired = true,
name = 'pass',
text = Lang('INTRODUCE_PASSWORD')
},
}
})
if inputData then
if not inputData.pass then
SendTextMessage(Lang('BAD_PASSWORD'), 'error')
return
end
backpack_metadata.trypassword = inputData.pass
OpenBackpack(backpack_metadata)
end
else
OpenBackpack(backpack_metadata)
end
end
@@ -0,0 +1,32 @@
if Config.SkinScript ~= 'esx_skin' then
return
end
function putClothes(backpack)
ESX.TriggerServerCallback('esx_skin:getPlayerSkin', function(skin, jobSkin)
local clothes = {
male = { ['bags_1'] = backpack.cloth['male'].bag['item'], ['bags_2'] = backpack.cloth['male'].bag['texture'] },
female = { ['bags_1'] = backpack.cloth['female'].bag['item'], ['bags_2'] = backpack.cloth['male'].bag['texture'] },
}
if skin.sex == 0 then
TriggerEvent('skinchanger:loadClothes', skin, clothes.male)
elseif skin.sex == 1 then
TriggerEvent('skinchanger:loadClothes', skin, clothes.female)
end
end)
end
function RemoveClothes()
local cloth = {
male = { ['bags_1'] = 0 },
female = { ['bags_1'] = 0 },
}
ESX.TriggerServerCallback('esx_skin:getPlayerSkin', function(skin, jobSkin)
if skin.sex == 0 then
TriggerEvent('skinchanger:loadClothes', skin, cloth.male)
elseif skin.sex == 1 then
TriggerEvent('skinchanger:loadClothes', skin, cloth.female)
end
end)
end
@@ -0,0 +1,19 @@
if Config.SkinScript ~= 'illenium-appearance' then
return
end
function putClothes(backpack)
if getSex() == 0 then
TriggerEvent('qb-clothing:client:loadOutfit', { outfitData = backpack.cloth['male'] })
else
TriggerEvent('qb-clothing:client:loadOutfit', { outfitData = backpack.cloth['female'] })
end
end
function RemoveClothes()
TriggerEvent('qb-clothing:client:loadOutfit', {
outfitData = {
['bag'] = { item = -1, texture = 0 }
}
})
end
@@ -0,0 +1,19 @@
if Config.SkinScript ~= 'qb-clothing' then
return
end
function putClothes(backpack)
if getSex() == 0 then
TriggerEvent('qb-clothing:client:loadOutfit', { outfitData = backpack.cloth['male'] })
else
TriggerEvent('qb-clothing:client:loadOutfit', { outfitData = backpack.cloth['female'] })
end
end
function RemoveClothes()
TriggerEvent('qb-clothing:client:loadOutfit', {
outfitData = {
['bag'] = { item = -1, texture = 0 }
}
})
end
@@ -0,0 +1,34 @@
fx_version 'adamant'
game 'gta5'
lua54 'yes'
shared_scripts {
'@ox_lib/init.lua',
'shared/*.lua',
'locales/*.lua',
'client/shared.lua'
}
server_scripts {
'server/**/**/**.lua'
}
client_scripts {
'client/**/**/**.lua'
}
escrow_ignore {
'shared/*.lua',
'locales/*.lua',
'client/custom/**/*.lua'
}
dependencies {
'/server:4752', -- ⚠️PLEASE READ⚠️ This requires at least server build 4700 or higher
'/assetpacks',
'qs-inventory'
}
dependency '/assetpacks'
@@ -0,0 +1,60 @@
# FOR QBCore `qb-core/shared/items`
```lua
['backpack'] = { ['name'] = 'backpack', ['label'] = 'backpack', ['weight'] = 0, ['type'] = 'item', ['image'] = 'backpack.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'No have' },
['backpack2'] = { ['name'] = 'backpack2', ['label'] = 'backpack2', ['weight'] = 0, ['type'] = 'item', ['image'] = 'backpack2.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'No have' },
['briefcase'] = { ['name'] = 'briefcase', ['label'] = 'briefcase', ['weight'] = 0, ['type'] = 'item', ['image'] = 'briefcase.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'No have' },
['paramedicbag'] = { ['name'] = 'paramedicbag', ['label'] = 'paramedicbag', ['weight'] = 0, ['type'] = 'item', ['image'] = 'paramedicbag.png', ['unique'] = true, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'No have' },
```
# FOR ESX `qs-inventory/shared/items.lua`
```lua
['backpack'] = {
['name'] = 'backpack',
['label'] = 'backpack',
['weight'] = 0,
['type'] = 'item',
['image'] = 'backpack.png',
['unique'] = true,
['useable'] = true,
['shouldClose'] = true,
['combinable'] = nil,
['description'] = 'No have'
},
['backpack2'] = {
['name'] = 'backpack2',
['label'] = 'backpack2',
['weight'] = 0,
['type'] = 'item',
['image'] = 'backpack2.png',
['unique'] = true,
['useable'] = true,
['shouldClose'] = true,
['combinable'] = nil,
['description'] = 'No have'
},
['briefcase'] = {
['name'] = 'briefcase',
['label'] = 'briefcase',
['weight'] = 0,
['type'] = 'item',
['image'] = 'briefcase.png',
['unique'] = true,
['useable'] = true,
['shouldClose'] = true,
['combinable'] = nil,
['description'] = 'No have'
},
['paramedicbag'] = {
['name'] = 'paramedicbag',
['label'] = 'paramedicbag',
['weight'] = 0,
['type'] = 'item',
['image'] = 'paramedicbag.png',
['unique'] = true,
['useable'] = true,
['shouldClose'] = true,
['combinable'] = nil,
['description'] = 'No have'
},
```
@@ -0,0 +1,14 @@
Locales['cs'] = {
['INTRODUCE_PASSWORD'] = 'Zadejte heslo',
['INTRODUCE_PASSWORD_2'] = 'Heslo',
['CREATE_PASSWORD'] = 'Vytvořit heslo',
['OPEN'] = 'Otevírám...',
['CLOSE'] = 'Zavírám...',
['BAD_PASSWORD'] = 'Nesprávné heslo...',
['ADDED_PASSWORD'] = 'Přidáno heslo..',
['MORE_PASSWORD'] = 'Heslo musí mít více znaků',
['LESS_PASSWORD'] = 'Heslo musí mít méně znaků',
['EMPLY_PASSWORD'] = 'Musíte něco vložit',
['NO_BACKPACK'] = 'Batoh nemáte po ruce.',
['FAILED_PASSWORD'] = 'Nepodařilo se přidat heslo.',
}
@@ -0,0 +1,14 @@
Locales['de'] = {
['INTRODUCE_PASSWORD'] = 'Passwort eingeben',
['INTRODUCE_PASSWORD_2'] = 'Passwort',
['CREATE_PASSWORD'] = 'Erstelle ein Passwort',
['OPEN'] = 'Öffnen...',
['CLOSE'] = 'Schließen...',
['BAD_PASSWORD'] = 'Falsches Passwort...',
['ADDED_PASSWORD'] = 'Passwort hinzugefügt...',
['MORE_PASSWORD'] = 'Das Passwort muss länger sein',
['LESS_PASSWORD'] = 'Das Passwort muss kürzer sein',
['EMPLY_PASSWORD'] = 'Du musst ein Passwort eingeben',
['NO_BACKPACK'] = 'Der Rucksack befindet sich nicht in deiner Hand.',
['FAILED_PASSWORD'] = 'Passwort konnte nicht hinzugefügt werden.',
}
@@ -0,0 +1,14 @@
Locales['en'] = {
['INTRODUCE_PASSWORD'] = 'Enter the password',
['INTRODUCE_PASSWORD_2'] = 'Password',
['CREATE_PASSWORD'] = 'Create a password',
['OPEN'] = 'Opening...',
['CLOSE'] = 'Closing...',
['BAD_PASSWORD'] = 'Incorrect password...',
['ADDED_PASSWORD'] = 'Added password..',
['MORE_PASSWORD'] = 'The password must have more characters',
['LESS_PASSWORD'] = 'The password must have fewer characters',
['EMPLY_PASSWORD'] = 'You need to put something',
['NO_BACKPACK'] = 'Backpack is not on your hand.',
['FAILED_PASSWORD'] = 'Failed to add password.',
}
@@ -0,0 +1,14 @@
Locales['es'] = {
['INTRODUCE_PASSWORD'] = 'Introduce la contraseña',
['INTRODUCE_PASSWORD_2'] = 'Contraseña',
['CREATE_PASSWORD'] = 'Crea una contraseña',
['OPEN'] = 'Abriendo...',
['CLOSE'] = 'Cerrando...',
['BAD_PASSWORD'] = 'Contraseña incorrecta...',
['ADDED_PASSWORD'] = 'Contraseña incorrecta...',
['MORE_PASSWORD'] = 'La contraseña tiene que tener mas caracteres',
['LESS_PASSWORD'] = 'La contraseña tiene que tener menos caracteres',
['EMPLY_PASSWORD'] = 'Necesitas poner algo',
['NO_BACKPACK'] = 'La mochila no esta en tu mano.',
['FAILED_PASSWORD'] = 'No pudiste agregar la contraseña.',
}
@@ -0,0 +1,14 @@
Locales['fr'] = {
['INTRODUCE_PASSWORD'] = 'Entrer un mot de passe',
['INTRODUCE_PASSWORD_2'] = 'Mot de passe',
['CREATE_PASSWORD'] = 'Créez votre mot de passe',
['OPEN'] = 'Ouverture...',
['CLOSE'] = 'Fermeture...',
['BAD_PASSWORD'] = 'Mot de passe incorrect...',
['ADDED_PASSWORD'] = 'Nouveau mot de passe..',
['MORE_PASSWORD'] = 'Votre mot de passe est trop court.',
['LESS_PASSWORD'] = 'Votre mot de passe est trop long.',
['EMPLY_PASSWORD'] = 'Vous devez remplir les champs.',
['NO_BACKPACK'] = "Le sac n'est pas dans votre inventaire.",
['FAILED_PASSWORD'] = "Erreur lors de l'ajout du mot de passe.",
}
@@ -0,0 +1,14 @@
Locales['hu'] = {
['INTRODUCE_PASSWORD'] = 'Írja be a jelszót',
['INTRODUCE_PASSWORD_2'] = 'Jelszó',
['CREATE_PASSWORD'] = 'Hozzon létre egy jelszót',
['OPEN'] = 'Nyítás...',
['CLOSE'] = 'Zárás...',
['BAD_PASSWORD'] = 'hibás jelszó...',
['ADDED_PASSWORD'] = 'Hozzáadta jelszót..',
['MORE_PASSWORD'] = 'A jelszónak több karakterből kell állnia',
['LESS_PASSWORD'] = 'A jelszónak kevesebb karakterből kell állnia',
['EMPLY_PASSWORD'] = 'Be kell tenni valamit,',
['NO_BACKPACK'] = 'A hátizsák nincs a kezedben.',
['FAILED_PASSWORD'] = 'Nem sikerült a jelszó hozzáadása.',
}
@@ -0,0 +1,14 @@
Locales['nl'] = {
['INTRODUCE_PASSWORD'] = 'Vul wachtwoord in',
['INTRODUCE_PASSWORD_2'] = 'Wachtwoord',
['CREATE_PASSWORD'] = 'Wachtwoord aanmaken',
['OPEN'] = 'Openen...',
['CLOSE'] = 'Sluiten...',
['BAD_PASSWORD'] = 'Onjuist wachtwoord...',
['ADDED_PASSWORD'] = 'Wachtwoord toegevoegd..',
['MORE_PASSWORD'] = 'Het wachtwoord voldoet niet aan de hoeveelheid tekens',
['LESS_PASSWORD'] = 'Het wachtwoord heeft teveel tekens',
['EMPLY_PASSWORD'] = 'Je moet iets ingeven',
['NO_BACKPACK'] = 'Je draagt momenteel geen tas in je hand.',
['FAILED_PASSWORD'] = 'Wachtwoord toevoegen mislukt.',
}
@@ -0,0 +1,14 @@
Locales['pl'] = {
['INTRODUCE_PASSWORD'] = 'Wprowadź hasło',
['INTRODUCE_PASSWORD_2'] = 'Podaj hasło',
['CREATE_PASSWORD'] = 'Utwórz hasło',
['OPEN'] = 'Otwarcie...',
['CLOSE'] = 'Zamknięcie...',
['BAD_PASSWORD'] = 'Nieprawidłowe hasło...',
['ADDED_PASSWORD'] = 'Dodane hasło...',
['MORE_PASSWORD'] = 'Hasło musi mieć więcej znaków',
['LESS_PASSWORD'] = 'Hasło musi mieć mniej znaków',
['EMPLY_PASSWORD'] = 'Musisz coś wpisać',
['NO_BACKPACK'] = 'Plecak nie jest pod ręką',
['FAILED_PASSWORD'] = 'Nie udało się dodać hasła.',
}
@@ -0,0 +1,14 @@
Locales['pt'] = {
['INTRODUCE_PASSWORD'] = 'Insira a senha',
['INTRODUCE_PASSWORD_2'] = 'Senha',
['CREATE_PASSWORD'] = 'Criar senha',
['OPEN'] = 'Abrindo...',
['CLOSE'] = 'Fechando...',
['BAD_PASSWORD'] = 'Senha incorreta...',
['ADDED_PASSWORD'] = 'Password adicionada.',
['MORE_PASSWORD'] = 'Senha muito curta',
['LESS_PASSWORD'] = 'Senha muito longa',
['EMPLY_PASSWORD'] = 'É necessário inserir algum valor',
['NO_BACKPACK'] = 'A mochila não está na sua mão.',
['FAILED_PASSWORD'] = 'Erro ao adicionar a senha.',
}
@@ -0,0 +1,151 @@
Config = Config or {}
-- Clarification if you are going to create more backpacks you have to add the information in these parts:
-- qs-inventory/config/metadata.js
-- Save information
--[[
} else if (itemData.name == "YOUR_BACKPACK_NAME") {
$(".item-info-title").html("<p>" + label + "</p>");
$(".item-info-description").html(
"<p><strong>ID: </strong><span>" +
itemData.info.ID +
"</span></p><p><strong>Weight: </strong><span>" +
itemData.info.weight +
"</span></p><p><strong>Slots: </strong><span>" +
itemData.info.slots +
"</span></p>"
);
]]
-- qs-inventory/server/custom/GiveItemToPlayer.lua
-- For giveitem admin
--[[
elseif itemData["name"] == "YOUR_BACKPACK_NAME" then
info.ID = 'backpack_'..math.random(111111,999999)
info.weight = 10000
info.slots = 10
]]
-- (IMPORTANT INTEGRATION WITH qs-advancedshops or qs-shops)
-- If you want to add the backpack to a qs-shop, you must add an ID to the item. this is the example :
--[[
qs-shops/config/config.lua or qs-advancedshops/config/shops.lua
[1] = {
name = "backpack",
label = 'Backpack',
price = 250,
amount = 100,
info = {}, -- If you put here info = {}, it will automatically take the weight of your configuration
type = "item",
slot = 1,
},
[2] = {
name = "my_custom_backpack",
label = 'UwU Backpack',
price = 250,
amount = 100,
info = { ID = 'ID_'..math.random(111111,999999), weight = 10000 , slots = 10}, -- If you put this information, it will take the information you put in it
type = "item",
slot = 2,
},
]]
-- (important) do not use both prop and cloth at same time just one.
Config.Items = {
['backpack'] = { --- Item name
slots = 10, -- Change in `qs-inventory/server/custom/GiveItemToPlayer.lua`
weight = 100000, -- Change in `qs-inventory/server/custom/GiveItemToPlayer.lua`
locked = false, -- If you want to have a password change false to true
prop = {
model = 'vw_prop_vw_backpack_01a',
animation = {
dict = 'amb@world_human_hiker_standing@female@base',
anim = 'base',
bone = 'Back', -- LeftHand | RightHand
attaching_position = {
x = -0.20, -- Up - Down
y = -0.10, -- Forward Backward
z = 0.0, -- Left - Right
x_rotation = 10.0,
y_rotation = 90.0,
z_rotation = 175.0,
}
},
},
},
['backpack2'] = {
slots = 6, -- Change in `qs-inventory/server/custom/GiveItemToPlayer.lua`
weight = 10000, -- Change in `qs-inventory/server/custom/GiveItemToPlayer.lua`
cloth = {
male = {
['bag'] = { item = 45, texture = 0 }
},
female = {
['bag'] = { item = 45, texture = 0 }
}
}
},
['briefcase'] = {
slots = 3,
weight = 5000,
locked = true, -- If you want to have a password change false to true
prop = {
model = 'prop_ld_suitcase_01',
animation = {
dict = 'missheistdocksprep1hold_cellphone',
anim = 'static',
bone = 'RightHand',
attaching_position = {
x = 0.10,
y = 0.0,
z = 0.0,
x_rotation = 0.0,
y_rotation = 280.0,
z_rotation = 53.0,
}
},
},
},
['paramedicbag'] = {
slots = 10, -- Change in `qs-inventory/server/custom/GiveItemToPlayer.lua`
weight = 10000, -- Change in `qs-inventory/server/custom/GiveItemToPlayer.lua`
prop = {
model = 'xm_prop_smug_crate_s_medical',
animation = {
dict = 'missheistdocksprep1hold_cellphone',
anim = 'static',
bone = 'RightHand',
attaching_position = {
x = 0.29,
y = -0.05,
z = 0.0,
x_rotation = -25.0,
y_rotation = 280.0,
z_rotation = 75.0,
}
},
}
},
}
Config.Bones = {
bones = {
['RightHand'] = {
bone = 57005,
current_active_porp = nil,
slot = -1,
},
['Back'] = {
bone = 24818,
current_active_porp = nil,
slot = -1,
},
['LeftHand'] = {
bone = 18905,
current_active_porp = nil,
slot = -1,
},
}
}
@@ -0,0 +1,92 @@
Config = Config or {}
Locales = Locales or {}
local esxHas = GetResourceState('es_extended') == 'started'
local qbHas = GetResourceState('qb-core') == 'started'
local qbxHas = GetResourceState('qbx_core') == 'started'
Config.Framework = esxHas and 'esx' or qbHas and 'qb' or qbxHas and 'qb' or 'esx'
--[[
Language settings.
Define the language file located in the locales folder.
]]
Config.Language = 'en' -- Set your lang in locales folder
--[[
Skin script configuration.
Supported options:
- 'qb-clothing': For servers using QBCore's clothing script.
- 'illenium-appearance': For servers using Illenium Appearance.
- 'esx_skin': For servers using the ESX Skin system.
]]
Config.SkinScript = 'illenium-appearance' -- 'qb-clothing', 'illenium-appearance', 'esx_skin'
--[[
Menu system configuration.
Supported options:
- 'qb-menu': For QBCore's menu system.
- 'ox_lib': For Ox Library's menu system.
- 'esx_menu_default': For ESX's default menu system.
]]
Config.Menu = 'qb-menu' -- 'qb-menu', 'ox_lib', 'esx_menu_default'
--[[
Hotbar slots configuration.
Specify the slots that will act as your hotbar.
Use an array of numbers, where each number represents a slot.
]]
Config.Hotbar = {
1, 2, 3, 4, 5
}
--[[
Backpack opening/closing duration.
Configure the time (in seconds) it takes to open or close the backpack.
]]
Config.duration = {
open = 1, -- Time in seconds to open the backpack.
close = 1 -- Time in seconds to close the backpack.
}
--[[
Password length settings.
Define the minimum and maximum length for passwords when required.
]]
Config.PasswordLength = {
min = 3, -- Minimum password length.
max = 5 -- Maximum password length.
}
--[[
Animation configuration for different backpack actions.
Each action includes:
- Dict: The animation dictionary used for the action.
- Anim: The specific animation name.
- Flag: The animation flag (e.g., 49 = upper body only).
]]
Config.Animation = {
close = { -- Animation for closing the backpack.
Dict = 'clothingshirt', -- Animation dictionary.
Anim = 'try_shirt_positive_d', -- Animation name.
Flag = 49 -- Animation flag.
},
open = { -- Animation for opening the backpack.
Dict = 'clothingshirt', -- Animation dictionary.
Anim = 'try_shirt_positive_d', -- Animation name.
Flag = 49 -- Animation flag.
},
inBackpack = { -- Animation for interacting with items in the backpack.
Dict = 'clothingshirt', -- Animation dictionary.
Anim = 'try_shirt_positive_d' -- Animation name.
},
}
@@ -0,0 +1,32 @@
Example to use a custom trigger
```lua
local data = {
label = 'License Example', ---@param Label on inventory
type = 'Weapon license', ---@param Licence type
name = 'id_card', ---@param Item name
price = 10, --- @param Price of licencie
}
TriggerEvent('qs-licenses:client:Target', data)
```
You need go to qs-inventory\config\metadata.js
Modify id_card
```js
if (itemData.name == "id_card") {
$(".item-info-title").html("<p>" + itemData.info.label + "</p>");
$(".item-info-description").html(
"</p><p><strong>First Name: </strong><span>" +
itemData.info.firstname +
"</span></p><p><strong>Last Name: </strong><span>" +
itemData.info.lastname +
"</span></p><p><strong>Birth Date: </strong><span>" +
itemData.info.birthdate +
"</span></p><p><strong>Gender: </strong><span>" +
gender +
"</span></p><p><strong>Type: </strong><span>" +
itemData.info.type +
"</span></p>"
);
};
```
@@ -0,0 +1,119 @@
if Config.Framework ~= 'esx' then
return
end
--[[ Uncomment if use old version
ESX = nil
CreateThread(function()
while ESX == nil do
TriggerEvent('esx:getSharedObject', function(obj) ESX = obj end)
Citizen.Wait(0)
end
end)
]]
ESX = exports['es_extended']:getSharedObject()
RegisterNetEvent('esx:playerLoaded')
AddEventHandler('esx:playerLoaded', function(playerData)
CreateBlips()
end)
function GetJob()
return ESX.GetPlayerData().job.name
end
function SendTextMessage(msg, type)
if type == 'inform' then
lib.notify({
title = 'Inventory',
description = msg,
type = 'inform'
})
end
if type == 'error' then
lib.notify({
title = 'Inventory',
description = msg,
type = 'error'
})
end
if type == 'success' then
lib.notify({
title = 'Inventory',
description = msg,
type = 'success'
})
end
end
function Progressbar(name, label, duration, useWhileDead, canCancel, disableControls, animation, prop, propTwo, onFinish, onCancel)
if lib.progressCircle({
duration = duration,
label = label,
position = 'bottom',
useWhileDead = useWhileDead,
canCancel = canCancel,
disable = disableControls,
anim = {
dict = animation.animDict,
clip = animation.anim,
flag = animation?.flags
},
prop = prop
}) then
onFinish()
else
onCancel()
end
end
RegisterNetEvent('qs-licenses:ShowId', function(sourceId, character)
local sourcePos = GetEntityCoords(GetPlayerPed(GetPlayerFromServerId(sourceId)), false)
local pos = GetEntityCoords(PlayerPedId(), false)
if sourceId == GetPlayerServerId(PlayerId()) then
ShowCard()
end
local dist = GetDistanceBetweenCoords(pos.x, pos.y, pos.z, sourcePos.x, sourcePos.y, sourcePos.z, true)
if ((dist > 0 and dist < 2.5) or sourceId == GetPlayerServerId(PlayerId())) then
TriggerEvent('chat:addMessage', {
template = '<div class="chat-message advert"><div class="chat-message-body"><strong style="font-size: 20px">{0}</strong><br>Firstname:</strong> {1} <br><strong>Lastname:</strong> {2} <br><strong>Date of birth:</strong> {3} <br><strong>Gender:</strong> {4}</div></div>',
args = { character.type, character.firstname, character.lastname, character.birthdate, character.gender }
})
end
end)
local texts = {}
if GetResourceState('qs-textui') == 'started' then
function DrawText3D(x, y, z, text, id, key)
local _id = id
if not texts[_id] then
CreateThread(function()
texts[_id] = 5
while texts[_id] > 0 do
texts[_id] = texts[_id] - 1
Wait(0)
end
texts[_id] = nil
exports['qs-textui']:DeleteDrawText3D(id)
end)
TriggerEvent('textui:DrawText3D', x, y, z, text, id, key)
end
texts[_id] = 5
end
else
function DrawText3D(x, y, z, text)
SetTextScale(0.35, 0.35)
SetTextFont(4)
SetTextProportional(1)
SetTextColour(255, 255, 255, 215)
SetTextEntry('STRING')
SetTextCentre(true)
AddTextComponentString(text)
SetDrawOrigin(x, y, z, 0)
DrawText(0.0, 0.0)
local factor = text:len() / 370
DrawRect(0.0, 0.0 + 0.0125, 0.017 + factor, 0.03, 0, 0, 0, 75)
ClearDrawOrigin()
end
end
@@ -0,0 +1,109 @@
if Config.Framework ~= 'qb' then
return
end
QBCore = exports['qb-core']:GetCoreObject()
RegisterNetEvent('QBCore:Client:OnPlayerLoaded')
AddEventHandler('QBCore:Client:OnPlayerLoaded', function(playerData)
CreateBlips()
end)
function GetJob()
return QBCore.Functions.GetPlayerData().job.name
end
function SendTextMessage(msg, type)
if type == 'inform' then
lib.notify({
title = 'Inventory',
description = msg,
type = 'inform'
})
end
if type == 'error' then
lib.notify({
title = 'Inventory',
description = msg,
type = 'error'
})
end
if type == 'success' then
lib.notify({
title = 'Inventory',
description = msg,
type = 'success'
})
end
end
function Progressbar(name, label, duration, useWhileDead, canCancel, disableControls, animation, prop, propTwo, onFinish, onCancel)
if lib.progressCircle({
duration = duration,
label = label,
position = 'bottom',
useWhileDead = useWhileDead,
canCancel = canCancel,
disable = disableControls,
anim = {
dict = animation.animDict,
clip = animation.anim,
flag = animation?.flags
},
prop = prop
}) then
onFinish()
else
onCancel()
end
end
RegisterNetEvent('qs-licenses:ShowId', function(sourceId, character)
local sourcePos = GetEntityCoords(GetPlayerPed(GetPlayerFromServerId(sourceId)), false)
local pos = GetEntityCoords(PlayerPedId(), false)
if sourceId == GetPlayerServerId(PlayerId()) then
ShowCard()
end
local dist = GetDistanceBetweenCoords(pos.x, pos.y, pos.z, sourcePos.x, sourcePos.y, sourcePos.z, true)
if ((dist > 0 and dist < 2.5) or sourceId == GetPlayerServerId(PlayerId())) then
TriggerEvent('chat:addMessage', {
template = '<div class="chat-message advert"><div class="chat-message-body"><strong style="font-size: 20px">{0}</strong><br>Firstname:</strong> {1} <br><strong>Lastname:</strong> {2} <br><strong>Date of birth:</strong> {3} <br><strong>Gender:</strong> {4}</div></div>',
args = { character.type, character.firstname, character.lastname, character.birthdate, character.gender }
})
end
end)
local texts = {}
if GetResourceState('qs-textui') == 'started' then
function DrawText3D(x, y, z, text, id, key)
local _id = id
if not texts[_id] then
CreateThread(function()
texts[_id] = 5
while texts[_id] > 0 do
texts[_id] = texts[_id] - 1
Wait(0)
end
texts[_id] = nil
exports['qs-textui']:DeleteDrawText3D(id)
end)
TriggerEvent('textui:DrawText3D', x, y, z, text, id, key)
end
texts[_id] = 5
end
else
function DrawText3D(x, y, z, text)
SetTextScale(0.35, 0.35)
SetTextFont(4)
SetTextProportional(1)
SetTextColour(255, 255, 255, 215)
SetTextEntry('STRING')
SetTextCentre(true)
AddTextComponentString(text)
SetDrawOrigin(x, y, z, 0)
DrawText(0.0, 0.0)
local factor = text:len() / 370
DrawRect(0.0, 0.0 + 0.0125, 0.017 + factor, 0.03, 0, 0, 0, 75)
ClearDrawOrigin()
end
end
@@ -0,0 +1,28 @@
fx_version "adamant"
game "gta5"
lua54 'yes'
shared_scripts {
'@ox_lib/init.lua',
'shared/*.lua'
}
client_scripts {
'client/custom/*.lua',
'client/main.lua'
}
server_scripts {
'@mysql-async/lib/MySQL.lua',
'server/custom/*.lua',
'server/main.lua',
}
escrow_ignore {
'client/custom/*.lua',
'server/custom/*.lua',
'shared/*.lua'
}
dependency '/assetpacks'
@@ -0,0 +1,53 @@
if Config.Framework ~= "esx" then
return
end
local version = GetResourceMetadata('es_extended', 'version', 0)
if version == '1.1.0' or version == '1.2.0' or version == 'legacy' then
ESX = nil
TriggerEvent('esx:getSharedObject', function(obj) ESX = obj end)
else
ESX = exports['es_extended']:getSharedObject()
end
function GetPlayerFromIdFramework(player)
return ESX.GetPlayerFromId(player)
end
function GetCharacterData(source)
local xPlayer = GetPlayerFromIdFramework(source)
local firstName, lastName, sex, dateofbirth
if xPlayer.get then
firstName = xPlayer.get("firstName")
lastName = xPlayer.get("lastName")
if xPlayer.get("sex") == 'm' then
sex = Lang('LICENSES_MAN_LABEL')
elseif xPlayer.get("sex") == 'f' then
sex = Lang('LICENSES_WOMEN_LABEL')
end
dateofbirth = xPlayer.get("dateofbirth") or "01/01/2000"
else
local name = MySQL.Sync.fetchAll("SELECT `firstname`, `lastname`, `dateofbirth`, `sex` FROM `users` WHERE `identifier`=@identifier", {["@identifier"] = ESX.GetIdentifier(source)})
firstName = name[1]?.firstname
lastName = name[1]?.lastname
if name[1]?.sex == 'm' then
sex = Lang('LICENSES_MAN_LABEL')
elseif name[1]?.sex == 'f' then
sex = Lang('LICENSES_WOMEN_LABEL')
end
dateofbirth = name[1]?.dateofbirth
end
return firstName, lastName, sex, dateofbirth
end
function GetBankMoney(source)
local xPlayer = GetPlayerFromIdFramework(source)
return xPlayer.getAccount('bank').money
end
function RemoveBankMoney(source, price)
local xPlayer = GetPlayerFromIdFramework(source)
xPlayer.removeAccountMoney('bank', price)
end
@@ -0,0 +1,36 @@
if Config.Framework ~= 'qb' then
return
end
QBCore = exports['qb-core']:GetCoreObject()
function GetPlayerFromIdFramework(player)
local Player = QBCore.Functions.GetPlayer(player)
if Player then
Player.citizenid = Player?.PlayerData?.citizenid
Player.identifier = Player?.PlayerData?.citizenid
Player.source = Player?.PlayerData?.source
end
return Player
end
function GetCharacterData(source)
local player = GetPlayerFromIdFramework(source)?.PlayerData?.charinfo
local sex
if player.gender == 0 then
sex = Lang('LICENSES_MAN_LABEL')
elseif player.gender == 1 then
sex = Lang('LICENSES_WOMEN_LABEL')
end
return player.firstname, player.lastname, sex, player.birthdate
end
function GetBankMoney(source)
local xPlayer = GetPlayerFromIdFramework(source)
return xPlayer?.PlayerData?.money['bank']
end
function RemoveBankMoney(source, price)
local xPlayer = GetPlayerFromIdFramework(source)
xPlayer.Functions.RemoveMoney('bank', price)
end
@@ -0,0 +1,75 @@
Config = Config or {}
local esxHas = GetResourceState('es_extended') == 'started'
local qbHas = GetResourceState('qb-core') == 'started'
local qbxHas = GetResourceState('qbx_core') == 'started'
Config.Framework = esxHas and 'esx' or qbHas and 'qb' or qbxHas and 'qb' or 'esx'
-- Marker configuration for the shop locations
Config.Marker = {
type = 2, -- Marker type (refer to GTA marker types)
scale = {x = 0.2, y = 0.2, z = 0.1}, -- Marker scale
colour = {r = 71, g = 181, b = 255, a = 120}, -- Marker color with transparency (RGBA)
movement = 1 -- Marker animation (0 = no movement, 1 = with movement)
}
-- Shop configuration
Config.Shops = {
[1] = {
name = 'id_card', -- Unique identifier for the item
text = "[E] - Identity License", -- Interaction text
label = 'ID', -- Item label
type = "Document", -- Item type
progbar = "Purchasing license...", -- Progress bar text
price = 150, -- Item price
isjob = false, -- Required job to access this shop (false = no job required)
timer = 2500, -- Interaction duration (milliseconds)
location = vec3(-545.08, -204.13, 38.22), -- Shop location (vector3 format)
blip = { -- Blip configuration for the map
enable = true, -- Enable or disable the blip
name = 'Identity License', -- Blip name
sprite = 409, -- Blip sprite (icon)
color = 0, -- Blip color
scale = 0.7 -- Blip size
},
},
[2] = {
name = 'weaponlicense', -- Unique identifier for the item
isjob = false, -- Required job to access this shop (false = no job required)
text = "[E] - Weapons License", -- Interaction text
label = 'License', -- Item label
type = "Weapons License", -- Item type
price = 10, -- Item price
progbar = "Purchasing license...", -- Progress bar text
timer = 2500, -- Interaction duration (milliseconds)
location = vec3(14.01, -1106.11, 29.8), -- Shop location (vector3 format)
blip = { -- Blip configuration for the map
enable = false, -- Enable or disable the blip
name = 'Weapons License', -- Blip name
sprite = 89, -- Blip sprite (icon)
color = 1, -- Blip color
scale = 0.5 -- Blip size
},
},
[3] = {
name = 'driver_license', -- Unique identifier for the item
isjob = false, -- Required job to access this shop (false = no job required)
text = "[E] - Driving License", -- Interaction text
label = 'Driving License', -- Item label
type = "License", -- Item type
price = 10, -- Item price
progbar = "Purchasing license...", -- Progress bar text
timer = 2500, -- Interaction duration (milliseconds)
location = vec3(239.78, -1380.27, 33.74), -- Shop location (vector3 format)
blip = { -- Blip configuration for the map
enable = true, -- Enable or disable the blip
name = 'Driving License', -- Blip name
sprite = 67, -- Blip sprite (icon)
color = 3, -- Blip color
scale = 0.6 -- Blip size
},
},
}
@@ -0,0 +1,27 @@
Config = Config or {}
Config.Language = 'en'
Config.Languages = {
['en'] = {
['LICENSES_PROGRESS'] = 'Getting licensed...',
['LICENSES_SUCCESS'] = 'Thanks for waiting, here is your new',
['LICENSES_NO_MONEY'] = "You don't have enough money",
['LICENSES_WOMEN_LABEL'] = 'Female',
['LICENSES_MAN_LABEL'] = 'Man',
['LICENSES_DIALOG_HEADER'] = 'Do you want to buy this license?',
['LICENSES_DIALOG_CONTENT'] = 'This license will cost you ${price} and will take {timer} seconds to complete.',
},
['es'] = {
['LICENSES_PROGRESS'] = 'Obteniendo licencia...',
['LICENSES_SUCCESS'] = 'Gracias por esperar, aquí tienes tu nueva',
['LICENSES_NO_MONEY'] = 'No tienes dinero suficiente',
['LICENSES_WOMEN_LABEL'] = 'Mujer',
['LICENSES_MAN_LABEL'] = 'Hombre',
['LICENSES_DIALOG_HEADER'] = '¿Quieres comprar esta licencia?',
['LICENSES_DIALOG_CONTENT'] = 'Esta licencia costará ${price} y tardará {timer} segundos en completarse.',
},
}
@@ -0,0 +1,16 @@
Config = {}
Config.WeapDraw = {
variants = { 130, 122, 3, 6, 8 },
weapons = {
'WEAPON_PISTOL',
'WEAPON_PISTOL_MK2',
'WEAPON_COMBATPISTOL',
'WEAPON_APPISTOL',
'WEAPON_PISTOL50',
'WEAPON_REVOLVER',
'WEAPON_SNSPISTOL',
'WEAPON_HEAVYPISTOL',
'WEAPON_VINTAGEPISTOL'
}
}
@@ -0,0 +1,24 @@
fx_version 'cerulean'
game 'gta5'
lua54 'yes'
shared_scripts {
'config.lua'
}
client_script {
'client.lua'
}
escrow_ignore {
'config.lua'
}
dependencies {
'/server:4752', -- ⚠️PLEASE READ⚠️ This requires at least server build 4700 or higher
'qs-inventory' -- Required.
}
dependency '/assetpacks'
@@ -0,0 +1,23 @@
if Config.Framework ~= 'esx' then
return
end
ESX = exports['es_extended']:getSharedObject()
RegisterNetEvent('esx:playerLoaded')
AddEventHandler('esx:playerLoaded', function()
Wait(3500)
ESX.PlayerLoaded = true
end)
function IsPlayerLoaded()
return ESX.PlayerLoaded
end
function GetPlayerData()
return ESX.GetPlayerData()
end
function GetInventory()
return GetPlayerData().inventory
end
@@ -0,0 +1,23 @@
if Config.Framework ~= 'qb' then
return
end
QBCore = exports['qb-core']:GetCoreObject()
RegisterNetEvent('QBCore:Client:OnPlayerLoaded')
AddEventHandler('QBCore:Client:OnPlayerLoaded', function()
Wait(3500)
LocalPlayer.state:set('isLoggedIn', true, false)
end)
function IsPlayerLoaded()
return LocalPlayer.state['isLoggedIn']
end
function GetPlayerData()
return QBCore.Functions.GetPlayerData()
end
function GetInventory()
return GetPlayerData().items
end
@@ -0,0 +1,242 @@
--[[
Welcome to the qb-weaponsonback configuration!
To start configuring your new asset, please read carefully
each step in the documentation that we will attach at the end of this message.
Each important part of the configuration will be highlighted with a box.
like this one you are reading now, where I will explain step by step each
configuration available within this file.
This is not all, most of the settings, you are free to modify it
as you wish and adapt it to your framework in the most comfortable way possible.
The configurable files you will find all inside client/custom/*
or inside server/custom/*.
Direct link to the resource documentation, read it before you start:
https://docs.quasar-store.com/information/welcome
]]
Config = {}
--[[
The current system will detect if you use qb-core or es_extended,
but if you rename it, you can remove the value from Config.Framework
and add it yourself after you have modified the framework files inside
this script.
Please keep in mind that this code is automatic, do not edit if
you do not know how to do it.
]]
local esxHas = GetResourceState('es_extended') == 'started'
local qbHas = GetResourceState('qb-core') == 'started'
Config.Framework = esxHas and 'esx' or qbxHas and 'qbx' or qbHas and 'qb' or 'standalone'
--[[
Weapon configuration to be shown on the back, torso
or where you configure it on your character's coord.
Please note that you must have knowledge
basics and do everything by trial and error.
]]
Config.WeaponPositions = {
['weapon_carbinerifle'] = {
model = 'w_ar_carbinerifle',
hash = -2084633992,
bone = 10706,
x = 0.0,
y = 0.17,
z = -0.25,
x_rotation = 0.0,
y_rotation = 75.0,
z_rotation = 180.0
},
['weapon_carbinerifle_mk2'] = {
model = 'w_ar_carbineriflemk2',
hash = GetHashKey('WEAPON_CARBINERIFLE_MK2'),
bone = 24816,
x = 0.2275,
y = -0.17,
z = -0.110,
x_rotation = 0.0,
y_rotation = 20.0,
z_rotation = 1.0
},
['weapon_assaultrifle'] = {
model = 'w_ar_assaultrifle',
hash = -1074790547,
bone = 24816,
x = 0.2275,
y = -0.16,
z = 0.110,
x_rotation = 0.0,
y_rotation = -15.0,
z_rotation = 2.0
},
['weapon_tacticalrifle'] = {
model = 'w_ar_tacticalrifle',
hash = `weapon_tacticalrifle`,
bone = 24816,
x = 0.2275,
y = -0.16,
z = 0.110,
x_rotation = 0.0,
y_rotation = -15.0,
z_rotation = 2.0
},
['weapon_specialcarbine'] = {
model = 'w_ar_specialcarbine',
hash = -1063057011,
bone = 24816,
x = 0.2275,
y = -0.16,
z = 0.030,
x_rotation = 0.0,
y_rotation = 5.0,
z_rotation = 1.0
},
['weapon_bullpuprifle'] = {
model = 'w_ar_bullpuprifle',
hash = 2132975508,
bone = 24816,
x = 0.2275,
y = -0.16,
z = 0.055,
x_rotation = 0.0,
y_rotation = 0.0,
z_rotation = 1.0
},
['weapon_advancedrifle'] = {
model = 'w_ar_advancedrifle',
hash = -1357824103,
bone = 24816,
x = 0.2275,
y = -0.16,
z = -0.055,
x_rotation = 0.0,
y_rotation = 35.0,
z_rotation = 1.0
},
['weapon_appistol'] = {
model = 'w_pi_appistol',
hash = 584646201,
bone = 24816,
x = -0.140,
y = 0.05,
z = -0.210,
x_rotation = 90.0,
y_rotation = 90.0,
z_rotation = 50.0
},
['weapon_microsmg'] = {
model = 'w_sb_microsmg',
hash = 324215364,
bone = 24816,
x = -0.200,
y = 0.05,
z = -0.210,
x_rotation = 90.0,
y_rotation = 110.0,
z_rotation = 50.0
},
['weapon_assaultsmg'] = {
model = 'w_sb_assaultsmg',
hash = -270015777,
bone = 10706,
x = 0.0,
y = 0.17,
z = -0.35,
x_rotation = 0.0,
y_rotation = 55.0,
z_rotation = 180.0
},
['weapon_smg'] = {
model = 'w_sb_smg',
hash = 736523883,
bone = 24816,
x = 0.1275,
y = -0.16,
z = -0.055,
x_rotation = 0.0,
y_rotation = 35.0,
z_rotation = 1.0
},
['weapon_smg_mk2'] = {
model = 'w_sb_smgmk2',
hash = GetHashKey('WEAPON_SMG_MK2'),
bone = 24816,
x = -0.140,
y = 0.05,
z = 0.210,
x_rotation = 90.0,
y_rotation = 120.0,
z_rotation = 50.0
},
['weapon_sniperrifle'] = {
model = 'w_sr_sniperrifle',
hash = 100416529,
bone = 24816,
x = 0.005,
y = -0.16,
z = 0.0,
x_rotation = 0.0,
y_rotation = -15.0,
z_rotation = 2.0
},
['weapon_assaultshotgun'] = {
model = 'w_sg_assaultshotgun',
hash = -494615257,
bone = 24816,
x = 0.2275,
y = -0.16,
z = 0.015,
x_rotation = 0.0,
y_rotation = 160.0,
z_rotation = 1.0
},
['weapon_pumpshotgun'] = {
model = 'w_sg_pumpshotgun',
hash = 487013001,
bone = 24816,
x = 0.1275,
y = -0.16,
z = 0.030,
x_rotation = 0.0,
y_rotation = 25.0,
z_rotation = 1.0
},
['weapon_musket'] = {
model = 'w_ar_musket',
hash = -1466123874,
bone = 24816,
x = 0.0,
y = -0.16,
z = 0.0,
x_rotation = 0.0,
y_rotation = 15.0,
z_rotation = 2.0
},
['weapon_heavyshotgun'] = {
model = 'w_sg_heavyshotgun',
hash = GetHashKey('WEAPON_HEAVYSHOTGUN'),
bone = 10706,
x = 0.100,
y = 0.17,
z = -0.20,
x_rotation = 0.0,
y_rotation = 60.0,
z_rotation = 190.0
},
-- Add more weapons as needed
}
--[[
Debug mode, this mode is to receive constant prints and information
from the system, we do not recommend enabling it if you are not a
developer, but it will help to understand how the resource works.
]]
Config.Debug = false
@@ -0,0 +1,32 @@
fx_version 'bodacious'
game 'gta5'
lua54 'yes'
version '2.0.2'
shared_scripts {
'config.lua',
'utils.lua'
}
client_scripts {
'client/custom/framework/*.lua',
'client/*.lua'
}
server_scripts {
'server/*.lua'
}
escrow_ignore {
'config.lua',
'client/custom/framework/*.lua'
}
dependencies {
'qs-inventory' -- Required
}
dependency '/assetpacks'
@@ -0,0 +1,69 @@
UPDATE `users` SET `inventory` = '[]' WHERE identifier IS NOT NULL;
ALTER TABLE `users` ADD IF NOT EXISTS `metadata` mediumtext DEFAULT NULL;
ALTER TABLE `users` ADD IF NOT EXISTS `inventory_skill` TEXT NULL DEFAULT NULL;
DROP TABLE IF EXISTS `inventory_glovebox`;
CREATE TABLE IF NOT EXISTS `inventory_glovebox` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`plate` varchar(255) DEFAULT NULL,
`items` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL,
PRIMARY KEY (`plate`),
KEY `id` (`id`)
) ENGINE = InnoDB AUTO_INCREMENT = 1 DEFAULT CHARSET = latin1;
DROP TABLE IF EXISTS `inventory_stash`;
CREATE TABLE IF NOT EXISTS `inventory_stash` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`stash` varchar(255) DEFAULT NULL,
`items` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL,
PRIMARY KEY (`stash`),
KEY `id` (`id`)
) ENGINE = InnoDB AUTO_INCREMENT = 1 DEFAULT CHARSET = latin1;
DROP TABLE IF EXISTS `inventory_trunk`;
CREATE TABLE IF NOT EXISTS `inventory_trunk` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`plate` varchar(255) DEFAULT NULL,
`items` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL,
PRIMARY KEY (`plate`),
KEY `id` (`id`)
) ENGINE = InnoDB AUTO_INCREMENT = 1 DEFAULT CHARSET = latin1;
DROP TABLE IF EXISTS `inventory_metadata`;
CREATE TABLE IF NOT EXISTS `inventory_metadata` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`identifier` VARCHAR(50) NULL DEFAULT NULL COLLATE 'utf8mb4_unicode_ci',
`data` TEXT NULL DEFAULT NULL COLLATE 'utf8mb4_unicode_ci',
PRIMARY KEY (`id`) USING BTREE
) COLLATE = 'utf8mb4_unicode_ci' ENGINE = InnoDB;
DROP TABLE IF EXISTS `inventory_clothes`;
CREATE TABLE IF NOT EXISTS `inventory_clothes` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`identifier` VARCHAR(50) NOT NULL DEFAULT '' COLLATE 'utf8mb4_general_ci',
`items` TEXT NULL DEFAULT NULL COLLATE 'utf8mb4_general_ci',
PRIMARY KEY (`identifier`) USING BTREE,
INDEX `id` (`id`) USING BTREE
) COLLATE = 'utf8mb4_general_ci' ENGINE = InnoDB AUTO_INCREMENT = 6;
DROP TABLE IF EXISTS `inventory_quests`;
CREATE TABLE `inventory_quests` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(50) NOT NULL DEFAULT '0' COLLATE 'utf8mb3_general_ci',
`owner` VARCHAR(80) NOT NULL DEFAULT '0' COLLATE 'utf8mb3_general_ci',
`title` VARCHAR(80) NOT NULL DEFAULT '0' COLLATE 'utf8mb3_general_ci',
`description` MEDIUMTEXT NOT NULL COLLATE 'utf8mb3_general_ci',
`reward` INT(11) NOT NULL DEFAULT '0',
`requiredLevel` INT(11) NOT NULL DEFAULT '0',
`default` TINYINT(1) NOT NULL DEFAULT '0',
`status` VARCHAR(50) NOT NULL DEFAULT 'active' COLLATE 'utf8mb3_general_ci',
`progress` INT(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `name_owner` (`name`, `owner`) USING BTREE
)
COLLATE='utf8mb3_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=1
;
ALTER TABLE users ADD COLUMN IF NOT EXISTS unlocked_skills LONGTEXT NULL;
@@ -0,0 +1,68 @@
ALTER TABLE `players` ADD IF NOT EXISTS `inventory_skill` TEXT NULL DEFAULT NULL;
DROP TABLE IF EXISTS `inventory_glovebox`;
CREATE TABLE IF NOT EXISTS `inventory_glovebox` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`plate` varchar(255) DEFAULT NULL,
`items` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL,
PRIMARY KEY (`plate`),
KEY `id` (`id`)
) ENGINE = InnoDB AUTO_INCREMENT = 1 DEFAULT CHARSET = latin1;
DROP TABLE IF EXISTS `inventory_stash`;
CREATE TABLE IF NOT EXISTS `inventory_stash` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`stash` varchar(255) DEFAULT NULL,
`items` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL,
PRIMARY KEY (`stash`),
KEY `id` (`id`)
) ENGINE = InnoDB AUTO_INCREMENT = 1 DEFAULT CHARSET = latin1;
DROP TABLE IF EXISTS `inventory_trunk`;
CREATE TABLE IF NOT EXISTS `inventory_trunk` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`plate` varchar(255) DEFAULT NULL,
`items` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL,
PRIMARY KEY (`plate`),
KEY `id` (`id`)
) ENGINE = InnoDB AUTO_INCREMENT = 1 DEFAULT CHARSET = latin1;
DROP TABLE IF EXISTS `inventory_metadata`;
CREATE TABLE IF NOT EXISTS `inventory_metadata` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`identifier` VARCHAR(50) NULL DEFAULT NULL COLLATE 'utf8mb4_unicode_ci',
`data` TEXT NULL DEFAULT NULL COLLATE 'utf8mb4_unicode_ci',
PRIMARY KEY (`id`) USING BTREE
) COLLATE = 'utf8mb4_unicode_ci' ENGINE = InnoDB;
DROP TABLE IF EXISTS `inventory_clothes`;
CREATE TABLE IF NOT EXISTS `inventory_clothes` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`identifier` VARCHAR(50) NOT NULL DEFAULT '' COLLATE 'utf8mb4_general_ci',
`items` TEXT NULL DEFAULT NULL COLLATE 'utf8mb4_general_ci',
PRIMARY KEY (`identifier`) USING BTREE,
INDEX `id` (`id`) USING BTREE
) COLLATE = 'utf8mb4_general_ci' ENGINE = InnoDB AUTO_INCREMENT = 6;
DROP TABLE IF EXISTS `inventory_quests`;
CREATE TABLE `inventory_quests` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(50) NOT NULL DEFAULT '0' COLLATE 'utf8mb3_general_ci',
`owner` VARCHAR(80) NOT NULL DEFAULT '0' COLLATE 'utf8mb3_general_ci',
`title` VARCHAR(80) NOT NULL DEFAULT '0' COLLATE 'utf8mb3_general_ci',
`description` MEDIUMTEXT NOT NULL COLLATE 'utf8mb3_general_ci',
`reward` INT(11) NOT NULL DEFAULT '0',
`requiredLevel` INT(11) NOT NULL DEFAULT '0',
`default` TINYINT(1) NOT NULL DEFAULT '0',
`status` VARCHAR(50) NOT NULL DEFAULT 'active' COLLATE 'utf8mb3_general_ci',
`progress` INT(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `name_owner` (`name`, `owner`) USING BTREE
)
COLLATE='utf8mb3_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=1
;
ALTER TABLE players ADD COLUMN IF NOT EXISTS unlocked_skills LONGTEXT NULL;
@@ -0,0 +1,61 @@
if not Config.UseTarget then
return
end
local target_name = GetResourceState('ox_target'):find('started') and 'qtarget' or 'qb-target'
function InitializeTargetPed(k, v, ped)
if ped then
exports[target_name]:AddTargetEntity(ped, {
options = {
{
label = v.name .. ' | ' .. v.label,
icon = 'fa-solid fa-basket-shopping',
action = function()
openShop(v)
end
}
},
distance = 2.0
})
else
for a, x in pairs(v.coords) do
exports[target_name]:AddCircleZone(v.name, vector3(x.coords.x, x.coords.y, x.coords.z), 0.5, {
name = v.name,
debugPoly = Config.ZoneDebug,
useZ = true
}, {
options = {
{
label = v.name .. ' | ' .. v.label,
icon = 'fa-solid fa-basket-shopping',
action = function()
openShop(v)
end
}
},
distance = 2.0
})
end
end
end
CreateThread(function()
for k, v in pairs(Config.Stashes) do
exports[target_name]:AddCircleZone(v.label .. k, vector3(v.coords.x, v.coords.y, v.coords.z), 0.5, {
name = v.label .. k,
debugPoly = false,
useZ = true
}, {
options = {
{
label = v.targetLabel,
icon = 'fas fa-shopping-cart',
event = 'shops:openStash',
stash = v
}
},
distance = 2.0
})
end
end)
@@ -0,0 +1,173 @@
local success, result = pcall(lib.load, ('custom.%s.client'):format(Config.Framework))
if not success then
error(result, 0)
end
_G.cfr = result --[[@as ClientFramework]]
---@param msg string
---@param type 'info' | 'error' | 'success'
function Notification(msg, type)
if GetResourceState('qs-interface') == 'started' then
if type == 'info' then
exports['qs-interface']:AddNotify(msg, 'Inform', 2500, 'fas fa-file')
elseif type == 'error' then
exports['qs-interface']:AddNotify(msg, 'Error', 2500, 'fas fa-bug')
elseif type == 'success' then
exports['qs-interface']:AddNotify(msg, 'Success', 2500, 'fas fa-thumbs-up')
end
return
end
if type == 'info' then
lib.notify({
title = 'Shops',
description = msg,
type = 'info'
})
elseif type == 'error' then
lib.notify({
title = 'Shops',
description = msg,
type = 'error'
})
elseif type == 'success' then
lib.notify({
title = 'Shops',
description = msg,
type = 'success'
})
end
end
RegisterNetEvent('shops:notification', Notification)
print('^2[INFO]^7 Successfully loaded the framework.', Config.Framework)
local texts = {}
if GetResourceState('qs-textui') == 'started' then
function DrawText3D(x, y, z, text, id, key)
local _id = id
if not texts[_id] then
CreateThread(function()
texts[_id] = 5
while texts[_id] > 0 do
texts[_id] = texts[_id] - 1
Wait(0)
end
texts[_id] = nil
exports['qs-textui']:DeleteDrawText3D(id)
Debug('Deleted text', id)
end)
TriggerEvent('textui:DrawText3D', x, y, z, text, id, key)
end
texts[_id] = 5
end
else
function DrawText3D(x, y, z, text)
SetTextScale(0.35, 0.35)
SetTextFont(4)
SetTextProportional(1)
SetTextColour(255, 255, 255, 215)
SetTextEntry('STRING')
SetTextCentre(true)
AddTextComponentString(text)
SetDrawOrigin(x, y, z, 0)
DrawText(0.0, 0.0)
local factor = text:len() / 370
DrawRect(0.0, 0.0 + 0.0125, 0.017 + factor, 0.03, 0, 0, 0, 75)
ClearDrawOrigin()
end
end
function DrawGenericText(text)
SetTextColour(186, 186, 186, 255)
SetTextFont(4)
SetTextScale(0.5, 0.5)
SetTextWrap(0.0, 1.0)
SetTextCentre(false)
SetTextDropshadow(0, 0, 0, 0, 255)
SetTextEdge(1, 0, 0, 0, 205)
SetTextEntry('STRING')
AddTextComponentString(text)
DrawText(0.40, 0.00)
end
local _world3dToSreen2d, _getGameplayCamCoords, _getGameplayCamFov = World3dToScreen2d, GetGameplayCamCoords, GetGameplayCamFov
DrawText3DX = function(text, coords)
local _coords = vec3(coords.x, coords.y, coords.z)
local onScreen, x, y = _world3dToSreen2d(_coords.x, _coords.y, _coords.z)
local camCoords = _getGameplayCamCoords()
local dist = #(camCoords - _coords)
local size = 2
local scale = (size / dist) * 2
local fov = (1 / _getGameplayCamFov()) * 100
scale = scale * fov
if onScreen then
SetTextScale(0.0 * scale, 0.55 * scale)
SetTextFont(0)
SetTextColour(255, 255, 255, 255)
SetTextDropshadow(0, 0, 0, 0, 255)
SetTextDropShadow()
SetTextOutline()
SetTextEntry('STRING')
SetTextCentre(1)
AddTextComponentString(text)
DrawText(x, y)
end
end
function ProgressBar(name, label, duration, useWhileDead, canCancel, disableControls, animation, prop, propTwo, onFinish, onCancel)
if disableControls then
disableControls.move = disableControls.disableMovement
disableControls.car = disableControls.disableCarMovement
disableControls.mouse = disableControls.disableMouse
disableControls.combat = disableControls.disableCombat
end
if GetResourceState('qs-interface') == 'started' then
local success = exports['qs-interface']:ProgressBar({
duration = duration,
label = label,
position = 'bottom',
useWhileDead = useWhileDead,
canCancel = canCancel,
disable = disableControls,
anim = {
dict = animation?.animDict,
clip = animation?.anim,
flag = animation?.flags
},
prop = prop
})
if success then
onFinish()
else
onCancel()
end
return
end
if lib.progressCircle({
duration = duration,
label = label,
position = 'bottom',
useWhileDead = useWhileDead,
canCancel = canCancel,
disable = disableControls,
anim = {
dict = animation?.animDict,
clip = animation?.anim,
flag = animation?.flags
},
prop = prop
}) then
onFinish()
else
onCancel()
end
end
@@ -0,0 +1,38 @@
local framework = {}
local ESX = exports['es_extended']:getSharedObject()
RegisterNetEvent('esx:playerLoaded', function(playerData)
PlayerData = playerData
Debug('player loaded', playerData)
end)
function framework:getPlayerData()
return ESX.GetPlayerData()
end
CreateThread(function()
PlayerData = framework:getPlayerData()
Debug('init playerData')
end)
RegisterNetEvent('esx:setJob', function(jobData)
PlayerData.job = jobData
end)
function framework:getIdentifier()
return PlayerData?.identifier or 'none'
end
function framework:getJobName()
return PlayerData?.job?.name or 'unemployed'
end
function framework:getJobGrade()
return PlayerData?.job?.grade or 0
end
function framework:getPlayers()
return ESX.Game.GetPlayers()
end
return framework
@@ -0,0 +1,129 @@
--[[
Hi dear customer or developer, here you can fully configure your server's
framework or you could even duplicate this file to create your own framework.
If you do not have much experience, we recommend you download the base version
of the framework that you use in its latest version and it will work perfectly.
]]
local framework = {}
local ESX = exports['es_extended']:getSharedObject()
function framework:registerUsableItem(item, cb)
ESX.RegisterUsableItem(item, cb)
end
function framework:getPlayerFromId(source)
return ESX.GetPlayerFromId(source)
end
function framework:getSourceFromIdentifier(identifier)
return ESX.GetPlayerFromIdentifier(identifier).source
end
function framework:getIdentifier(source)
if source == 0 then return 'automated' end
local player = self:getPlayerFromId(source)
return player?.identifier
end
function framework:getAccountMoney(source, account)
local player = self:getPlayerFromId(source)
return player.getAccount(account).money
end
function framework:removeAccountMoney(source, account, amount)
local player = self:getPlayerFromId(source)
if self:getAccountMoney(source, account) < amount then
return false
end
player.removeAccountMoney(account, amount)
return true
end
function framework:addAccountMoney(source, account, amount)
local player = self:getPlayerFromId(source)
player.addAccountMoney(account, amount)
end
function framework:removeItem(source, item, count)
local player = self:getPlayerFromId(source)
player.removeInventoryItem(item, count)
end
function framework:addItem(source, item, count, slot, info)
local player = self:getPlayerFromId(source)
if player.canCarryItem(item, count) then
player.addInventoryItem(item, count, info, slot)
return true
end
return false
end
---@param player table
---@param item string
function framework:getItem(player, item)
local data = player.getInventoryItem(item)
if not data then
return {
count = 0
}
end
return data
end
function framework:playerIsAdmin(source)
local player = self:getPlayerFromId(source)
return player.getGroup() == 'admin' or player.getGroup() == 'superadmin'
end
function framework:getUserName(source)
local xPlayer = self:getPlayerFromId(source)
local firstName, lastName
if xPlayer.get and xPlayer.get('firstName') and xPlayer.get('lastName') then
firstName = xPlayer.get('firstName')
lastName = xPlayer.get('lastName')
else
local name = MySQL.Sync.fetchAll('SELECT firstname, lastname FROM users WHERE identifier = ?', { xPlayer.identifier })
firstName, lastName = name[1]?.firstname or '', name[1]?.lastname or ''
end
return firstName, lastName
end
function framework:getUserNameFromIdentifier(identifier)
local name = MySQL.Sync.fetchAll('SELECT `firstname`, `lastname` FROM `users` WHERE `identifier`=@identifier', { ['@identifier'] = identifier })
return name[1]?.firstname or '', name[1]?.lastname or ''
end
function framework:getJobName(source)
local xPlayer = self:getPlayerFromId(source)
return xPlayer.getJob().name
end
function framework:getPlayers()
return ESX.GetPlayers()
end
-- This is a so much expensive function. Be careful with it !
function framework:getItemList()
ESX = exports['es_extended']:getSharedObject()
return ESX.Items
end
function framework:getLicenses(source)
if not GetResourceState('esx_license'):find('started') then
return
end
local promise = promise.new()
TriggerEvent('esx_license:getLicenses', source, function(licenses)
local data = {}
for k, v in pairs(licenses) do
data[v.type] = true
end
promise:resolve(data)
end)
return Citizen.Await(promise)
end
return framework
@@ -0,0 +1,36 @@
local framework = {}
local QBCore = exports['qb-core']:GetCoreObject()
RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function()
PlayerData = framework:getPlayerData()
end)
RegisterNetEvent('QBCore:Client:OnJobUpdate', function(jobData)
PlayerData.job = jobData
end)
CreateThread(function()
PlayerData = framework:getPlayerData()
end)
function framework:getPlayerData()
return QBCore.Functions.GetPlayerData()
end
function framework:getIdentifier()
return PlayerData.citizenid
end
function framework:getJobName()
return PlayerData?.job?.name or 'unemployed'
end
function framework:getJobGrade()
return PlayerData?.job?.grade?.level or 0
end
function framework:getPlayers()
return QBCore.Functions.GetPlayers()
end
return framework
@@ -0,0 +1,160 @@
--[[
Hi dear customer or developer, here you can fully configure your server's
framework or you could even duplicate this file to create your own framework.
If you do not have much experience, we recommend you download the base version
of the framework that you use in its latest version and it will work perfectly.
]]
local framework = {}
local QBCore = exports['qb-core']:GetCoreObject()
function framework:registerUsableItem(name, cb)
QBCore.Functions.CreateUseableItem(name, cb)
end
function framework:getPlayerFromId(source)
return QBCore.Functions.GetPlayer(source)
end
function framework:getSourceFromIdentifier(identifier)
local src = QBCore.Functions.GetPlayerByCitizenId(identifier).PlayerData.source
return src
end
function framework:getIdentifier(source)
if source == 0 then return 'automated' end
local player = self:getPlayerFromId(source)
return player.PlayerData.citizenid
end
---@param player table
---@return number
local function getBlackMoney(player)
local items = player.PlayerData.items
local totalWorth = 0
for k, v in pairs(items) do
if v.name == 'markedbills' then
totalWorth = totalWorth + v.info.worth
end
end
return totalWorth
end
function framework:getAccountMoney(source, account)
local player = self:getPlayerFromId(source)
if account == 'money' then account = 'cash' end
if account == 'black_money' then return getBlackMoney(player) end
return player.PlayerData.money[account]
end
local function removeBlackMoney(player, amount)
local items = player.PlayerData.items
local blackMoney = getBlackMoney(player)
while blackMoney > 0 and amount > 0 do
Wait(10)
Debug('blackMoney:', blackMoney, 'removed:', 'amount:', amount)
for k, v in pairs(items) do
if v.name ~= 'markedbills' then goto continue end
if v.info.worth > amount then
v.info.worth = v.info.worth - amount
amount = 0
break
else
amount = amount - v.info.worth
items[k] = nil
Debug('removed:', v.info.worth, 'amount:', amount)
end
::continue::
end
end
SaveInventory(player.PlayerData.source, items)
end
function framework:removeAccountMoney(source, account, amount)
local player = self:getPlayerFromId(source)
if account == 'money' then account = 'cash' end
if account == 'black_money' then
removeBlackMoney(player, amount)
return
end
if self:getAccountMoney(source, account) < amount then
return false
end
player.Functions.RemoveMoney(account, amount)
return true
end
function framework:addAccountMoney(source, account, amount)
local player = self:getPlayerFromId(source)
if account == 'money' then account = 'cash' end
if account == 'black_money' then
local info = { worth = amount }
sfr:addItem(source, 'markedbills', 1, false, info)
return
end
player.Functions.AddMoney(account, amount)
end
function framework:removeItem(source, item, count)
local player = self:getPlayerFromId(source)
player.Functions.RemoveItem(item, count)
end
function framework:addItem(source, item, count, slot, info)
local player = self:getPlayerFromId(source)
return player.Functions.AddItem(item, count, slot, info)
end
function framework:getItem(player, item)
local data = player.Functions.GetItemByName(item)
if not data then
return {
count = 0
}
end
data.count = data.amount
return data
end
function framework:playerIsAdmin(source)
return QBCore.Functions.HasPermission(source, 'god') or IsPlayerAceAllowed(source, 'command') or QBCore.Functions.HasPermission(source, 'admin')
end
function framework:getUserName(source)
local player = self:getPlayerFromId(source)
return player.PlayerData.charinfo.firstname, player.PlayerData.charinfo.lastname
end
function framework:getUserNameFromIdentifier(identifier)
local result = MySQL.Sync.fetchAll('SELECT charinfo FROM `players` WHERE citizenid = ?', { identifier })
if not result[1] then
return '', ''
end
result = result[1]
result = json.decode(result.charinfo)
return result?.firstname, result?.lastname
end
function framework:getJobName(source)
local player = self:getPlayerFromId(source)
return player.PlayerData.job.name
end
function framework:getPlayers()
return QBCore.Functions.GetPlayers()
end
function framework:getItemList()
if Config.QBX then
return exports['qs-inventory']:GetItemList()
end
return QBCore.Shared.Items
end
function framework:getLicenses(source)
local player = self:getPlayerFromId(source)
return player.PlayerData.metadata['licences']
end
return framework ---@type ServerFramework
@@ -0,0 +1,8 @@
local success, result = pcall(lib.load, ('custom.%s.server'):format(Config.Framework))
if not success then
error(result, 0)
end
_G.sfr = result --[[@as ServerFramework]]
print('^2[INFO]^7 Successfully loaded the framework.', Config.Framework)
@@ -0,0 +1,59 @@
fx_version 'cerulean'
game 'gta5'
lua54 'yes'
name 'qs-advancedshops'
author 'Quasar Store'
ui_page 'html/index.html'
files {
'html/index.html',
'html/index.js',
'html/style.css',
'html/*otf',
'html/*png',
'fonts/*.ttf',
'fonts/*.otf',
'custom/**'
}
ox_libs {
'table',
}
client_scripts {
'client/custom/**/**',
'custom/client.lua',
'client/*.lua',
}
shared_scripts {
'@ox_lib/init.lua',
'shared/functions.lua',
'shared/config.lua',
'locales/**'
}
server_scripts {
'custom/server.lua',
'server/*.lua',
}
dependencies {
'ox_lib',
'qs-inventory'
}
escrow_ignore {
'client/custom/**',
'custom/**/*',
'shared/**/*',
'config/*',
'type.lua',
'locales/*'
}
dependency '/assetpacks'

Some files were not shown because too many files have changed in this diff Show More