fix(rv-maphold): foloseste QBCore nativ pt HasItem, fara export qb-inventory

This commit is contained in:
2026-04-01 22:42:06 +03:00
parent 6112500590
commit ddc4d116db
705 changed files with 10 additions and 1 deletions

Binary file not shown.

View 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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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')

View File

@@ -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)

View File

@@ -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

View File

@@ -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)

View File

@@ -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)

View File

@@ -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

View 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', {})

View File

@@ -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)

View 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 (15).
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
}

View 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 (1100%)
- 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...
}

View File

@@ -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.01.0; higher = wears faster)
-- },
}

View File

@@ -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.01.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

View 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,
},
},
}
},
}

View 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;
}

View File

@@ -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,
},
}
},
}

View File

@@ -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.
}

View 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.
}

View 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' },
}

File diff suppressed because it is too large Load Diff

View 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'

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@@ -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;
}

View 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;
}

View File

@@ -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;
}

File diff suppressed because it is too large Load Diff

View 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;
}

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