323 lines
10 KiB
Lua
Raw Normal View History

2025-04-07 01:41:12 +00:00
local sharedConfig = require 'config.shared'
local function checkIsSpikeObject(spikeStrips, fixedCoords, position, maxDistance)
if #spikeStrips == 0 then return end
for i = 1, #spikeStrips do
local coords = fixedCoords[spikeStrips[i]]
local distance = #(position - coords)
if distance < maxDistance then
return true
end
end
end
local function getClosestObject(objects, position, maxDistance, isFixed)
if #objects == 0 then return end
local minDistance, currentIndex
for i = 1, #objects do
local coords
if isFixed then
coords = GlobalState.fixedCoords[objects[i]]
else
local object = NetworkGetEntityFromNetworkId(objects[i])
coords = GetEntityCoords(object)
end
local distance = #(position - coords)
if distance < maxDistance then
if not minDistance or distance < minDistance then
minDistance = distance
currentIndex = i
end
end
end
return currentIndex
end
---Spawn police object.
---@param item string name from `config/shared.lua`
RegisterNetEvent('police:client:spawnPObj', function(item)
if QBX.PlayerData.job.type ~= 'leo' or not QBX.PlayerData.job.onduty then return end
if cache.vehicle then return exports.qbx_core:Notify(locale('error.in_vehicle'), 'error') end
if lib.progressBar({
duration = 2500,
label = locale('progressbar.place_object'),
useWhileDead = false,
canCancel = true,
disable = {
car = true,
move = true,
combat = true,
mouse = false
},
anim = {
dict = 'anim@narcotics@trash',
clip = 'drop_front'
}
}) then
local objectConfig = sharedConfig.objects[item]
local forward = GetEntityForwardVector(cache.ped)
local spawnCoords = GetEntityCoords(cache.ped) + forward * 0.5
local netid, error = lib.callback.await('police:server:spawnObject', false,
objectConfig.model, spawnCoords, GetEntityHeading(cache.ped))
if not netid then return exports.qbx_core:Notify(locale(error), 'error') end
local object = NetworkGetEntityFromNetworkId(netid)
PlaceObjectOnGroundProperly(object)
FreezeEntityPosition(object, objectConfig.freeze)
else
exports.qbx_core:Notify(locale('error.canceled'), 'error')
end
end)
RegisterNetEvent('police:client:deleteObject', function()
local objectId = getClosestObject(GlobalState.policeObjects, GetEntityCoords(cache.ped) , 5.0)
if not objectId then return end
if lib.progressBar({
duration = 2500,
label = locale('progressbar.remove_object'),
useWhileDead = false,
canCancel = true,
disable = {
car = true,
move = true,
combat = true,
mouse = false
},
anim = {
dict = 'weapons@first_person@aim_rng@generic@projectile@thermal_charge@',
clip = 'plant_floor'
}
}) then
TriggerServerEvent('police:server:despawnObject', objectId)
else
exports.qbx_core:Notify(locale('error.canceled'), 'error')
end
end)
---Spawn a spike strip.
RegisterNetEvent('police:client:SpawnSpikeStrip', function()
if QBX.PlayerData.job.type ~= 'leo' or not QBX.PlayerData.job.onduty then return end
if #GlobalState.spikeStrips >= sharedConfig.maxSpikes then
return exports.qbx_core:Notify(locale('error.no_spikestripe'), 'error')
end
if cache.vehicle then return exports.qbx_core:Notify(locale('error.in_vehicle'), 'error') end
if lib.progressBar({
duration = 2500,
label = locale('progressbar.place_object'),
useWhileDead = false,
canCancel = true,
disable = {
car = true,
move = true,
combat = true,
mouse = false
},
anim = {
dict = 'amb@medic@standing@kneel@enter',
clip = 'enter'
}
}) then
local spawnCoords = GetOffsetFromEntityInWorldCoords(cache.ped, 0.0, 2.0, 0)
local netid, error = lib.callback.await('police:server:spawnSpikeStrip', false,
spawnCoords, GetEntityHeading(cache.ped))
if not netid then
return exports.qbx_core:Notify(locale(error), 'error')
end
lib.requestAnimDict('p_ld_stinger_s')
local spike = NetworkGetEntityFromNetworkId(netid)
PlayEntityAnim(spike, 'p_stinger_s_deploy', 'p_ld_stinger_s', 1000.0, false, false, false, 0.0, 0)
PlaceObjectOnGroundProperly(spike)
RemoveAnimDict('p_ld_stinger_s')
else
exports.qbx_core:Notify(locale('error.canceled'), 'error')
end
RemoveAnimDict('amb@medic@standing@kneel@enter')
end)
local WHEEL_NAMES = {
'wheel_lf',
'wheel_rf',
'wheel_lm',
'wheel_rm',
'wheel_lr',
'wheel_rr',
}
local isSpike
CreateThread(function()
while true do
if LocalPlayer.state.isLoggedIn then
isSpike = checkIsSpikeObject(GlobalState.spikeStrips, GlobalState.fixedCoords, GetEntityCoords(cache.ped), 30)
end
Wait(500)
end
end)
local isWatchInVehicleBusy
local function burstTyreOnSpikeCollision(vehicle)
CreateThread(function ()
if isWatchInVehicleBusy then return end
isWatchInVehicleBusy = true
local wheels = {}
for i = 1, #WHEEL_NAMES do
local w = GetEntityBoneIndexByName(vehicle, WHEEL_NAMES[i])
if w ~= -1 then
wheels[#wheels + 1] = { wheel = w, index = i - 1 }
end
end
pcall(lib.waitFor(function() return cache.value end, nil, sharedConfig.timeout))
while cache.vehicle do
local spikeStrips = GlobalState.spikeStrips
local fixedCoords = GlobalState.fixedCoords
if isSpike then
for i = 1, #wheels do
if wheels[i].wheel then
local wheelPosition = GetWorldPositionOfEntityBone(cache.vehicle, wheels[i].wheel)
if checkIsSpikeObject(spikeStrips, fixedCoords, wheelPosition, 1.8) then
local index = wheels[i].index
if not IsVehicleTyreBurst(cache.vehicle, index, true)
or IsVehicleTyreBurst(cache.vehicle, index, false)
then
SetVehicleTyreBurst(cache.vehicle, index, false, 1000.0)
end
end
end
end
Wait(0)
else
Wait(250)
end
end
isWatchInVehicleBusy = nil
end)
end
local function displayInfoCloseToSpike()
CreateThread(function ()
pcall(lib.waitFor(function() return cache.value and nil or false end, nil, sharedConfig.timeout))
while not cache.vehicle and LocalPlayer.state.isLoggedIn and QBX.PlayerData.job.type == 'leo' and QBX.PlayerData.job.onduty do
local isOpen, text = lib.isTextUIOpen()
if isSpike and checkIsSpikeObject(GlobalState.spikeStrips, GlobalState.fixedCoords, GetEntityCoords(cache.ped), 3) then
if not isOpen or text ~= locale('info.delete_spike') then
lib.showTextUI(locale('info.delete_spike'))
end
else
if isOpen and text == locale('info.delete_spike') then
lib.hideTextUI()
end
end
Wait(500)
end
local isOpen, text = lib.isTextUIOpen()
if isOpen and text == locale('info.delete_spike') then
lib.hideTextUI()
end
end)
end
local keybind
local function onPressed()
if cache.vehicle then return end
keybind:disable(true)
local spike = getClosestObject(GlobalState.spikeStrips, GetEntityCoords(cache.ped), 4, true)
if spike ~= nil then
if lib.progressBar({
duration = 2500,
label = locale('progressbar.remove_object'),
useWhileDead = false,
canCancel = true,
disable = {
car = true,
move = true,
combat = true,
mouse = false
},
anim = {
dict = 'weapons@first_person@aim_rng@generic@projectile@thermal_charge@',
clip = 'plant_floor'
}
}) then
TriggerServerEvent('police:server:despawnSpikeStrip', spike)
lib.hideTextUI()
else
exports.qbx_core:Notify(locale('error.canceled'), 'error')
end
end
keybind:disable(false)
end
keybind = lib.addKeybind({
name = 'despawnSpikeStrip',
description = locale('info.delete_spike'),
defaultKey = 'E',
secondaryMapper = 'PAD_DIGITALBUTTONANY',
secondaryKey = 'LRIGHT_INDEX',
onPressed = onPressed
})
local function toggleJobFunctions(isWorkingLeo)
if isWorkingLeo then
keybind:disable(false)
if not cache.vehicle then
displayInfoCloseToSpike()
end
else
keybind:disable(true)
end
end
RegisterNetEvent('QBCore:Client:OnJobUpdate', function(job)
toggleJobFunctions(LocalPlayer.state.isLoggedIn and job.type == 'leo' and job.onduty)
end)
RegisterNetEvent('QBCore:Client:SetDuty', function(onDuty)
local job = QBX.PlayerData.job
toggleJobFunctions(LocalPlayer.state.isLoggedIn and job and job.type == 'leo' and onDuty)
end)
AddStateBagChangeHandler('isLoggedIn', ('player:%s'):format(cache.serverId), function(_, _, isLoggedIn)
local job = QBX.PlayerData.job
toggleJobFunctions(isLoggedIn and job and job.type == 'leo' and job.onduty)
if cache.vehicle then
burstTyreOnSpikeCollision(cache.vehicle)
end
end)
lib.onCache('vehicle', function(vehicle)
if vehicle then
burstTyreOnSpikeCollision(vehicle)
else
displayInfoCloseToSpike()
end
end)
AddEventHandler('onResourceStop', function (resource)
if resource ~= GetCurrentResourceName() then return end
local isOpen, text = lib.isTextUIOpen()
if isOpen and text == locale('info.delete_spike') then
lib.hideTextUI()
end
end)