local QBCore = exports['qb-core']:GetCoreObject() local firstAlarm = false local smashing = false -- Functions local function loadParticle() if not HasNamedPtfxAssetLoaded('scr_jewelheist') then RequestNamedPtfxAsset('scr_jewelheist') end while not HasNamedPtfxAssetLoaded('scr_jewelheist') do Wait(0) end SetPtfxAssetNextCall('scr_jewelheist') end local function loadAnimDict(dict) while (not HasAnimDictLoaded(dict)) do RequestAnimDict(dict) Wait(3) end end local function validWeapon() local ped = PlayerPedId() local pedWeapon = GetSelectedPedWeapon(ped) -- Allow if the player is armed with a firearm (category 4) - NO MELEE if IsPedArmed(ped, 4) then return true end -- Fallback for specific items in the whitelist for k, _ in pairs(Config.WhitelistedWeapons) do if pedWeapon == k then return true end end return false end local function smashVitrine(k) if not firstAlarm then exports['ps-dispatch']:SuspiciousActivity() firstAlarm = true end QBCore.Functions.TriggerCallback('thugs-jewelery:server:getCops', function(cops) if cops >= Config.RequiredCops then local animDict = 'missheist_jewel' local animName = 'smash_case' local ped = PlayerPedId() local plyCoords = GetOffsetFromEntityInWorldCoords(ped, 0, 0.6, 0) local pedWeapon = GetSelectedPedWeapon(ped) if math.random(1, 100) <= 80 and not QBCore.Functions.IsWearingGloves() then TriggerServerEvent('evidence:server:CreateFingerDrop', plyCoords) elseif math.random(1, 100) <= 5 and QBCore.Functions.IsWearingGloves() then TriggerServerEvent('evidence:server:CreateFingerDrop', plyCoords) QBCore.Functions.Notify(Lang:t('error.fingerprints'), 'error') end local timeOut = 10000 -- Fallback timeout if Config.WhitelistedWeapons[pedWeapon] and Config.WhitelistedWeapons[pedWeapon]['timeOut'] then timeOut = Config.WhitelistedWeapons[pedWeapon]['timeOut'] end TriggerServerEvent('thugs-jewelery:server:setVitrineState', 'isBusy', true, k) smashing = true CreateThread(function() local smashedGlass = false while smashing do if not HasAnimDictLoaded(animDict) then RequestAnimDict(animDict) Wait(100) end TaskPlayAnim(ped, animDict, animName, 3.0, 3.0, -1, 2, 0, 0, 0, 0) Wait(500) if not smashedGlass then -- Glass native destruction local vitrineCoords = Config.Locations[k].coords ShootSingleBulletBetweenCoords(vitrineCoords.x, vitrineCoords.y, vitrineCoords.z + 1.0, vitrineCoords.x, vitrineCoords.y, vitrineCoords.z - 1.0, 200, true, pedWeapon, ped, false, true, 250.0) smashedGlass = true end TriggerServerEvent('InteractSound_SV:PlayOnSource', 'breaking_vitrine_glass', 0.25) if not HasNamedPtfxAssetLoaded('scr_jewelheist') then RequestNamedPtfxAsset('scr_jewelheist') Wait(100) end if HasNamedPtfxAssetLoaded('scr_jewelheist') then SetPtfxAssetNextCall('scr_jewelheist') StartParticleFxLoopedAtCoord('scr_jewel_cab_smash', plyCoords.x, plyCoords.y, plyCoords.z, 0.0, 0.0, 0.0, 1.0, false, false, false, false) end Wait(4500) -- Loop exactly every 5 seconds end end) QBCore.Functions.Progressbar('smash_vitrine', Lang:t('info.progressbar'), timeOut, false, true, { disableMovement = true, disableCarMovement = true, disableMouse = false, disableCombat = true, }, {}, {}, {}, function() -- Done TriggerServerEvent('thugs-jewelery:server:vitrineReward', k) TriggerServerEvent('thugs-jewelery:server:setTimeout') local camId = '31 | 32 | 33 | 34' exports['ps-dispatch']:VangelicoRobbery(camId) smashing = false StopAnimTask(ped, animDict, animName, 1.0) end, function() -- Cancel TriggerServerEvent('thugs-jewelery:server:setVitrineState', 'isBusy', false, k) smashing = false StopAnimTask(ped, animDict, animName, 1.0) end) else QBCore.Functions.Notify(Lang:t('error.minimum_police', { value = Config.RequiredCops }), 'error') end end) end -- Events RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function() QBCore.Functions.TriggerCallback('thugs-jewelery:server:getVitrineState', function(result) Config.Locations = result end) end) RegisterNetEvent('thugs-jewelery:client:setVitrineState', function(stateType, state, k) Config.Locations[k][stateType] = state end) -- Threads CreateThread(function() if not Config.JewelleryLocation or not Config.JewelleryLocation['coords'] then return end local Dealer = AddBlipForCoord(Config.JewelleryLocation['coords']['x'], Config.JewelleryLocation['coords']['y'], Config.JewelleryLocation['coords']['z']) SetBlipSprite(Dealer, 617) SetBlipDisplay(Dealer, 4) SetBlipScale(Dealer, 0.7) SetBlipAsShortRange(Dealer, true) SetBlipColour(Dealer, 3) BeginTextCommandSetBlipName('STRING') AddTextComponentSubstringPlayerName('Vangelico Jewelry') EndTextCommandSetBlipName(Dealer) end) local listen = false local function Listen4Control(case) listen = true CreateThread(function() while listen do if IsControlJustPressed(0, 38) then listen = false if not Config.Locations[case]['isBusy'] and not Config.Locations[case]['isOpened'] then exports['qb-core']:KeyPressed() if validWeapon() then smashVitrine(case) else QBCore.Functions.Notify(Lang:t('error.wrong_weapon'), 'error') end else exports['qb-core']:DrawText(Lang:t('general.drawtextui_broken'), 'left') end end Wait(1) end end) end CreateThread(function() if Config.UseTarget then for k, v in pairs(Config.Locations) do exports['qb-target']:AddBoxZone('jewelstore' .. k, v.coords, 1, 1, { name = 'jewelstore' .. k, heading = 40, minZ = v.coords.z - 1, maxZ = v.coords.z + 1, debugPoly = false }, { options = { { type = 'client', icon = 'fa fa-hand', label = Lang:t('general.target_label'), action = function() if validWeapon() then smashVitrine(k) else QBCore.Functions.Notify(Lang:t('error.wrong_weapon'), 'error') end end, canInteract = function() if v['isOpened'] or v['isBusy'] then return false end return true end, } }, distance = 1.5 }) end else for k, v in pairs(Config.Locations) do local boxZone = BoxZone:Create(v.coords, 1, 1, { name = 'jewelstore' .. k, heading = 40, minZ = v.coords.z - 1, maxZ = v.coords.z + 1, debugPoly = false }) boxZone:onPlayerInOut(function(isPointInside) if isPointInside then Listen4Control(k) exports['qb-core']:DrawText(Lang:t('general.drawtextui_grab'), 'left') else listen = false exports['qb-core']:HideText() end end) end end end)