local QBCore = exports['qb-core']:GetCoreObject() --[[ This is PlayerSlots here we define the Category of the weapons that goes on the Player This means that instead of giving each weapon a designated slot on the back, we can just add a weapon with the designated slot This will also allow for weapons to feel and look more natural when added. All items that go on your back -> MUST have a SLOT CATEGORY, everything that we CARRY must have Carry = true ]] local PlayerSlots = { [1] = { -- Bigger weapons such as bats, crowbars, Assaultrifles, and also good place for wet weed. [1] = { bone = 24817, x = 0.04, y = -0.15, z = 0.12, xr = 0.0, yr = 0.0, zr = 0.0, isBusy = false }, [2] = { bone = 24817, x = 0.04, y = -0.17, z = 0.02, xr = 0.0, yr = 0.0, zr = 0.0, isBusy = false }, [3] = { bone = 24817, x = 0.04, y = -0.15, z = -0.12, xr = 0.0, yr = 0.0, zr = 0.0, isBusy = false }, }, [2] = { -- Use this for katana knives etc. stuff that goes sideways on the players body [1] = { bone = 24817, x = -0.13, y = -0.16, z = -0.14, xr = 5.0, yr = 62.0, zr = 0.0, isBusy = false }, [2] = { bone = 24817, x = -0.13, y = -0.15, z = 0.10, xr = 5.0, yr = 124.0, zr = 0.0, isBusy = false }, }, [3] = { -- Contraband like Drugs and shit [1] = { bone = 24817, x = -0.28, y = -0.14, z = 0.15, xr = 0.0, yr = 92.0, zr = -13.0 }, [2] = { bone = 24817, x = -0.27, y = -0.14, z = 0.15, xr = 0.0, yr = 92.0, zr = 13.0 }, }, [4] = { -- I use this for the pelts for hunting [1] = { bone = 24817, x = -0.18, y = -0.26, z = -0.02, xr = 0.0, yr = 91.0, zr = 5.0 }, [2] = { bone = 24817, x = 0.10, y = -0.26, z = -0.02, xr = 0.0, yr = 91.0, zr = 5.0 }, [3] = { bone = 24817, x = 0.38, y = -0.21, z = -0.02, xr = 0.0, yr = 91.0, zr = 5.0 }, }, [5] = { -- I use this for chains, make sure your CHAIN is a CUSTOM prop, will NOT work with a clothing item, if you want to add a CHAIN make sure to have a chain = true as it will not work the same as weapons -- [1] = { bone = 10706, x = 0.11, y = 0.080, z = -0.473, xr = -366.0, yr = 19.0, zr = -163.0 }, }, } -- Add your items here -- local props = { ---- ** Drugs ** ---- -- Weed ["wetbud"] = { model = "bkr_prop_weed_drying_02a", hash = joaat("bkr_prop_weed_drying_02a"), tier = 1, yr = 90.0 }, -- This is more of an item that deserves a -- meth ["meth"] = { model = "hei_prop_pill_bag_01", hash = joaat("hei_prop_pill_bag_01"), tier = 3 }, ["pack1"] = { carry = true, model = "prop_cs_box_clothes", bone = 28422, x = 0.01, y = -0.02, z = -0.14, xr = 0.0, yr = 0.0, zr = 0.0, blockAttack = true, blockCar = true, blockRun = true}, ["pack2"] = { carry = true, model = "prop_cs_cardbox_01", bone = 28422, x = 0.01, y = -0.02, z = -0.12, xr = 0.0, yr = 0.0, zr = 0.0, blockAttack = true, blockCar = true, blockRun = true}, ["pack3"] = { carry = true, model = "prop_hat_box_06", bone = 28422, x = 0.01, y = -0.02, z = -0.17, xr = 0.0, yr = 0.0, zr = -90.0, blockAttack = true, blockCar = true, blockRun = true}, -- Contraband ["markedbills"] = { model = "prop_money_bag_01", hash = joaat("prop_money_bag_01"), tier = 3, x = -0.47, zr = 0 }, -- If you put any x,y,z,xr,yr,zr it will offset it from the slots to make it fit perfectly -- Custom Weapons Tier 1 -- ["weapon_assaultrifle"] = { model = "w_ar_assaultrifle", hash = joaat("weapon_assaultrifle"), tier = 1 }, -- ["weapon_carbinerifle"] = { model = "w_ar_carbinerifle", hash = joaat("weapon_carbinerifle"), tier = 1 }, -- ["weapon_advancedrifle"] = { model = "w_ar_advancedrifle", hash = joaat("weapon_advancedrifle"), tier = 1 }, -- ["weapon_combatpdw"] = { model = "w_sb_mpx", hash = joaat("weapon_combatpdw"), tier = 1 }, -- ["weapon_compactrifle"] = { model = "w_ar_draco", hash = joaat("weapon_compactrifle"), tier = 1 }, -- ["weapon_m4"] = { model = "w_ar_m4", hash = joaat("weapon_m4"), tier = 1 }, -- tier2 -- ["weapon_bats"] = { model = "w_me_baseball_bat_barbed", hash = joaat("weapon_bats"), tier = 2 }, -- ["weapon_katana"] = { model = "katana_sheath", hash = joaat("weapon_katana"), tier = 2, zr = -90.0, xr = -40.0, -- y = -0.14, x = 0.2, z = -0.08 }, -- ["weapon_golfclub"] = { model = "w_me_gclub", hash = joaat("weapon_golfclub"), tier = 2 }, -- ["weapon_battleaxe"] = { model = "w_me_battleaxe", hash = joaat("weapon_battleaxe"), tier = 2 }, -- ["weapon_crowbar"] = { model = "w_me_crowbar", hash = joaat("weapon_crowbar"), tier = 2 }, -- ["weapon_wrench"] = { model = "w_me_wrench", hash = joaat("weapon_wrench"), tier = 2 }, -- These Utilize the NoPixel pelts from their packages get them here: https://3dstore.nopixel.net/package/5141816 -- ["deer_pelt_1"] = { model = "hunting_pelt_01_a", hash = joaat("hunting_pelt_01_a"), tier = 4 }, ["deer_pelt_2"] = { model = "hunting_pelt_01_b", hash = joaat("hunting_pelt_01_b"), tier = 4 }, ["deer_pelt_3"] = { model = "hunting_pelt_01_c", hash = joaat("hunting_pelt_01_c"), tier = 4 }, -- I use these for my house robbery when they steal the objects -- ["telescope"] = { carry = true, model = "prop_t_telescope_01b", bone = 24817, x = -0.23, y = 0.43, z = 0.05, xr = -10.0, yr = 93.0, zr = 0.0, blockAttack = true, blockCar = true, blockRun = true, }, ["pcequipment"] = { carry = true, model = "prop_dyn_pc_02", bone = 24817, x = 0.09, y = 0.43, z = 0.05, xr = 91.0, yr = 0.0, zr = -265.0, blockAttack = true, blockCar = true, blockRun = true }, ["coffeemaker"] = { carry = true, model = "prop_coffee_mac_02", bone = 24817, x = 0.00, y = 0.43, z = 0.05, xr = 91.0, yr = 0.0, zr = -265.0, blockAttack = true, blockCar = true, blockRun = true }, ["musicequipment"] = { carry = true, model = "prop_speaker_06", bone = 24817, x = 0.00, y = 0.43, z = 0.05, xr = 91.0, yr = 0.0, zr = -265.0, blockAttack = true, blockCar = true, blockRun = true }, ["microwave"] = { carry = true, model = "prop_microwave_1", bone = 24817, x = -0.20, y = 0.43, z = 0.05, xr = 91.0, yr = 0.0, zr = -265.0, blockAttack = true, blockCar = true, blockRun = true }, } local items_attatched = {} local itemSlots = {} local override = false local PlayerData = QBCore.Functions.GetPlayerData() local FullyLoaded = LocalPlayer.state.isLoggedIn local function loadmodel(hash) if HasModelLoaded(hash) then return end RequestModel(hash) while not HasModelLoaded(hash) do Wait(0) end end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- ** Weapon Functions ** -- local function getFreeSlot(tier) local amount = 0 for i = 1, #PlayerSlots[tier] do if not PlayerSlots[tier][i].isBusy then amount = amount + 1 end end return amount end local function UseSlot(tier) local slot = nil for i = 1, #PlayerSlots[tier] do if not PlayerSlots[tier][i].isBusy then PlayerSlots[tier][i].isBusy = true slot = i break end end return slot end local function calcOffsets(x, y, z, xr, yr, zr, item) local X, Y, Z, XR, YR, ZR = x, y, z, xr, yr, zr if props[item].x then X = props[item].x end if props[item].y then Y = props[item].y end if props[item].z then Z = props[item].z end if props[item].xr then XR = props[item].xr end if props[item].yr then YR = props[item].yr end if props[item].zr then ZR = props[item].zr end return X, Y, Z, XR, YR, ZR end local function AttachWeapon(attachModel, modelHash, tier, item) local hash = joaat(attachModel) local slot = UseSlot(tier) if not slot then return end local v = PlayerSlots[tier][slot] local bone = GetPedBoneIndex(PlayerPedId(), v.bone) loadmodel(hash) items_attatched[attachModel] = { hash = modelHash, handle = CreateObject(attachModel, 1.0, 1.0, 1.0, true, true, false), slot = slot, tier = tier } local x, y, z, xr, yr, zr = calcOffsets(v.x, v.y, v.z, v.xr, v.yr, v.zr, item) AttachEntityToEntity(items_attatched[attachModel].handle, PlayerPedId(), bone, x, y, z, xr, yr, zr, 1, 1, 0, 0, 2, 1) SetModelAsNoLongerNeeded(hash) SetEntityCompletelyDisableCollision(items_attatched[attachModel].handle, false, true) end local WeapDelete = false local function DeleteWeapon(item) local ped = PlayerPedId() local hash = items_attatched[item].hash if WeapDelete then return end WeapDelete = true local wait = 0 -- if above 3 seconds then return this function while GetSelectedPedWeapon(ped) ~= hash do Wait(100) wait = wait + 1 if wait >= 30 then return end -- If they figure out a way to spam then this we just return the function end if items_attatched[item] then DeleteObject(items_attatched[item].handle) if items_attatched[item].slot then PlayerSlots[items_attatched[item].tier][items_attatched[item].slot].isBusy = false end items_attatched[item] = nil end WeapDelete = false end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- local carryingBox = nil local function requestAnimDict(animDict) if not HasAnimDictLoaded(animDict) then RequestAnimDict(animDict) while not HasAnimDictLoaded(animDict) do Wait(0) end end end local function doAnim(item) if carryingBox then return end -- Only allow the function to be run once at a time carryingBox = item local ped = PlayerPedId() local dict, anim = props[item].dict or 'anim@heists@box_carry@', props[item].anim or 'idle' if not anim or not dict then return end requestAnimDict(dict) CreateThread(function() while carryingBox do if not IsEntityPlayingAnim(ped, dict, anim, 3) then TaskPlayAnim(ped, dict, anim, 8.0, -8, -1, 49, 0, 0, 0, 0) end if props[carryingBox].blockAttack then DisableControlAction(0, 24, true) -- disable attack DisableControlAction(0, 25, true) -- disable aim DisableControlAction(0, 47, true) -- disable weapon DisableControlAction(0, 58, true) -- disable weapon DisableControlAction(0, 263, true) -- disable melee DisableControlAction(0, 264, true) -- disable melee DisableControlAction(0, 257, true) -- disable melee DisableControlAction(0, 140, true) -- disable melee DisableControlAction(0, 141, true) -- disable melee DisableControlAction(0, 142, true) -- disable melee DisableControlAction(0, 143, true) -- disable melee end if props[carryingBox].blockCar and IsPedGettingIntoAVehicle(ped) then ClearPedTasksImmediately(ped) -- Stops all tasks for the ped end if props[carryingBox].blockRun then DisableControlAction(0, 22, true) -- disable jumping DisableControlAction(0, 21, true) -- disable sprinting end Wait(1) end ClearPedTasks(ped) end) end local function AttatchProp(item) if carryingBox then return end local ped = PlayerPedId() local attachModel = props[item].model local hash = joaat(props[item].model) local bone = GetPedBoneIndex(ped, props[item].bone) SetCurrentPedWeapon(ped, 0xA2719263) loadmodel(hash) items_attatched[attachModel] = { hash = hash, handle = CreateObject(attachModel, 1.0, 1.0, 1.0, true, true, false), carry = true } local x, y, z, xr, yr, zr = props[item].x, props[item].y, props[item].z, props[item].xr, props[item].yr, props[item].zr AttachEntityToEntity(items_attatched[attachModel].handle, ped, bone, x, y, z, xr, yr, zr, 1, 1, 0, 0, 2, 1) SetModelAsNoLongerNeeded(hash) SetEntityCompletelyDisableCollision(items_attatched[attachModel].handle, false, true) doAnim(item) end local tempBox = nil -- Exports to trick the script into thinking we got an item we can carry -- local function carryProp(item) if not item then return print("ITEM NOT DEFINED") end if not props[item] then return print("ITEM NOT REGISTERED IN THE CONFIG") end if carryingBox then return print("PED IS ALREADY CARRYING AN OBJECT") end tempBox = item AttatchProp(item) end exports('carryProp', carryProp) local function removeProp(item) if not item then return print("ITEM NOT DEFINED") end if not props[item] then return print("ITEM NOT REGISTERED IN THE CONFIG") end if carryingBox ~= item then return print("Item is not whats being carried...") end DeleteObject(items_attatched[props[item].model].handle) items_attatched[props[item].model] = nil carryingBox = nil tempBox = nil end exports('removeProp', removeProp) local carryingChain = nil local function AttatchChain(attachModel, modelHash, tier, item) if carryingChain then return end carryingChain = attachModel local slot = UseSlot(tier) if not slot then return end local v = PlayerSlots[tier][slot] local bone = GetPedBoneIndex(PlayerPedId(), v.bone) loadmodel(modelHash) ClearPedTasks(PlayerPedId()) items_attatched[attachModel] = { hash = modelHash, handle = CreateObject(attachModel, 1.0, 1.0, 1.0, true, true, false), slot = slot, tier = tier, chain = true, } local x, y, z, xr, yr, zr = calcOffsets(v.x, v.y, v.z, v.xr, v.yr, v.zr, item) AttachEntityToEntity(items_attatched[attachModel].handle, PlayerPedId(), bone, x, y, z, xr, yr, zr, 1, 1, 0, 0, 2, 1) SetModelAsNoLongerNeeded(modelHash) SetEntityCompletelyDisableCollision(items_attatched[attachModel].handle, false, true) end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --** Generic Functions **-- local function getItemByhash(hash) for k, v in pairs(props) do if v.hash == hash or hash == joaat(v.model) then return k end end end local function removeItems() if items_attatched then for k, v in pairs(items_attatched) do local hasitem = false local item = getItemByhash(v.hash) if item then if tempBox ~= item then if itemSlots[item] then hasitem = true end if not hasitem or (props[item] and props[item].busy) then DeleteObject(v.handle) if v.slot then PlayerSlots[v.tier][v.slot].isBusy = false end if v.chain then carryingChain = nil end if v.carry then carryingBox = nil end items_attatched[k] = nil end end end end end end local PlayerId = PlayerId() local doingCheck = false local function DoItemCheck() if not FullyLoaded then return end if doingCheck then return end if IsPedShooting(ped) or IsPlayerFreeAiming(PlayerId) then return end -- reduces the shooting spamming doingCheck = true Wait(math.random(1, 100)) -- When shooting a gun, the event is called HUNDREDS of times, this here is to prevent that from affecting the players MS too much at a time. local ped = PlayerPedId() local items = PlayerData.items itemSlots = {} if items then for _, item in pairs(items) do item.name = item.name:lower() if item and item.name and props and props[item.name] and not itemSlots[item.name] then itemSlots[item.name] = props[item.name] if props[item.name].carry then if not carryingBox then AttatchProp(item.name) end elseif props[item.name].chain then if not carryingChain then AttatchChain(props[item.name].model, props[item.name].hash, props[item.name].tier, item.name) end elseif not items_attatched[props[item.name].model] and GetSelectedPedWeapon(ped) ~= props[item.name].hash and getFreeSlot(props[item.name].tier) >= 1 then AttachWeapon(props[item.name].model, props[item.name].hash, props[item.name].tier, item.name) end end end end removeItems() Wait(math.random(1, 100)) -- When shooting a gun, the event is called HUNDREDS of times, this here is to prevent that from affecting the players MS too much at a time. doingCheck = false end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- ** EXPORTS ** -- local function toggleProps() if override then if items_attatched then for k, v in pairs(items_attatched) do DeleteObject(v.handle) if v.slot then PlayerSlots[v.tier][v.slot].isBusy = false end if v.carry then carryingBox = nil end if v.chain then carryingChain = nil end items_attatched[k] = nil end end override = false else override = true if items_attatched then for k, v in pairs(items_attatched) do DeleteObject(v.handle) if v.slot then PlayerSlots[v.tier][v.slot].isBusy = false end if v.carry then carryingBox = nil end if v.chain then carryingChain = nil end items_attatched[k] = nil end end end end exports("toggleProps", toggleProps) local function isCarryingObject() return carryingBox ~= nil and true or false end exports('isCarryingObject', isCarryingObject) local function isCarryingAnObject(item) if items_attatched[props[item].model] then return true else return false end end exports('isCarryingAnObject', isCarryingAnObject) local function GetPlayerCarryItems() return items_attatched end exports('GetPlayerCarryItems', GetPlayerCarryItems) local function refreshProps() if not FullyLoaded then return end if items_attatched then for k, v in pairs(items_attatched) do DeleteObject(v.handle) if v.slot then PlayerSlots[v.tier][v.slot].isBusy = false end if v.carry then carryingBox = nil end if v.chain then carryingChain = nil end items_attatched[k] = nil end end DoItemCheck() end exports('refreshProps', refreshProps) local function makeObjectBusy(item, state) if not FullyLoaded then return end if not item or not state then return print("YOU ARE MISSING ARGS FOR THIS EXPORT") end if not props[item] then return print("ITEM: " .. item .. " DOES NOT EXIST") end if props[item] and props[item].busy == nil then return print("ITEM: " .. item .. " CANNOT BE SET TO BUSY") end props[item].busy = state DoItemCheck() end exports('makeObjectBusy', makeObjectBusy) ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- ** GENERIC EVENTS ** -- AddEventHandler('ox_inventory:currentWeapon', function(data) if not FullyLoaded then return end if override then return end if data then data.name = data.name:lower() if props[data.name] and items_attatched[props[data.name].model] then DeleteWeapon(props[data.name].model) end else Wait(1000) DoItemCheck() end end) RegisterNetEvent('weapons:client:SetCurrentWeapon', function(data) if data and LocalPlayer.state.isLoggedIn then if props[data.name] and items_attatched[props[data.name].model] then DeleteWeapon(props[data.name].model) end elseif not data and LocalPlayer.state.isLoggedIn then Wait(1000) if not override then DoItemCheck() elseif override and PlayerData.metadata.inside.apartment.apartmentId then DoItemCheck() end end end) -- Handles state right when the player selects their character and location. RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function() Wait(20000) PlayerData = QBCore.Functions.GetPlayerData() FullyLoaded = true Wait(250) if not override then DoItemCheck() elseif override and PlayerData.metadata.inside.apartment.apartmentId then DoItemCheck() end end) -- Resets state on logout, in case of character change. RegisterNetEvent('QBCore:Client:OnPlayerUnload', function() PlayerData = nil FullyLoaded = false end) -- Handles state when PlayerData is changed. We're just looking for inventory updates. RegisterNetEvent('QBCore:Player:SetPlayerData', function(val) PlayerData = val Wait(50) if not override then DoItemCheck() elseif override and PlayerData.metadata.inside.apartment.apartmentId then DoItemCheck() end end) -- Handles state if resource is restarted live. AddEventHandler('onResourceStart', function(resource) if GetCurrentResourceName() == resource then Wait(100) if not FullyLoaded then return end DoItemCheck() end end) AddEventHandler('onResourceStop', function(resource) if resource == GetCurrentResourceName() then for key, attached_object in pairs(items_attatched) do DeleteObject(attached_object.handle) items_attatched[key] = nil end end end)