local QBCore = exports['qb-core']:GetCoreObject() local PlayerData = QBCore.Functions.GetPlayerData() local marketItems, orderLocation, tabletProp, currentMoney local targetZones = {} local displayingUI = false local function removeTargetZones() for i=1, #targetZones do exports['qb-target']:RemoveZone(targetZones[i]) end end local function tabletAnim(state) local ped = PlayerPedId() if state then local tabletHash = joaat(Config.tabletAnim.prop) loadModel(tabletHash) loadAnimDict(Config.tabletAnim.dict) tabletProp = CreateObject(tabletHash, GetEntityCoords(ped), true, true, false) AttachEntityToEntity(tabletProp, ped, GetPedBoneIndex(ped, 28422), -0.05, 0.0, 0.0, 0.0, 0.0, 0.0, true, true, false, true, 1, true) SetModelAsNoLongerNeeded(tabletHash) TaskPlayAnim(ped, Config.tabletAnim.dict, Config.tabletAnim.anim, 1.0, 1.0, -1, 51, 0, 0, 0, 0) else DeleteObject(tabletProp) ClearPedTasks(ped) end end local function displayUI(state) displayingUI = state tabletAnim(state) if state then SendNUIMessage({ action = "setVisible", data = true, }) else SendNUIMessage({ action = "setVisible", data = false, }) end SetNuiFocus(state, state) end local function tabletNotification(text, notifType) SendNUIMessage({ action = "notification", data = { text = text, notifType = notifType, } }) end local function doContainerAnim(index, containerNetId, lockNetId, collisionNetId) local container = NetworkGetEntityFromNetworkId(containerNetId) local lock = NetworkGetEntityFromNetworkId(lockNetId) local collision = NetworkGetEntityFromNetworkId(collisionNetId) NetworkRequestControlOfEntity(container) NetworkRequestControlOfEntity(lock) local timer = GetGameTimer() while not NetworkHasControlOfEntity(container) or not NetworkHasControlOfEntity(lock) do Wait(0) if GetGameTimer() - timer > 5000 then printError("Failed to get control of object") break end end loadAnimDict(Config.containerAnim.dict) loadPtfx(Config.containerAnim.ptfx) loadAudio(Config.containerAnim.audioBank) local grinderHash = joaat(Config.props.grinder) local bagHash = joaat(Config.props.bag) loadModel(grinderHash) loadModel(bagHash) local ped = PlayerPedId() local containerCoords = GetEntityCoords(container) local containerRot = GetEntityRotation(container) local playerCoords = GetEntityCoords(ped) local grinder = CreateObject(grinderHash, playerCoords, true, true, false) local bag = CreateObject(bagHash, playerCoords, true, true, false) SetEntityCollision(bag, false, false) FreezeEntityPosition(ped, true) local containerScene = NetworkCreateSynchronisedScene(containerCoords, containerRot, 2, true, false, 1.0, 0.0, 1.0) NetworkAddPedToSynchronisedScene(ped, containerScene, Config.containerAnim.dict, Config.containerAnim.player, 10.0, 10.0, 0, 0, 1000.0, 0) NetworkAddEntityToSynchronisedScene(lock, containerScene, Config.containerAnim.dict, Config.containerAnim.lock, 2.0, -4.0, 134149) NetworkAddEntityToSynchronisedScene(grinder, containerScene, Config.containerAnim.dict, Config.containerAnim.grinder, 2.0, -4.0, 134149) NetworkAddEntityToSynchronisedScene(bag, containerScene, Config.containerAnim.dict, Config.containerAnim.bag, 2.0, -4.0, 134149) NetworkStartSynchronisedScene(containerScene) PlayEntityAnim(container, Config.containerAnim.container, Config.containerAnim.dict, 8.0, false, true, false, 0, 0) CreateThread(function() while NetworkGetLocalSceneFromNetworkId(containerScene) == -1 do Wait(0) end local localScene = NetworkGetLocalSceneFromNetworkId(containerScene) local ptfx while IsSynchronizedSceneRunning(localScene) do if HasAnimEventFired(ped, -1953940906) then UseParticleFxAsset("scr_tn_tr") ptfx = StartNetworkedParticleFxLoopedOnEntity("scr_tn_tr_angle_grinder_sparks", grinder, 0.0, 0.25, 0.0, 0.0, 0.0, 0.0, 1.0, false, false, false, 1065353216, 1065353216, 1065353216, 1) elseif HasAnimEventFired(ped, -258875766) then StopParticleFxLooped(ptfx, false) end Wait(0) end end) Wait(GetAnimDuration(Config.containerAnim.dict, Config.containerAnim.container) * 1000) FreezeEntityPosition(ped, false) NetworkStopSynchronisedScene(containerScene) DeleteObject(grinder) DeleteObject(lock) DeleteObject(bag) ClearPedTasks(ped) TriggerServerEvent("qb-blackmarket_sv:openContainer", index) DisposeSynchronizedScene(containerScene) RemoveNamedPtfxAsset(Config.containerAnim.ptfx) ReleaseNamedScriptAudioBank(Config.containerAnim.audioBank) RemoveAnimDict(Config.containerAnim.dict) end local function spawnObject(model, coords) local propHash = type(model) == 'string' and joaat(model) or model loadModel(propHash) local object = CreateObject(propHash, coords.xyz, true, true, false) while not DoesEntityExist(object) do Wait(10) end SetEntityAsMissionEntity(object, true, true) FreezeEntityPosition(object, true) SetEntityHeading(object, coords.w) SetModelAsNoLongerNeeded(propHash) return object end local function spawnContainer(coords) loadAnimDict(Config.containerAnim.dict) local container = spawnObject(Config.props.container, vector4(coords.x, coords.y, coords.z - 1, coords.w - 180)) local containerCoords = GetEntityCoords(container) local lockCoords = GetAnimInitialOffsetPosition(Config.containerAnim.dict, Config.containerAnim.lock, GetEntityCoords(container), GetEntityRotation(container), 0.0, 0) local lock = spawnObject(Config.props.lock, vector4(lockCoords, coords.w - 180)) SetEntityCoords(lock, lockCoords) local crateCoords = GetObjectOffsetFromCoords(coords, 0.0, -0.6, -0.8) local crate = spawnObject(Config.props.crate, vector4(crateCoords, coords.w + 90)) local collision = spawnObject(Config.props.containerCollison, vector4(containerCoords, coords.w - 180)) SetEntityCoords(collision, containerCoords, false, false, false) SetEntityCollision(collision, false, false) local props = { container = container, lock = lock, crate = crate, collision = collision, } return props end RegisterNetEvent("qb-blackmarket_cl:openUI", function() displayUI(true) end) RegisterNetEvent("qb-blackmarket_cl:updateMarketItems", function(items) marketItems = items SendNUIMessage({ action = "updateMarketItems", data = items }) end) RegisterNetEvent("qb-blackmarket_cl:updateStock", function(items, orderSrc) marketItems = items if displayingUI then local isOwner = false if orderSrc == GetPlayerServerId(PlayerId()) then isOwner = true end SendNUIMessage({ action = "updateStock", data = { items = items, notif = Config.notifText.stockUpdate, isOwner = isOwner, }, }) end end) RegisterNetEvent("qb-blackmarket_cl:orderReady", function(index, coords) orderLocation = coords local props = spawnContainer(orderLocation) local netIds = {} for k, v in pairs(props) do netIds[k] = NetworkGetNetworkIdFromEntity(v) end TriggerServerEvent("qb-blackmarket_sv:propsSpawned", netIds, index) if not displayingUI then QBCore.Functions.Notify(Config.notifText.orderReady, "success") else tabletNotification(Config.notifText.orderReady, "success") end SendNUIMessage({ action = "orderReady", }) if math.random() <= Config.policeNotifChance then Config.policeNotify(orderLocation) end end) RegisterNetEvent("qb-blackmarket_cl:addLockTarget", function(index, coords) local zoneName = "bm_lock_"..index for i=1, #targetZones do if targetZones[i] == zoneName then print("lock exists") return end end local min, max = GetModelDimensions(joaat(Config.props.lock)) local lockDimensions = max - min exports["qb-target"]:AddBoxZone(zoneName, coords.xyz, lockDimensions.y, lockDimensions.x, { name = zoneName, heading = coords.w, debugPoly = false, minZ = coords.z - lockDimensions.z/2, maxZ = coords.z + lockDimensions.z/2, }, { options = { { icon = "fa-solid fa-unlock", label = "Ă…ben", action = function() TriggerServerEvent("qb-blackmarket_sv:attemptContainer", index) end } }, distance = 2.0 }) targetZones[#targetZones + 1] = zoneName end) RegisterNetEvent("qb-blackmarket_cl:openContainer", function(index, propIds) doContainerAnim(index, propIds.container, propIds.lock, propIds.collision) end) RegisterNetEvent("qb-blackmarket_cl:updateOpenContainer", function(index, containerNetId, collisionNetId, crateCoords, removeLockTarget) local container = NetworkGetEntityFromNetworkId(containerNetId) local collision = NetworkGetEntityFromNetworkId(collisionNetId) SetEntityCollision(collision, true, true) SetEntityCompletelyDisableCollision(container, false, false) if removeLockTarget then exports['qb-target']:RemoveZone("bm_lock_"..index) for i=1, #targetZones do if targetZones[i] == "bm_lock_"..index then table.remove(targetZones, i) break end end end local zoneName = "bm_crate_"..index local min, max = GetModelDimensions(joaat(Config.props.crate)) local crateDimensions = max - min exports["qb-target"]:AddBoxZone(zoneName, crateCoords.xyz, crateDimensions.y, crateDimensions.x, { name = zoneName, heading = crateCoords.w, debugPoly = false, minZ = crateCoords.z, maxZ = crateCoords.z + crateDimensions.z, }, { options = { { icon = "fa-solid fa-boxes-stacked", label = "Tag", action = function() TriggerServerEvent("qb-blackmarket_sv:attemptLoot", index) end } }, distance = 2.0 }) targetZones[#targetZones + 1] = zoneName end) RegisterNetEvent("qb-blackmarket_cl:removeLockTarget", function(index) print("removing lock target ", index) exports['qb-target']:RemoveZone("bm_lock_"..index) for i=1, #targetZones do if targetZones[i] == "bm_lock_"..index then table.remove(targetZones, i) break end end end) RegisterNetEvent("qb-blackmarket_cl:removeLootTarget", function(index) exports['qb-target']:RemoveZone("bm_crate_"..index) for i=1, #targetZones do if targetZones[i] == "bm_crate_"..index then table.remove(targetZones, i) break end end end) RegisterNetEvent("qb-blackmarket_cl:lootContainer", function(index) local ped = PlayerPedId() loadAnimDict(Config.lootAnim.dict) TaskPlayAnim(ped, Config.lootAnim.dict, Config.lootAnim.anim, 1.0, 1.0, -1, 1, 0, 0, 0, 0) QBCore.Functions.Progressbar("looting_crate", "Tager ting..", Config.lootTime, false, true, { disableMovement = true, disableCarMovement = true, disableMouse = false, disableCombat = true }, {}, {}, {}, function() -- Done TriggerServerEvent("qb-blackmarket_sv:finishLooting", index) end, function() -- Cancel TriggerServerEvent("qb-blackmarket_sv:cancelLooting", index) QBCore.Functions.Notify("Annulleret", "error") end) end) RegisterNetEvent("qb-blackmarket_cl:orderComplete", function() SendNUIMessage({ action = "clearOrder" }) end) RegisterNetEvent("qb-blackmarket_cl:hasPendingOrder", function(items, order, epochTime) SendNUIMessage({ action = "loadPendingOrder", data = { marketItems = items, order = order, epochTime = epochTime, } }) end) RegisterNetEvent("qb-blackmarket_cl:enableLocateButton", function(index) orderLocation = Config.deliveryLocations[index] SendNUIMessage({ action = "orderReady", }) end) RegisterNUICallback("getClientData", function(data, cb) currentMoney = PlayerData.money[Config.paymentType] if not marketItems then QBCore.Functions.TriggerCallback("qb-blackmarket_sv:getMarketItems", function(items) marketItems = items cb({ marketItems = marketItems, currencyAmt = currentMoney }) end) else cb({ marketItems = marketItems, currencyAmt = currentMoney }) end end) RegisterNUICallback("submitOrder", function(data, cb) QBCore.Functions.TriggerCallback("qb-blackmarket_sv:attemptOrder", function(result) cb(result) if result.notif then if result.success then tabletNotification(result.notif, "success") else tabletNotification(result.notif, "error") end end if result.error then printError(result.error) end end, (data)) end) RegisterNUICallback("deliveryLocation", function(data, cb) if orderLocation then SetNewWaypoint(orderLocation.x, orderLocation.y) tabletNotification(Config.notifText.gpsSet, "success") end cb({}) end) RegisterNUICallback("close", function(data, cb) displayUI(false) cb({}) end) RegisterNUICallback("fetchConfig", function(data, cb) cb({ configData = { inventory = Config.inventory, paymentType = Config.paymentType, acronym = Config.cryptoAcronym, cryptoIcon = Config.cryptoIcon, estDeliveryTime = tostring(math.floor((Config.deliveryTime.min + Config.deliveryTime.max)/2)), tabletColour = Config.tabletColour, }, notifData = Config.notifs, }) end) RegisterNetEvent('QBCore:Player:SetPlayerData', function(val) PlayerData = val if displayingUI then if PlayerData.money[Config.paymentType] ~= currentMoney then SendNUIMessage({ action = "updateCash", data = PlayerData.money[Config.paymentType] }) end end end) RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function() PlayerData = QBCore.Functions.GetPlayerData() TriggerServerEvent("qb-blackmarket_sv:initPendingOrders") end) RegisterNetEvent('QBCore:Client:OnPlayerUnload', function() PlayerData = nil removeTargetZones() targetZones = {} SendNUIMessage({ SendNUIMessage({ action = "clearOrder" }) }) end) AddEventHandler('onResourceStop', function(resourceName) if resourceName ~= GetCurrentResourceName() then return end for i=1, #targetZones do exports['qb-target']:RemoveZone(targetZones[i]) end targetZones = {} end)