fix(rv-maphold): foloseste QBCore nativ pt HasItem, fara export qb-inventory
BIN
resources/[framework]/[addons]/qs-inventory/.fxap
Normal file
@@ -0,0 +1,310 @@
|
||||
if Config.Framework ~= 'esx' then
|
||||
return
|
||||
end
|
||||
|
||||
ESX = exports['es_extended']:getSharedObject()
|
||||
|
||||
function GetPlayerData()
|
||||
return ESX.GetPlayerData()
|
||||
end
|
||||
|
||||
function TriggerServerCallback(name, cb, ...)
|
||||
ESX.TriggerServerCallback(name, cb, ...)
|
||||
end
|
||||
|
||||
local playerLoaded = ESX.IsPlayerLoaded()
|
||||
function IsPlayerLoaded()
|
||||
return playerLoaded
|
||||
end
|
||||
|
||||
RegisterNetEvent('esx:playerLoaded', function(xPlayer)
|
||||
PlayerData = xPlayer
|
||||
LocalPlayer.state:set('inv_busy', false, true)
|
||||
Wait(1250)
|
||||
for k, data in pairs(Config.WeaponRepairPoints) do
|
||||
Config.WeaponRepairPoints[k].IsRepairing = data.IsRepairing
|
||||
Config.WeaponRepairPoints[k].RepairingData = data.RepairingData
|
||||
end
|
||||
if Config.Crafting then
|
||||
CreateBlips()
|
||||
end
|
||||
Wait(5000)
|
||||
playerLoaded = true
|
||||
end)
|
||||
|
||||
RegisterNetEvent('esx:onPlayerLogout')
|
||||
AddEventHandler('esx:onPlayerLogout', function()
|
||||
PlayerData = {}
|
||||
LocalPlayer.state:set('inv_busy', true, true)
|
||||
RemoveAllNearbyDrops()
|
||||
for k in pairs(Config.WeaponRepairPoints) do
|
||||
Config.WeaponRepairPoints[k].IsRepairing = false
|
||||
Config.WeaponRepairPoints[k].RepairingData = {}
|
||||
end
|
||||
TriggerServerEvent('inventory:handleLogout')
|
||||
end)
|
||||
|
||||
RegisterNetEvent('esx:setJob', function()
|
||||
PlayerData = GetPlayerData()
|
||||
if Config.Crafting then
|
||||
CreateBlips()
|
||||
end
|
||||
end)
|
||||
|
||||
AddEventHandler('esx_status:onTick', function(status)
|
||||
TriggerEvent('esx_status:getStatus', 'hunger', function(status)
|
||||
hunger = status.val / 10000
|
||||
end)
|
||||
TriggerEvent('esx_status:getStatus', 'thirst', function(status)
|
||||
thirst = status.val / 10000
|
||||
end)
|
||||
end)
|
||||
|
||||
function GetPlayerIdentifier()
|
||||
return GetPlayerData().identifier
|
||||
end
|
||||
|
||||
function GetPlayersInArea()
|
||||
local playerPed = PlayerPedId()
|
||||
return ESX.Game.GetPlayersInArea(GetEntityCoords(playerPed), 3.0)
|
||||
end
|
||||
|
||||
function GetJobName()
|
||||
return GetPlayerData()?.job?.name
|
||||
end
|
||||
|
||||
function GetJobGrade()
|
||||
return GetPlayerData().job.grade
|
||||
end
|
||||
|
||||
function GetGang()
|
||||
return false
|
||||
end
|
||||
|
||||
function GetGangLevel()
|
||||
return false
|
||||
end
|
||||
|
||||
function SendTextMessage(msg, type)
|
||||
if GetResourceState('qs-interface') == 'started' then
|
||||
if type == 'inform' then
|
||||
exports['qs-interface']:AddNotify(msg, 'Inform', 2500, 'fa-solid 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 == 'inform' then
|
||||
lib.notify({
|
||||
title = 'Inventory',
|
||||
description = msg,
|
||||
type = 'inform'
|
||||
})
|
||||
elseif type == 'error' then
|
||||
lib.notify({
|
||||
title = 'Inventory',
|
||||
description = msg,
|
||||
type = 'error'
|
||||
})
|
||||
elseif type == 'success' then
|
||||
lib.notify({
|
||||
title = 'Inventory',
|
||||
description = msg,
|
||||
type = 'success'
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
function ShowHelpNotification(msg)
|
||||
AddTextEntry('helpNotification', msg)
|
||||
BeginTextCommandDisplayHelp('helpNotification')
|
||||
EndTextCommandDisplayHelp(0, true, true, -1)
|
||||
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)
|
||||
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 DrawText3Ds(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 = string.len(text) / 370
|
||||
DrawRect(0.0, 0.0125, 0.017 + factor, 0.03, 0, 0, 0, 75)
|
||||
ClearDrawOrigin()
|
||||
end
|
||||
|
||||
function ToggleHud(bool)
|
||||
if bool then
|
||||
Debug('Event to show the hud [client/custom/framework/esx.lua line 174]')
|
||||
DisplayRadar(true) -- You can enable or disable mini-map here
|
||||
if GetResourceState('qs-interface') == 'started' then
|
||||
exports['qs-interface']:ToggleHud(true)
|
||||
end
|
||||
else
|
||||
Debug('Event to hide the hud [client/custom/framework/esx.lua line 174]')
|
||||
DisplayRadar(false) -- You can enable or disable mini-map here
|
||||
if GetResourceState('qs-interface') == 'started' then
|
||||
exports['qs-interface']:ToggleHud(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ProgressBar(name, label, duration, useWhileDead, canCancel, disableControls, animation, prop, propTwo, onFinish, onCancel)
|
||||
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
|
||||
|
||||
function ProgressBarSync(name, label, duration, useWhileDead, canCancel, disableControls, animation, prop)
|
||||
if GetResourceState('qs-interface') == 'started' then
|
||||
return exports['qs-interface']:ProgressBar({
|
||||
duration = duration,
|
||||
label = label,
|
||||
useWhileDead = useWhileDead,
|
||||
canCancel = canCancel,
|
||||
disable = disableControls,
|
||||
anim = animation,
|
||||
prop = prop
|
||||
})
|
||||
end
|
||||
return lib.progressBar({
|
||||
duration = duration,
|
||||
label = label,
|
||||
useWhileDead = useWhileDead,
|
||||
canCancel = canCancel,
|
||||
disable = disableControls,
|
||||
anim = animation,
|
||||
prop = prop
|
||||
})
|
||||
end
|
||||
|
||||
function SetPlayerStatus(values)
|
||||
for name, value in pairs(values) do
|
||||
if value > 0 then
|
||||
TriggerEvent('esx_status:add', name, value)
|
||||
else
|
||||
TriggerEvent('esx_status:remove', name, -value)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function DropMarker(coords)
|
||||
DrawMarker(20, coords.x, coords.y, coords.z, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.3, 0.3, 0.15, 120, 10, 20, 155, false, false, false, 1, false, false, false)
|
||||
end
|
||||
|
||||
function CanUseInventory()
|
||||
local ped = PlayerPedId()
|
||||
local wasabiHas = GetResourceState('wasabi_ambulance') == 'started'
|
||||
if wasabiHas and exports.wasabi_ambulance:isPlayerDead() then
|
||||
return false
|
||||
end
|
||||
if LocalPlayer.state.isDead and LocalPlayer.state.isDead == 1 then
|
||||
return false
|
||||
end
|
||||
if GetEntityHealth(ped) >= 1 then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function checkEntityDead(id, entity)
|
||||
if Player(id).state.isDead then
|
||||
return true
|
||||
end
|
||||
local check = false
|
||||
if GetEntityHealth(entity) <= 1 then
|
||||
check = true
|
||||
end
|
||||
return check
|
||||
end
|
||||
|
||||
function reputationCrafing(rep)
|
||||
--- @param rep Name of reputation
|
||||
return 99999
|
||||
end
|
||||
|
||||
RegisterNetEvent('qs-inventory:client:updateItem', function(item, data)
|
||||
if not ItemList[item] then
|
||||
return
|
||||
end
|
||||
ItemList[item] = data
|
||||
end)
|
||||
@@ -0,0 +1,315 @@
|
||||
if Config.Framework ~= 'qb' then
|
||||
return
|
||||
end
|
||||
|
||||
QBCore = exports['qb-core']:GetCoreObject()
|
||||
if not Config.QBX then
|
||||
WeaponList = QBCore.Shared.Weapons
|
||||
ItemList = QBCore.Shared.Items
|
||||
end
|
||||
|
||||
local playerLoaded = LocalPlayer.state['isLoggedIn']
|
||||
function IsPlayerLoaded()
|
||||
return playerLoaded
|
||||
end
|
||||
|
||||
function GetPlayerData()
|
||||
return QBCore.Functions.GetPlayerData()
|
||||
end
|
||||
|
||||
function TriggerServerCallback(name, cb, ...)
|
||||
QBCore.Functions.TriggerCallback(name, cb, ...)
|
||||
end
|
||||
|
||||
RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function()
|
||||
PlayerData = GetPlayerData()
|
||||
LocalPlayer.state:set('inv_busy', false, true)
|
||||
Wait(1250)
|
||||
for k, data in pairs(Config.WeaponRepairPoints) do
|
||||
Config.WeaponRepairPoints[k].IsRepairing = data.IsRepairing
|
||||
Config.WeaponRepairPoints[k].RepairingData = data.RepairingData
|
||||
end
|
||||
if Config.Crafting then
|
||||
CreateBlips()
|
||||
end
|
||||
TriggerServerEvent(Config.InventoryPrefix .. ':server:OnLoadUpdateCash')
|
||||
Wait(5000)
|
||||
playerLoaded = true
|
||||
end)
|
||||
|
||||
RegisterNetEvent('QBCore:Client:OnPlayerUnload', function()
|
||||
PlayerData = {}
|
||||
LocalPlayer.state:set('inv_busy', true, true)
|
||||
RemoveAllNearbyDrops()
|
||||
for k in pairs(Config.WeaponRepairPoints) do
|
||||
Config.WeaponRepairPoints[k].IsRepairing = false
|
||||
Config.WeaponRepairPoints[k].RepairingData = {}
|
||||
end
|
||||
TriggerServerEvent('inventory:handleLogout')
|
||||
end)
|
||||
|
||||
RegisterNetEvent('QBCore:Player:SetPlayerData', function(val)
|
||||
PlayerData = val
|
||||
if Config.Crafting then
|
||||
CreateBlips()
|
||||
end
|
||||
end)
|
||||
|
||||
function GetPlayerIdentifier()
|
||||
return GetPlayerData().citizenid
|
||||
end
|
||||
|
||||
function GetPlayersInArea()
|
||||
local playerPed = PlayerPedId()
|
||||
return QBCore.Functions.GetPlayersFromCoords(GetEntityCoords(playerPed), 3.0)
|
||||
end
|
||||
|
||||
function GetJobName()
|
||||
return GetPlayerData()?.job?.name
|
||||
end
|
||||
|
||||
function GetJobGrade()
|
||||
return GetPlayerData().job.grade
|
||||
end
|
||||
|
||||
function GetGang()
|
||||
return false
|
||||
end
|
||||
|
||||
function GetGangLevel()
|
||||
return false
|
||||
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)
|
||||
AddTextEntry('helpNotification', msg)
|
||||
BeginTextCommandDisplayHelp('helpNotification')
|
||||
EndTextCommandDisplayHelp(0, true, true, -1)
|
||||
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)
|
||||
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 DrawText3Ds(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 = string.len(text) / 370
|
||||
DrawRect(0.0, 0.0125, 0.017 + factor, 0.03, 0, 0, 0, 75)
|
||||
ClearDrawOrigin()
|
||||
end
|
||||
|
||||
function ToggleHud(bool)
|
||||
if bool then
|
||||
Debug('Event to show the hud [client/custom/framework/esx.lua line 174]')
|
||||
DisplayRadar(true) -- You can enable or disable mini-map here
|
||||
if GetResourceState('qs-interface') == 'started' then
|
||||
exports['qs-interface']:ToggleHud(true)
|
||||
end
|
||||
else
|
||||
Debug('Event to hide the hud [client/custom/framework/esx.lua line 174]')
|
||||
DisplayRadar(false) -- You can enable or disable mini-map here
|
||||
if GetResourceState('qs-interface') == 'started' then
|
||||
exports['qs-interface']:ToggleHud(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ProgressBar(name, label, duration, useWhileDead, canCancel, disableControls, animation, prop, propTwo, onFinish, onCancel)
|
||||
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?.flag
|
||||
},
|
||||
prop = prop
|
||||
}) then
|
||||
onFinish()
|
||||
else
|
||||
onCancel()
|
||||
end
|
||||
end
|
||||
|
||||
function ProgressBarSync(name, label, duration, useWhileDead, canCancel, disableControls, animation, prop)
|
||||
if GetResourceState('qs-interface') == 'started' then
|
||||
return exports['qs-interface']:ProgressBar({
|
||||
duration = duration,
|
||||
label = label,
|
||||
useWhileDead = useWhileDead,
|
||||
canCancel = canCancel,
|
||||
disable = disableControls,
|
||||
anim = animation,
|
||||
prop = prop
|
||||
})
|
||||
end
|
||||
return lib.progressBar({
|
||||
duration = duration,
|
||||
label = label,
|
||||
useWhileDead = useWhileDead,
|
||||
canCancel = canCancel,
|
||||
disable = disableControls,
|
||||
anim = animation,
|
||||
prop = prop
|
||||
})
|
||||
end
|
||||
|
||||
function DropMarker(coords)
|
||||
DrawMarker(20, coords.x, coords.y, coords.z, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.3, 0.3, 0.15, 120, 10, 20, 155, false, false, false, 1, false, false, false)
|
||||
end
|
||||
|
||||
function SetPlayerStatus(values)
|
||||
for name, value in pairs(values) do
|
||||
-- compatibility for ESX style values
|
||||
if value > 100 or value < -100 then
|
||||
value = value * 0.0001
|
||||
end
|
||||
|
||||
if name == 'hunger' then
|
||||
TriggerServerEvent('inventory:consumables:addHunger', QBCore.Functions.GetPlayerData().metadata.hunger + value)
|
||||
elseif name == 'thirst' then
|
||||
TriggerServerEvent('inventory:consumables:addThirst', QBCore.Functions.GetPlayerData().metadata.thirst + value)
|
||||
elseif name == 'stress' then
|
||||
if value > 0 then
|
||||
TriggerServerEvent('hud:server:GainStress', value)
|
||||
else
|
||||
value = math.abs(value)
|
||||
TriggerServerEvent('hud:server:RelieveStress', value)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function CanUseInventory()
|
||||
local check = false
|
||||
local data = GetPlayerData()
|
||||
if not data.metadata['isdead'] and not data.metadata['inlaststand'] and not data.metadata['ishandcuffed'] and not IsPauseMenuActive() then
|
||||
check = true
|
||||
end
|
||||
return check
|
||||
end
|
||||
|
||||
function checkEntityDead(id, entity)
|
||||
local isDead = false
|
||||
TriggerServerCallback(Config.InventoryPrefix .. ':server:checkDead', function(result)
|
||||
isDead = result
|
||||
end, id)
|
||||
repeat Wait(250) until isDead ~= nil
|
||||
return isDead
|
||||
end
|
||||
|
||||
function reputationCrafing(rep)
|
||||
local PlayerData = QBCore.Functions.GetPlayerData()
|
||||
if not PlayerData then return 0 end
|
||||
|
||||
local reputation = PlayerData.metadata[rep] or 0
|
||||
|
||||
if reputation == nil then
|
||||
reputation = 0
|
||||
end
|
||||
|
||||
return reputation
|
||||
end
|
||||
|
||||
RegisterNetEvent('QBCore:Client:OnSharedUpdate', function(type, item, data)
|
||||
if type == 'Items' then
|
||||
ItemList[item] = data
|
||||
end
|
||||
end)
|
||||
|
||||
RegisterNetEvent('QBCore:Client:OnSharedUpdateMultiple', function(type, data)
|
||||
if type == 'Items' then
|
||||
for k, v in pairs(data) do
|
||||
ItemList[k] = v
|
||||
end
|
||||
end
|
||||
end)
|
||||
@@ -0,0 +1,69 @@
|
||||
RegisterNetEvent(Config.InventoryPrefix .. ':client:CraftItems', function(itemName, itemCosts, points, amount, toSlot, rep, time, chance)
|
||||
local ped = PlayerPedId()
|
||||
local itemData = ItemList[itemName:lower()]
|
||||
local randomNum = math.random(1, 100)
|
||||
|
||||
SendNUIMessage({
|
||||
action = 'close',
|
||||
})
|
||||
inInventory = false
|
||||
if itemData['type'] == 'weapon' and tonumber(amount) > 1 then
|
||||
return SendTextMessage(Lang('INVENTORY_NOTIFICATION_CRAFTING_WEAPONS'), 'error')
|
||||
end
|
||||
|
||||
if chance then
|
||||
Debug('Crafting started with a chance of ' .. randomNum .. '% and you had ' .. chance .. '%')
|
||||
else
|
||||
chance = 100
|
||||
Debug('There is no chance option in your configuration or in this item, and the crafting chance is set to 100%')
|
||||
end
|
||||
|
||||
isCrafting = true
|
||||
time = time or 1000
|
||||
ProgressBar('crafting_item', Lang('INVENTORY_PROGRESS_CRAFTING'), (time * amount), false, false, {
|
||||
move = true,
|
||||
car = true,
|
||||
mouse = false,
|
||||
combat = true,
|
||||
}, {
|
||||
animDict = 'mini@repair',
|
||||
anim = 'fixing_a_player',
|
||||
flags = 1,
|
||||
}, {}, {}, function()
|
||||
if randomNum <= chance then
|
||||
Debug('Crafting successful with ' .. randomNum .. '% chance and you had ' .. chance .. '%')
|
||||
itemData.count = tonumber(amount)
|
||||
StopAnimTask(ped, 'mini@repair', 'fixing_a_player', 1.0)
|
||||
else
|
||||
Debug('Crafting failed with ' .. randomNum .. '% chance and you had ' .. chance .. '%')
|
||||
StopAnimTask(ped, 'mini@repair', 'fixing_a_player', 1.0)
|
||||
SendTextMessage(Lang('INVENTORY_NOTIFICATION_CRAFTING_FAILED'), 'inform')
|
||||
Wait(550)
|
||||
TaskPlayAnim(ped, 'gestures@m@standing@casual', 'gesture_damn', 8.0, -8.0, -1, 1, 0, false, false, false)
|
||||
Wait(1250)
|
||||
StopAnimTask(ped, 'gestures@m@standing@casual', 'gesture_damn', 1.0)
|
||||
end
|
||||
TriggerServerEvent(Config.InventoryPrefix .. ':server:CraftItems', itemName, itemCosts, points, amount, toSlot, rep, randomNum, chance)
|
||||
isCrafting = false
|
||||
end, function()
|
||||
StopAnimTask(ped, 'mini@repair', 'fixing_a_player', 1.0)
|
||||
isCrafting = false
|
||||
end)
|
||||
TriggerScreenblurFadeOut(300)
|
||||
if Config.Clothing then DeletePedScreen() end
|
||||
end)
|
||||
|
||||
-- RegisterCommand('tt', function(source, args)
|
||||
-- ProgressBar('crafting_item', Lang('INVENTORY_PROGRESS_CRAFTING'), (1000), false, false, {
|
||||
-- move = true,
|
||||
-- car = true,
|
||||
-- mouse = false,
|
||||
-- combat = true,
|
||||
-- }, {
|
||||
-- animDict = 'mini@repair',
|
||||
-- anim = 'fixing_a_player',
|
||||
-- flags = 1,
|
||||
-- }, {}, {}, function()
|
||||
-- end, function()
|
||||
-- end)
|
||||
-- end, false)
|
||||
@@ -0,0 +1,10 @@
|
||||
--[[
|
||||
We recommend not modifying anything on this side, the Starter Items
|
||||
are all in your server/custom/framework/esx.lua, it won't work in
|
||||
qb-core since that framework has its native ones that do it automatically.
|
||||
]]
|
||||
|
||||
AddEventHandler(Config.InventoryPrefix .. ':client:GiveStarterItems', function()
|
||||
local id = PlayerId()
|
||||
TriggerServerEvent(Config.InventoryPrefix .. ':server:GiveStarterItems', id)
|
||||
end)
|
||||
@@ -0,0 +1,105 @@
|
||||
local checkDistanceInventories = {
|
||||
'shop',
|
||||
'stash',
|
||||
'crafting',
|
||||
'attachment_crafting',
|
||||
'traphouse',
|
||||
'customcrafting'
|
||||
}
|
||||
|
||||
RegisterNetEvent(Config.InventoryPrefix .. ':client:OpenInventory', function(PlayerAmmo, inventory, other, otherName)
|
||||
if not inventory then return Error('Inventory is not working, clear the inventory column [sql] to continue.') end
|
||||
inventory = FormatItemsToInfo(inventory)
|
||||
ToggleHud(false)
|
||||
ToggleHotbar(false)
|
||||
SetFocus(true)
|
||||
IdleCamera(true)
|
||||
SetPedCanPlayAmbientAnims(PlayerPedId(), false)
|
||||
SetResourceKvp('idleCam', 'off')
|
||||
|
||||
if other then
|
||||
currentOtherInventory = other.name
|
||||
end
|
||||
|
||||
OpenedInventoryCoords = GetEntityCoords(PlayerPedId())
|
||||
|
||||
TriggerServerCallback(Config.InventoryPrefix .. ':server:QualityDecay', function(data)
|
||||
local hungerValue = hunger
|
||||
local thirstValue = thirst
|
||||
if Config.Framework == 'qb' then
|
||||
local data = GetPlayerData()
|
||||
hungerValue = data.metadata and data.metadata.hunger
|
||||
thirstValue = data.metadata and data.metadata.thirst
|
||||
end
|
||||
|
||||
local PlayerSlots = Config.InventoryWeight.slots
|
||||
if not Config.BlockedSlot then
|
||||
PlayerSlots = Config.InventoryWeight.slots - 1
|
||||
end
|
||||
|
||||
inventory = data.inventory
|
||||
other = data.other
|
||||
|
||||
data = GetPlayerData()
|
||||
if Config.Framework == 'esx' then
|
||||
firstName = data.firstName or ''
|
||||
lastName = data.lastName or ''
|
||||
for i = 1, #data.accounts do
|
||||
if data.accounts[i].name == 'money' then
|
||||
money = data.accounts[i].money or 'Not found'
|
||||
elseif data.accounts[i].name == 'bank' then
|
||||
bank = data.accounts[i].money or 'Not found'
|
||||
elseif data.accounts[i].name == 'black_money' then
|
||||
blackmoney = data.accounts[i].money or 'Not found'
|
||||
end
|
||||
end
|
||||
elseif Config.Framework == 'qb' then
|
||||
firstName = data.charinfo.firstname or ''
|
||||
lastName = data.charinfo.lastname or ''
|
||||
money = data.money.cash or 'Not found'
|
||||
bank = data.money.bank or 'Not found'
|
||||
blackmoney = data.money.crypto or 'Not found'
|
||||
end
|
||||
|
||||
|
||||
SendNUIMessage({
|
||||
action = 'open',
|
||||
inventory = inventory,
|
||||
slots = PlayerSlots,
|
||||
other = other,
|
||||
maxweight = Config.InventoryWeight.weight,
|
||||
Ammo = PlayerAmmo,
|
||||
playerName = firstName .. ' ' .. lastName,
|
||||
logo = Config.Logo,
|
||||
openAnimation = Config.OpenInventoryScene,
|
||||
optionClothes = Config.InventoryOptions.clothes,
|
||||
optionConfiguration = Config.InventoryOptions.configuration,
|
||||
optionHealth = Config.InventoryOptions.health,
|
||||
optionArmor = Config.InventoryOptions.armor,
|
||||
optionHunger = Config.InventoryOptions.hunger,
|
||||
optionThirst = Config.InventoryOptions.thirst,
|
||||
optionId = Config.InventoryOptions.id,
|
||||
optionMoney = Config.InventoryOptions.money,
|
||||
optionBank = Config.InventoryOptions.bank,
|
||||
optionBlackMoney = Config.InventoryOptions.blackmoney,
|
||||
playerhp = GetEntityHealth(PlayerPedId()),
|
||||
playerarmor = GetPedArmour(PlayerPedId()),
|
||||
playerhunger = hungerValue or 0,
|
||||
playerthirst = thirstValue or 0,
|
||||
playerId = GetPlayerServerId(PlayerId()),
|
||||
playerMoney = money,
|
||||
playerBank = bank,
|
||||
playerBlackMoney = blackmoney,
|
||||
notStolenItems = Config.notStolenItems,
|
||||
notStoredItems = Config.notStoredItems,
|
||||
labelChanger = Config.LabelChange
|
||||
})
|
||||
inInventory = true
|
||||
if table.includes(checkDistanceInventories, otherName) then
|
||||
CheckNearbyOtherInventory()
|
||||
end
|
||||
end, inventory, other)
|
||||
|
||||
if not Config.Handsup then return end
|
||||
checkPlayerRobbery(other)
|
||||
end)
|
||||
@@ -0,0 +1,48 @@
|
||||
if not Config.UseTarget then
|
||||
local nearby = false
|
||||
CreateThread(function()
|
||||
while true do
|
||||
local sleep = 1000
|
||||
if nearby then
|
||||
DrawText3D(Config.SellItems[nearby].coords.x, Config.SellItems[nearby].coords.y, Config.SellItems[nearby].coords.z, Lang('INVENTORY_TEXT_SELLING'), 'selling', 'E')
|
||||
sleep = 1
|
||||
if IsControlJustPressed(0, 38) then
|
||||
local PawnshopItems = {}
|
||||
PawnshopItems.label = nearby
|
||||
PawnshopItems.items = Config.SellItems[nearby].items
|
||||
PawnshopItems.slots = #Config.SellItems[nearby].items
|
||||
TriggerServerEvent(Config.InventoryPrefix .. ':server:OpenInventory', 'selling', 'itemselling_' .. nearby, PawnshopItems)
|
||||
end
|
||||
end
|
||||
Wait(sleep)
|
||||
end
|
||||
end)
|
||||
|
||||
CreateThread(function()
|
||||
for k, v in pairs(Config.SellItems) do
|
||||
if v.blip and v.blip.active then
|
||||
local ff = v.blip
|
||||
local blip = AddBlipForCoord(v.coords)
|
||||
SetBlipSprite(blip, ff.sprite)
|
||||
SetBlipColour(blip, ff.color)
|
||||
SetBlipScale(blip, ff.scale)
|
||||
BeginTextCommandSetBlipName('STRING')
|
||||
AddTextComponentString(ff.name)
|
||||
EndTextCommandSetBlipName(blip)
|
||||
SetBlipAsShortRange(blip, true)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
CreateThread(function()
|
||||
while true do
|
||||
local playercoords = GetEntityCoords(PlayerPedId())
|
||||
local finded = false
|
||||
for k, v in pairs(Config.SellItems) do
|
||||
if #(playercoords - v.coords) <= 2 then finded = k end
|
||||
end
|
||||
nearby = finded
|
||||
Wait(700)
|
||||
end
|
||||
end)
|
||||
end
|
||||
@@ -0,0 +1,72 @@
|
||||
RegisterNetEvent(Config.InventoryPrefix .. ':client:UseWeapon', function(weaponData, shootbool)
|
||||
if FiringWeapon then
|
||||
SendTextMessage(Lang('INVENTORY_NOTIFICATION_STOP_FIRING'), 'error')
|
||||
return false
|
||||
end
|
||||
local ped = PlayerPedId()
|
||||
local weaponName = tostring(weaponData.name)
|
||||
local weaponHash = joaat(weaponData.name)
|
||||
for i = 1, #Config.WeaponTints do
|
||||
if tostring(GetHashKey(weaponName)) == Config.WeaponTints[i].hash then
|
||||
AddReplaceTexture(Config.WeaponTints[i].ytd, Config.WeaponTints[i].texture, Config.WeaponTints[i].ytd, Config.WeaponTints[i].texture)
|
||||
break
|
||||
end
|
||||
end
|
||||
if currentWeapon == weaponName then
|
||||
TriggerEvent('weapons:client:DrawWeapon', nil)
|
||||
SetCurrentPedWeapon(ped, `WEAPON_UNARMED`, true)
|
||||
RemoveAllPedWeapons(ped, true)
|
||||
TriggerEvent('weapons:client:SetCurrentWeapon', nil, shootbool)
|
||||
currentWeapon = nil
|
||||
elseif weaponName == 'weapon_stickybomb' or weaponName == 'weapon_pipebomb' or weaponName == 'weapon_smokegrenade' or weaponName == 'weapon_flare' or weaponName == 'weapon_proxmine' or weaponName == 'weapon_ball' or weaponName == 'weapon_molotov' or weaponName == 'weapon_grenade' or weaponName == 'weapon_bzgas' then
|
||||
TriggerEvent('weapons:client:DrawWeapon', weaponName)
|
||||
GiveWeaponToPed(ped, weaponHash, 1, false, false)
|
||||
SetPedAmmo(ped, weaponHash, 1)
|
||||
SetCurrentPedWeapon(ped, weaponHash, true)
|
||||
TriggerEvent('weapons:client:SetCurrentWeapon', weaponData, shootbool)
|
||||
TriggerServerEvent(Config.InventoryPrefix .. ':server:RemoveItem', weaponName, 1)
|
||||
currentWeapon = weaponName
|
||||
elseif weaponName == 'weapon_snowball' then
|
||||
TriggerEvent('weapons:client:DrawWeapon', weaponName)
|
||||
GiveWeaponToPed(ped, weaponHash, 10, false, false)
|
||||
SetPedAmmo(ped, weaponHash, 10)
|
||||
SetCurrentPedWeapon(ped, weaponHash, true)
|
||||
TriggerServerEvent(Config.InventoryPrefix .. ':server:snowball', 'remove')
|
||||
TriggerEvent('weapons:client:SetCurrentWeapon', weaponData, shootbool)
|
||||
currentWeapon = weaponName
|
||||
elseif weaponName == 'weapon_petrolcan' then
|
||||
GiveWeaponToPed(ped, weaponHash, 10, false, false)
|
||||
SetPedAmmo(ped, weaponHash, weaponData.info.ammo or 4500)
|
||||
SetCurrentPedWeapon(ped, weaponHash, true)
|
||||
TriggerEvent('weapons:client:SetCurrentWeapon', weaponData, shootbool)
|
||||
currentWeapon = weaponName
|
||||
else
|
||||
TriggerEvent('weapons:client:DrawWeapon', weaponName)
|
||||
TriggerEvent('weapons:client:SetCurrentWeapon', weaponData, shootbool)
|
||||
local ammo = tonumber(weaponData.info.ammo) or 0
|
||||
|
||||
if weaponName == 'weapon_petrolcan' or weaponName == 'weapon_fireextinguisher' then
|
||||
ammo = 4000
|
||||
end
|
||||
|
||||
GiveWeaponToPed(ped, weaponHash, ammo, false, false)
|
||||
SetPedAmmo(ped, weaponHash, ammo)
|
||||
SetCurrentPedWeapon(ped, weaponHash, true)
|
||||
|
||||
if weaponData.info.attachments then
|
||||
for _, attachment in pairs(weaponData.info.attachments) do
|
||||
if attachment.tint then
|
||||
if attachment.urltint ~= 'none' then
|
||||
ChangeWeaponTintWithUrl(weaponHash, attachment.urltint)
|
||||
else
|
||||
SetPedWeaponTintIndex(ped, weaponHash, attachment.tint)
|
||||
end
|
||||
else
|
||||
GiveWeaponComponentToPed(ped, weaponHash, joaat(attachment.component))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
currentWeapon = weaponName
|
||||
end
|
||||
end)
|
||||
@@ -0,0 +1,175 @@
|
||||
local isAdminGiveItemOpen = false
|
||||
local currentPlayers = {}
|
||||
local currentItems = {}
|
||||
local selectedPlayer = nil
|
||||
local selectedItem = nil
|
||||
|
||||
-- Open the admin giveitem interface
|
||||
RegisterNetEvent('inventory:admin:openGiveItemInterface', function()
|
||||
Debug('Opening admin interface...')
|
||||
if isAdminGiveItemOpen then
|
||||
return
|
||||
end
|
||||
|
||||
isAdminGiveItemOpen = true
|
||||
SetNuiFocus(true, true)
|
||||
|
||||
-- Get initial data
|
||||
GetOnlinePlayers()
|
||||
GetAllItems()
|
||||
|
||||
-- Open the UI
|
||||
SendNUIMessage({
|
||||
action = 'openAdminGiveItem',
|
||||
data = {
|
||||
title = 'Admin Give Item System',
|
||||
subtitle = 'Player item giving system'
|
||||
}
|
||||
})
|
||||
end)
|
||||
|
||||
-- Get online players
|
||||
function GetOnlinePlayers()
|
||||
lib.callback('inventory:admin:getOnlinePlayers', false, function(players)
|
||||
currentPlayers = players
|
||||
SendNUIMessage({
|
||||
action = 'updatePlayers',
|
||||
data = players
|
||||
})
|
||||
end)
|
||||
end
|
||||
|
||||
-- Get all items
|
||||
function GetAllItems()
|
||||
local items = {}
|
||||
for itemName, itemData in pairs(ItemList) do
|
||||
table.insert(items, {
|
||||
name = itemName,
|
||||
label = itemData.label,
|
||||
type = itemData.type,
|
||||
weight = itemData.weight,
|
||||
unique = itemData.unique or false,
|
||||
image = itemData.image or 'default.png'
|
||||
})
|
||||
end
|
||||
|
||||
-- Sort items alphabetically
|
||||
table.sort(items, function(a, b)
|
||||
return a.label < b.label
|
||||
end)
|
||||
|
||||
SendNUIMessage({
|
||||
action = 'updateItems',
|
||||
data = items
|
||||
})
|
||||
end
|
||||
|
||||
-- Search players
|
||||
function SearchPlayers(searchTerm)
|
||||
lib.callback('inventory:admin:searchPlayers', false, function(players)
|
||||
currentPlayers = players
|
||||
SendNUIMessage({
|
||||
action = 'updatePlayers',
|
||||
data = players
|
||||
})
|
||||
end, searchTerm)
|
||||
end
|
||||
|
||||
-- Search items
|
||||
function SearchItems(searchTerm)
|
||||
local items = {}
|
||||
local searchLower = string.lower(searchTerm or '')
|
||||
|
||||
for itemName, itemData in pairs(ItemList) do
|
||||
local itemLabelLower = string.lower(itemData.label)
|
||||
local itemNameLower = string.lower(itemName)
|
||||
|
||||
if searchLower == '' or
|
||||
string.find(itemLabelLower, searchLower, 1, true) or
|
||||
string.find(itemNameLower, searchLower, 1, true) then
|
||||
table.insert(items, {
|
||||
name = itemName,
|
||||
label = itemData.label,
|
||||
type = itemData.type,
|
||||
weight = itemData.weight,
|
||||
unique = itemData.unique or false,
|
||||
image = itemData.image or 'default.png'
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
-- Sort items alphabetically
|
||||
table.sort(items, function(a, b)
|
||||
return a.label < b.label
|
||||
end)
|
||||
|
||||
SendNUIMessage({
|
||||
action = 'updateItems',
|
||||
data = items
|
||||
})
|
||||
end
|
||||
|
||||
function GiveItemToPlayer(targetId, itemName, amount, metadata)
|
||||
lib.callback('inventory:admin:giveItem', false, function(success, message)
|
||||
if success then
|
||||
SendTextMessage(message, 'success')
|
||||
CloseAdminGiveItemInterface()
|
||||
else
|
||||
SendTextMessage(message, 'error')
|
||||
end
|
||||
end, targetId, itemName, amount, metadata)
|
||||
end
|
||||
|
||||
-- Close admin giveitem interface
|
||||
function CloseAdminGiveItemInterface()
|
||||
Debug('Closing admin interface...')
|
||||
isAdminGiveItemOpen = false
|
||||
SetNuiFocus(false, false)
|
||||
SendNUIMessage({
|
||||
action = 'closeAdminGiveItem'
|
||||
})
|
||||
end
|
||||
|
||||
-- NUI Callbacks
|
||||
RegisterNUICallback('closeAdminGiveItem', function(data, cb)
|
||||
CloseAdminGiveItemInterface()
|
||||
cb('ok')
|
||||
end)
|
||||
|
||||
RegisterNUICallback('searchPlayers', function(data, cb)
|
||||
SearchPlayers(data.searchTerm)
|
||||
cb('ok')
|
||||
end)
|
||||
|
||||
RegisterNUICallback('searchItems', function(data, cb)
|
||||
SearchItems(data.searchTerm)
|
||||
cb('ok')
|
||||
end)
|
||||
|
||||
RegisterNUICallback('selectPlayer', function(data, cb)
|
||||
selectedPlayer = data.player
|
||||
SendNUIMessage({
|
||||
action = 'updateSelectedPlayer',
|
||||
data = data.player
|
||||
})
|
||||
cb('ok')
|
||||
end)
|
||||
|
||||
RegisterNUICallback('selectItem', function(data, cb)
|
||||
selectedItem = data.item
|
||||
SendNUIMessage({
|
||||
action = 'updateSelectedItem',
|
||||
data = data.item
|
||||
})
|
||||
cb('ok')
|
||||
end)
|
||||
|
||||
RegisterNUICallback('giveItem', function(data, cb)
|
||||
local player = data.player
|
||||
local item = data.item
|
||||
local amount = tonumber(data.amount) or 1
|
||||
local metadata = data.metadata or ''
|
||||
|
||||
GiveItemToPlayer(player.id, item.name, amount, metadata)
|
||||
cb('ok')
|
||||
end)
|
||||
@@ -0,0 +1,208 @@
|
||||
RegisterNetEvent(Config.InventoryPrefix .. ':client:openVending')
|
||||
AddEventHandler(Config.InventoryPrefix .. ':client:openVending', function(Data)
|
||||
local Category = Data['category']
|
||||
TriggerServerEvent('inventory:openVending', Category)
|
||||
end)
|
||||
|
||||
local spamCount = 0
|
||||
local lastSpamId = nil
|
||||
|
||||
local inventory_opening_anim = {
|
||||
-- dict = 'mp_player_inteat@burger',
|
||||
-- clip = 'mp_player_int_eat_burger_fp'
|
||||
}
|
||||
|
||||
local inventory_opening_disable = {
|
||||
move = true,
|
||||
car = true,
|
||||
mouse = true,
|
||||
combat = true
|
||||
}
|
||||
|
||||
local openingInv = false
|
||||
RegisterCommand('inventory', function()
|
||||
if inInventory then
|
||||
return Debug('Inventory is already open')
|
||||
end
|
||||
if Config.OpenProgressBar and openingInv then return end
|
||||
if IsNuiFocused() then return Debug('NUI Focused') end
|
||||
if spamCount > 2 then
|
||||
SendTextMessage(Lang('INVENTORY_NOTIFICATION_SPAM'), 'error')
|
||||
return
|
||||
end
|
||||
spamCount = spamCount + 1
|
||||
lastSpamId = math.random(1, 999999)
|
||||
local spamId = lastSpamId
|
||||
SetTimeout(1000, function()
|
||||
if spamId == lastSpamId then
|
||||
spamCount = 0
|
||||
end
|
||||
end)
|
||||
if LocalPlayer.state.inv_busy or not CanUseInventory() then
|
||||
Warning("You can't use this action because inv_busy is active (avoids dupes)")
|
||||
return SendTextMessage(Lang('INVENTORY_NOTIFICATION_NOT_ACCESSIBLE'), 'error')
|
||||
end
|
||||
|
||||
if Config.OpenProgressBar then
|
||||
openingInv = true
|
||||
local success = ProgressBarSync('inventory', 'Inventory opening', 800, true, true, inventory_opening_disable, inventory_opening_anim)
|
||||
openingInv = false
|
||||
if not success then
|
||||
print('failed')
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
if inInventory and not IsNuiFocused() then
|
||||
SetFocus(true)
|
||||
return
|
||||
end
|
||||
|
||||
if not isCrafting and not inInventory and not inventoryDisabled then
|
||||
if not IsPauseMenuActive() then
|
||||
local ped = PlayerPedId()
|
||||
local curVeh = nil
|
||||
local VendingMachine = nil
|
||||
local garbage = nil
|
||||
local CurrentGarbage = {}
|
||||
local entity, entityModel, data = GetNearbyGarbage()
|
||||
if entity then
|
||||
local x, y, z = table.unpack(GetEntityCoords(entity))
|
||||
local _, floorZ = GetGroundZFor_3dCoord(x, y, z, false)
|
||||
garbage = getOwnerFromCoordsForGarbage(vector3(x, y, floorZ))
|
||||
CurrentGarbage.label = data.label
|
||||
CurrentGarbage.items = data.items
|
||||
CurrentGarbage.slots = data.slots
|
||||
end
|
||||
|
||||
if not Config.UseTarget then
|
||||
VendingMachine = GetClosestVending()
|
||||
end
|
||||
|
||||
if IsPedInAnyVehicle(ped, false) then -- Is Player In Vehicle
|
||||
local vehicle = GetVehiclePedIsIn(ped, false)
|
||||
CurrentGlovebox = Trim(GetVehicleNumberPlateText(vehicle))
|
||||
curVeh = vehicle
|
||||
CurrentVehicle = nil
|
||||
else
|
||||
local vehicle = getClosestVehicle()
|
||||
if vehicle ~= 0 and vehicle ~= nil then
|
||||
local pos = GetEntityCoords(ped)
|
||||
local dimensionMin, dimensionMax = GetModelDimensions(GetEntityModel(vehicle))
|
||||
local trunkpos = GetOffsetFromEntityInWorldCoords(vehicle, 0.0, (dimensionMin.y), 0.0)
|
||||
if (IsBackEngine(GetEntityModel(vehicle))) then
|
||||
trunkpos = GetOffsetFromEntityInWorldCoords(vehicle, 0.0, (dimensionMax.y), 0.0)
|
||||
end
|
||||
if #(pos - trunkpos) < 1.5 and not IsPedInAnyVehicle(ped) then
|
||||
if GetVehicleDoorLockStatus(vehicle) < 2 then
|
||||
CurrentVehicle = Trim(GetVehicleNumberPlateText(vehicle))
|
||||
curVeh = vehicle
|
||||
CurrentGlovebox = nil
|
||||
else
|
||||
SendTextMessage(Lang('INVENTORY_NOTIFICATION_VEHICLE_LOCKED'), 'error')
|
||||
return
|
||||
end
|
||||
else
|
||||
CurrentVehicle = nil
|
||||
end
|
||||
else
|
||||
CurrentVehicle = nil
|
||||
end
|
||||
end
|
||||
|
||||
if CurrentVehicle then -- Trunk
|
||||
local vehicleClass = GetVehicleClass(curVeh)
|
||||
Debug('Current vehicleClass of the vehicle that is being unlocked:', vehicleClass)
|
||||
local maxweight = Config.VehicleClass[vehicleClass].trunk.maxweight or 60000
|
||||
local slots = Config.VehicleClass[vehicleClass].trunk.slots or 35
|
||||
local isCustomVehicle = Config.CustomTrunk[GetEntityModel(curVeh)]
|
||||
|
||||
if isCustomVehicle then
|
||||
maxweight = isCustomVehicle.maxweight
|
||||
slots = isCustomVehicle.slots
|
||||
end
|
||||
|
||||
local other = {
|
||||
maxweight = maxweight,
|
||||
slots = slots,
|
||||
}
|
||||
TriggerServerEvent(Config.InventoryPrefix .. ':server:OpenInventory', 'trunk', CurrentVehicle, other)
|
||||
OpenTrunk()
|
||||
elseif CurrentGlovebox then
|
||||
local vehicleClass = GetVehicleClass(curVeh)
|
||||
Debug('Current vehicleClass of the vehicle that is being unlocked:', vehicleClass)
|
||||
local maxweight = Config.VehicleClass[vehicleClass].glovebox.maxweight or 60000
|
||||
local slots = Config.VehicleClass[vehicleClass].glovebox.slots or 35
|
||||
local isCustomVehicle = Config.CustomGlovebox[GetEntityModel(curVeh)]
|
||||
|
||||
if isCustomVehicle then
|
||||
maxweight = isCustomVehicle.maxweight
|
||||
slots = isCustomVehicle.slots
|
||||
end
|
||||
local other = {
|
||||
maxweight = maxweight,
|
||||
slots = slots
|
||||
}
|
||||
TriggerServerEvent(Config.InventoryPrefix .. ':server:OpenInventory', 'glovebox', CurrentGlovebox, other)
|
||||
elseif CurrentDrop ~= 0 then
|
||||
TriggerServerEvent(Config.InventoryPrefix .. ':server:OpenInventory', 'drop', CurrentDrop)
|
||||
elseif garbage then
|
||||
TriggerServerEvent(Config.InventoryPrefix .. ':server:OpenInventory', 'garbage', garbage, CurrentGarbage, entityModel)
|
||||
OpenGarbage()
|
||||
elseif VendingMachine then
|
||||
local vendingCategory = nil
|
||||
local vendingModel = GetEntityModel(VendingMachine)
|
||||
for _, vendingData in pairs(Config.Vendings) do
|
||||
local vendingDataModel = GetHashKey(vendingData.Model)
|
||||
if vendingDataModel == vendingModel then
|
||||
vendingCategory = vendingData.Category
|
||||
break
|
||||
end
|
||||
end
|
||||
if vendingCategory then
|
||||
TriggerEvent(Config.InventoryPrefix .. ':client:openVending', { category = vendingCategory })
|
||||
end
|
||||
else
|
||||
OpenAnim()
|
||||
TriggerServerEvent(Config.InventoryPrefix .. ':server:OpenInventory')
|
||||
end
|
||||
end
|
||||
end
|
||||
end, false)
|
||||
|
||||
RegisterKeyMapping('inventory', Lang('INVENTORY_KEYMAPPING_OPEN_LABEL'), 'keyboard', Config.KeyBinds.inventory)
|
||||
|
||||
RegisterNetEvent(Config.InventoryPrefix .. ':client:OpenPlayerInventory')
|
||||
AddEventHandler(Config.InventoryPrefix .. ':client:OpenPlayerInventory', function()
|
||||
ExecuteCommand('inventory')
|
||||
end)
|
||||
|
||||
RegisterCommand('hotbar', function()
|
||||
if inventoryDisabled then return end
|
||||
if IsNuiFocused() then return end
|
||||
if LocalPlayer.state.inv_busy or not CanUseInventory() then
|
||||
Warning("You can't use this action because inv_busy is active (avoids dupes)")
|
||||
return
|
||||
end
|
||||
|
||||
isHotbar = not isHotbar
|
||||
if not IsPauseMenuActive() then
|
||||
ToggleHotbar(isHotbar)
|
||||
end
|
||||
end, false)
|
||||
|
||||
RegisterKeyMapping('hotbar', Lang('INVENTORY_KEYMAPPING_HOTBAR_LABEL'), 'keyboard', Config.KeyBinds.hotbar)
|
||||
|
||||
RegisterKeyMapping('reloadweapon', Lang('INVENTORY_KEYMAPPING_RELOAD_LABEL'), 'keyboard', Config.KeyBinds.reload)
|
||||
|
||||
RegisterCommand('reloadweapon', function()
|
||||
if not CurrentWeaponData?.name then return end
|
||||
local weaponData = WeaponList[joaat(CurrentWeaponData?.name)]
|
||||
if not weaponData then return end
|
||||
|
||||
if LocalPlayer.state.inv_busy or not CanUseInventory() then
|
||||
Debug("You can't use this action because inv_busy is active (avoids dupes)")
|
||||
return SendTextMessage(Lang('INVENTORY_NOTIFICATION_NOT_ACCESSIBLE'), 'error')
|
||||
end
|
||||
TriggerServerEvent('weapons:reloadWeapon', weaponData.ammotype)
|
||||
end, false)
|
||||
@@ -0,0 +1,41 @@
|
||||
local color = {} --[[@as Color]]
|
||||
|
||||
---@param data Color
|
||||
RegisterNUICallback('updateColors', function(data, cb)
|
||||
color.primaryColor = data.primaryColor or color.primaryColor
|
||||
color.primaryOpacity = data.primaryOpacity or color.primaryOpacity
|
||||
color.secondaryColor = data.secondaryColor or color.secondaryColor
|
||||
color.secondaryOpacity = data.secondaryOpacity or color.secondaryOpacity
|
||||
color.borderColor = data.borderColor or color.borderColor
|
||||
color.borderOpacity = data.borderOpacity or color.borderOpacity
|
||||
color.borderRadius = data.borderRadius or color.borderRadius
|
||||
|
||||
LocalPlayer.state:set('primaryColor', color.primaryColor, true)
|
||||
LocalPlayer.state:set('primaryOpacity', color.primaryOpacity, true)
|
||||
|
||||
TriggerEvent('inventory:updateColors', color)
|
||||
cb(true)
|
||||
end)
|
||||
|
||||
exports('getColors', function()
|
||||
return color
|
||||
end)
|
||||
|
||||
|
||||
local function handleThemeChange()
|
||||
local handler
|
||||
handler = AddEventHandler('inventory:updateColors', function()
|
||||
if not IsPlayerLoaded() then
|
||||
Debug('handleThemeChange', 'Player not loaded, skipping color update')
|
||||
return
|
||||
end
|
||||
|
||||
Debug('handleThemeChange', 'Theme color updated successfully')
|
||||
|
||||
RemoveEventHandler(handler)
|
||||
handler = nil
|
||||
end)
|
||||
end
|
||||
|
||||
handleThemeChange()
|
||||
TriggerEvent('inventory:updateColors')
|
||||
@@ -0,0 +1,41 @@
|
||||
if not GetResourceState('jobs_creator') == 'missing' then
|
||||
return
|
||||
end
|
||||
|
||||
-- Warning('Started the compatibility module with jobs_creator')
|
||||
|
||||
CreateThread(function()
|
||||
local other = {}
|
||||
other.maxweight = 100000 -- Custom weight stash.
|
||||
other.slots = 50 -- Custom slots spaces.
|
||||
|
||||
RegisterNetEvent('jobs_creator:stash:openStash', function(markerId)
|
||||
local stashId = 'job_stash_' .. markerId
|
||||
|
||||
TriggerServerEvent(Config.InventoryPrefix .. ':server:OpenInventory', 'stash', stashId, other)
|
||||
TriggerEvent(Config.InventoryPrefix .. ':client:SetCurrentStash', stashId)
|
||||
end)
|
||||
|
||||
RegisterNetEvent('jobs_creator:safe:openSafe', function(markerId)
|
||||
local safeId = 'job_safe_' .. markerId
|
||||
|
||||
TriggerServerEvent(Config.InventoryPrefix .. ':server:OpenInventory', 'stash', safeId, other)
|
||||
TriggerEvent(Config.InventoryPrefix .. ':client:SetCurrentStash', safeId)
|
||||
end)
|
||||
|
||||
RegisterNetEvent('jobs_creator:armory:openArmory', function(markerId)
|
||||
local armoryId = 'job_armory_' .. markerId
|
||||
|
||||
TriggerServerEvent(Config.InventoryPrefix .. ':server:OpenInventory', 'stash', armoryId, other)
|
||||
TriggerEvent(Config.InventoryPrefix .. ':client:SetCurrentStash', armoryId)
|
||||
end)
|
||||
|
||||
RegisterNetEvent('jobs_creator:framework:ready', function()
|
||||
-- Disables the default script search (otherwise there would be 2 searches)
|
||||
exports['jobs_creator']:disableScriptEvent('jobs_creator:actions:search:searchPlayer')
|
||||
end)
|
||||
|
||||
RegisterNetEvent('jobs_creator:actions:search:searchPlayer', function(targetServerId)
|
||||
TriggerServerEvent(Config.InventoryPrefix .. ':server:OpenInventory', 'otherplayer', targetServerId)
|
||||
end)
|
||||
end)
|
||||
@@ -0,0 +1,10 @@
|
||||
function JonskaItemThrow(item)
|
||||
local data = {
|
||||
name = item.name, -- needed for adding and removing item
|
||||
label = item.label, -- MUST HAVE!
|
||||
amount = item.amount, -- needed for adding and removing item
|
||||
info = item.info, -- needed for adding item
|
||||
created = item.created or 0 -- needed for adding item (if your inventory have decay system)
|
||||
}
|
||||
return exports['jonska-itemthrowing']:throwItem(data, item.name, item.amount)
|
||||
end
|
||||
@@ -0,0 +1,196 @@
|
||||
if not Config.Handsup then
|
||||
return
|
||||
end
|
||||
|
||||
local lib, anim = 'missminuteman_1ig_2', 'handsup_base'
|
||||
local canHandsUp = true
|
||||
local deadPlayer = false
|
||||
|
||||
local function LoadAnimDict(dict)
|
||||
if HasAnimDictLoaded(dict) then return end
|
||||
|
||||
RequestAnimDict(dict)
|
||||
while not HasAnimDictLoaded(dict) do
|
||||
Wait(10)
|
||||
end
|
||||
end
|
||||
|
||||
RegisterKeyMapping('+handsup', Lang('INVENTORY_KEYMAPPING_HANDSUP_LABEL'), 'keyboard', Config.KeyBinds.handsup)
|
||||
|
||||
local handsUpActive = false
|
||||
|
||||
RegisterCommand('+handsup', function()
|
||||
if not IsPedInAnyVehicle(PlayerPedId(), false) and GetEntityHealth(PlayerPedId()) > 1 then
|
||||
if canHandsUp and not handsUpActive then
|
||||
handsUpActive = true
|
||||
RequestAnimDict(lib)
|
||||
while not HasAnimDictLoaded(lib) do
|
||||
Wait(100)
|
||||
end
|
||||
SetCurrentPedWeapon(PlayerPedId(), GetHashKey('WEAPON_UNARMED'), true)
|
||||
TaskPlayAnim(PlayerPedId(), lib, anim, 2.0, 2.5, -1, 49, 0, 0, 0, 0)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
RegisterCommand('-handsup', function()
|
||||
if handsUpActive then
|
||||
handsUpActive = false
|
||||
ClearPedSecondaryTask(PlayerPedId())
|
||||
end
|
||||
end)
|
||||
|
||||
RegisterNetEvent(Config.InventoryPrefix .. ':client:RobPlayer')
|
||||
AddEventHandler(Config.InventoryPrefix .. ':client:RobPlayer', function(TargetId)
|
||||
local ped = PlayerPedId()
|
||||
if IsPedArmed(ped, 1) or IsPedArmed(ped, 2) or IsPedArmed(ped, 4) or deadPlayer or Config.StealWithoutWeapons then
|
||||
SendNUIMessage({
|
||||
action = 'RobPlayer',
|
||||
TargetId = TargetId,
|
||||
})
|
||||
end
|
||||
deadPlayer = false
|
||||
end)
|
||||
|
||||
local function checkPlayerIsNear(targetPlayer)
|
||||
CreateThread(function()
|
||||
while true do
|
||||
Wait(100)
|
||||
local targetPed = GetPlayerPed(targetPlayer)
|
||||
|
||||
if not DoesEntityExist(targetPed) or NetworkIsPlayerActive(targetPlayer) == false then
|
||||
TriggerEvent(Config.InventoryPrefix .. ':client:closeinv')
|
||||
SendTextMessage(Lang('INVENTORY_NOTIFICATION_ROBBERY_AWAY'), 'inform')
|
||||
break
|
||||
end
|
||||
|
||||
local playerCoords = GetEntityCoords(PlayerPedId())
|
||||
local targetCoords = GetEntityCoords(targetPed)
|
||||
local distance = #(playerCoords - targetCoords)
|
||||
|
||||
if distance > 5 then
|
||||
Wait(500)
|
||||
TriggerEvent(Config.InventoryPrefix .. ':client:closeinv')
|
||||
SendTextMessage(Lang('INVENTORY_NOTIFICATION_ROBBERY_AWAY'), 'inform')
|
||||
break
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
RegisterNetEvent(Config.InventoryPrefix .. ':client:search', function()
|
||||
local player, distance = GetClosestPlayer(GetEntityCoords(PlayerPedId()))
|
||||
if player ~= -1 and distance < 2.5 then
|
||||
local playerId = GetPlayerServerId(player)
|
||||
local searchPlayerPed = GetPlayerPed(player)
|
||||
if IsEntityPlayingAnim(searchPlayerPed, 'missminuteman_1ig_2', 'handsup_base', 3) or Config.StealDeadPlayer and checkEntityDead(playerId, searchPlayerPed) or GetEntityHealth(searchPlayerPed) <= 0 then
|
||||
TriggerServerEvent(Config.InventoryPrefix .. ':server:OpenInventory', 'otherplayer', playerId)
|
||||
checkPlayerIsNear(player)
|
||||
inRobbery = true
|
||||
else
|
||||
SendTextMessage(Lang('INVENTORY_NOTIFICATION_NO_HANDSUP'), 'error')
|
||||
end
|
||||
else
|
||||
SendTextMessage(Lang('INVENTORY_NOTIFICATION_NO_PLAYERS'), 'error')
|
||||
end
|
||||
end)
|
||||
|
||||
RegisterNetEvent(Config.InventoryPrefix .. ':client:playerRobbery')
|
||||
AddEventHandler(Config.InventoryPrefix .. ':client:playerRobbery', function()
|
||||
local player, distance = GetClosestPlayer(GetEntityCoords(PlayerPedId()))
|
||||
if player ~= -1 and distance < 3.0 then
|
||||
local searchPlayerPed = GetPlayerPed(player)
|
||||
local playerId = GetPlayerServerId(player)
|
||||
TriggerEvent(Config.InventoryPrefix .. ':client:forceCloseInventory')
|
||||
Wait(500)
|
||||
|
||||
if checkEntityDead(playerId, searchPlayerPed) then
|
||||
RequestAnimDict('amb@world_human_gardener_plant@male@base')
|
||||
while not HasAnimDictLoaded('amb@world_human_gardener_plant@male@base') do
|
||||
Wait(100)
|
||||
end
|
||||
TaskPlayAnim(PlayerPedId(), 'amb@world_human_gardener_plant@male@base', 'base', 8.0, -8, -1, 1, 0, 0, 0, 0)
|
||||
ProgressBar('steal_playerdead', Lang('INVENTORY_PROGRESS_STEAL'), 5500, false, true, {
|
||||
move = true,
|
||||
car = true,
|
||||
mouse = false,
|
||||
combat = true,
|
||||
}, {}, {}, {}, function() -- Done
|
||||
TaskPlayAnim(PlayerPedId(), 'amb@world_human_gardener_plant@male@base', 'base', 8.0, -8, -1, 1, 0, 0, 0, 0)
|
||||
TriggerServerEvent(Config.InventoryPrefix .. ':server:OpenInventory', 'otherplayer', playerId)
|
||||
checkPlayerIsNear(player)
|
||||
inRobbery = true
|
||||
end, function() -- Cancel
|
||||
ClearPedTasks(PlayerPedId())
|
||||
end)
|
||||
return
|
||||
end
|
||||
|
||||
if DoesEntityExist(searchPlayerPed) and IsEntityPlayingAnim(searchPlayerPed, lib, anim, 3) and not checkEntityDead(playerId, searchPlayerPed) then
|
||||
LoadAnimDict('combat@aim_variations@arrest')
|
||||
TaskPlayAnim(PlayerPedId(), 'combat@aim_variations@arrest', 'cop_med_arrest_01', 8.0, -8, -1, 1, 0, 0, 0, 0)
|
||||
ProgressBar('steal_player', Lang('INVENTORY_PROGRESS_STEAL'), 5500, false, true, {
|
||||
move = true,
|
||||
car = true,
|
||||
mouse = false,
|
||||
combat = true,
|
||||
}, {}, {}, {}, function() -- Done
|
||||
TaskPlayAnim(PlayerPedId(), 'combat@aim_variations@arrest', 'cop_med_arrest_01', 8.0, -8, -1, 1, 0, 0, 0, 0)
|
||||
TriggerServerEvent(Config.InventoryPrefix .. ':server:OpenInventory', 'otherplayer', playerId)
|
||||
SetPedConfigFlag(PlayerPedId(), 36, true)
|
||||
checkPlayerIsNear(player)
|
||||
inRobbery = true
|
||||
end, function() -- Cancel
|
||||
ClearPedTasks(PlayerPedId())
|
||||
end)
|
||||
else
|
||||
SendTextMessage(Lang('INVENTORY_NOTIFICATION_NO_HANDSUP'), 'error')
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
function checkPlayerRobbery(other)
|
||||
if other and other.id then
|
||||
local target = tonumber(other.id)
|
||||
local playerTarget = GetPlayerFromServerId(target)
|
||||
local pedTarget = GetPlayerPed(playerTarget)
|
||||
if other ~= nil then
|
||||
currentOtherInventory = other.name
|
||||
end
|
||||
if target and DoesEntityExist(pedTarget) then
|
||||
local pos = GetEntityCoords(playerPed)
|
||||
local targetPos = GetEntityCoords(pedTarget)
|
||||
local distance = GetDistanceBetweenCoords(pos.x, pos.y, pos.z, targetPos.x, targetPos.y, targetPos.z, true)
|
||||
if distance < 3.0 then
|
||||
inInventory = true
|
||||
deadPlayer = true
|
||||
StealingPed = pedTarget
|
||||
TriggerEvent(Config.InventoryPrefix .. ':client:RobPlayer', target)
|
||||
end
|
||||
end
|
||||
else
|
||||
local closestPlayer, closestDistance = GetClosestPlayer(GetEntityCoords(PlayerPedId()))
|
||||
if closestPlayer and closestPlayer ~= -1 and closestDistance < 3.0 then
|
||||
local playerId = GetPlayerServerId(closestPlayer)
|
||||
local searchPlayerPed = GetPlayerPed(closestPlayer)
|
||||
if searchPlayerPed and searchPlayerPed ~= 0 then
|
||||
if Config.StealDeadPlayer and checkEntityDead(playerId, searchPlayerPed) then
|
||||
inInventory = true
|
||||
deadPlayer = true
|
||||
StealingPed = searchPlayerPed
|
||||
TriggerEvent(Config.InventoryPrefix .. ':client:RobPlayer', playerId)
|
||||
end
|
||||
if IsEntityPlayingAnim(searchPlayerPed, lib, anim, 3) then
|
||||
inInventory = true
|
||||
deadPlayer = false
|
||||
StealingPed = searchPlayerPed
|
||||
TriggerEvent(Config.InventoryPrefix .. ':client:RobPlayer', playerId)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
RegisterNetEvent('inventory:robClosestPlayer', function()
|
||||
checkPlayerRobbery()
|
||||
end)
|
||||
@@ -0,0 +1,7 @@
|
||||
local function exportHandler(exportName, func)
|
||||
AddEventHandler(('__cfx_export_qb-inventory_%s'):format(exportName), function(setCB)
|
||||
setCB(func)
|
||||
end)
|
||||
end
|
||||
|
||||
exportHandler('HasItem', HasItem)
|
||||
@@ -0,0 +1,122 @@
|
||||
if not Config.UseTarget then
|
||||
return
|
||||
end
|
||||
|
||||
local target_name = GetResourceState('ox_target'):find('started') and 'qtarget' or 'qb-target'
|
||||
|
||||
CreateThread(function()
|
||||
-- Selling
|
||||
for k, v in pairs(Config.SellItems) do
|
||||
exports[target_name]:AddBoxZone(k .. '_selling', vec3(v['coords'].x, v['coords'].y, v['coords'].z), 1.5, 1.5, {
|
||||
name = k .. '_selling',
|
||||
heading = 90.0,
|
||||
debugPoly = Config.ZoneDebug,
|
||||
minZ = v['coords'].z - 1,
|
||||
maxZ = v['coords'].z + 1,
|
||||
}, {
|
||||
options = {
|
||||
{
|
||||
type = 'client',
|
||||
icon = 'fa-solid fa-cash-register',
|
||||
label = Lang('INVENTORY_TEXT_SELLING'),
|
||||
canInteract = function(entity, distance, data)
|
||||
return true
|
||||
end,
|
||||
action = function(entity)
|
||||
local PawnshopItems = {}
|
||||
PawnshopItems.label = k
|
||||
PawnshopItems.items = v['items']
|
||||
PawnshopItems.slots = #v['items']
|
||||
TriggerServerEvent(Config.InventoryPrefix .. ':server:OpenInventory', 'selling', 'itemselling_' .. k, PawnshopItems)
|
||||
end,
|
||||
},
|
||||
},
|
||||
distance = 2.5
|
||||
})
|
||||
end
|
||||
|
||||
-- Crafting
|
||||
if Config.Crafting then
|
||||
for k, v in pairs(Config.CraftingTables) do
|
||||
exports[target_name]:AddBoxZone(k .. '_crafting', vec3(v.location.x, v.location.y, v.location.z), 2.5, 2.5, {
|
||||
name = k .. '_crafting',
|
||||
heading = 90.0,
|
||||
debugPoly = Config.ZoneDebug,
|
||||
minZ = v.location.z - 1,
|
||||
maxZ = v.location.z + 1,
|
||||
}, {
|
||||
options = {
|
||||
{
|
||||
type = 'client',
|
||||
icon = 'fa-solid fa-hammer',
|
||||
label = 'Crafting',
|
||||
canInteract = function(entity, distance, data)
|
||||
return true
|
||||
end,
|
||||
action = function(entity)
|
||||
if isCrafting then return end
|
||||
if v.isjob then
|
||||
if IsPlayerAuthorized(v) then
|
||||
CurrentCrafting = k
|
||||
local crafting = {
|
||||
label = v.name,
|
||||
items = GeneralInfos(k)
|
||||
}
|
||||
TriggerServerEvent(Config.InventoryPrefix .. ':server:OpenInventory', 'crafting', math.random(1, 99), crafting)
|
||||
end
|
||||
else
|
||||
CurrentCrafting = k
|
||||
local crafting = {
|
||||
label = v.name,
|
||||
items = GeneralInfos(k)
|
||||
}
|
||||
TriggerServerEvent(Config.InventoryPrefix .. ':server:OpenInventory', 'crafting', math.random(1, 99), crafting)
|
||||
end
|
||||
end,
|
||||
},
|
||||
},
|
||||
distance = 2.5
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
-- Vending shops
|
||||
if Config.Vendings then
|
||||
for k, v in pairs(Config.Vendings) do
|
||||
exports[target_name]:AddTargetModel(v['Model'], {
|
||||
options = {
|
||||
{
|
||||
icon = 'fa-solid fa-cash-register',
|
||||
label = 'Vending',
|
||||
action = function()
|
||||
TriggerEvent(Config.InventoryPrefix .. ':client:openVending', { category = v['Category'] })
|
||||
end
|
||||
},
|
||||
},
|
||||
distance = 2.5
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
-- Gargabe Code
|
||||
exports[target_name]:AddTargetModel(Config.GarbageObjects, {
|
||||
options = {
|
||||
{
|
||||
icon = 'fa-solid fa-trash',
|
||||
label = 'Open Garbage',
|
||||
action = function()
|
||||
ExecuteCommand('inventory')
|
||||
end
|
||||
},
|
||||
},
|
||||
distance = 1.0
|
||||
})
|
||||
end)
|
||||
|
||||
function AddTargetEntity(entity, options, distance)
|
||||
distance = distance or 5.0
|
||||
exports[target_name]:AddTargetEntity(entity, {
|
||||
options = options,
|
||||
distance = distance
|
||||
})
|
||||
end
|
||||
BIN
resources/[framework]/[addons]/qs-inventory/client/main.lua
Normal file
@@ -0,0 +1,37 @@
|
||||
TriggerEvent('chat:addSuggestion', '/giveitem', 'Administrative command to give items to another player', {
|
||||
{ name = 'id', help = 'Id of the player to whom the item will be delivered' },
|
||||
{ name = 'item', help = 'Name of the item to deliver' },
|
||||
{ name = 'amount', help = 'Quantity of the item, if it is a weapon it will be ammo' },
|
||||
})
|
||||
|
||||
TriggerEvent('chat:addSuggestion', '/giveweapon', 'Administrative command to give weapons to another player', {
|
||||
{ name = 'id', help = 'Id of the player to whom the weapon will be delivered' },
|
||||
{ name = 'weapon', help = 'Name of the weapon to deliver' },
|
||||
{ name = 'ammo', help = 'Amount of ammo for the weapon' },
|
||||
})
|
||||
|
||||
TriggerEvent('chat:addSuggestion', '/resetinv', 'Administrative command to reset an inventory, it will not delete it', {
|
||||
{ name = 'type', help = 'Type of inventory to reset, example: [stash], [trunk], [glovebox]' },
|
||||
})
|
||||
|
||||
TriggerEvent('chat:addSuggestion', '/clearinv', 'Administrative command to remove all items of a certain player', {
|
||||
{ name = 'id', help = 'Enter the id of the player whose inventory you want to empty' },
|
||||
})
|
||||
|
||||
TriggerEvent('chat:addSuggestion', '/repairweapon', 'Administrative command to repair certain players weapons', {
|
||||
{ name = 'id', help = 'Select the id of the player to repair his weapon' },
|
||||
})
|
||||
|
||||
TriggerEvent('chat:addSuggestion', '/openinventorytarget', 'Administrative command to check the inventory of a target player', {
|
||||
{ name = 'id', help = 'Select player id' },
|
||||
})
|
||||
|
||||
TriggerEvent('chat:addSuggestion', '/inventory', 'Command to open the inventory, useful for keybinds', {})
|
||||
TriggerEvent('chat:addSuggestion', '/hotbar', 'Command to open the hotbar inventory, useful for keybinds', {})
|
||||
TriggerEvent('chat:addSuggestion', '/handsup', 'Command to raise your arms, useful for keybinds, if you have your arms raised they can steal you', {})
|
||||
TriggerEvent('chat:addSuggestion', '/reloadweapon', 'Command to reload your weapon, useful for keybinds', {})
|
||||
TriggerEvent('chat:addSuggestion', '/randomitems', 'Administrative command that delivers various random items to your inventory, helps with debugging', {})
|
||||
TriggerEvent('chat:addSuggestion', '/searchplayer', 'Command to steal from a nearby player, although we recommend doing it with the NUI raising his hands', {})
|
||||
TriggerEvent('chat:addSuggestion', '/rob', 'Exclusive qb command to steal players, used for police job frequently', {})
|
||||
TriggerEvent('chat:addSuggestion', '/invitems', 'Example of code used for getInventory, it will return all the items in your inventory', {})
|
||||
TriggerEvent('chat:addSuggestion', '/dataitem', 'Example command to give an item with customizable and automatic metadata', {})
|
||||
@@ -0,0 +1,414 @@
|
||||
local PlayerData = GetPlayerData()
|
||||
local CanShoot, MultiplierAmount = true, 0
|
||||
CurrentWeaponData = {}
|
||||
|
||||
exports('GetCurrentWeapon', function()
|
||||
return CurrentWeaponData
|
||||
end)
|
||||
|
||||
lib.callback.register('weapons:client:GetCurrentWeapon', function()
|
||||
return CurrentWeaponData
|
||||
end)
|
||||
|
||||
CreateThread(function()
|
||||
while not Config.WeaponsOnVehicle do
|
||||
Wait(250)
|
||||
local playerPed = PlayerPedId()
|
||||
|
||||
if IsPedInAnyVehicle(playerPed, false) then
|
||||
local playerVeh = GetVehiclePedIsIn(playerPed, false)
|
||||
TriggerEvent('weapons:ResetHolster')
|
||||
SetCurrentPedWeapon(playerPed, GetHashKey('WEAPON_UNARMED'), true)
|
||||
RemoveAllPedWeapons(playerPed, true)
|
||||
currentWeapon = nil
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
RegisterNetEvent('weapons:client:SyncRepairShops', function(NewData, key)
|
||||
Config.WeaponRepairPoints[key].IsRepairing = NewData.IsRepairing
|
||||
Config.WeaponRepairPoints[key].RepairingData = NewData.RepairingData
|
||||
end)
|
||||
|
||||
FiringWeapon = false
|
||||
CreateThread(function()
|
||||
while true do
|
||||
local ped = PlayerPedId()
|
||||
if IsPedArmed(ped, 7) == 1 and not inInventory then
|
||||
if IsControlJustPressed(0, 24) or IsDisabledControlJustPressed(0, 24) then
|
||||
FiringWeapon = true
|
||||
elseif IsControlJustReleased(0, 24) or IsDisabledControlJustReleased(0, 24) and not inInventory then
|
||||
FiringWeapon = false
|
||||
end
|
||||
end
|
||||
Wait(0)
|
||||
end
|
||||
end)
|
||||
|
||||
CreateThread(function()
|
||||
while true do
|
||||
local ped = PlayerPedId()
|
||||
local weapon = GetSelectedPedWeapon(ped)
|
||||
if WeaponList[weapon] and WeaponList[weapon]['name'] == 'weapon_unarmed' and FiringWeapon then
|
||||
FiringWeapon = false
|
||||
end
|
||||
Wait(500)
|
||||
end
|
||||
end)
|
||||
|
||||
---@return AttachmentItem?
|
||||
local function componentIsTint(component)
|
||||
local tints = GetConfigTints()
|
||||
local attachment = table.find(tints, function(tint)
|
||||
return tint.attachment == component
|
||||
end)
|
||||
return attachment
|
||||
end
|
||||
|
||||
RegisterNetEvent('addAttachment', function(component, urltint)
|
||||
local ped = PlayerPedId()
|
||||
local weapon = GetSelectedPedWeapon(ped)
|
||||
local WeaponData = WeaponList[weapon]
|
||||
local tintData = componentIsTint(component)
|
||||
if tintData then
|
||||
if tintData.isUrlTint then
|
||||
for i = 1, #Config.WeaponTints do
|
||||
if tostring(weapon) == Config.WeaponTints[i].hash then
|
||||
local txd = CreateRuntimeTxd(Config.WeaponTints[i].name)
|
||||
local duiObj = CreateDui(urltint, 250, 250)
|
||||
local dui = GetDuiHandle(duiObj)
|
||||
CreateRuntimeTextureFromDuiHandle(txd, 'skin', dui)
|
||||
while not IsDuiAvailable(duiObj) do Wait(150) end
|
||||
AddReplaceTexture(Config.WeaponTints[i].ytd, Config.WeaponTints[i].texture, Config.WeaponTints[i].name, 'skin')
|
||||
break
|
||||
end
|
||||
end
|
||||
else
|
||||
SetPedWeaponTintIndex(ped, weapon, tintData.tint)
|
||||
end
|
||||
return
|
||||
end
|
||||
GiveWeaponComponentToPed(ped, GetHashKey(WeaponData.name), GetHashKey(component))
|
||||
end)
|
||||
|
||||
RegisterNetEvent('weapons:client:SetCurrentWeapon', function(data, bool)
|
||||
if data ~= false then
|
||||
CurrentWeaponData = data
|
||||
else
|
||||
CurrentWeaponData = {}
|
||||
end
|
||||
CanShoot = bool
|
||||
end)
|
||||
|
||||
RegisterNetEvent('weapons:client:SetWeaponQuality', function(amount)
|
||||
if CurrentWeaponData and next(CurrentWeaponData) then
|
||||
TriggerServerEvent('weapons:server:SetWeaponQuality', CurrentWeaponData, amount)
|
||||
TriggerEvent('weapons:client:SetCurrentWeapon', CurrentWeaponData, true)
|
||||
end
|
||||
end)
|
||||
|
||||
RegisterNetEvent('weapons:client:masterAmmo', function(amount, itemData)
|
||||
local ped = PlayerPedId()
|
||||
local weapon = GetSelectedPedWeapon(ped)
|
||||
if CurrentWeaponData and WeaponList[weapon] and WeaponList[weapon]['name'] ~= 'weapon_unarmed' then
|
||||
local weaponAmmoType = WeaponList[weapon]['ammotype']
|
||||
if not weaponAmmoType then
|
||||
SendTextMessage(Lang('INVENTORY_NOTIFICATION_NO_AMMO'), 'error')
|
||||
return
|
||||
end
|
||||
TriggerEvent('weapons:client:AddAmmo', weaponAmmoType, amount, itemData, true)
|
||||
else
|
||||
SendTextMessage(Lang('INVENTORY_NOTIFICATION_NO_WEAPON'), 'error')
|
||||
end
|
||||
end)
|
||||
|
||||
lib.callback.register('weapons:addAmmo', function(itemData)
|
||||
local ped = cache.ped
|
||||
if IsPedReloading(ped) then
|
||||
return
|
||||
end
|
||||
local weapon = GetSelectedPedWeapon(ped)
|
||||
if not CurrentWeaponData or not WeaponList[weapon] or WeaponList[weapon]['name'] == 'weapon_unarmed' then
|
||||
SendTextMessage(Lang('INVENTORY_NOTIFICATION_NO_WEAPON'), 'error')
|
||||
return
|
||||
end
|
||||
local total = GetAmmoInPedWeapon(ped, weapon)
|
||||
local retval = GetMaxAmmoInClip(ped, weapon, 1)
|
||||
local _, ammoclip = GetAmmoInClip(ped, weapon)
|
||||
local _, maxammo = GetMaxAmmo(ped, weapon)
|
||||
if IsPedInAnyVehicle(ped, false) and Config.ForceToOnlyOneMagazine then
|
||||
SendTextMessage(Lang('INVENTORY_NOTIFICATION_VEHICLE_ITEMS'), 'error')
|
||||
return
|
||||
end
|
||||
if Config.ForceToOnlyOneMagazine and total > 0 then
|
||||
SendTextMessage(Lang('INVENTORY_NOTIFICATION_MAGAZINE_LIMIT'), 'error')
|
||||
return
|
||||
end
|
||||
if not retval then
|
||||
return
|
||||
end
|
||||
retval = tonumber(retval)
|
||||
|
||||
if maxammo ~= total then
|
||||
TriggerServerCallback('weapon:server:GetWeaponAmmo', function(ammo)
|
||||
if ammo then
|
||||
SetAmmoInClip(ped, weapon, 0)
|
||||
AddAmmoToPed(ped, weapon, retval + ammoclip)
|
||||
TriggerServerEvent('weapons:server:AddWeaponAmmo', CurrentWeaponData, total + retval)
|
||||
--TriggerServerEvent("weapons:server:UpdateWeaponAmmo", CurrentWeaponData, total + retval)
|
||||
TriggerServerEvent('weapons:server:removeWeaponAmmoItem', itemData)
|
||||
end
|
||||
end, CurrentWeaponData)
|
||||
else
|
||||
SendTextMessage(Lang('INVENTORY_NOTIFICATION_MAX_AMMO'), 'error')
|
||||
end
|
||||
end)
|
||||
|
||||
RegisterNetEvent('weapons:client:AddAmmo', function(ammoType, amount, itemData, masterAmmo)
|
||||
local ped = PlayerPedId()
|
||||
if IsPedReloading(ped) then
|
||||
return -- SendTextMessage('Do not spam the reload', 'error')
|
||||
end
|
||||
local weapon = GetSelectedPedWeapon(ped)
|
||||
if not CurrentWeaponData or not WeaponList[weapon] or WeaponList[weapon]['name'] == 'weapon_unarmed' then
|
||||
SendTextMessage(Lang('INVENTORY_NOTIFICATION_NO_WEAPON'), 'error')
|
||||
return
|
||||
end
|
||||
local weaponAmmoType = type(WeaponList[weapon]['ammotype']) == 'table' and WeaponList[weapon]['ammotype'] or { WeaponList[weapon]['ammotype'] }
|
||||
if not table.includes(weaponAmmoType, ammoType:upper()) then
|
||||
SendTextMessage(Lang('INVENTORY_NOTIFICATION_NO_AMMO'), 'error')
|
||||
return
|
||||
end
|
||||
local total = GetAmmoInPedWeapon(ped, weapon)
|
||||
local retval = GetMaxAmmoInClip(ped, weapon, 1)
|
||||
local _, ammoclip = GetAmmoInClip(ped, weapon)
|
||||
local _, maxammo = GetMaxAmmo(ped, weapon)
|
||||
if IsPedInAnyVehicle(ped, false) and Config.ForceToOnlyOneMagazine then
|
||||
SendTextMessage(Lang('INVENTORY_NOTIFICATION_VEHICLE_ITEMS'), 'error')
|
||||
return
|
||||
end
|
||||
if Config.ForceToOnlyOneMagazine and total > 0 then
|
||||
SendTextMessage(Lang('INVENTORY_NOTIFICATION_MAGAZINE_LIMIT'), 'error')
|
||||
return
|
||||
end
|
||||
if retval then
|
||||
retval = tonumber(retval)
|
||||
itemData = lib.callback.await('weapons:GetWeaponAmmoItem', 0, ammoType, masterAmmo)
|
||||
|
||||
if not itemData then
|
||||
print('Nice try forehead :)')
|
||||
return
|
||||
end
|
||||
|
||||
if maxammo ~= total then
|
||||
TriggerServerCallback('weapon:server:GetWeaponAmmo', function(ammo)
|
||||
if ammo then
|
||||
SetAmmoInClip(ped, weapon, 0)
|
||||
AddAmmoToPed(ped, weapon, retval + ammoclip)
|
||||
TriggerServerEvent('weapons:server:AddWeaponAmmo', CurrentWeaponData, total + retval)
|
||||
--TriggerServerEvent("weapons:server:UpdateWeaponAmmo", CurrentWeaponData, total + retval)
|
||||
TriggerServerEvent('weapons:server:removeWeaponAmmoItem', itemData)
|
||||
end
|
||||
end, CurrentWeaponData)
|
||||
else
|
||||
SendTextMessage(Lang('INVENTORY_NOTIFICATION_MAX_AMMO'), 'error')
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
RegisterNetEvent('weapons:client:ConfigureTint')
|
||||
AddEventHandler('weapons:client:ConfigureTint', function(ItemData)
|
||||
TintItemData = ItemData
|
||||
SetFocus(true)
|
||||
SendNUIMessage({
|
||||
action = 'showTintMenu'
|
||||
})
|
||||
end)
|
||||
|
||||
function closeGui()
|
||||
SetFocus(false)
|
||||
SendNUIMessage({ action = 'hide' })
|
||||
end
|
||||
|
||||
RegisterNUICallback('quit', function(data, cb)
|
||||
closeGui()
|
||||
TintItemData = {}
|
||||
cb('ok')
|
||||
end)
|
||||
|
||||
RegisterNUICallback('addtinturl', function(data, cb)
|
||||
closeGui()
|
||||
SendTextMessage(Lang('INVENTORY_NOTIFICATION_CUSTOM_TINT_ADDED') .. ' ' .. data.urldatatint, 'success')
|
||||
local tinturl = tostring(data.urldatatint)
|
||||
TriggerServerEvent('weapons:server:AddUrlTint', TintItemData, tinturl)
|
||||
Wait(5)
|
||||
TintItemData = {}
|
||||
cb('ok')
|
||||
end)
|
||||
|
||||
RegisterNetEvent('weapons:client:EquipAttachment', function(ItemData, attachment, WeaponData)
|
||||
if WeaponData then
|
||||
TriggerServerEvent('weapons:server:EquipAttachment', ItemData, WeaponData, Config.WeaponAttachments[WeaponData.name:upper()][attachment], true)
|
||||
return
|
||||
end
|
||||
local ped = PlayerPedId()
|
||||
local weapon = GetSelectedPedWeapon(ped)
|
||||
local WeaponData = WeaponList[weapon]
|
||||
if weapon == `WEAPON_UNARMED` then
|
||||
SendTextMessage(Lang('INVENTORY_NOTIFICATION_NO_WEAPON'), 'error')
|
||||
return
|
||||
end
|
||||
WeaponData.name = WeaponData.name:upper()
|
||||
if not Config.WeaponAttachments[WeaponData.name] then
|
||||
SendTextMessage(Lang('INVENTORY_NOTIFICATION_ATTACHMENT_NOT_COMPATIBLE'), 'error')
|
||||
return
|
||||
end
|
||||
if not Config.WeaponAttachments[WeaponData.name][attachment] then
|
||||
SendTextMessage(Lang('INVENTORY_NOTIFICATION_ATTACHMENT_NOT_COMPATIBLE'), 'error')
|
||||
return
|
||||
end
|
||||
if Config.WeaponAttachments[WeaponData.name][attachment]['item'] == ItemData.name then
|
||||
TriggerServerEvent('weapons:server:EquipAttachment', ItemData, CurrentWeaponData, Config.WeaponAttachments[WeaponData.name][attachment])
|
||||
return
|
||||
end
|
||||
SendTextMessage(Lang('INVENTORY_NOTIFICATION_ATTACHMENT_NOT_COMPATIBLE'), 'error')
|
||||
end)
|
||||
|
||||
function SplitStr(str, delimiter)
|
||||
local result = {}
|
||||
local from = 1
|
||||
local delim_from, delim_to = string.find(str, delimiter, from)
|
||||
while delim_from do
|
||||
result[#result + 1] = string.sub(str, from, delim_from - 1)
|
||||
from = delim_to + 1
|
||||
delim_from, delim_to = string.find(str, delimiter, from)
|
||||
end
|
||||
result[#result + 1] = string.sub(str, from)
|
||||
return result
|
||||
end
|
||||
|
||||
CreateThread(function()
|
||||
SetWeaponsNoAutoswap(true)
|
||||
end)
|
||||
|
||||
LastUpdatedAmmoTime = nil
|
||||
CreateThread(function()
|
||||
while true do
|
||||
local ped = PlayerPedId()
|
||||
if GetSelectedPedWeapon(ped) ~= `WEAPON_UNARMED` and CurrentWeaponData?.info and (IsControlJustReleased(0, 24) or IsDisabledControlJustReleased(0, 24)) then
|
||||
local weapon = GetSelectedPedWeapon(ped)
|
||||
local ammo = GetAmmoInPedWeapon(ped, weapon)
|
||||
TriggerServerEvent('weapons:server:UpdateWeaponAmmo', CurrentWeaponData, tonumber(ammo))
|
||||
CurrentWeaponData.info.ammo = ammo
|
||||
LastUpdatedAmmoTime = GetGameTimer()
|
||||
if MultiplierAmount > 0 then
|
||||
TriggerServerEvent('weapons:server:UpdateWeaponQuality', CurrentWeaponData, MultiplierAmount, ammo)
|
||||
MultiplierAmount = 0
|
||||
end
|
||||
end
|
||||
Wait(0)
|
||||
end
|
||||
end)
|
||||
|
||||
CreateThread(function()
|
||||
while true do
|
||||
local ped = PlayerPedId()
|
||||
if CurrentWeaponData and next(CurrentWeaponData) then
|
||||
if IsPedShooting(ped) or IsControlJustPressed(0, 24) then
|
||||
local weapon = GetSelectedPedWeapon(ped)
|
||||
if CanShoot then
|
||||
if weapon and weapon ~= 0 and WeaponList[weapon] then
|
||||
TriggerServerCallback('prison:server:checkThrowable', function(result)
|
||||
if result or GetAmmoInPedWeapon(ped, weapon) <= 0 then return end
|
||||
MultiplierAmount += 1
|
||||
end, weapon)
|
||||
Wait(200)
|
||||
end
|
||||
else
|
||||
if weapon ~= `WEAPON_UNARMED` then
|
||||
TriggerEvent(Config.InventoryPrefix .. ':client:CheckWeapon', WeaponList[weapon]['name'])
|
||||
SendTextMessage(Lang('INVENTORY_NOTIFICATION_WEAPON_BROKEN'), 'error')
|
||||
MultiplierAmount = 0
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Wait(0)
|
||||
end
|
||||
end)
|
||||
|
||||
RegisterNetEvent(Config.InventoryPrefix .. ':client:LegacyFuel', function(fuel)
|
||||
Debug('Your gasoline can has: %', fuel)
|
||||
TriggerServerEvent('weapons:server:UpdateWeaponAmmo', CurrentWeaponData, fuel)
|
||||
TriggerServerEvent('weapons:server:UpdateWeaponQuality', CurrentWeaponData, 1, fuel)
|
||||
end)
|
||||
|
||||
---@param data ServerProgressBar
|
||||
lib.callback.register('inventory:progressBarSync', function(data)
|
||||
Debug('Progress bar sync: ', data)
|
||||
local success = ProgressBarSync(data.name, data.label, data.duration, data.useWhileDead, data.canCancel, data.disableControls, data.anim, data.prop)
|
||||
return success
|
||||
end)
|
||||
|
||||
CreateThread(function()
|
||||
while true do
|
||||
local inRange = false
|
||||
local ped = PlayerPedId()
|
||||
local pos = GetEntityCoords(ped)
|
||||
for k, data in pairs(Config.WeaponRepairPoints) do
|
||||
local distance = #(pos - data.coords)
|
||||
if distance < 10 then
|
||||
inRange = true
|
||||
if distance < 1 then
|
||||
if data.IsRepairing then
|
||||
if data.RepairingData.CitizenId ~= GetPlayerIdentifier() then
|
||||
DrawText3Ds(data.coords.x, data.coords.y, data.coords.z, Lang('INVENTORY_TEXT_REPAIR_NOT_AVAILABLE'))
|
||||
else
|
||||
if not data.RepairingData.Ready then
|
||||
DrawText3Ds(data.coords.x, data.coords.y, data.coords.z, Lang('INVENTORY_TEXT_REPAIR_REPAIRED'))
|
||||
else
|
||||
DrawText3D(data.coords.x, data.coords.y, data.coords.z, Lang('INVENTORY_TEXT_REPAIR_TAKE'), 'repair_take1', 'E')
|
||||
end
|
||||
end
|
||||
else
|
||||
if CurrentWeaponData and next(CurrentWeaponData) then
|
||||
if not data.RepairingData.Ready then
|
||||
local WeaponData = WeaponList[GetHashKey(CurrentWeaponData.name)]
|
||||
DrawText3D(data.coords.x, data.coords.y, data.coords.z, Lang('INVENTORY_TEXT_REPAIR_PRICE') .. Config.WeaponRepairCosts[WeaponData.weapontype], 'repair_weapon', 'E')
|
||||
if IsControlJustPressed(0, 38) then
|
||||
TriggerServerCallback('weapons:server:RepairWeapon', function(HasMoney)
|
||||
if HasMoney then
|
||||
CurrentWeaponData = {}
|
||||
end
|
||||
end, k, CurrentWeaponData)
|
||||
end
|
||||
else
|
||||
if data.RepairingData.CitizenId ~= GetPlayerIdentifier() then
|
||||
DrawText3Ds(data.coords.x, data.coords.y, data.coords.z, Lang('INVENTORY_TEXT_REPAIR_NOT_AVAILABLE'))
|
||||
else
|
||||
DrawText3D(data.coords.x, data.coords.y, data.coords.z, Lang('INVENTORY_TEXT_REPAIR_TAKE'), 'repair_take2', 'E')
|
||||
if IsControlJustPressed(0, 38) then
|
||||
TriggerServerEvent('weapons:server:TakeBackWeapon', k, data)
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
if data.RepairingData.CitizenId == nil then
|
||||
DrawText3Ds(data.coords.x, data.coords.y, data.coords.z, Lang('INVENTORY_TEXT_REPAIR_NO_WEAPON'))
|
||||
elseif data.RepairingData.CitizenId == GetPlayerIdentifier() then
|
||||
DrawText3D(data.coords.x, data.coords.y, data.coords.z, Lang('INVENTORY_TEXT_REPAIR_TAKE'), 'repair_take3', 'E')
|
||||
if IsControlJustPressed(0, 38) then
|
||||
TriggerServerEvent('weapons:server:TakeBackWeapon', k, data)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if not inRange then
|
||||
Wait(1250)
|
||||
end
|
||||
Wait(3)
|
||||
end
|
||||
end)
|
||||
515
resources/[framework]/[addons]/qs-inventory/config/config.lua
Normal file
@@ -0,0 +1,515 @@
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- Quasar Store · Configuration Guidelines
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- This configuration file defines all adjustable parameters for the script.
|
||||
-- Comments are standardized to help you identify which sections you can safely edit.
|
||||
--
|
||||
-- • [EDIT] – Safe for users to modify. Adjust these values as needed.
|
||||
-- • [INFO] – Informational note describing what the variable or block does.
|
||||
-- • [ADV] – Advanced settings. Change only if you understand the logic behind it.
|
||||
-- • [CORE] – Core functionality. Do not modify unless you are a developer.
|
||||
-- • [AUTO] – Automatically handled by the system. Never edit manually.
|
||||
--
|
||||
-- Always make a backup before editing configuration files.
|
||||
-- Incorrect changes in [CORE] or [AUTO] sections can break the resource.
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
---@generic T
|
||||
---@param data {[string]: string}
|
||||
---@return string | false
|
||||
local function DependencyCheck(data) -- [CORE] Detects the first started dependency and returns its alias.
|
||||
for k, v in pairs(data) do
|
||||
if GetResourceState(k):find('started') ~= nil then
|
||||
return v
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
Config = Config or {} -- [CORE] Main configuration table.
|
||||
Locales = Locales or {} -- [CORE] Language packs container.
|
||||
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- Language Selection [EDIT]
|
||||
-- [INFO] Choose your preferred language in locales/* or add your own.
|
||||
-- Available:
|
||||
-- 'ar','bg','ca','cs','da','de','el','en','es','fa','fr','hi','hu','it','ja',
|
||||
-- 'ko','nl','no','pl','pt','ro','ru','sl','sv','th','tr','zh-CN','zh-TW'
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
Config.Language = 'ro' -- [EDIT]
|
||||
|
||||
--[[ [INFO]
|
||||
Choose your preferred language!
|
||||
|
||||
In this section, you can select the main language for your asset. We have a wide
|
||||
selection of default languages available, located in the locales/* folder.
|
||||
|
||||
If your language is not listed, you can create a new one by adding a file
|
||||
in locales and customizing it to your needs.
|
||||
]]
|
||||
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- Framework Detection & Configuration (Inventory) [AUTO]
|
||||
-- [INFO] Auto-detects qb-core / es_extended / qbx_core. If you renamed them,
|
||||
-- set adapters or assign manually. Avoid edits unless you know the framework.
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
local frameworks = { -- [CORE] Resource name → internal alias
|
||||
['es_extended'] = 'esx',
|
||||
['qb-core'] = 'qb',
|
||||
['qbx_core'] = 'qb'
|
||||
}
|
||||
Config.Framework = DependencyCheck(frameworks) or 'none' -- [AUTO]
|
||||
|
||||
local qbxHas = GetResourceState('qbx_core') == 'started' -- [AUTO]
|
||||
Config.QBX = qbxHas -- [AUTO]
|
||||
|
||||
--[[ [INFO]
|
||||
Manual setup (only if necessary):
|
||||
1) Clear Config.Framework auto-detection and set your custom alias.
|
||||
2) Update framework-specific calls in client/server where required.
|
||||
Warning: Wrong edits here can break core functionality.
|
||||
]]
|
||||
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- Security [EDIT]
|
||||
-- [INFO] Disables client-side shop generation via `inventory:server:OpenInventory`.
|
||||
-- If enabled, you must use the provided server exports/events to create & open shops.
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
Config.DisableShopGenerationOnClient = false -- [EDIT] true = client shop-gen disabled
|
||||
|
||||
-- [INFO] Safe APIs to use when disabling client shop-gen:
|
||||
-- Server exports: CreateShop, OpenShop
|
||||
-- Server event: inventory:openShop
|
||||
-- Example (client): TriggerServerEvent('inventory:openShop', 'shop_name')
|
||||
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- Backward Compatibility (qs-inventory Migration) [EDIT]
|
||||
-- [INFO] One-time migration from older qs-inventory data. Set true ONCE.
|
||||
-- After completion (console shows 'Backward compatibility has been completed'),
|
||||
-- immediately set back to false. Do NOT change other settings during migration.
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
Config.FetchOldInventory = false -- [EDIT] Use true once for migration, then false.
|
||||
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- Targeting [EDIT]
|
||||
-- [INFO] Enable qb-target / ox_target. If false, targeting is disabled.
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
Config.UseTarget = true -- [EDIT]
|
||||
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- General Inventory Settings [EDIT]
|
||||
-- [INFO] Core behavior for interactions, UI and safety features.
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
Config.ThrowKeybind = 'E' -- [EDIT] Key to throw items; false to disable.
|
||||
Config.PoliceCanSeeSixthSlot = true -- [EDIT] Police can see protected 6th slot.
|
||||
Config.PoliceJobs = { 'police', 'sheriff' } -- [EDIT] Jobs treated as police.
|
||||
Config.BlockedSlot = true -- [EDIT] Lock 6th slot to prevent stealing.
|
||||
Config.GiveItemHideName = false -- [EDIT] Hide item names on give; show only ID.
|
||||
Config.OpenProgressBar = false -- [EDIT] Show progress bar on open (dup-prevention).
|
||||
Config.EnableSounds = true -- [EDIT] Toggle default inventory sounds.
|
||||
Config.EnableThrow = true -- [EDIT] Allow throwing items.
|
||||
Config.UseJonskaItemThrow = false -- [EDIT] Use custom throw (see custom/misc/jonska.lua).
|
||||
Config.EnableTrade = true -- [EDIT] Safe MMORPG-style trade.
|
||||
Config.EnableChangeLabel = true -- [EDIT] One-click rename items.
|
||||
|
||||
Config.Handsup = true -- [EDIT] Enable hands-up & robbery options.
|
||||
Config.StealDeadPlayer = true -- [EDIT] Allow looting dead players.
|
||||
Config.StealWithoutWeapons = false -- [EDIT] Can only rob if target is hands-up w/o weapon.
|
||||
Config.PlaceableItems = true -- [EDIT] Enable placeable items.
|
||||
Config.KQPlaceableItems = false -- [EDIT] Use KQ Placeable Items for item placement (requires kq_placeable_items resource).
|
||||
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- Player Inventory Capacity [EDIT]
|
||||
-- [INFO] Changing weight/slots can require wipes to avoid dupes. Be cautious.
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
Config.InventoryWeight = { -- [EDIT]
|
||||
weight = 5000, -- [INFO] Max weight (grams).
|
||||
slots = 41, -- [INFO] Set 40 to remove protected 6th slot.
|
||||
}
|
||||
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- Drop (Ground) Capacity [EDIT]
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
Config.DropWeight = { -- [EDIT]
|
||||
weight = 20000000, -- [INFO] Max ground drop capacity (grams).
|
||||
slots = 130, -- [INFO] Max slots for a ground drop.
|
||||
}
|
||||
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- Label Change [EDIT]
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
Config.LabelChange = false -- [EDIT] Allow item renaming.
|
||||
Config.LabelChangePrice = false -- [EDIT] Price or false for free.
|
||||
Config.BlockedLabelChangeItems = { -- [EDIT] Items that cannot be renamed.
|
||||
money = true,
|
||||
phone = true,
|
||||
}
|
||||
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- Hotbar [EDIT]
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
Config.UsableItemsFromHotbar = true -- [EDIT] Use items from hotbar (1–5).
|
||||
Config.BlockedItemsHotbar = { -- [EDIT] Items blocked from hotbar use.
|
||||
'lockpick',
|
||||
-- Add more here ...
|
||||
}
|
||||
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- Backpack & Item Rules [EDIT]
|
||||
-- [INFO] One-per-item limits, non-stealable and non-storable item lists.
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
Config.OnePerItem = { -- [EDIT] Max quantity per item type.
|
||||
backpack = 1,
|
||||
-- Add more items as needed.
|
||||
}
|
||||
|
||||
Config.notStolenItems = { -- [EDIT] Items that cannot be stolen.
|
||||
id_card = true,
|
||||
water_bottle = true,
|
||||
tosti = true,
|
||||
}
|
||||
|
||||
Config.notStoredItems = { -- [EDIT] Items that cannot be stashed.
|
||||
backpack = true,
|
||||
}
|
||||
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- Armor [EDIT]
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
Config.DrawableArmor = 100 -- [EDIT] Armor points granted when wearing an armor vest.
|
||||
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- Clothing System Integration [EDIT]
|
||||
-- [INFO] Enables or disables clothing system integration. Refer to documentation:
|
||||
-- ESX Docs: https://docs.quasar-store.com/ Inventory > Functions > Clothing
|
||||
-- QB Docs: https://docs.quasar-store.com/
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
Config.Clothing = true -- [EDIT] Enables clothing options in inventory (adds clothing button).
|
||||
|
||||
---@type ClotheSlot[]
|
||||
Config.ClothingSlots = { -- [EDIT] Define which slots are used for clothing pieces.
|
||||
{
|
||||
name = 'helmet',
|
||||
slot = 1,
|
||||
type = 'head',
|
||||
wearType = 'prop',
|
||||
componentId = 0,
|
||||
anim = { dict = 'mp_masks@standard_car@ds@', anim = 'put_on_mask', flags = 49 }
|
||||
},
|
||||
{
|
||||
name = 'mask',
|
||||
slot = 2,
|
||||
type = 'head',
|
||||
wearType = 'drawable',
|
||||
componentId = 1,
|
||||
anim = { dict = 'mp_masks@standard_car@ds@', anim = 'put_on_mask', flags = 49 }
|
||||
},
|
||||
{
|
||||
name = 'glasses',
|
||||
slot = 3,
|
||||
type = 'head',
|
||||
wearType = 'prop',
|
||||
componentId = 1,
|
||||
anim = { dict = 'clothingspecs', anim = 'take_off', flags = 49 }
|
||||
},
|
||||
{
|
||||
name = 'torso',
|
||||
slot = 4,
|
||||
type = 'body',
|
||||
wearType = 'drawable',
|
||||
componentId = 11,
|
||||
anim = { dict = 'missmic4', anim = 'michael_tux_fidget', flags = 49 }
|
||||
},
|
||||
{
|
||||
name = 'tshirt',
|
||||
slot = 5,
|
||||
type = 'body',
|
||||
wearType = 'drawable',
|
||||
componentId = 8,
|
||||
anim = { dict = 'clothingtie', anim = 'try_tie_negative_a', flags = 49 }
|
||||
},
|
||||
{
|
||||
name = 'jeans',
|
||||
slot = 6,
|
||||
type = 'body',
|
||||
wearType = 'drawable',
|
||||
componentId = 4,
|
||||
anim = { dict = 'missmic4', anim = 'michael_tux_fidget', flags = 49 }
|
||||
},
|
||||
{
|
||||
name = 'arms',
|
||||
slot = 7,
|
||||
type = 'body',
|
||||
wearType = 'drawable',
|
||||
componentId = 3,
|
||||
anim = { dict = 'nmt_3_rcm-10', anim = 'cs_nigel_dual-10', flags = 49 }
|
||||
},
|
||||
{
|
||||
name = 'shoes',
|
||||
slot = 8,
|
||||
type = 'body',
|
||||
wearType = 'drawable',
|
||||
componentId = 6,
|
||||
anim = { dict = 'random@domestic', anim = 'pickup_low', flags = 49 }
|
||||
},
|
||||
{
|
||||
name = 'ears',
|
||||
slot = 9,
|
||||
type = 'body',
|
||||
wearType = 'prop',
|
||||
componentId = 2,
|
||||
anim = { dict = 'mp_cp_stolen_tut', anim = 'b_think', flags = 49 }
|
||||
},
|
||||
{
|
||||
name = 'bag',
|
||||
slot = 10,
|
||||
type = 'addon',
|
||||
wearType = 'drawable',
|
||||
componentId = 5,
|
||||
anim = { dict = 'anim@heists@ornate_bank@grab_cash', anim = 'intro', flags = 49 }
|
||||
},
|
||||
{
|
||||
name = 'watch',
|
||||
slot = 11,
|
||||
type = 'addon',
|
||||
wearType = 'prop',
|
||||
componentId = 6,
|
||||
anim = { dict = 'nmt_3_rcm-10', anim = 'cs_nigel_dual-10', flags = 49 }
|
||||
},
|
||||
{
|
||||
name = 'bracelets',
|
||||
slot = 12,
|
||||
type = 'addon',
|
||||
wearType = 'prop',
|
||||
componentId = 7,
|
||||
anim = { dict = 'nmt_3_rcm-10', anim = 'cs_nigel_dual-10', flags = 49 }
|
||||
},
|
||||
{
|
||||
name = 'chain',
|
||||
slot = 13,
|
||||
type = 'addon',
|
||||
wearType = 'drawable',
|
||||
componentId = 7,
|
||||
anim = { dict = 'nmt_3_rcm-10', anim = 'cs_nigel_dual-10', flags = 49 }
|
||||
},
|
||||
{
|
||||
name = 'vest',
|
||||
slot = 14,
|
||||
type = 'addon',
|
||||
wearType = 'drawable',
|
||||
componentId = 9,
|
||||
anim = { dict = 'nmt_3_rcm-10', anim = 'cs_nigel_dual-10', flags = 49 }
|
||||
},
|
||||
}
|
||||
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- Appearance System Detection [AUTO]
|
||||
-- [INFO] Auto-detects supported appearance/clothing resources.
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
local appearances = { -- [CORE] Resource name → internal alias
|
||||
['illenium-appearance'] = 'illenium',
|
||||
['qs-appearance'] = 'illenium',
|
||||
['rcore_clothing'] = 'rcore',
|
||||
['esx_skin'] = 'esx',
|
||||
['qb-clothing'] = 'qb'
|
||||
}
|
||||
Config.Appearance = DependencyCheck(appearances) or 'standalone' -- [AUTO]
|
||||
|
||||
Config.TakePreviousClothes = false -- [EDIT] Adds previous worn clothes back to inventory when changing.
|
||||
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- Drop Settings [EDIT]
|
||||
-- [INFO] Control dropped items visuals and refresh system.
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
Config.ItemDropObject = `prop_paper_bag_small` -- [EDIT] Model for dropped items (false = no object)
|
||||
Config.DropRefreshTime = 15 * 60 -- [EDIT] Refresh time for ground items (seconds)
|
||||
Config.MaxDropViewDistance = 9.5 -- [EDIT] Max view distance for dropped items
|
||||
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- Gender System [EDIT]
|
||||
-- [INFO] Defines available gender labels for use in UI and logic.
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
Config.Genders = {
|
||||
['m'] = 'Male',
|
||||
['f'] = 'Female',
|
||||
[1] = 'Male',
|
||||
[2] = 'Female'
|
||||
}
|
||||
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- Visual Configuration [EDIT]
|
||||
-- [INFO] Controls animations, UI logo, idle camera and sidebar visibility.
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
Config.OpenInventoryAnim = true -- [EDIT] Play animation when opening inventory
|
||||
Config.OpenInventoryScene = false -- [EDIT] Toggle scene animation
|
||||
Config.Logo = 'https://i.ibb.co/CJfj6KV/Mini-copia.png' -- [EDIT] Logo (URL or local path)
|
||||
Config.IdleCamera = true -- [EDIT] Enable idle camera while inventory open
|
||||
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- Sidebar & Display Options [EDIT]
|
||||
-- [INFO] Defines what stats and menus appear in the UI.
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
Config.InventoryOptions = {
|
||||
['clothes'] = Config.Clothing, -- [EDIT] Enable clothing button
|
||||
['configuration'] = true, -- [EDIT] Show config menu
|
||||
['health'] = true, -- [EDIT] Show player health
|
||||
['armor'] = true, -- [EDIT] Show armor level
|
||||
['hunger'] = true, -- [EDIT] Show hunger
|
||||
['thirst'] = true, -- [EDIT] Show thirst
|
||||
['id'] = true, -- [EDIT] Show player ID
|
||||
['money'] = true, -- [EDIT] Show cash
|
||||
['bank'] = false, -- [EDIT] Show bank balance
|
||||
['blackmoney'] = false, -- [EDIT] Show black money
|
||||
}
|
||||
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- Item Mini Icons [EDIT]
|
||||
-- [INFO] Assign FontAwesome icons to items in UI. (https://fontawesome.com/)
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
Config.ItemMiniIcons = {
|
||||
['tosti'] = { icon = 'fa-solid fa-utensils' },
|
||||
['water_bottle'] = { icon = 'fa-solid fa-utensils' },
|
||||
}
|
||||
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- Item Rarities [EDIT]
|
||||
-- [INFO] Define rarity gradients for inventory visuals.
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
Config.ItemRarities = {
|
||||
{ name = 'common', css = 'background-image: linear-gradient(to top, rgba(211,211,211,0.5), rgba(211,211,211,0) 60%)' },
|
||||
{ name = 'epic', css = 'background-image: linear-gradient(to top, rgba(128,0,128,0.5), rgba(128,0,128,0) 60%)' },
|
||||
{ name = 'legendary', css = 'background-image: linear-gradient(to top, rgba(255,215,0,0.5), rgba(255,215,0,0) 60%)' },
|
||||
}
|
||||
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- Default Character Appearance [EDIT]
|
||||
-- [INFO] Base clothing sets per gender. Adjust for custom clothing systems.
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
Config.Defaults = {
|
||||
['female'] = {
|
||||
torso = 18,
|
||||
jeans = 19,
|
||||
shoes = 34,
|
||||
arms = 15,
|
||||
helmet = -1,
|
||||
glasses = -1,
|
||||
mask = 0,
|
||||
tshirt = 2,
|
||||
ears = -1,
|
||||
bag = 0,
|
||||
watch = -1,
|
||||
chain = 0,
|
||||
bracelets = -1,
|
||||
vest = 0,
|
||||
},
|
||||
['male'] = {
|
||||
torso = 15,
|
||||
jeans = 14,
|
||||
shoes = 34,
|
||||
arms = 15,
|
||||
helmet = -1,
|
||||
glasses = -1,
|
||||
mask = 0,
|
||||
tshirt = 15,
|
||||
ears = -1,
|
||||
bag = 0,
|
||||
watch = -1,
|
||||
chain = 0,
|
||||
bracelets = -1,
|
||||
vest = 0,
|
||||
}
|
||||
}
|
||||
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- Compact Inventory [EDIT]
|
||||
-- [INFO] Turns your inventory into a compact, side-mounted interface allowing
|
||||
-- movement while open — signature Quasar experience.
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
Config.CompactInventory = false -- [EDIT] Enables compact view for a smaller, mobile-friendly layout.
|
||||
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- Key Bindings [EDIT]
|
||||
-- [INFO] Define shortcut keys for inventory actions. See documentation for keymap setup.
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
Config.KeyBinds = { -- [EDIT]
|
||||
inventory = 'TAB', -- [INFO] Open inventory
|
||||
hotbar = 'Z', -- [INFO] Show hotbar
|
||||
reload = 'R', -- [INFO] Reload action
|
||||
handsup = 'X', -- [INFO] Hands-up/robbery gesture
|
||||
}
|
||||
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- Debug & Development Tools [EDIT]
|
||||
-- [INFO] Enables development logs and debugging prints. Use only during testing.
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
Config.Debug = false -- [EDIT] Detailed console prints
|
||||
Config.ZoneDebug = false -- [EDIT] Display additional zone debug info
|
||||
Config.InventoryPrefix = 'inventory' -- [ADV] Internal prefix; changing requires code adjustments
|
||||
Config.SaveInventoryInterval = 12500 -- [EDIT] Autosave interval (ms)
|
||||
Config.BypassQbInventory = true -- [EDIT] Bypass qb-inventory for QS compatibility
|
||||
|
||||
--[[ [INFO]
|
||||
The system now saves inventories when updates occur instead of on close,
|
||||
reducing duplication risks. Avoid frequent restarts, as unsaved data may be lost.
|
||||
|
||||
Command available:
|
||||
/save-inventories → Manually saves all inventories before restart.
|
||||
]]
|
||||
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- Free Mode Keys [EDIT]
|
||||
-- [INFO] Controls for object manipulation during free placement/edit modes.
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
Config.FreeModeKeys = {
|
||||
ChangeKey = Keys['LEFTCTRL'], -- [EDIT] Toggle free mode
|
||||
MoreSpeed = Keys['.'], -- [EDIT] Increase move speed
|
||||
LessSpeed = Keys[','], -- [EDIT] Decrease move speed
|
||||
MoveToTop = Keys['TOP'], -- [EDIT] Move upward
|
||||
MoveToDown = Keys['DOWN'], -- [EDIT] Move downward
|
||||
MoveToForward = Keys['TOP'], -- [EDIT] Move forward
|
||||
MoveToBack = Keys['DOWN'], -- [EDIT] Move backward
|
||||
MoveToRight = Keys['RIGHT'], -- [EDIT] Move right
|
||||
MoveToLeft = Keys['LEFT'], -- [EDIT] Move left
|
||||
RotateToTop = Keys['6'], -- [EDIT] Rotate upward
|
||||
RotateToDown = Keys['7'], -- [EDIT] Rotate downward
|
||||
RotateToLeft = Keys['8'], -- [EDIT] Rotate left
|
||||
RotateToRight = Keys['9'], -- [EDIT] Rotate right
|
||||
TiltToTop = Keys['Z'], -- [EDIT] Tilt upward
|
||||
TiltToDown = Keys['X'], -- [EDIT] Tilt downward
|
||||
TiltToLeft = Keys['C'], -- [EDIT] Tilt left
|
||||
TiltToRight = Keys['V'], -- [EDIT] Tilt right
|
||||
StickToTheGround = Keys['LEFTALT'], -- [EDIT] Snap object to ground
|
||||
}
|
||||
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- Editor Action Controls [EDIT]
|
||||
-- [INFO] Keybinds used in world/zone editing for point and rotation handling.
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
ActionControls = {
|
||||
leftClick = { label = 'Place Object', codes = { 24 } }, -- [EDIT]
|
||||
forward = { label = 'Forward +/-', codes = { 33, 32 } }, -- [EDIT] Move forward/backward
|
||||
right = { label = 'Right +/-', codes = { 35, 34 } }, -- [EDIT] Move left/right
|
||||
up = { label = 'Up +/-', codes = { 52, 51 } }, -- [EDIT] Raise/lower vertically
|
||||
add_point = { label = 'Add Point', codes = { 24 } }, -- [EDIT]
|
||||
undo_point = { label = 'Undo Last', codes = { 25 } }, -- [EDIT]
|
||||
rotate_z = { label = 'RotateZ +/-', codes = { 20, 79 } }, -- [EDIT] Z-axis rotation
|
||||
rotate_y = { label = 'RotateY +/-', codes = { 29, 249 } }, -- [EDIT] Y-axis rotation
|
||||
rotate_x = { label = 'RotateX +/-', codes = { 311, 182 } }, -- [EDIT] X-axis rotation
|
||||
rotate_z_scroll = { label = 'RotateZ +/-', codes = { 17, 16 } }, -- [EDIT] Z-axis via scroll modifiers
|
||||
offset_z = { label = 'Offset Z +/-', codes = { 44, 46 } }, -- [EDIT] Vertical offset
|
||||
boundary_height = { label = 'Z Boundary +/-', codes = { 20, 73 } }, -- [EDIT] Change Z boundary
|
||||
done = { label = 'Done', codes = { 191 } }, -- [EDIT] Confirm/finish
|
||||
cancel = { label = 'Cancel', codes = { 194 } }, -- [EDIT] Cancel current action
|
||||
throw = { label = 'Throw', codes = { 24, 25 } }, -- [EDIT] Throw current weapon
|
||||
}
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- Free Camera Options [EDIT]
|
||||
-- [INFO] Camera movement and rotation speed configuration for editors/previews.
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
CameraOptions = {
|
||||
lookSpeedX = 1000.0, -- [EDIT] Horizontal camera movement speed
|
||||
lookSpeedY = 1000.0, -- [EDIT] Vertical camera movement speed
|
||||
moveSpeed = 20.0, -- [EDIT] Free camera move speed
|
||||
climbSpeed = 10.0, -- [EDIT] Up/Down movement speed
|
||||
rotateSpeed = 20.0, -- [EDIT] Rotation speed
|
||||
}
|
||||
236
resources/[framework]/[addons]/qs-inventory/config/crafting.lua
Normal file
@@ -0,0 +1,236 @@
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- Quasar Store · Configuration Guidelines
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- This configuration file defines all adjustable parameters for the script.
|
||||
-- Comments are standardized to help you identify which sections you can safely edit.
|
||||
--
|
||||
-- • [EDIT] – Safe for users to modify. Adjust these values as needed.
|
||||
-- • [INFO] – Informational note describing what the variable or block does.
|
||||
-- • [ADV] – Advanced settings. Change only if you understand the logic behind it.
|
||||
-- • [CORE] – Core functionality. Do not modify unless you are a developer.
|
||||
-- • [AUTO] – Automatically handled by the system. Never edit manually.
|
||||
--
|
||||
-- Always make a backup before editing configuration files.
|
||||
-- Incorrect changes in [CORE] or [AUTO] sections can break the resource.
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- Crafting System [EDIT]
|
||||
-- [INFO] Independent crafting, no DLC required. Supports success chance, and
|
||||
-- (opcional) reputación en QBCore para bloquear/mostrar recetas.
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
Config.Crafting = true -- [EDIT] Toggle the crafting system on/off
|
||||
|
||||
--[[ [INFO]
|
||||
Noteworthy features:
|
||||
- Per-item success chance (1–100%)
|
||||
- Reputation-based visibility (QBCore): 'craftingrep' / 'attachmentcraftingrep'
|
||||
- Configure 'rep' fields and thresholds per your server design.
|
||||
]]
|
||||
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- Reputation (QBCore only) [EDIT]
|
||||
-- [INFO] Gate items behind reputation levels. Only for QBCore frameworks.
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
Config.CraftingReputation = false -- [EDIT] Enable reputation gating (QBCore)
|
||||
Config.ThresholdItems = false -- [EDIT] Show items only if rep >= threshold (QBCore)
|
||||
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- Example Item Entry (Reference) [INFO]
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
--[[
|
||||
[1] = {
|
||||
name = "weapon_pistol",
|
||||
amount = 50,
|
||||
info = {},
|
||||
costs = {
|
||||
["iron"] = 80,
|
||||
["metalscrap"] = 120,
|
||||
["rubber"] = 8,
|
||||
["steel"] = 133,
|
||||
["lockpick"] = 5,
|
||||
},
|
||||
type = "weapon", -- "item" | "weapon"
|
||||
slot = 1,
|
||||
rep = 'attachmentcraftingrep', -- QBCore only
|
||||
points = 1, -- QBCore only (reward on craft)
|
||||
threshold = 0, -- QBCore only (visibility)
|
||||
time = 5500, -- ms
|
||||
chance = 100 -- 1..100 success probability
|
||||
},
|
||||
]]
|
||||
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- External Crafting Event (Sample) [ADV]
|
||||
-- [INFO] Example to open a custom crafting menu from another script/event.
|
||||
-- ⚠ Posible typo: export 'SetUpCrafing' → suele ser 'SetUpCrafting'. Mantengo tu nombre.
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
function OpenCrafting()
|
||||
local CustomCrafting = {
|
||||
[1] = {
|
||||
name = 'weapon_pistol',
|
||||
amount = 50,
|
||||
info = {},
|
||||
costs = { ['tosti'] = 1 },
|
||||
type = 'weapon',
|
||||
slot = 1,
|
||||
rep = 'attachmentcraftingrep',
|
||||
points = 1,
|
||||
threshold = 0,
|
||||
time = 5500,
|
||||
chance = 100
|
||||
},
|
||||
[2] = {
|
||||
name = 'water_bottle',
|
||||
amount = 1,
|
||||
info = {},
|
||||
costs = { ['tosti'] = 1 },
|
||||
type = 'item',
|
||||
slot = 2,
|
||||
rep = 'attachmentcraftingrep',
|
||||
points = 1,
|
||||
threshold = 0,
|
||||
time = 8500,
|
||||
chance = 100
|
||||
},
|
||||
}
|
||||
|
||||
local items = exports['qs-inventory']:SetUpCrafing(CustomCrafting) -- [INFO] Revisa el nombre del export si fuera necesario.
|
||||
local crafting = { label = 'Craft', items = items }
|
||||
|
||||
TriggerServerEvent('inventory:server:SetInventoryItems', items)
|
||||
TriggerServerEvent('inventory:server:OpenInventory', 'customcrafting', crafting.label, crafting)
|
||||
end
|
||||
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- Crafting Tables [EDIT]
|
||||
-- [INFO] Define mesas de crafteo por job/ubicación, con blip y recetas propias.
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
Config.CraftingTables = {
|
||||
-- [1] = {
|
||||
-- name = 'Police Crafting',
|
||||
-- isjob = 'police',
|
||||
-- grades = 'all',
|
||||
-- text = '[E] - Police Craft',
|
||||
-- blip = {
|
||||
-- enabled = true,
|
||||
-- title = 'Police Crafting',
|
||||
-- scale = 1.0,
|
||||
-- display = 4,
|
||||
-- colour = 0,
|
||||
-- id = 365
|
||||
-- },
|
||||
-- location = vec3(459.771423, -989.050537, 24.898926),
|
||||
-- items = {
|
||||
-- [1] = {
|
||||
-- name = 'weapon_pistol',
|
||||
-- amount = 50,
|
||||
-- info = {},
|
||||
-- costs = {
|
||||
-- ['iron'] = 80,
|
||||
-- ['metalscrap'] = 70,
|
||||
-- ['rubber'] = 8,
|
||||
-- ['steel'] = 60,
|
||||
-- ['lockpick'] = 5,
|
||||
-- },
|
||||
-- type = 'weapon',
|
||||
-- slot = 1,
|
||||
-- rep = 'attachmentcraftingrep',
|
||||
-- points = 1,
|
||||
-- threshold = 0,
|
||||
-- time = 5500,
|
||||
-- chance = 100
|
||||
-- },
|
||||
-- [2] = {
|
||||
-- name = 'weapon_smg',
|
||||
-- amount = 1,
|
||||
-- info = {},
|
||||
-- costs = {
|
||||
-- ['iron'] = 80,
|
||||
-- ['metalscrap'] = 120,
|
||||
-- ['rubber'] = 10,
|
||||
-- ['steel'] = 65,
|
||||
-- ['lockpick'] = 10,
|
||||
-- },
|
||||
-- type = 'weapon',
|
||||
-- slot = 2,
|
||||
-- rep = 'attachmentcraftingrep',
|
||||
-- points = 1,
|
||||
-- threshold = 0,
|
||||
-- time = 8500,
|
||||
-- chance = 100
|
||||
-- },
|
||||
-- [3] = {
|
||||
-- name = 'weapon_carbinerifle',
|
||||
-- amount = 1,
|
||||
-- info = {},
|
||||
-- costs = {
|
||||
-- ['iron'] = 120,
|
||||
-- ['metalscrap'] = 120,
|
||||
-- ['rubber'] = 20,
|
||||
-- ['steel'] = 90,
|
||||
-- ['lockpick'] = 14,
|
||||
-- },
|
||||
-- type = 'weapon',
|
||||
-- slot = 3,
|
||||
-- rep = 'craftingrep',
|
||||
-- points = 2,
|
||||
-- threshold = 0,
|
||||
-- time = 12000,
|
||||
-- chance = 100
|
||||
-- }
|
||||
-- }
|
||||
-- },
|
||||
-- [2] = {
|
||||
-- name = 'Attachment Crafting',
|
||||
-- isjob = false,
|
||||
-- grades = 'all',
|
||||
-- text = '[E] - Craft Attachment',
|
||||
-- blip = {
|
||||
-- enabled = true,
|
||||
-- title = 'Attachment Crafting',
|
||||
-- scale = 1.0,
|
||||
-- display = 4,
|
||||
-- colour = 0,
|
||||
-- id = 365
|
||||
-- },
|
||||
-- location = vec3(90.303299, 3745.503418, 39.771484),
|
||||
-- items = {
|
||||
-- [1] = {
|
||||
-- name = 'pistol_extendedclip',
|
||||
-- amount = 50,
|
||||
-- info = {},
|
||||
-- costs = {
|
||||
-- ['metalscrap'] = 140,
|
||||
-- ['steel'] = 250,
|
||||
-- ['rubber'] = 60,
|
||||
-- },
|
||||
-- type = 'item',
|
||||
-- slot = 1,
|
||||
-- rep = 'attachmentcraftingrep',
|
||||
-- points = 1,
|
||||
-- threshold = 0,
|
||||
-- time = 8000,
|
||||
-- chance = 90
|
||||
-- },
|
||||
-- [2] = {
|
||||
-- name = 'pistol_suppressor',
|
||||
-- amount = 50,
|
||||
-- info = {},
|
||||
-- costs = {
|
||||
-- ['metalscrap'] = 165,
|
||||
-- ['steel'] = 285,
|
||||
-- ['rubber'] = 75,
|
||||
-- },
|
||||
-- type = 'item',
|
||||
-- slot = 2,
|
||||
-- rep = 'attachmentcraftingrep',
|
||||
-- points = 1,
|
||||
-- threshold = 0,
|
||||
-- time = 8000,
|
||||
-- chance = 90
|
||||
-- },
|
||||
-- }
|
||||
-- },
|
||||
-- Continue with the same structure for the other Crafting Tables...
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- Custom Weapons [EDIT]
|
||||
-- [INFO] Map weapon names to allowed attachments and durability loss per shot.
|
||||
-- [INFO] You must also register these in items.lua and weapons.lua.
|
||||
-- [REF] Example reference: https://github.com/NoobySloth/Custom-Weapons/tree/main
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
Config.CustomWeapons = {
|
||||
-- -- Example:
|
||||
-- ['WEAPON_AK47'] = {
|
||||
-- attachments = {
|
||||
-- defaultclip = { component = 'COMPONENT_AK47_CLIP_01', item = 'rifle_defaultclip' }, -- [EDIT]
|
||||
-- extendedclip = { component = 'COMPONENT_AK47_CLIP_02', item = 'rifle_extendedclip' }, -- [EDIT]
|
||||
-- -- Add more: scope = { component = 'COMPONENT_AK47_SCOPE', item = 'rifle_scope' },
|
||||
-- },
|
||||
-- durability = 0.15 -- [EDIT] Durability decay per shot (0.0–1.0; higher = wears faster)
|
||||
-- },
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
//──────────────────────────────────────────────────────────────────────────────
|
||||
// Quasar Store · Configuration Guidelines
|
||||
//──────────────────────────────────────────────────────────────────────────────
|
||||
// This configuration file defines all adjustable parameters for the script.
|
||||
// Comments are standardized to help you identify which sections you can safely edit.
|
||||
//
|
||||
// • [EDIT] – Safe for users to modify. Adjust these values as needed.
|
||||
// • [INFO] – Informational note describing what the variable or block does.
|
||||
// • [ADV] – Advanced settings. Change only if you understand the logic behind it.
|
||||
// • [CORE] – Core functionality. Do not modify unless you are a developer.
|
||||
// • [AUTO] – Automatically handled by the system. Never edit manually.
|
||||
//
|
||||
// Always make a backup before editing configuration files.
|
||||
// Incorrect changes in [CORE] or [AUTO] sections can break the resource.
|
||||
//──────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
//──────────────────────────────────────────────────────────────────────────────
|
||||
// Interface · Default Color Configuration [EDIT]
|
||||
//──────────────────────────────────────────────────────────────────────────────
|
||||
// [INFO] Defines the base color palette and visual balance for the interface.
|
||||
// All values must be in hexadecimal format. Avoid RGB to prevent rendering issues.
|
||||
// Use the RESET button in UI to restore factory defaults.
|
||||
//──────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
// Primary and Secondary Colors
|
||||
const defaultPrimaryColor = "#0E151B" // [EDIT] Base color for main UI backgrounds and buttons
|
||||
const defaultPrimaryOpacity = "0.2" // [EDIT] Opacity level for primary color (0.0–1.0)
|
||||
const defaultSecondaryColor = "#0E151B" // [EDIT] Secondary UI color for complementary elements
|
||||
const defaultSecondaryOpacity = "1.0" // [EDIT] Full opacity for strong visibility
|
||||
|
||||
// Borders and Text
|
||||
const defaultBorderColor = "#00A3FF" // [EDIT] Highlight color for UI borders and interactive elements
|
||||
const defaultBorderOpacity = "0.6" // [EDIT] Semi-transparent level for UI borders
|
||||
const defaultBorderRadius = "1px" // [EDIT] Defines corner roundness for UI boxes
|
||||
const defaultTextColor = "#FFFFFF" // [EDIT] Default text color ensuring readability on dark UI
|
||||
340
resources/[framework]/[addons]/qs-inventory/config/garbage.lua
Normal file
@@ -0,0 +1,340 @@
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- Quasar Store · Configuration Guidelines
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- This configuration file defines all adjustable parameters for the script.
|
||||
-- Comments are standardized to help you identify which sections you can safely edit.
|
||||
--
|
||||
-- • [EDIT] – Safe for users to modify. Adjust these values as needed.
|
||||
-- • [INFO] – Informational note describing what the variable or block does.
|
||||
-- • [ADV] – Advanced settings. Change only if you understand the logic behind it.
|
||||
-- • [CORE] – Core functionality. Do not modify unless you are a developer.
|
||||
-- • [AUTO] – Automatically handled by the system. Never edit manually.
|
||||
--
|
||||
-- Always make a backup before editing configuration files.
|
||||
-- Incorrect changes in [CORE] or [AUTO] sections can break the resource.
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- Garbage Scavenging [EDIT]
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- [INFO] Controls the lootable garbage cans system. Players can search bins or dumpsters
|
||||
-- around the map to find random items with dynamic amounts and rarity.
|
||||
-- Each prop listed below can be configured individually for slot count and loot pool.
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
Config.GarbageItems = {} -- [INFO] Reserved for future garbage-related flags or logic extensions.
|
||||
Config.GarbageRefreshTime = 2 * 60 -- 2 hours
|
||||
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- Garbage Objects (Registered Props) [EDIT]
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- [INFO] This list defines the in-world dumpster models that can be looted.
|
||||
-- If your server does not use targeting, this section can be ignored.
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
Config.GarbageObjects = {
|
||||
'prop_dumpster_02a', -- Standard dumpster
|
||||
'prop_dumpster_4b', -- Large blue dumpster
|
||||
'prop_dumpster_4a', -- Large green dumpster
|
||||
'prop_dumpster_3a', -- Small gray dumpster
|
||||
'prop_dumpster_02b', -- Alternate dumpster model
|
||||
'prop_dumpster_01a' -- Basic dumpster model
|
||||
}
|
||||
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- Loot Tables Per Prop [EDIT]
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- [INFO] Maps dumpster models (joaat hashes) to their respective loot inventories.
|
||||
-- Each entry defines:
|
||||
-- • label → UI label shown when looting
|
||||
-- • slots → max number of items the container can hold
|
||||
-- • items → actual loot entries with random quantity ranges
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
Config.GarbageItemsForProp = {
|
||||
[joaat('prop_dumpster_02a')] = {
|
||||
label = 'Garbage', -- [INFO] UI label displayed when interacting
|
||||
slots = 30, -- [EDIT] Total available item slots in dumpster
|
||||
items = {
|
||||
[1] = {
|
||||
[1] = {
|
||||
name = 'aluminum',
|
||||
amount = { min = 1, max = 5 },
|
||||
info = {},
|
||||
type = 'item',
|
||||
slot = 1,
|
||||
},
|
||||
[2] = {
|
||||
name = 'metalscrap',
|
||||
amount = { min = 1, max = 5 },
|
||||
info = {},
|
||||
type = 'item',
|
||||
slot = 2,
|
||||
},
|
||||
},
|
||||
[2] = {
|
||||
[1] = {
|
||||
name = 'iron',
|
||||
amount = { min = 1, max = 5 },
|
||||
info = {},
|
||||
type = 'item',
|
||||
slot = 1,
|
||||
},
|
||||
[2] = {
|
||||
name = 'steel',
|
||||
amount = { min = 1, max = 5 },
|
||||
info = {},
|
||||
type = 'item',
|
||||
slot = 2,
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
[joaat('prop_dumpster_4b')] = {
|
||||
label = 'Garbage',
|
||||
slots = 30,
|
||||
items = {
|
||||
[1] = {
|
||||
[1] = {
|
||||
name = 'aluminum',
|
||||
amount = {
|
||||
min = 1,
|
||||
max = 5
|
||||
},
|
||||
info = {},
|
||||
type = 'item',
|
||||
slot = 1,
|
||||
},
|
||||
[2] = {
|
||||
name = 'plastic',
|
||||
amount = {
|
||||
min = 1,
|
||||
max = 5
|
||||
},
|
||||
info = {},
|
||||
type = 'item',
|
||||
slot = 2,
|
||||
},
|
||||
},
|
||||
[2] = {
|
||||
[1] = {
|
||||
name = 'plastic',
|
||||
amount = {
|
||||
min = 1,
|
||||
max = 5
|
||||
},
|
||||
info = {},
|
||||
type = 'item',
|
||||
slot = 1,
|
||||
},
|
||||
[2] = {
|
||||
name = 'metalscrap',
|
||||
amount = {
|
||||
min = 1,
|
||||
max = 5
|
||||
},
|
||||
info = {},
|
||||
type = 'item',
|
||||
slot = 2,
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
[joaat('prop_dumpster_4a')] = {
|
||||
label = 'Garbage',
|
||||
slots = 30,
|
||||
items = {
|
||||
[1] = {
|
||||
[1] = {
|
||||
name = 'aluminum',
|
||||
amount = {
|
||||
min = 1,
|
||||
max = 5
|
||||
},
|
||||
info = {},
|
||||
type = 'item',
|
||||
slot = 1,
|
||||
},
|
||||
[2] = {
|
||||
name = 'metalscrap',
|
||||
amount = {
|
||||
min = 1,
|
||||
max = 5
|
||||
},
|
||||
info = {},
|
||||
type = 'item',
|
||||
slot = 2,
|
||||
},
|
||||
},
|
||||
[2] = {
|
||||
[1] = {
|
||||
name = 'glass',
|
||||
amount = {
|
||||
min = 1,
|
||||
max = 5
|
||||
},
|
||||
info = {},
|
||||
type = 'item',
|
||||
slot = 1,
|
||||
},
|
||||
[2] = {
|
||||
name = 'joint',
|
||||
amount = {
|
||||
min = 1,
|
||||
max = 5
|
||||
},
|
||||
info = {},
|
||||
type = 'item',
|
||||
slot = 2,
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
[joaat('prop_dumpster_3a')] = {
|
||||
label = 'Garbage',
|
||||
slots = 30,
|
||||
items = {
|
||||
[1] = {
|
||||
[1] = {
|
||||
name = 'aluminum',
|
||||
amount = {
|
||||
min = 1,
|
||||
max = 5
|
||||
},
|
||||
info = {},
|
||||
type = 'item',
|
||||
slot = 1,
|
||||
},
|
||||
[2] = {
|
||||
name = 'lighter',
|
||||
amount = {
|
||||
min = 1,
|
||||
max = 5
|
||||
},
|
||||
info = {},
|
||||
type = 'item',
|
||||
slot = 2,
|
||||
},
|
||||
},
|
||||
[2] = {
|
||||
[1] = {
|
||||
name = 'metalscrap',
|
||||
amount = {
|
||||
min = 1,
|
||||
max = 5
|
||||
},
|
||||
info = {},
|
||||
type = 'item',
|
||||
slot = 1,
|
||||
},
|
||||
[2] = {
|
||||
name = 'rubber',
|
||||
amount = {
|
||||
min = 1,
|
||||
max = 5
|
||||
},
|
||||
info = {},
|
||||
type = 'item',
|
||||
slot = 2,
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
[joaat('prop_dumpster_02b')] = {
|
||||
label = 'Garbage',
|
||||
slots = 30,
|
||||
items = {
|
||||
[1] = {
|
||||
[1] = {
|
||||
name = 'metalscrap',
|
||||
amount = {
|
||||
min = 1,
|
||||
max = 5
|
||||
},
|
||||
info = {},
|
||||
type = 'item',
|
||||
slot = 1,
|
||||
},
|
||||
[2] = {
|
||||
name = 'rubber',
|
||||
amount = {
|
||||
min = 1,
|
||||
max = 5
|
||||
},
|
||||
info = {},
|
||||
type = 'item',
|
||||
slot = 2,
|
||||
},
|
||||
},
|
||||
[2] = {
|
||||
[1] = {
|
||||
name = 'iron',
|
||||
amount = {
|
||||
min = 1,
|
||||
max = 5
|
||||
},
|
||||
info = {},
|
||||
type = 'item',
|
||||
slot = 1,
|
||||
},
|
||||
[2] = {
|
||||
name = 'steel',
|
||||
amount = {
|
||||
min = 1,
|
||||
max = 5
|
||||
},
|
||||
info = {},
|
||||
type = 'item',
|
||||
slot = 2,
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
[joaat('prop_dumpster_01a')] = {
|
||||
label = 'Garbage',
|
||||
slots = 30,
|
||||
items = {
|
||||
[1] = {
|
||||
[1] = {
|
||||
name = 'plastic',
|
||||
amount = {
|
||||
min = 1,
|
||||
max = 5
|
||||
},
|
||||
info = {},
|
||||
type = 'item',
|
||||
slot = 1,
|
||||
},
|
||||
[2] = {
|
||||
name = 'metalscrap',
|
||||
amount = {
|
||||
min = 1,
|
||||
max = 5
|
||||
},
|
||||
info = {},
|
||||
type = 'item',
|
||||
slot = 2,
|
||||
},
|
||||
},
|
||||
[2] = {
|
||||
[1] = {
|
||||
name = 'lighter',
|
||||
amount = {
|
||||
min = 1,
|
||||
max = 5
|
||||
},
|
||||
info = {},
|
||||
type = 'item',
|
||||
slot = 1,
|
||||
},
|
||||
[2] = {
|
||||
name = 'metalscrap',
|
||||
amount = {
|
||||
min = 1,
|
||||
max = 5
|
||||
},
|
||||
info = {},
|
||||
type = 'item',
|
||||
slot = 2,
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
366
resources/[framework]/[addons]/qs-inventory/config/metadata.js
Normal file
@@ -0,0 +1,366 @@
|
||||
/*──────────────────────────────────────────────────────────────────────────────
|
||||
Item Info Formatter [EDIT]
|
||||
[INFO] Renders item metadata into the NUI side panel. Prioritizes metadata
|
||||
(itemData.info) over base fields and supports a verbose "showItemData"
|
||||
mode that prints all metadata as a table.
|
||||
|
||||
Main behaviors:
|
||||
• Phones list (phoneMeta) – Helper array to identify phone items. [INFO]
|
||||
• FormatItemInfo(itemData) – Entry point. Safely reads metadata and renders. [CORE]
|
||||
- If info.showItemData === true → prints all metadata via tableToString().
|
||||
- Special case: "id_card" → prints structured ID details.
|
||||
- Fallbacks ensure safe, predictable output when fields are missing.
|
||||
|
||||
Notes:
|
||||
• Keep DOM selectors (.item-info-title / .item-info-description) in sync with your UI.
|
||||
• Use `escapeHtml` for any untrusted string to avoid injection. [SEC]
|
||||
──────────────────────────────────────────────────────────────────────────────*/
|
||||
|
||||
let phoneMeta = ['phone', 'black_phone', 'yellow_phone', 'red_phone', 'green_phone', 'white_phone']; // [INFO]
|
||||
|
||||
function FormatItemInfo(itemData) {
|
||||
// Checks if itemData is valid and contains metadata info
|
||||
if (itemData != null && itemData.info != "") {
|
||||
let label = itemData?.info?.label || itemData?.label; // Sets the item label, prioritizing info metadata
|
||||
|
||||
// If item has showItemData flag, display all metadata in a table format
|
||||
if (itemData.info.showItemData) {
|
||||
$(".item-info-title").html("<p>" + itemData.label + "</p>");
|
||||
$(".item-info-description").html("<p>" + tableToString(itemData.info) + "</p>");
|
||||
return;
|
||||
}
|
||||
|
||||
// ID Card: Display CSN, first and last name, birthdate, gender, and nationality
|
||||
if (itemData.name == "id_card") {
|
||||
$(".item-info-title").html("<p>" + `${itemData.info.label || label}` + "</p>");
|
||||
$(".item-info-description").html(
|
||||
"<p><strong>CSN: </strong><span>" +
|
||||
(itemData.info.citizenid !== undefined ? itemData.info.citizenid : 'ID-Card ' + Math.floor(Math.random() * 99999)) +
|
||||
"</span></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>" +
|
||||
(itemData.info.gender !== undefined ? itemData.info.gender : 'AH-64 Apache Helicopter') +
|
||||
"</span></p><p><strong>Nationality: </strong><span>" +
|
||||
(itemData.info.nationality !== undefined ? itemData.info.nationality : 'No information') +
|
||||
"</span></p>"
|
||||
);
|
||||
}
|
||||
// Phone Items: Check if item is a phone and display relevant details if available
|
||||
else if (phoneMeta.includes(itemData.name) && itemData.info.phoneNumber) {
|
||||
$(".item-info-title").html("<p>" + `${itemData.info.label || label}` + "</p>");
|
||||
$(".item-info-description").html(
|
||||
"<p><strong>Phone Number: </strong><span>" +
|
||||
itemData.info.phoneNumber +
|
||||
"</span></p><p><strong>Firstname: </strong><span>" +
|
||||
itemData.info.charinfo.firstname +
|
||||
"</span></p><p><strong>Lastname: </strong><span>" +
|
||||
itemData.info.charinfo.lastname +
|
||||
"</span></p>"
|
||||
);
|
||||
// Other items
|
||||
} else if (itemData.name == "tradingcard_psa") {
|
||||
$(".item-info-title").html("<p>" + label + "</p>");
|
||||
$(".item-info-description").html(
|
||||
"<p><strong>PSA ID: </strong><span>" +
|
||||
itemData.info.serial +
|
||||
"</span></p>"
|
||||
);
|
||||
} else if (itemData.name == "photo") {
|
||||
$(".item-info-title").html("<p>" + `${itemData.info.label || label}` + "</p>");
|
||||
$(".item-info-description").html(
|
||||
"<p><span>" +
|
||||
itemData.info.location +
|
||||
"</span></p><span>" +
|
||||
itemData.info.date + "</span></p>"
|
||||
);
|
||||
} else if (itemData.name == "vehiclekeys") {
|
||||
$(".item-info-title").html("<p>" + label + "</p>");
|
||||
$(".item-info-description").html(
|
||||
"<p><strong>Plate: </strong><span>" +
|
||||
itemData.info.plate +
|
||||
"</span></p><p><strong>Model: </strong><span>" +
|
||||
itemData.info.description +
|
||||
"</span></p>"
|
||||
);
|
||||
} else if (itemData.name == "plate") {
|
||||
$(".item-info-title").html("<p>" + label + "</p>");
|
||||
$(".item-info-description").html(
|
||||
"<p><strong>Plate: </strong><span>" +
|
||||
itemData.info.plate +
|
||||
"</span></p>"
|
||||
);
|
||||
} else if (itemData.name == "backpack") {
|
||||
$(".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>"
|
||||
);
|
||||
} else if (itemData.name == "backpack2") {
|
||||
$(".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>"
|
||||
);
|
||||
} else if (itemData.name == "briefcase") {
|
||||
$(".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>"
|
||||
);
|
||||
} else if (itemData.name == "paramedicbag") {
|
||||
$(".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>"
|
||||
);
|
||||
} else if (itemData.name == "driver_license") {
|
||||
$(".item-info-title").html("<p>" + `${itemData.info.label || label}` + "</p>");
|
||||
$(".item-info-description").html(
|
||||
"<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>Licenses: </strong><span>" +
|
||||
itemData.info.type +
|
||||
"</span></p>"
|
||||
);
|
||||
} else if (itemData.name == "weaponlicense") {
|
||||
$(".item-info-title").html("<p>" + `${itemData.info.label || label}` + "</p>");
|
||||
$(".item-info-description").html(
|
||||
"<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>"
|
||||
);
|
||||
} else if (itemData.name == "lawyerpass") {
|
||||
$(".item-info-title").html("<p>" + `${itemData.info.label || label}` + "</p>");
|
||||
$(".item-info-description").html(
|
||||
"<p><strong>Pass-ID: </strong><span>" +
|
||||
itemData.info.id +
|
||||
"</span></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>CSN: </strong><span>" +
|
||||
itemData.info.citizenid +
|
||||
"</span></p>"
|
||||
);
|
||||
} else if (itemData.name == "harness") {
|
||||
$(".item-info-title").html("<p>" + `${itemData.info.label || label}` + "</p>");
|
||||
$(".item-info-description").html(
|
||||
"<p>" + itemData.info.uses + " uses left.</p>"
|
||||
);
|
||||
} else if (itemData.name == "weapontint_url") {
|
||||
$(".item-info-title").html("<p>" + `${itemData.info.label || label}` + "</p>");
|
||||
$(".item-info-description").html(
|
||||
"<p><strong>Tint status: </strong><span> " +
|
||||
(itemData.info.urltint !== undefined ? "Used" : "Without use") +
|
||||
"</span></p><p><strong>URL Link: </strong><span>" +
|
||||
(itemData.info.urltint !== undefined ? itemData.info.urltint.substring(0, 40) + "..." : "N/A") +
|
||||
"</span></p>"
|
||||
);
|
||||
} else if (itemData.type == "weapon") {
|
||||
$(".item-info-title").html("<p>" + `${itemData.info.label || label}` + "</p>");
|
||||
if (itemData.info.ammo == undefined) {
|
||||
itemData.info.ammo = 0;
|
||||
} else {
|
||||
itemData.info.ammo != null ? itemData.info.ammo : 0;
|
||||
}
|
||||
if (itemData.info.attachments != null) {
|
||||
var attachmentString = "";
|
||||
$.each(itemData.info.attachments, function (i, attachment) {
|
||||
if (i == itemData.info.attachments.length - 1) {
|
||||
attachmentString += attachment.label;
|
||||
} else {
|
||||
attachmentString += attachment.label + ", ";
|
||||
}
|
||||
});
|
||||
$(".item-info-description").html(
|
||||
"<p><strong>Serial Number: </strong><span>" +
|
||||
itemData.info.serie +
|
||||
"</span></p><p><strong>Munition: </strong><span>" +
|
||||
itemData.info.ammo +
|
||||
"</span></p><p><strong>Attachments: </strong><span>" +
|
||||
attachmentString +
|
||||
"</span></p>"
|
||||
);
|
||||
} else {
|
||||
$(".item-info-description").html(
|
||||
"<p><strong>Serial Number: </strong><span>" +
|
||||
itemData.info.serie +
|
||||
"</span></p><p><strong>Munition: </strong><span>" +
|
||||
itemData.info.ammo +
|
||||
"</span></p><p>" +
|
||||
itemData.description +
|
||||
"</p>"
|
||||
);
|
||||
}
|
||||
} else if (itemData.name == "filled_evidence_bag") {
|
||||
$(".item-info-title").html("<p>" + `${itemData.info.label || label}` + "</p>");
|
||||
if (itemData.info.type == "casing") {
|
||||
$(".item-info-description").html(
|
||||
"<p><strong>Evidence material: </strong><span>" +
|
||||
itemData.info.label +
|
||||
"</span></p><p><strong>Type number: </strong><span>" +
|
||||
itemData.info.ammotype +
|
||||
"</span></p><p><strong>Caliber: </strong><span>" +
|
||||
itemData.info.ammolabel +
|
||||
"</span></p><p><strong>Serial Number: </strong><span>" +
|
||||
itemData.info.serie +
|
||||
"</span></p><p><strong>Crime scene: </strong><span>" +
|
||||
itemData.info.street +
|
||||
"</span></p><br /><p>" +
|
||||
itemData.description +
|
||||
"</p>"
|
||||
);
|
||||
|
||||
} else if (itemData.info.type == "blood") {
|
||||
$(".item-info-description").html(
|
||||
"<p><strong>Evidence material: </strong><span>" +
|
||||
itemData.info.label +
|
||||
"</span></p><p><strong>Blood type: </strong><span>" +
|
||||
itemData.info.bloodtype +
|
||||
"</span></p><p><strong>DNA Code: </strong><span>" +
|
||||
itemData.info.dnalabel +
|
||||
"</span></p><p><strong>Crime scene: </strong><span>" +
|
||||
itemData.info.street +
|
||||
"</span></p><br /><p>" +
|
||||
itemData.description +
|
||||
"</p>"
|
||||
);
|
||||
} else if (itemData.info.type == "fingerprint") {
|
||||
$(".item-info-description").html(
|
||||
"<p><strong>Evidence material: </strong><span>" +
|
||||
itemData.info.label +
|
||||
"</span></p><p><strong>Fingerprint: </strong><span>" +
|
||||
itemData.info.fingerprint +
|
||||
"</span></p><p><strong>Crime Scene: </strong><span>" +
|
||||
itemData.info.street +
|
||||
"</span></p><br /><p>" +
|
||||
itemData.description +
|
||||
"</p>"
|
||||
);
|
||||
} else if (itemData.info.type == "dna") {
|
||||
$(".item-info-description").html(
|
||||
"<p><strong>Evidence material: </strong><span>" +
|
||||
itemData.info.label +
|
||||
"</span></p><p><strong>DNA Code: </strong><span>" +
|
||||
itemData.info.dnalabel +
|
||||
"</span></p><br /><p>" +
|
||||
itemData.description +
|
||||
"</p>"
|
||||
);
|
||||
}
|
||||
} else if (
|
||||
itemData.info.costs != undefined &&
|
||||
itemData.info.costs != null
|
||||
) {
|
||||
$(".item-info-title").html("<p>" + `${itemData.info.label || label}` + "</p>");
|
||||
$(".item-info-description").html("<p>" + itemData.info.costs + "</p>");
|
||||
} else if (itemData.name == "stickynote") {
|
||||
$(".item-info-title").html("<p>" + `${itemData.info.label || label}` + "</p>");
|
||||
$(".item-info-description").html("<p>" + itemData.info.label + "</p>");
|
||||
} else if (itemData.name == "moneybag") {
|
||||
$(".item-info-title").html("<p>" + `${itemData.info.label || label}` + "</p>");
|
||||
$(".item-info-description").html(
|
||||
"<p><strong>Amount of cash: </strong><span>$" +
|
||||
itemData.info.cash +
|
||||
"</span></p>"
|
||||
);
|
||||
} else if (itemData.name == "cash") {
|
||||
$(".item-info-title").html("<p>" + `${itemData.info.label || label}` + "</p>");
|
||||
$(".item-info-description").html(
|
||||
"<p><strong>" + Lang('INVENTORY_NUI_OPTION_AMOUNT') + ": </strong><span>$" +
|
||||
itemData.amount +
|
||||
"</span></p>"
|
||||
);
|
||||
} else if (itemData.name == "money") {
|
||||
$(".item-info-title").html("<p>" + `${itemData.info.label || label}` + "</p>");
|
||||
$(".item-info-description").html(
|
||||
"<p><strong>" + Lang('INVENTORY_NUI_OPTION_AMOUNT') + ": </strong><span>$" +
|
||||
itemData.amount +
|
||||
"</span></p>"
|
||||
);
|
||||
} else if (itemData.name == "markedbills") {
|
||||
$(".item-info-title").html("<p>" + `${itemData.info.label || label}` + "</p>");
|
||||
$(".item-info-description").html(
|
||||
"<p><strong>" + Lang('INVENTORY_NUI_OPTION_AMOUNT') + ": </strong><span>$" +
|
||||
itemData.info.worth +
|
||||
"</span></p>"
|
||||
);
|
||||
} else if (itemData.name == "visa" || itemData.name == "creditcard") {
|
||||
$(".item-info-title").html('<p>' + label + '</p>')
|
||||
var str = "" + itemData.info.cardNumber + "";
|
||||
var res = str.slice(12);
|
||||
var cardNumber = "************" + res;
|
||||
$(".item-info-description").html('<p><strong>Card Owner: </strong><span>' + itemData.info.ownerName + '</span></p><p><strong>Card Type: </strong><span>' + itemData.info.cardType + '</span></p><p><strong>Card Number: </strong><span>' + cardNumber + '</span></p>');
|
||||
} else if (itemData.name == "motelkey" && itemData.info) {
|
||||
$(".item-info-title").html('<p>' + label + '</p>')
|
||||
$(".item-info-description").html('<p>Motel Key: ' + itemData.info.motel + '</p>');
|
||||
} else if (itemData.name == "labkey") {
|
||||
$(".item-info-title").html("<p>" + `${itemData.info.label || label}` + "</p>");
|
||||
$(".item-info-description").html("<p>Lab: " + itemData.info.lab + "</p>");
|
||||
} else if (itemData.name == "ls_liquid_meth" || itemData.name == "ls_meth") {
|
||||
$(".item-info-title").html("<p>" + `${itemData.info.label || label}` + "</p>");
|
||||
$(".item-info-description").html(
|
||||
"<p><strong>Strain: </strong><span>" +
|
||||
itemData.info.strain +
|
||||
"</span></p><p><strong>Purity: </strong><span>" +
|
||||
itemData.info.purity +
|
||||
"%</span></p>"
|
||||
);
|
||||
} else if (itemData.name == "ls_ammonia" || itemData.name == "ls_iodine" || itemData.name == "ls_acetone") {
|
||||
$(".item-info-title").html("<p>" + `${itemData.info.label || label}` + "</p>");
|
||||
$(".item-info-description").html(
|
||||
"<p><strong>Remaining: </strong><span>" +
|
||||
itemData.info.quality +
|
||||
"%</span></p>"
|
||||
);
|
||||
} else {
|
||||
$(".item-info-title").html("<p>" + `${itemData.info.label || label}` + "</p>");
|
||||
$(".item-info-description").html("<p>" + itemData.description + "</p>");
|
||||
}
|
||||
|
||||
} else {
|
||||
$(".item-info-title").html("<p>" + itemData.label + "</p>");
|
||||
$(".item-info-description").html("<p>" + itemData.description + "</p>");
|
||||
}
|
||||
}
|
||||
|
||||
const tableToString = (data) => {
|
||||
let table = '<table class="table table-striped table-dark">';
|
||||
for (const [key, value] of Object.entries(data)) {
|
||||
table += `<tr><td>${key}</td><td>${value}</td></tr>`;
|
||||
}
|
||||
table += '</table>';
|
||||
return table;
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- Quasar Store · Configuration Guidelines
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- This configuration file defines all adjustable parameters for the script.
|
||||
-- Comments are standardized to help you identify which sections you can safely edit.
|
||||
--
|
||||
-- • [EDIT] – Safe for users to modify. Adjust these values as needed.
|
||||
-- • [INFO] – Informational note describing what the variable or block does.
|
||||
-- • [ADV] – Advanced settings. Change only if you understand the logic behind it.
|
||||
-- • [CORE] – Core functionality. Do not modify unless you are a developer.
|
||||
-- • [AUTO] – Automatically handled by the system. Never edit manually.
|
||||
--
|
||||
-- Always make a backup before editing configuration files.
|
||||
-- Incorrect changes in [CORE] or [AUTO] sections can break the resource.
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- Seller Configuration [EDIT]
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- [INFO] Defines in-game stores and seller NPCs, including item lists, prices,
|
||||
-- payment accounts, and map blip settings. Each entry represents a store
|
||||
-- with its own location, available items, and visual configuration.
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
Config.SellItems = {
|
||||
|
||||
--──────────────────────────────────────────────────────────────────────────
|
||||
-- Seller NPC Configuration [EDIT]
|
||||
--──────────────────────────────────────────────────────────────────────────
|
||||
['Seller item'] = {
|
||||
coords = vec3(2682.7588, 3284.8857, 55.2103), -- [EDIT] Store location on map
|
||||
|
||||
blip = { -- [EDIT] Map blip configuration
|
||||
active = true, -- [EDIT] Enables or disables visibility
|
||||
name = 'Seller', -- [EDIT] Blip title displayed on the map
|
||||
sprite = 89, -- [EDIT] Blip icon ID
|
||||
color = 1, -- [EDIT] Color of the blip
|
||||
scale = 0.5, -- [EDIT] Blip icon size
|
||||
account = 'money', -- [EDIT] Payment source ('money', 'bank', etc.)
|
||||
},
|
||||
|
||||
items = { -- [EDIT] Items available for sale
|
||||
{
|
||||
name = 'sandwich',
|
||||
price = 3,
|
||||
amount = 1,
|
||||
info = {},
|
||||
type = 'item',
|
||||
slot = 1,
|
||||
},
|
||||
{
|
||||
name = 'tosti',
|
||||
price = 2,
|
||||
amount = 1,
|
||||
info = {},
|
||||
type = 'item',
|
||||
slot = 2,
|
||||
},
|
||||
{
|
||||
name = 'water_bottle',
|
||||
price = 2,
|
||||
amount = 1,
|
||||
info = {},
|
||||
type = 'item',
|
||||
slot = 3,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
--──────────────────────────────────────────────────────────────────────────
|
||||
-- 24/7 Store Configuration [EDIT]
|
||||
--──────────────────────────────────────────────────────────────────────────
|
||||
['24/7'] = {
|
||||
coords = vec3(2679.9326, 3276.6897, 54.4058), -- [EDIT] Store location
|
||||
|
||||
blip = { -- [EDIT] Blip settings for 24/7 store
|
||||
active = true,
|
||||
name = '24/7 Store',
|
||||
sprite = 89,
|
||||
color = 1,
|
||||
scale = 0.5,
|
||||
account = 'money',
|
||||
},
|
||||
|
||||
items = { -- [EDIT] Items sold in this store
|
||||
{
|
||||
name = 'tosti',
|
||||
price = 1,
|
||||
amount = 1,
|
||||
info = {},
|
||||
type = 'item',
|
||||
slot = 1,
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- Quasar Store · Configuration Guidelines
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- This configuration file defines all adjustable parameters for the script.
|
||||
-- Comments are standardized to help you identify which sections you can safely edit.
|
||||
--
|
||||
-- • [EDIT] – Safe for users to modify. Adjust these values as needed.
|
||||
-- • [INFO] – Informational note describing what the variable or block does.
|
||||
-- • [ADV] – Advanced settings. Change only if you understand the logic behind it.
|
||||
-- • [CORE] – Core functionality. Do not modify unless you are a developer.
|
||||
-- • [AUTO] – Automatically handled by the system. Never edit manually.
|
||||
--
|
||||
-- Always make a backup before editing configuration files.
|
||||
-- Incorrect changes in [CORE] or [AUTO] sections can break the resource.
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- Storage Containers [EDIT]
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- [INFO] Defines items that act as physical containers capable of holding other items.
|
||||
-- Example: a cigarette box containing multiple cigarettes.
|
||||
-- Containers have their own weight, slot capacity, and optional default contents.
|
||||
--
|
||||
-- How it works:
|
||||
-- • Define a container item (e.g. 'cigarettebox').
|
||||
-- • Set its internal storage capacity (slots + weight).
|
||||
-- • Optionally preload items inside with metadata and amounts.
|
||||
--
|
||||
-- This feature enhances immersion and realism, especially for roleplay setups.
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
Config.Storage = {
|
||||
|
||||
[1] = {
|
||||
name = "cigarettebox", -- [EDIT] Unique name of the container item
|
||||
label = "Cigarette Box", -- [EDIT] Display name in inventory
|
||||
weight = 50, -- [EDIT] Max total weight the container can hold
|
||||
slots = 1, -- [EDIT] Max number of different item types allowed
|
||||
|
||||
items = { -- [EDIT] Default contents of this container
|
||||
[1] = {
|
||||
name = "cigarette", -- [INFO] Item identifier
|
||||
label = "Cigarette", -- [INFO] Display name
|
||||
description = "A single cigarette",-- [INFO] Short description
|
||||
useable = true, -- [EDIT] Can the item be used
|
||||
type = "item", -- [INFO] Inventory type
|
||||
amount = 20, -- [EDIT] Default quantity
|
||||
weight = 1, -- [EDIT] Weight per unit
|
||||
unique = false, -- [EDIT] Unique (non-stackable)
|
||||
slot = 1, -- [INFO] Slot position inside container
|
||||
info = {}, -- [ADV] Metadata or custom data
|
||||
},
|
||||
-- [EDIT] Add more default items here if needed.
|
||||
},
|
||||
},
|
||||
|
||||
-- [EDIT] Add more container definitions below.
|
||||
}
|
||||
123
resources/[framework]/[addons]/qs-inventory/config/vehicles.lua
Normal file
@@ -0,0 +1,123 @@
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- Quasar Store · Configuration Guidelines
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- This configuration file defines all adjustable parameters for the script.
|
||||
-- Comments are standardized to help you identify which sections you can safely edit.
|
||||
--
|
||||
-- • [EDIT] – Safe for users to modify. Adjust these values as needed.
|
||||
-- • [INFO] – Informational note describing what the variable or block does.
|
||||
-- • [ADV] – Advanced settings. Change only if you understand the logic behind it.
|
||||
-- • [CORE] – Core functionality. Do not modify unless you are a developer.
|
||||
-- • [AUTO] – Automatically handled by the system. Never edit manually.
|
||||
--
|
||||
-- Always make a backup before editing configuration files.
|
||||
-- Incorrect changes in [CORE] or [AUTO] sections can break the resource.
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- Vehicle Configuration System [EDIT]
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- [INFO] Defines storage and access rules for vehicles, including trunk and glovebox.
|
||||
-- Supports ownership checks, police access overrides, and custom vehicle setups.
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
Config.IsVehicleOwned = false -- [EDIT] If true, only owned vehicles retain trunk data.
|
||||
Config.UseItemInVehicle = true -- [EDIT] Disable item usage inside vehicles when false.
|
||||
Config.WeaponsOnVehicle = true -- [EDIT] Disable weapon storage in vehicles when false (may affect performance).
|
||||
|
||||
Config.OpenTrunkAll = true -- [EDIT] Allow any player to open any trunk.
|
||||
Config.OpenTrunkPolice = true -- [EDIT] Allow police to bypass trunk restrictions.
|
||||
Config.OpenTrunkPoliceGrade = 0 -- [EDIT] Minimum police grade to open trunks when restricted.
|
||||
|
||||
Config.OpenGloveboxesAll = true -- [EDIT] Allow any player to open any glovebox.
|
||||
Config.OpenGloveboxesPolice = true -- [EDIT] Allow police to bypass glovebox restrictions.
|
||||
Config.OpenGloveboxesPoliceGrade = 0 -- [EDIT] Minimum police grade to open gloveboxes when restricted.
|
||||
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- Vehicle Class Storage Capacities [EDIT]
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- [INFO] Defines weight and slot capacity for gloveboxes and trunks by vehicle class.
|
||||
-- Reference: https://docs.fivem.net/natives/?_0x29439776AAA00A62
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
Config.VehicleClass = {
|
||||
[0] = { glovebox = { maxweight = 100000, slots = 5 }, trunk = { maxweight = 38000, slots = 30 } },
|
||||
[1] = { glovebox = { maxweight = 100000, slots = 5 }, trunk = { maxweight = 50000, slots = 40 } },
|
||||
[2] = { glovebox = { maxweight = 100000, slots = 5 }, trunk = { maxweight = 75000, slots = 50 } },
|
||||
[3] = { glovebox = { maxweight = 100000, slots = 5 }, trunk = { maxweight = 42000, slots = 35 } },
|
||||
[4] = { glovebox = { maxweight = 100000, slots = 5 }, trunk = { maxweight = 38000, slots = 30 } },
|
||||
[5] = { glovebox = { maxweight = 100000, slots = 5 }, trunk = { maxweight = 30000, slots = 25 } },
|
||||
[6] = { glovebox = { maxweight = 100000, slots = 5 }, trunk = { maxweight = 30000, slots = 25 } },
|
||||
[7] = { glovebox = { maxweight = 100000, slots = 5 }, trunk = { maxweight = 30000, slots = 25 } },
|
||||
[8] = { glovebox = { maxweight = 100000, slots = 5 }, trunk = { maxweight = 15000, slots = 15 } },
|
||||
[9] = { glovebox = { maxweight = 100000, slots = 5 }, trunk = { maxweight = 60000, slots = 35 } },
|
||||
[10] = { glovebox = { maxweight = 100000, slots = 5 }, trunk = { maxweight = 60000, slots = 35 } },
|
||||
[11] = { glovebox = { maxweight = 100000, slots = 5 }, trunk = { maxweight = 60000, slots = 35 } },
|
||||
[12] = { glovebox = { maxweight = 100000, slots = 5 }, trunk = { maxweight = 120000, slots = 35 } },
|
||||
[13] = { glovebox = { maxweight = 100000, slots = 5 }, trunk = { maxweight = 0, slots = 0 } },
|
||||
[14] = { glovebox = { maxweight = 100000, slots = 5 }, trunk = { maxweight = 120000, slots = 50 } },
|
||||
[15] = { glovebox = { maxweight = 100000, slots = 5 }, trunk = { maxweight = 120000, slots = 50 } },
|
||||
[16] = { glovebox = { maxweight = 100000, slots = 5 }, trunk = { maxweight = 120000, slots = 50 } },
|
||||
[17] = { glovebox = { maxweight = 100000, slots = 5 }, trunk = { maxweight = 120000, slots = 50 } },
|
||||
[18] = { glovebox = { maxweight = 100000, slots = 5 }, trunk = { maxweight = 120000, slots = 50 } },
|
||||
[19] = { glovebox = { maxweight = 100000, slots = 5 }, trunk = { maxweight = 120000, slots = 50 } },
|
||||
[20] = { glovebox = { maxweight = 100000, slots = 5 }, trunk = { maxweight = 120000, slots = 50 } },
|
||||
}
|
||||
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- Custom Vehicle Storage (Model Overrides) [EDIT]
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- [INFO] Defines specific trunk/glovebox capacities for individual models, overriding class values.
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
Config.CustomTrunk = {
|
||||
[joaat('adder')] = { slots = 5, maxweight = 100000 },
|
||||
}
|
||||
|
||||
Config.CustomGlovebox = {
|
||||
[joaat('adder')] = { slots = 5, maxweight = 100000 },
|
||||
}
|
||||
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- Front Trunk (Rear Engine Vehicles) [EDIT]
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- [INFO] For vehicles with rear engines, defines models where trunk is accessed from the front.
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
Config.BackEngineVehicles = {
|
||||
[`ninef`] = true,
|
||||
[`adder`] = true,
|
||||
[`vagner`] = true,
|
||||
[`t20`] = true,
|
||||
[`infernus`] = true,
|
||||
[`zentorno`] = true,
|
||||
[`reaper`] = true,
|
||||
[`comet2`] = true,
|
||||
[`comet3`] = true,
|
||||
[`jester`] = true,
|
||||
[`jester2`] = true,
|
||||
[`cheetah`] = true,
|
||||
[`cheetah2`] = true,
|
||||
[`prototipo`] = true,
|
||||
[`turismor`] = true,
|
||||
[`pfister811`] = true,
|
||||
[`ardent`] = true,
|
||||
[`nero`] = true,
|
||||
[`nero2`] = true,
|
||||
[`tempesta`] = true,
|
||||
[`vacca`] = true,
|
||||
[`bullet`] = true,
|
||||
[`osiris`] = true,
|
||||
[`entityxf`] = true,
|
||||
[`turismo2`] = true,
|
||||
[`fmj`] = true,
|
||||
[`re7b`] = true,
|
||||
[`tyrus`] = true,
|
||||
[`italigtb`] = true,
|
||||
[`penetrator`] = true,
|
||||
[`monroe`] = true,
|
||||
[`ninef2`] = true,
|
||||
[`stingergt`] = true,
|
||||
[`surfer`] = true,
|
||||
[`surfer2`] = true,
|
||||
[`gp1`] = true,
|
||||
[`autarch`] = true,
|
||||
[`tyrant`] = true,
|
||||
-- [EDIT] Add more front-trunk vehicles here if needed.
|
||||
}
|
||||
119
resources/[framework]/[addons]/qs-inventory/config/vending.lua
Normal file
@@ -0,0 +1,119 @@
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- Quasar Store · Configuration Guidelines
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- This configuration file defines all adjustable parameters for the script.
|
||||
-- Comments are standardized to help you identify which sections you can safely edit.
|
||||
--
|
||||
-- • [EDIT] – Safe for users to modify. Adjust these values as needed.
|
||||
-- • [INFO] – Informational note describing what the variable or block does.
|
||||
-- • [ADV] – Advanced settings. Change only if you understand the logic behind it.
|
||||
-- • [CORE] – Core functionality. Do not modify unless you are a developer.
|
||||
-- • [AUTO] – Automatically handled by the system. Never edit manually.
|
||||
--
|
||||
-- Always make a backup before editing configuration files.
|
||||
-- Incorrect changes in [CORE] or [AUTO] sections can break the resource.
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- Vending Machine Configuration [EDIT]
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- [INFO] Defines vending machine categories, their available items, and prop models.
|
||||
-- Each category can contain multiple items with prices and stock amounts.
|
||||
-- Machines link to these categories by model name for contextual interaction.
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
Config.VendingMachines = {
|
||||
|
||||
--──────────────────────────────────────────────────────────────────────────
|
||||
-- Drinks Category [EDIT]
|
||||
--──────────────────────────────────────────────────────────────────────────
|
||||
['drinks'] = {
|
||||
Label = 'Drinks',
|
||||
Items = {
|
||||
[1] = {
|
||||
name = 'kurkakola', -- [INFO] Drink item name
|
||||
price = 4, -- [EDIT] Item price
|
||||
amount = 50, -- [EDIT] Stock quantity
|
||||
info = {}, -- [ADV] Metadata
|
||||
type = 'item', -- [INFO] Type of entry
|
||||
slot = 1, -- [INFO] Slot index in menu
|
||||
},
|
||||
[2] = {
|
||||
name = 'water_bottle',
|
||||
price = 4,
|
||||
amount = 50,
|
||||
info = {},
|
||||
type = 'item',
|
||||
slot = 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
--──────────────────────────────────────────────────────────────────────────
|
||||
-- Candy Category [EDIT]
|
||||
--──────────────────────────────────────────────────────────────────────────
|
||||
['candy'] = {
|
||||
Label = 'Candy',
|
||||
Items = {
|
||||
[1] = {
|
||||
name = 'chocolate', -- [INFO] Candy item
|
||||
price = 4, -- [EDIT] Item price
|
||||
amount = 50, -- [EDIT] Stock
|
||||
info = {},
|
||||
type = 'item',
|
||||
slot = 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
--──────────────────────────────────────────────────────────────────────────
|
||||
-- Coffee Category [EDIT]
|
||||
--──────────────────────────────────────────────────────────────────────────
|
||||
['coffee'] = {
|
||||
Label = 'Coffee',
|
||||
Items = {
|
||||
[1] = {
|
||||
name = 'coffee', -- [INFO] Coffee item
|
||||
price = 4,
|
||||
amount = 50,
|
||||
info = {},
|
||||
type = 'item',
|
||||
slot = 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
--──────────────────────────────────────────────────────────────────────────
|
||||
-- Water Category [EDIT]
|
||||
--──────────────────────────────────────────────────────────────────────────
|
||||
['water'] = {
|
||||
Label = 'Water',
|
||||
Items = {
|
||||
[1] = {
|
||||
name = 'water_bottle', -- [INFO] Water bottle item
|
||||
price = 4,
|
||||
amount = 50,
|
||||
info = {},
|
||||
type = 'item',
|
||||
slot = 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- Vending Machine Models [EDIT]
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
-- [INFO] Lists vending machine props and links them to a category defined above.
|
||||
-- Allows interaction with corresponding items based on prop model type.
|
||||
--──────────────────────────────────────────────────────────────────────────────
|
||||
Config.Vendings = {
|
||||
[1] = { Model = 'prop_vend_coffe_01', Category = 'coffee' },
|
||||
[2] = { Model = 'prop_vend_water_01', Category = 'water' },
|
||||
[3] = { Model = 'prop_watercooler', Category = 'water' },
|
||||
[4] = { Model = 'prop_watercooler_Dark', Category = 'water' },
|
||||
[5] = { Model = 'prop_vend_snak_01', Category = 'candy' },
|
||||
[6] = { Model = 'prop_vend_snak_01_tu', Category = 'candy' },
|
||||
[7] = { Model = 'prop_vend_fridge01', Category = 'drinks' },
|
||||
[8] = { Model = 'prop_vend_soda_01', Category = 'drinks' },
|
||||
[9] = { Model = 'prop_vend_soda_02', Category = 'drinks' },
|
||||
}
|
||||
1174
resources/[framework]/[addons]/qs-inventory/config/weapons.lua
Normal file
91
resources/[framework]/[addons]/qs-inventory/fxmanifest.lua
Normal file
@@ -0,0 +1,91 @@
|
||||
fx_version 'cerulean'
|
||||
|
||||
game 'gta5'
|
||||
|
||||
lua54 'yes'
|
||||
|
||||
version '3.7.16'
|
||||
|
||||
name 'qs-inventory'
|
||||
author 'Quasar Store'
|
||||
|
||||
data_file 'WEAPONINFO_FILE_PATCH' 'weaponsnspistol.meta'
|
||||
|
||||
-- 'http://127.0.0.1:5500/html/ui.html'
|
||||
ui_page 'html/ui.html'
|
||||
|
||||
ox_libs {
|
||||
'table',
|
||||
}
|
||||
|
||||
files {
|
||||
'config/*.js',
|
||||
'html/ui.html',
|
||||
'html/css/*.css',
|
||||
'html/js/*.js',
|
||||
'html/js/modules/*.js',
|
||||
'html/images/*.png',
|
||||
'html/images/*.jpg',
|
||||
'html/cloth/*.png',
|
||||
'html/icons/**',
|
||||
'html/font/**',
|
||||
'html/*.ttf',
|
||||
'weaponsnspistol.meta',
|
||||
'html/sounds/*.wav',
|
||||
}
|
||||
|
||||
shared_scripts {
|
||||
'@ox_lib/init.lua',
|
||||
'shared/*.lua',
|
||||
'config/*.lua',
|
||||
'locales/*.lua',
|
||||
}
|
||||
|
||||
client_script {
|
||||
'client/custom/framework/*.lua',
|
||||
'client/*.lua',
|
||||
'client/modules/*.lua',
|
||||
'client/custom/misc/*.lua',
|
||||
'client/custom/clothing/*.lua',
|
||||
'client/custom/target/*.lua',
|
||||
'client/custom/provider/*.lua'
|
||||
}
|
||||
|
||||
server_scripts {
|
||||
'@oxmysql/lib/MySQL.lua',
|
||||
'server/custom/framework/*.lua',
|
||||
'server/custom/webhook/*.lua',
|
||||
'server/*.lua',
|
||||
'server/modules/*.lua',
|
||||
'server/custom/**/**.lua',
|
||||
}
|
||||
|
||||
escrow_ignore {
|
||||
'shared/items.lua',
|
||||
'shared/weapons.lua',
|
||||
'config/*.lua',
|
||||
'locales/*.lua',
|
||||
'client/custom/framework/*.lua',
|
||||
'client/custom/misc/*.lua',
|
||||
'client/custom/target/*.lua',
|
||||
'client/custom/provider/*.lua',
|
||||
'client/modules/suggestion.lua',
|
||||
'server/custom/framework/*.lua',
|
||||
'server/custom/webhook/*.lua',
|
||||
'server/custom/misc/*.lua',
|
||||
'client/modules/weapons.lua',
|
||||
'server/modules/weapons.lua'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
'/server:4752', -- ⚠️PLEASE READ⚠️ This requires at least server build 4700 or higher
|
||||
'ox_lib', -- Required
|
||||
}
|
||||
|
||||
provide {
|
||||
-- 'ox_inventory' -- Uncomment this line only if you have qbx but better way is the remove 'ox_inventory' dependency on every scripts.
|
||||
}
|
||||
|
||||
dependency '/assetpacks'
|
||||
|
||||
dependency '/assetpacks'
|
||||
BIN
resources/[framework]/[addons]/qs-inventory/html/cloth/arms.png
Normal file
|
After Width: | Height: | Size: 4.8 KiB |
BIN
resources/[framework]/[addons]/qs-inventory/html/cloth/bag.png
Normal file
|
After Width: | Height: | Size: 4.8 KiB |
|
After Width: | Height: | Size: 6.5 KiB |
BIN
resources/[framework]/[addons]/qs-inventory/html/cloth/chain.png
Normal file
|
After Width: | Height: | Size: 6.3 KiB |
BIN
resources/[framework]/[addons]/qs-inventory/html/cloth/ears.png
Normal file
|
After Width: | Height: | Size: 5.3 KiB |
|
After Width: | Height: | Size: 8.0 KiB |
BIN
resources/[framework]/[addons]/qs-inventory/html/cloth/hat.png
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 6.3 KiB |
BIN
resources/[framework]/[addons]/qs-inventory/html/cloth/jeans.png
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
BIN
resources/[framework]/[addons]/qs-inventory/html/cloth/mask.png
Normal file
|
After Width: | Height: | Size: 7.5 KiB |
BIN
resources/[framework]/[addons]/qs-inventory/html/cloth/shoes.png
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
resources/[framework]/[addons]/qs-inventory/html/cloth/torso.png
Normal file
|
After Width: | Height: | Size: 5.5 KiB |
|
After Width: | Height: | Size: 4.8 KiB |
BIN
resources/[framework]/[addons]/qs-inventory/html/cloth/vest.png
Normal file
|
After Width: | Height: | Size: 5.7 KiB |
BIN
resources/[framework]/[addons]/qs-inventory/html/cloth/watch.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
@@ -0,0 +1,601 @@
|
||||
@import "https://fonts.googleapis.com/css2?family=Poppins:wght@200;400;500;600;700;800;900&display=swap";
|
||||
@import "https://fonts.googleapis.com/css2?family=Rajdhani:wght@500&display=swap";
|
||||
|
||||
:root {
|
||||
--d: 5000ms;
|
||||
--angle: 90deg;
|
||||
--gradX: 100%;
|
||||
--gradY: 50%;
|
||||
--c1: rgba(0, 163, 255, 1);
|
||||
--c2: transparent;
|
||||
--primary-color: #00a3ff;
|
||||
--secondary-gradient: linear-gradient(180deg, #34445200 0%, #2d2d2d 100%);
|
||||
--border-color: #0190e1;
|
||||
--panel-bg: radial-gradient(
|
||||
120.05% 120.05% at 50.14% -58.24%,
|
||||
rgba(69, 100, 129, 0) 0%,
|
||||
#0e151b 100%
|
||||
);
|
||||
}
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
font-family: "Poppins", sans-serif;
|
||||
background: transparent;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.admin-giveitem-container {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 9999;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.admin-giveitem-modal {
|
||||
position: relative;
|
||||
width: 90%;
|
||||
max-width: 1400px;
|
||||
max-height: 100vh;
|
||||
background: var(--panel-bg);
|
||||
border-radius: 20px;
|
||||
border: 1px solid rgba(1, 144, 225, 0.35);
|
||||
box-shadow: 0 25px 50px rgba(0, 0, 0, 0.5);
|
||||
overflow: hidden;
|
||||
transform: scale(0.9) translateY(50px);
|
||||
opacity: 0;
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
animation: modalSlideIn 0.4s cubic-bezier(0.4, 0, 0.2, 1) forwards;
|
||||
}
|
||||
|
||||
.admin-giveitem-modal.open {
|
||||
transform: scale(1) translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.admin-giveitem-header {
|
||||
background: linear-gradient(135deg, var(--primary-color) 0%, #0e151b 100%);
|
||||
padding: 20px 30px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
border-bottom: 2px solid rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
|
||||
.admin-giveitem-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 15px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.admin-giveitem-title i {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.admin-giveitem-title h2 {
|
||||
margin: 0;
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
text-shadow: 0 0 5px rgba(255, 255, 255, 0.35);
|
||||
letter-spacing: 0.3px;
|
||||
}
|
||||
|
||||
.admin-giveitem-close {
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
border: 1px solid rgba(255, 255, 255, 0.18);
|
||||
color: #fff;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.admin-giveitem-close:hover {
|
||||
background: var(--primary-color);
|
||||
border-color: var(--primary-color);
|
||||
box-shadow: 0 0 20px rgba(0, 163, 255, 0.35);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.admin-giveitem-content {
|
||||
padding: 30px;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-template-rows: auto;
|
||||
gap: 30px;
|
||||
max-height: calc(130vh - 100px);
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.admin-giveitem-section {
|
||||
background: radial-gradient(
|
||||
49.48% 49.48% at 50.52% 50.52%,
|
||||
#28343c 0%,
|
||||
rgba(14, 21, 27, 0.8) 100%
|
||||
);
|
||||
border-radius: 15px;
|
||||
padding: 20px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.12);
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
.admin-giveitem-section:last-child {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
|
||||
.section-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 20px;
|
||||
padding-bottom: 15px;
|
||||
border-bottom: 2px solid rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
|
||||
.section-header h3 {
|
||||
color: #fff;
|
||||
margin: 0;
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
text-shadow: 0 0 5px rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
.search-container {
|
||||
position: relative;
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
.search-container input {
|
||||
width: 100%;
|
||||
padding: 12px 40px 12px 15px;
|
||||
background: rgba(255, 255, 255, 0.06);
|
||||
border: 2px solid rgba(255, 255, 255, 0.18);
|
||||
border-radius: 12px;
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.search-container input::placeholder {
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
.search-container input:focus {
|
||||
outline: none;
|
||||
border-color: var(--primary-color);
|
||||
box-shadow: 0 0 20px rgba(0, 163, 255, 0.25);
|
||||
}
|
||||
|
||||
.search-container i {
|
||||
position: absolute;
|
||||
right: 15px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
.player-list-container,
|
||||
.item-list-container {
|
||||
max-height: 280px;
|
||||
overflow-y: auto;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.player-list,
|
||||
.item-list {
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.player-card,
|
||||
.item-card {
|
||||
background: rgba(255, 255, 255, 0.06);
|
||||
border: 1px solid rgba(255, 255, 255, 0.12);
|
||||
border-radius: 12px;
|
||||
padding: 15px;
|
||||
margin-bottom: 10px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 15px;
|
||||
animation: fadeIn 0.3s ease forwards;
|
||||
}
|
||||
|
||||
.player-card:hover,
|
||||
.item-card:hover {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border-color: var(--primary-color);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 0 20px rgba(0, 163, 255, 0.25);
|
||||
}
|
||||
|
||||
.player-avatar,
|
||||
.item-image {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 10px;
|
||||
background: radial-gradient(
|
||||
49.48% 49.48% at 50.52% 50.52%,
|
||||
#28343c 0%,
|
||||
rgba(14, 21, 27, 0.8) 100%
|
||||
);
|
||||
display: grid;
|
||||
place-items: center;
|
||||
color: #fff;
|
||||
font-size: 20px;
|
||||
flex-shrink: 0;
|
||||
border: 1px solid rgba(255, 255, 255, 0.12);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.item-image img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.player-info,
|
||||
.item-info {
|
||||
flex: 1;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.player-info h4,
|
||||
.item-info h4 {
|
||||
margin: 0 0 5px 0;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.player-info p,
|
||||
.item-info p {
|
||||
margin: 2px 0;
|
||||
font-size: 12px;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
.select-player-btn,
|
||||
.select-item-btn {
|
||||
background: var(--primary-color);
|
||||
border: none;
|
||||
color: #fff;
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
transition: all 0.2s ease;
|
||||
opacity: 0;
|
||||
box-shadow: 0 0 14px rgba(0, 163, 255, 0.3);
|
||||
}
|
||||
|
||||
.player-card:hover .select-player-btn,
|
||||
.item-card:hover .select-item-btn {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.select-player-btn:hover,
|
||||
.select-item-btn:hover {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.selected-player-info,
|
||||
.selected-item-info {
|
||||
position: absolute;
|
||||
left: 25px;
|
||||
right: 25px;
|
||||
bottom: 25px;
|
||||
height: 84px;
|
||||
opacity: 0;
|
||||
transform: translateY(8px);
|
||||
transition: opacity 0.18s ease, transform 0.18s ease;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.selected-item-info {
|
||||
height: 120px;
|
||||
}
|
||||
|
||||
.selected-player-info.is-visible,
|
||||
.selected-item-info.is-visible {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.selected-item-card {
|
||||
height: 130px !important;
|
||||
}
|
||||
|
||||
.player-details p,
|
||||
.item-details p {
|
||||
font-size: 1.2vh;
|
||||
}
|
||||
|
||||
.selected-player-card,
|
||||
.selected-item-card {
|
||||
height: 94px;
|
||||
background: radial-gradient(
|
||||
49.48% 49.48% at 50.52% 50.52%,
|
||||
rgba(0, 163, 255, 0.15) 0%,
|
||||
rgba(14, 21, 27, 1) 100%
|
||||
);
|
||||
border: 2px solid var(--primary-color);
|
||||
border-radius: 12px;
|
||||
padding: 15px;
|
||||
display: grid;
|
||||
grid-template-columns: 50px 1fr 25px;
|
||||
align-items: center;
|
||||
gap: 15px;
|
||||
position: relative;
|
||||
box-shadow: 0 0 18px rgba(0, 163, 255, 0.35);
|
||||
overflow: hidden;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.clear-selection {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
background: rgba(0, 163, 255, 0.18);
|
||||
border: none;
|
||||
color: #fff;
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.clear-selection:hover {
|
||||
background: rgba(0, 163, 255, 0.28);
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.give-item-form {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
color: #fff;
|
||||
font-weight: 700;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.form-group input,
|
||||
.form-group textarea {
|
||||
padding: 12px 15px;
|
||||
background: rgba(255, 255, 255, 0.06);
|
||||
border: 2px solid rgba(255, 255, 255, 0.18);
|
||||
border-radius: 10px;
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.form-group input::placeholder,
|
||||
.form-group textarea::placeholder {
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
.form-group input:focus,
|
||||
.form-group textarea:focus {
|
||||
outline: none;
|
||||
border-color: var(--primary-color);
|
||||
box-shadow: 0 0 16px rgba(0, 163, 255, 0.25);
|
||||
}
|
||||
|
||||
.form-group textarea {
|
||||
resize: vertical;
|
||||
min-height: 80px;
|
||||
font-family: "Poppins", sans-serif;
|
||||
}
|
||||
|
||||
.give-item-summary {
|
||||
grid-column: 1 / -1;
|
||||
background: rgba(0, 163, 255, 0.08);
|
||||
border: 1px solid var(--primary-color);
|
||||
border-radius: 10px;
|
||||
padding: 15px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.give-item-summary h4 {
|
||||
color: var(--primary-color);
|
||||
margin: 0 0 10px 0;
|
||||
font-size: 16px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.give-item-summary p {
|
||||
color: #fff;
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.form-actions {
|
||||
grid-column: 1 / -1;
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
justify-content: flex-end;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.button-admin-secondary,
|
||||
.button-admin-primary {
|
||||
padding: 12px 25px;
|
||||
border: 2px solid rgba(0, 163, 255, 0.18); /* Borde sutil */
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
font-weight: 800;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
transition: all 0.2s ease;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
background: rgba(0, 163, 255, 0.18);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.button-admin-primary:hover,
|
||||
.button-admin-secondary:hover {
|
||||
background: rgba(0, 163, 255, 0.28);
|
||||
border-color: rgba(
|
||||
0,
|
||||
163,
|
||||
255,
|
||||
0.5
|
||||
); /* Borde más pronunciado al hacer hover */
|
||||
transform: scale(1.05);
|
||||
box-shadow: 0 0 8px rgba(0, 163, 255, 0.5); /* Sombra al pasar el mouse */
|
||||
}
|
||||
|
||||
.loading-spinner,
|
||||
.no-results {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
padding: 40px;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.loading-spinner i,
|
||||
.no-results i {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.unique-badge {
|
||||
background: linear-gradient(135deg, #1d67bb, #0fbeca);
|
||||
color: #000;
|
||||
padding: 2px 8px;
|
||||
border-radius: 12px;
|
||||
font-size: 10px;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
margin-top: 5px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.player-list-container::-webkit-scrollbar,
|
||||
.item-list-container::-webkit-scrollbar {
|
||||
width: 0.3vh;
|
||||
}
|
||||
|
||||
.player-list-container::-webkit-scrollbar-track,
|
||||
.item-list-container::-webkit-scrollbar-track {
|
||||
background: linear-gradient(
|
||||
270deg,
|
||||
rgba(69, 100, 129, 0) -26.87%,
|
||||
#0e151b 100%
|
||||
);
|
||||
border-radius: 0.2vh;
|
||||
}
|
||||
|
||||
.player-list-container::-webkit-scrollbar-thumb,
|
||||
.item-list-container::-webkit-scrollbar-thumb {
|
||||
background: var(--primary-color);
|
||||
box-shadow: 0 0.1vh 20px var(--primary-color);
|
||||
border-radius: 1.2vh;
|
||||
}
|
||||
|
||||
@media (max-width: 1200px) {
|
||||
.admin-giveitem-content {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.admin-giveitem-section:last-child {
|
||||
grid-column: 1;
|
||||
}
|
||||
.give-item-form {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.admin-giveitem-modal {
|
||||
width: 95%;
|
||||
margin: 20px;
|
||||
}
|
||||
.admin-giveitem-content {
|
||||
padding: 20px;
|
||||
gap: 20px;
|
||||
}
|
||||
.admin-giveitem-header {
|
||||
padding: 15px 20px;
|
||||
}
|
||||
.admin-giveitem-title h2 {
|
||||
font-size: 20px;
|
||||
}
|
||||
.search-container {
|
||||
width: 200px;
|
||||
}
|
||||
.form-actions {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes modalSlideIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: scale(0.8) translateY(-50px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: scale(1) translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.summary {
|
||||
max-height: 50vh;
|
||||
}
|
||||
204
resources/[framework]/[addons]/qs-inventory/html/css/compact.css
Normal file
@@ -0,0 +1,204 @@
|
||||
:root {
|
||||
font-size: min(.83333333vw, 1.8009478673vh) !important;
|
||||
}
|
||||
|
||||
.compact {
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
}
|
||||
|
||||
|
||||
.compact #inventory-container:before {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.compact .inv-container {
|
||||
display: flex !important;
|
||||
flex-direction: column;
|
||||
align-items: end;
|
||||
justify-content: space-between;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
width: 50% !important;
|
||||
padding-right: .25rem;
|
||||
}
|
||||
|
||||
.compact .inventory-playerstats {
|
||||
position: relative;
|
||||
top: 1rem;
|
||||
right: 1rem;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.compact .inventory-playerdata {
|
||||
position: absolute;
|
||||
top: 57vh;
|
||||
right: 1.2vh;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.compact .ply-inv-container {
|
||||
height: 50%;
|
||||
}
|
||||
|
||||
.compact .player-inventory {
|
||||
height: 90%;
|
||||
}
|
||||
|
||||
.compact .oth-inv-container {
|
||||
height: 40%; padding-right: 0 !important;
|
||||
}
|
||||
|
||||
.compact .other-inventory {
|
||||
position: relative;
|
||||
height: 20rem;
|
||||
}
|
||||
|
||||
.compact .inv-options {
|
||||
position: relative !important;
|
||||
display: flex;
|
||||
max-height: 5rem !important;
|
||||
margin-top: 2vh !important;
|
||||
min-width: unset !important;
|
||||
width: 564px;
|
||||
padding-right: 13px;
|
||||
align-items: center; justify-content: center;
|
||||
}
|
||||
|
||||
@media (min-width: 2501px) {
|
||||
.compact .inv-options {
|
||||
width: 850px !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* .compact .inv-options-list {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
height: unset !important;
|
||||
margin-top: 0 !important;
|
||||
} */
|
||||
|
||||
.compact .inv-options .inv-options-list {
|
||||
display: flex !important;
|
||||
justify-content: center; align-items: center;
|
||||
gap: .25rem;
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
margin-top: 0 !important;
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.compact .inv-option-item {
|
||||
position: relative;
|
||||
min-height: 3.25rem !important;
|
||||
max-width: 100% !important;
|
||||
width: 100% !important;
|
||||
font-size: 1.35vh !important;
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
|
||||
.compact #clothmenu {
|
||||
position: relative;
|
||||
min-height: 3.25rem !important;
|
||||
max-width: 100% !important;
|
||||
width: 100% !important;
|
||||
font-size: 1.735vh !important;
|
||||
}
|
||||
|
||||
.inv-option-item > p {
|
||||
font-size: 1.35vh !important;
|
||||
}
|
||||
|
||||
/* .compact #inventory-custom {
|
||||
bottom: 5vh;
|
||||
height: 4vh;
|
||||
} */
|
||||
|
||||
.compact .custom-inventory {
|
||||
margin-top: 2.5vh;
|
||||
height: 36vh;
|
||||
margin-left: 1.7vh;
|
||||
padding-right: .6vh;
|
||||
}
|
||||
|
||||
.compact #weapon-attachments {
|
||||
padding: 1vh;
|
||||
}
|
||||
|
||||
.compact .iconBigger {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.iconBigger > i {
|
||||
font-size: 1.35vh !important;
|
||||
}
|
||||
|
||||
.compact .clothes-inventory {
|
||||
position: relative;
|
||||
right: 95vh;
|
||||
top: -50vh !important;
|
||||
}
|
||||
|
||||
.compact .returnButton {
|
||||
width: 1vh !important;
|
||||
}
|
||||
|
||||
.compact .logo-container {
|
||||
top: 3vh;
|
||||
left: 8vh !important;
|
||||
}
|
||||
|
||||
.compact .sixth-slot {
|
||||
left: 5vh;
|
||||
}
|
||||
|
||||
.compact .ply-iteminfo-container {
|
||||
position: absolute;
|
||||
z-index: 9999;
|
||||
font-family: "CabinetGrotesk-Bold";
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: baseline;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 15vw;
|
||||
min-height: 16vh;
|
||||
display: none;
|
||||
min-width: auto;
|
||||
margin: auto;
|
||||
|
||||
padding: 1.5vh;
|
||||
border-radius: 0.5vh;
|
||||
border: 0.1vh solid rgba(15, 130, 230, 0);
|
||||
background: radial-gradient(
|
||||
120.05% 120.05% at 50.14% -58.24%,
|
||||
rgba(69, 100, 129, 0) 0%,
|
||||
#0e151b 100%
|
||||
)
|
||||
padding-box,
|
||||
linear-gradient(
|
||||
180deg,
|
||||
rgba(52, 68, 82, 0) 30%,
|
||||
var(--primary-color) 70%
|
||||
)
|
||||
border-box;
|
||||
border-image-source: linear-gradient(
|
||||
180deg,
|
||||
rgba(52, 68, 82, 0) 0%,
|
||||
#ffffff 100%
|
||||
);
|
||||
}
|
||||
|
||||
.compact #weapon-attachments p {
|
||||
font-size: 0.8vh !important;
|
||||
}
|
||||
|
||||
.compact #player-inv-label {
|
||||
font-size: 2rem !important;
|
||||
line-height: 4rem;
|
||||
max-width: 22.5rem !important;
|
||||
}
|
||||
|
||||
.compact .player-inv-info {
|
||||
padding-left: 1rem !important;
|
||||
}
|
||||
@@ -0,0 +1,259 @@
|
||||
/* ============================================================================================ */
|
||||
/* ==================================== DEFAULT THEME ========================================= */
|
||||
/* ============================================================================================ */
|
||||
|
||||
.context-menu-default {
|
||||
position: absolute;
|
||||
width: 170px;
|
||||
padding: .7rem 0;
|
||||
color: white;
|
||||
margin: 0;
|
||||
border-radius: 5px;
|
||||
background-color: #191e25;
|
||||
z-index: 100;
|
||||
outline: none;
|
||||
opacity: 0;
|
||||
-webkit-transform: translate(0, 15px) scale(0.95);
|
||||
transform: translate(0, 15px) scale(0.95);
|
||||
-webkit-transition: opacity 0.1s ease-out, -webkit-transform 0.1s ease-out;
|
||||
transition: opacity 0.1s ease-out, -webkit-transform 0.1s ease-out;
|
||||
transition: transform 0.1s ease-out, opacity 0.1s ease-out;
|
||||
transition: transform 0.1s ease-out, opacity 0.1s ease-out, -webkit-transform 0.1s ease-out;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.context-menu-default-item {
|
||||
display: block;
|
||||
position: relative;
|
||||
margin: 0;
|
||||
color: white;
|
||||
|
||||
padding: 0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.context-menu-default-btn:focus{
|
||||
border: 0;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.context-menu-default-icon{
|
||||
color: white;
|
||||
}
|
||||
|
||||
.context-menu-default-btn {
|
||||
background: none;
|
||||
line-height: normal;
|
||||
overflow: visible;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
display: block;
|
||||
outline: none;
|
||||
width: 100%;
|
||||
color: white;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
font-size: 13px;
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
border: 1px solid transparent;
|
||||
white-space: nowrap;
|
||||
padding: 8px 16px;
|
||||
}
|
||||
|
||||
.context-menu-default-btn::-moz-focus-inner,
|
||||
.context-menu-default-btn::-moz-focus-inner {
|
||||
border: 0;
|
||||
outline: none;
|
||||
|
||||
}
|
||||
|
||||
.context-menu-default-icon {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.context-menu-default-text {
|
||||
font-size: 14px;
|
||||
color: white;
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
.context-menu-default-item:hover > .context-menu-default-btn {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.context-menu-default-item.disabled {
|
||||
opacity: 0.5;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.context-menu-default-item.disabled .context-menu-default-btn {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.context-menu-default-separator {
|
||||
display: block;
|
||||
margin: 7px 5px;
|
||||
height: 1px;
|
||||
border-bottom: 1px solid #fff;
|
||||
background-color: rgb(255, 255, 255);
|
||||
}
|
||||
|
||||
.context-menu-default-item.subcontext-menu-default::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
right: 6px;
|
||||
top: 50%;
|
||||
-webkit-transform: translateY(-50%);
|
||||
transform: translateY(-50%);
|
||||
border: 5px solid transparent;
|
||||
border-left-color: #808080;
|
||||
}
|
||||
|
||||
.context-menu-default-item.subcontext-menu-default:hover::after {
|
||||
border-left-color: #fff;
|
||||
}
|
||||
|
||||
.context-menu-default .context-menu-default {
|
||||
top: 4px;
|
||||
left: 99%;
|
||||
}
|
||||
|
||||
.show-context-menu-default,
|
||||
.context-menu-default-item:hover > .context-menu-default {
|
||||
opacity: 1;
|
||||
-webkit-transform: translate(0, 0) scale(1);
|
||||
transform: translate(0, 0) scale(1);
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.context-menu-default-item:hover > .context-menu-default {
|
||||
-webkit-transition-delay: 100ms;
|
||||
transition-delay: 300ms;
|
||||
}
|
||||
|
||||
/* ============================================================================================ */
|
||||
/* ======================================= BLUE THEME ========================================= */
|
||||
/* ============================================================================================ */
|
||||
|
||||
.context-menu-blue {
|
||||
position: absolute;
|
||||
width: 250px;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
background: #23AFF7;
|
||||
background: linear-gradient(to bottom, #23AFF7 0%, #007BFF 100px, #007BFF 100%);
|
||||
z-index: 100;
|
||||
border-radius: 2px;
|
||||
-webkit-box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.2);
|
||||
box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.2);
|
||||
opacity: 0;
|
||||
-webkit-transform: translate(0, 15px) scale(0.95);
|
||||
transform: translate(0, 15px) scale(0.95);
|
||||
-webkit-transition: opacity 0.1s ease-out, -webkit-transform 0.1s ease-out;
|
||||
transition: opacity 0.1s ease-out, -webkit-transform 0.1s ease-out;
|
||||
transition: transform 0.1s ease-out, opacity 0.1s ease-out;
|
||||
transition: transform 0.1s ease-out, opacity 0.1s ease-out, -webkit-transform 0.1s ease-out;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.context-menu-blue-item {
|
||||
display: block;
|
||||
position: relative;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.context-menu-blue-btn {
|
||||
background: none;
|
||||
line-height: normal;
|
||||
overflow: visible;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
display: block;
|
||||
width: 100%;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
border: 1px solid transparent;
|
||||
white-space: nowrap;
|
||||
padding: 1rem 2rem;
|
||||
}
|
||||
|
||||
.context-menu-blue-btn::-moz-focus-inner,
|
||||
.context-menu-blue-btn::-moz-focus-inner {
|
||||
border: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.context-menu-blue-icon {
|
||||
color: white;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.context-menu-blue-text {
|
||||
color: white;
|
||||
font-family: 'Barlow', sans-serif;
|
||||
font-size: 1rem;
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.context-menu-blue-item:hover > .context-menu-blue-btn {
|
||||
color: #23AFF7;
|
||||
outline: none;
|
||||
background-color: #73D0FF;
|
||||
background: -webkit-gradient(linear, left top, left bottom, from(#73D0FF), to(#73D0FF));
|
||||
background: linear-gradient(to bottom, #73D0FF, #73D0FF);
|
||||
}
|
||||
|
||||
.context-menu-blue-item.disabled {
|
||||
opacity: 0.5;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.context-menu-blue-item.disabled .context-menu-blue-btn {
|
||||
cursor: blue;
|
||||
}
|
||||
|
||||
.context-menu-blue-separator {
|
||||
display: block;
|
||||
margin: 7px 5px;
|
||||
height: 1px;
|
||||
border-bottom: 1px solid #23AFF7;
|
||||
background-color: #aaa;
|
||||
}
|
||||
|
||||
.context-menu-blue-item.subcontext-menu-blue::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
right: 6px;
|
||||
top: 50%;
|
||||
-webkit-transform: translateY(-50%);
|
||||
transform: translateY(-50%);
|
||||
border: 5px solid transparent;
|
||||
border-left-color: #808080;
|
||||
}
|
||||
|
||||
.context-menu-blue-item.subcontext-menu-blue:hover::after {
|
||||
border-left-color: #23AFF7;
|
||||
}
|
||||
|
||||
.context-menu-blue .context-menu-blue {
|
||||
top: 4px;
|
||||
left: 99%;
|
||||
}
|
||||
|
||||
.show-context-menu-blue,
|
||||
.context-menu-blue-item:hover > .context-menu-blue {
|
||||
opacity: 1;
|
||||
-webkit-transform: translate(0, 0) scale(1);
|
||||
transform: translate(0, 0) scale(1);
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.context-menu-blue-item:hover > .context-menu-blue {
|
||||
-webkit-transition-delay: 100ms;
|
||||
transition-delay: 300ms;
|
||||
}
|
||||
3128
resources/[framework]/[addons]/qs-inventory/html/css/main.css
Normal file
263
resources/[framework]/[addons]/qs-inventory/html/css/trade.css
Normal file
@@ -0,0 +1,263 @@
|
||||
@import url("https://fonts.googleapis.com/css2?family=Alegreya+Sans:wght@100;300;400&display=swap");
|
||||
* {
|
||||
font-weight: 900;
|
||||
font-family: 'CabinetGrotesk-Bold';
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.trade-container {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
z-index: 99999999;
|
||||
margin: 20px auto;
|
||||
width: 1340px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
transform: translate(-50%,-50%);
|
||||
}
|
||||
|
||||
.buttons-group {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
margin: 0 0;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
border-top-left-radius: 5px;
|
||||
border-top-right-radius: 5px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.gray-text {
|
||||
color: white;
|
||||
font-size: 14px;
|
||||
background-color: rgba(255,255,255,0.125);
|
||||
width: 100%;
|
||||
padding: 5px;
|
||||
background: radial-gradient(120.05% 120.05% at 50.14% -58.24%, rgba(18,121,211,0.2) 0%, rgb(14,21,27) 100%) padding-box padding-box, linear-gradient(rgba(18,121,211,0.2) 30%, rgba(0,163,255,0.6) 70%) border-box border-box;
|
||||
border-bottom-left-radius: 5px;
|
||||
border-bottom-right-radius: 5px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 5px 120px;
|
||||
border-radius: 5px;
|
||||
margin: 10px 5px;
|
||||
transition: opacity 0.1s linear;
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-color: rgba(18,121,211,0.2);
|
||||
border-image-source: linear-gradient(rgb(14,21,27) 0%, rgb(255,255,255) 100%);
|
||||
border-image-slice: initial;
|
||||
border-image-width: initial;
|
||||
border-image-outset: initial;
|
||||
border-image-repeat: initial;
|
||||
background: radial-gradient(120.05% 120.05% at 50.14% -58.24%, rgba(18,121,211,0.2) 0%, rgb(14,21,27) 100%) padding-box padding-box, linear-gradient(rgba(18,121,211,0.2) 30%, rgba(0,163,255,0.6) 70%) border-box border-box;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.btn-red {
|
||||
background-color: #191e25;
|
||||
}
|
||||
|
||||
.btn-green {
|
||||
background-color: #191e25;
|
||||
}
|
||||
|
||||
.btn i {
|
||||
color: #6c757d;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
width: 51vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: radial-gradient(120.05% 120.05% at 50.14% -58.24%, rgba(18,121,211,0.2) 0%, rgb(14,21,27) 100%) padding-box padding-box, linear-gradient(rgba(18,121,211,0.2) 30%, rgba(0,163,255,0.6) 70%) border-box border-box;
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-color: rgba(18,121,211,0.2);
|
||||
border-image-source: linear-gradient(rgb(14,21,27) 0%, rgb(255,255,255) 100%);
|
||||
border-radius: 8px;
|
||||
color: #fff;
|
||||
flex-direction: column;
|
||||
overflow: hidden
|
||||
}
|
||||
|
||||
.border {
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
margin: 10px 0;
|
||||
border-bottom: 2px solid #222;
|
||||
}
|
||||
|
||||
.offer-container {
|
||||
width: 100%;
|
||||
min-height: 430px;
|
||||
max-height: 43px;
|
||||
}
|
||||
|
||||
.offer-container.receiver {
|
||||
border-bottom-right-radius: 5px;
|
||||
border-bottom-left-radius: 5px;
|
||||
}
|
||||
|
||||
.items {
|
||||
min-height: 127px;
|
||||
text-transform: capitalize;
|
||||
max-height: 127px;
|
||||
overflow: auto;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
padding: 0 10px;
|
||||
margin: 0 auto;
|
||||
justify-content: flex-start;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.items-header {
|
||||
font-size: 18px;
|
||||
color: #6c757d;
|
||||
margin: 10px 20px;
|
||||
}
|
||||
|
||||
.trade-item-slot {
|
||||
position: relative;
|
||||
height: 10.2vh;
|
||||
margin: 5px;
|
||||
width: 8.3vh;
|
||||
transition: 0.1s opacity linear;
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-color: rgba(18,121,211,0.2);
|
||||
border-image-source: linear-gradient(rgb(14,21,27) 0%, rgb(255,255,255) 100%);
|
||||
border-image-slice: initial;
|
||||
border-image-width: initial;
|
||||
border-image-outset: initial;
|
||||
border-image-repeat: initial;
|
||||
background: radial-gradient(120.05% 120.05% at 50.14% -58.24%, rgba(18,121,211,0.2) 0%, rgb(14,21,27) 100%) padding-box padding-box, linear-gradient(rgba(18,121,211,0.2) 30%, rgba(0,163,255,0.6) 70%) border-box border-box;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.item-slot:hover {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.item-infos {
|
||||
color: white;
|
||||
position: absolute;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
bottom: 0;
|
||||
padding: 3px;
|
||||
font-size: 14px;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.item-img {
|
||||
position: absolute;
|
||||
top: 45%;
|
||||
left: 50%;
|
||||
transform: translate(-50%,-50%);
|
||||
width: 4.5vh;
|
||||
}
|
||||
|
||||
.item-img img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.offer-items {
|
||||
min-height: 127px;
|
||||
max-height: 127px;
|
||||
overflow: auto;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
padding: 0 10px;
|
||||
margin: 0 auto;
|
||||
justify-content: flex-start;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.header-wrapper {
|
||||
padding: 10px;
|
||||
margin-bottom: 10px;
|
||||
color: white;
|
||||
display: flex;
|
||||
justify-content: space-evenly;
|
||||
}
|
||||
|
||||
.header-wrapper h2 {
|
||||
position: relative;
|
||||
top: .1vh;
|
||||
}
|
||||
|
||||
.header-wrapper input {
|
||||
width: 13%;
|
||||
text-align: right;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.item-trade-cut {
|
||||
width: 38vh;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.amount {
|
||||
background-color: #191e25;
|
||||
outline: none;
|
||||
border: none;
|
||||
padding-left: 10px;
|
||||
border-radius: 4px;
|
||||
height: 4vh;
|
||||
color: white;
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-color: rgba(18,121,211,0.2);
|
||||
border-image-source: linear-gradient(rgb(14,21,27) 0%, rgb(255,255,255) 100%);
|
||||
border-image-slice: initial;
|
||||
border-image-width: initial;
|
||||
border-image-outset: initial;
|
||||
border-image-repeat: initial;
|
||||
background: radial-gradient(120.05% 120.05% at 50.14% -58.24%, rgba(18,121,211,0.2) 0%, rgb(14,21,27) 100%) padding-box padding-box, linear-gradient(rgba(18,121,211,0.2) 30%, rgba(0,163,255,0.6) 70%) border-box border-box;
|
||||
}
|
||||
|
||||
.items, .offer-items {
|
||||
width: 49vh;
|
||||
}
|
||||
|
||||
.item-amount {
|
||||
padding-right: 5px;
|
||||
padding-top: 2px;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
text-align: right;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.item-label {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-size: 11.8764px;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
font-family: 'CabinetGrotesk-Extrabold';
|
||||
text-transform: uppercase;
|
||||
}
|
||||