312 lines
14 KiB
Lua
Raw Normal View History

2025-04-07 01:41:12 +00:00
local config = require 'config.client'
local sharedConfig = require 'config.shared'
local isHacking
local isSmashing
local closestVitrine = 1
local animName
local insideJewelry = false
local electricalBoxEntity
local function dropFingerprint()
if qbx.isWearingGloves() then return end
if config.fingerprintChance > math.random(0, 100) then
local coords = GetEntityCoords(cache.ped)
TriggerServerEvent('evidence:server:CreateFingerDrop', coords)
end
end
local function createElectricalBox()
lib.requestModel(`tr_prop_tr_elecbox_01a`)
electricalBoxEntity = CreateObjectNoOffset(joaat("tr_prop_tr_elecbox_01a"), sharedConfig.electrical.x, sharedConfig.electrical.y, sharedConfig.electrical.z, true, true, false)
SetModelAsNoLongerNeeded(`tr_prop_tr_elecbox_01a`)
while not DoesEntityExist(electricalBoxEntity) do
Wait(0)
end
SetEntityHeading(electricalBoxEntity, sharedConfig.electrical.w)
if config.useTarget then
exports.ox_target:addLocalEntity(electricalBoxEntity, {
{
name = 'qbx_jewelery:electricalBox',
icon = 'fab fa-usb',
label = locale('text.electricalTarget'),
distance = 1.6,
items = sharedConfig.doorlock.requiredItem,
onSelect = function()
lib.callback('qbx_jewelery:callback:electricalbox', false, function(CanHack)
if not CanHack then return end
TriggerEvent('qbx_jewelery:client:electricalHandler')
end)
end
}
})
end
end
local function removeElectricalBox()
if config.useTarget then
exports.ox_target:removeLocalEntity(electricalBoxEntity, 'qbx_jewelery:electricalBox')
end
if electricalBoxEntity ~= nil and DoesEntityExist(electricalBoxEntity) then
DeleteObject(electricalBoxEntity)
end
electricalBoxEntity = nil
end
if not config.useTarget then
CreateThread(function()
local hasShownText
while true do
local playerCoords = GetEntityCoords(cache.ped)
local electricalCoords = vector3(sharedConfig.electrical.x, sharedConfig.electrical.y, sharedConfig.electrical.z + 1.1)
local waitTime = 800
local nearby = false
if #(playerCoords - electricalCoords) <= 1.5 and not isHacking then
waitTime = 0
nearby = true
if config.useDrawText then
qbx.drawText3d({text = locale('text.electrical'), coords = electricalCoords})
elseif not config.useDrawText and not hasShownText then
hasShownText = true
lib.showTextUI(locale('text.electrical'), {position = 'left-center'})
end
if IsControlJustPressed(0, 38) then
lib.callback('qbx_jewelery:callback:electricalbox', false, function(CanHack)
if not CanHack then return end
isHacking = true
TriggerEvent('qbx_jewelery:client:electricalHandler')
end)
end
end
if not nearby and hasShownText then
hasShownText = false
lib.hideTextUI()
end
Wait(waitTime)
end
end)
end
AddEventHandler('qbx_jewelery:client:electricalHandler', function()
local animDictBox = 'anim@scripted@player@mission@tun_control_tower@male@'
lib.requestAnimDict(animDictBox)
local playerCoords = GetEntityCoords(cache.ped)
local box = GetClosestObjectOfType(playerCoords.x, playerCoords.y, playerCoords.z, 1.5, `tr_prop_tr_elecbox_01a`, false, false, false)
local enterScene = NetworkCreateSynchronisedScene(sharedConfig.electrical.x, sharedConfig.electrical.y, sharedConfig.electrical.z, 0, 0, sharedConfig.electrical.w, 2, true, false, 1065353216, -1, 1.0)
NetworkAddPedToSynchronisedScene(cache.ped, enterScene, animDictBox, 'enter', 1.5, -4.0, 1, 16, 1148846080, 0)
NetworkAddEntityToSynchronisedScene(box, enterScene, animDictBox, 'enter_electric_box', 4.0, -8.0, 1)
local loopingScene = NetworkCreateSynchronisedScene(sharedConfig.electrical.x, sharedConfig.electrical.y, sharedConfig.electrical.z, 0, 0, sharedConfig.electrical.w, 2, false, true, 1065353216, -1, 1.0)
NetworkAddPedToSynchronisedScene(cache.ped, loopingScene, animDictBox, 'loop', 1.5, -4.0, 1, 16, 1148846080, 0)
NetworkAddEntityToSynchronisedScene(box, loopingScene, animDictBox, 'loop_electric_box', 4.0, -8.0, 1)
local leavingScene = NetworkCreateSynchronisedScene(sharedConfig.electrical.x, sharedConfig.electrical.y, sharedConfig.electrical.z, 0, 0, sharedConfig.electrical.w, 2, true, false, 1065353216, -1, 1.0)
NetworkAddPedToSynchronisedScene(cache.ped, leavingScene, animDictBox, 'exit', 1.5, -4.0, 1, 16, 1148846080, 0)
NetworkAddEntityToSynchronisedScene(box, leavingScene, animDictBox, 'exit_electric_box', 4.0, -8.0, 1)
local duration = GetAnimDuration(animDictBox, 'enter')
NetworkStartSynchronisedScene(enterScene)
Wait(duration * 1000)
NetworkStartSynchronisedScene(loopingScene)
TriggerEvent('ultra-voltlab', math.random(sharedConfig.doorlock.hackTime.min, sharedConfig.doorlock.hackTime.max), function(result, reason)
Wait(2500)
NetworkStartSynchronisedScene(leavingScene)
isHacking = false
if result == 0 then -- Failed
TriggerServerEvent('qbx_jewelery:server:failedhackdoor')
exports.qbx_core:Notify(reason, 'error')
elseif result == 1 then -- Succeeded
TriggerServerEvent('qbx_jewelery:server:succeshackdoor')
elseif result == 2 then -- Timed out
TriggerServerEvent('qbx_jewelery:server:failedhackdoor')
exports.qbx_core:Notify(reason, 'error')
elseif result == -1 then -- Some error
TriggerServerEvent('qbx_jewelery:server:failedhackdoor')
exports.qbx_core:Notify('Failed hack', 'error')
print('Error occured', reason)
end
Wait(GetAnimDuration(animDictBox, 'exit') * 1000)
NetworkStopSynchronisedScene(leavingScene)
RemoveAnimDict(animDictBox)
end)
end)
local function startRayFire(coords, rayFire)
local RayFireObject = GetRayfireMapObject(coords.x, coords.y, coords.z, 1.4, rayFire)
SetStateOfRayfireMapObject(RayFireObject, 4)
Wait(100)
SetStateOfRayfireMapObject(RayFireObject, 6)
end
local function loadParticle()
lib.requestNamedPtfxAsset('scr_jewelheist')
UseParticleFxAsset('scr_jewelheist')
end
local function playSmashAudio(coords)
local soundId = GetSoundId()
PlaySoundFromCoord(soundId, 'Glass_Smash', coords.x, coords.y, coords.z, '', false, 6.0, false)
ReleaseSoundId(soundId)
end
if config.useTarget then
for i = 1, #sharedConfig.vitrines do
exports.ox_target:addBoxZone({
coords = sharedConfig.vitrines[i].coords,
size = vec3(1.2, 1.6, 1),
rotation = sharedConfig.vitrines[i].heading,
--debug = true,
options = {
{
icon = 'fas fa-gem',
label = locale('text.cabinetTarget'),
distance = 0.6,
onSelect = function()
closestVitrine = i
lib.callback('qbx_jewelery:callback:cabinet', false, function(CanSmash)
if not CanSmash then return end
TriggerEvent('qbx_jewelery:client:cabinetHandler')
end, closestVitrine)
end
}
}
})
end
else
CreateThread(function()
local hasShownText
while true do
local playerCoords = GetEntityCoords(cache.ped)
local nearby = false
local waitTime = 800
for i = 1, #sharedConfig.vitrines do
if #(playerCoords - sharedConfig.vitrines[i].coords) < 0.5 then
if not closestVitrine then closestVitrine = i
elseif #(playerCoords - sharedConfig.vitrines[i].coords) < #(playerCoords - sharedConfig.vitrines[closestVitrine].coords) then closestVitrine = i end
waitTime = 0
nearby = true
end
end
if nearby and not (isSmashing or sharedConfig.vitrines[closestVitrine].isOpened) then
if config.useDrawText then
qbx.drawText3d({text = locale('text.cabinet'), coords = sharedConfig.vitrines[closestVitrine].coords})
elseif not config.useDrawText and not hasShownText then
hasShownText = true
lib.showTextUI(locale('text.cabinet'), {position = 'left-center'})
end
if IsControlJustPressed(0, 38) then
lib.callback('qbx_jewelery:callback:cabinet', false, function(CanSmash)
if not CanSmash then return end
isSmashing = true
if hasShownText then hasShownText = false lib.hideTextUI() end
TriggerEvent('qbx_jewelery:client:cabinetHandler')
end, closestVitrine)
end
end
if not nearby and hasShownText then hasShownText = false lib.hideTextUI() end
Wait(waitTime)
end
end)
end
AddEventHandler('qbx_jewelery:client:cabinetHandler', function()
local animDictCabinet = 'missheist_jewel'
local animNameSmashFront = {
'smash_case_tray_b',
'smash_case_necklace_skull'
}
local animNameSmashTop = {
'smash_case_tray_a',
'smash_case_d',
'smash_case_e'
}
local playerCoords = GetEntityCoords(cache.ped)
dropFingerprint()
TaskAchieveHeading(cache.ped, sharedConfig.vitrines[closestVitrine].heading, 1500)
Wait(1500)
lib.requestAnimDict(animDictCabinet)
if sharedConfig.vitrines[closestVitrine].rayFire == 'DES_Jewel_Cab4' then
animName = animNameSmashFront[math.random(1, #animNameSmashFront)]
TaskPlayAnim(cache.ped, animDictCabinet, animName, 3.0, 3.0, -1, 2, 0, false, false, false)
Wait(150)
startRayFire(playerCoords, sharedConfig.vitrines[closestVitrine].rayFire)
elseif sharedConfig.vitrines[closestVitrine].rayFire then
animName = animNameSmashTop[math.random(1, #animNameSmashTop)]
TaskPlayAnim(cache.ped, animDictCabinet, animName, 3.0, 3.0, -1, 2, 0, false, false, false)
Wait(300)
startRayFire(playerCoords, sharedConfig.vitrines[closestVitrine].rayFire)
else
animName = animNameSmashTop[math.random(1, #animNameSmashTop)]
TaskPlayAnim(cache.ped, animDictCabinet, animName, 3.0, 3.0, -1, 2, 0, false, false, false)
Wait(300)
end
RemoveAnimDict(animDictCabinet)
loadParticle()
StartNetworkedParticleFxNonLoopedOnEntity('scr_jewel_cab_smash', GetCurrentPedWeaponEntityIndex(cache.ped), 0, 0, 0, 0, 0, 0, 1.6, false, false, false)
playSmashAudio(playerCoords)
Wait(GetAnimDuration(animDictCabinet, animName) * 850)
ClearPedTasks(cache.ped)
RemoveNamedPtfxAsset('scr_jewelheist')
isSmashing = false
TriggerServerEvent('qbx_jewelery:server:endcabinet')
end)
RegisterNetEvent('qbx_jewelery:client:synceffects', function(closestVitrines, originalPlayer)
closestVitrine = closestVitrines
Wait(1500)
if sharedConfig.vitrines[closestVitrine].rayFire == 'DES_Jewel_Cab4' then
Wait(150)
startRayFire(sharedConfig.vitrines[closestVitrine].coords, sharedConfig.vitrines[closestVitrine].rayFire)
elseif sharedConfig.vitrines[closestVitrine].rayFire then
Wait(300)
startRayFire(sharedConfig.vitrines[closestVitrine].coords, sharedConfig.vitrines[closestVitrine].rayFire)
end
loadParticle()
StartNetworkedParticleFxNonLoopedOnEntity('scr_jewel_cab_smash', GetCurrentPedWeaponEntityIndex(GetPlayerPed(GetPlayerFromServerId(originalPlayer))), 0, 0, 0, 0, 0, 0, 1.6, false, false, false)
playSmashAudio(sharedConfig.vitrines[closestVitrine].coords)
RemoveNamedPtfxAsset('scr_jewelheist')
end)
RegisterNetEvent('qbx_jewelery:client:syncconfig', function(vitrines)
sharedConfig.vitrines = vitrines
end)
RegisterNetEvent('qbx_jewelery:client:alarm', function()
PrepareAlarm('JEWEL_STORE_HEIST_ALARMS')
Wait(100)
StartAlarm('JEWEL_STORE_HEIST_ALARMS', false)
Wait(config.alarmDuration)
StopAlarm('JEWEL_STORE_HEIST_ALARMS', true)
end)
lib.zones.sphere({
coords = vec3(sharedConfig.vitrines[1].coords.x, sharedConfig.vitrines[1].coords.y, sharedConfig.vitrines[1].coords.z),
radius = 80,
--debug = true,
onEnter = function()
insideJewelry = true
createElectricalBox()
CreateThread(function()
while insideJewelry do
for i = 1, #sharedConfig.vitrines do
if sharedConfig.vitrines[i].isOpened then
local rayFire = GetRayfireMapObject(sharedConfig.vitrines[i].coords.x, sharedConfig.vitrines[i].coords.y, sharedConfig.vitrines[i].coords.z, 1.4, sharedConfig.vitrines[i].rayFire)
SetStateOfRayfireMapObject(rayFire, 9)
end
end
Wait(6000)
end
end)
end,
onExit = function()
removeElectricalBox()
insideJewelry = false
end,
})
AddEventHandler('onResourceStop', function(resource)
if resource ~= cache.resource then return end
removeElectricalBox()
end)