local PlayerData, CurrentActionData, handcuffTimer, dragStatus, blipsCops, currentTask, spawnedVehicles = {}, {}, {}, {}, {}, {}, {}
local HasAlreadyEnteredMarker, isDead, isHandcuffed, hasAlreadyJoined, playerInService, isInShopMenu = false, false, false, false, false, false
local LastStation, LastPart, LastPartNum, LastEntity, CurrentAction, CurrentActionMsg
dragStatus.isDragged = false
ESX = nil
Citizen.CreateThread(function()
while ESX == nil do
TriggerEvent('esx:getSharedObject', function(obj) ESX = obj end)
Citizen.Wait(0)
end
while ESX.GetPlayerData().job == nil do
Citizen.Wait(10)
end
PlayerData = ESX.GetPlayerData()
end)
function cleanPlayer(playerPed)
SetPedArmour(playerPed, 0)
ClearPedBloodDamage(playerPed)
ResetPedVisibleDamage(playerPed)
ClearPedLastWeaponDamage(playerPed)
ResetPedMovementClipset(playerPed, 0)
end
function setUniform(job, playerPed)
TriggerEvent('skinchanger:getSkin', function(skin)
if skin.sex == 0 then
if Config.Uniforms[job].male then
TriggerEvent('skinchanger:loadClothes', skin, Config.Uniforms[job].male)
else
ESX.ShowNotification(_U('no_outfit'))
end
if job == 'bullet_wear' then
SetPedArmour(playerPed, 100)
end
else
if Config.Uniforms[job].female then
TriggerEvent('skinchanger:loadClothes', skin, Config.Uniforms[job].female)
else
ESX.ShowNotification(_U('no_outfit'))
end
if job == 'bullet_wear' then
SetPedArmour(playerPed, 100)
end
end
end)
end
function OpenCloakroomMenu()
local playerPed = PlayerPedId()
local grade = PlayerData.job.grade_name
local elements = {
{ label = _U('citizen_wear'), value = 'citizen_wear' },
{ label = _U('bullet_wear'), value = 'bullet_wear' },
{ label = _U('gilet_wear'), value = 'gilet_wear' }
}
if grade == 'recruit' then
table.insert(elements, {label = _U('police_wear'), value = 'recruit_wear'})
elseif grade == 'officer' then
table.insert(elements, {label = _U('police_wear'), value = 'officer_wear'})
elseif grade == 'sergeant' then
table.insert(elements, {label = _U('police_wear'), value = 'sergeant_wear'})
elseif grade == 'intendent' then
table.insert(elements, {label = _U('police_wear'), value = 'intendent_wear'})
elseif grade == 'lieutenant' then
table.insert(elements, {label = _U('police_wear'), value = 'lieutenant_wear'})
elseif grade == 'chef' then
table.insert(elements, {label = _U('police_wear'), value = 'chef_wear'})
elseif grade == 'boss' then
table.insert(elements, {label = _U('police_wear'), value = 'boss_wear'})
end
if Config.EnableNonFreemodePeds then
table.insert(elements, {label = 'Sheriff wear', value = 'freemode_ped', maleModel = 's_m_y_sheriff_01', femaleModel = 's_f_y_sheriff_01'})
table.insert(elements, {label = 'Police wear', value = 'freemode_ped', maleModel = 's_m_y_cop_01', femaleModel = 's_f_y_cop_01'})
table.insert(elements, {label = 'Swat wear', value = 'freemode_ped', maleModel = 's_m_y_swat_01', femaleModel = 's_m_y_swat_01'})
end
ESX.UI.Menu.CloseAll()
ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'cloakroom', {
title = _U('cloakroom'),
align = 'top-left',
elements = elements
}, function(data, menu)
cleanPlayer(playerPed)
if data.current.value == 'citizen_wear' then
if Config.EnableNonFreemodePeds then
ESX.TriggerServerCallback('esx_skin:getPlayerSkin', function(skin, jobSkin)
local isMale = skin.sex == 0
TriggerEvent('skinchanger:loadDefaultModel', isMale, function()
ESX.TriggerServerCallback('esx_skin:getPlayerSkin', function(skin)
TriggerEvent('skinchanger:loadSkin', skin)
TriggerEvent('esx:restoreLoadout')
end)
end)
end)
else
ESX.TriggerServerCallback('esx_skin:getPlayerSkin', function(skin)
TriggerEvent('skinchanger:loadSkin', skin)
end)
end
if Config.MaxInService ~= -1 then
ESX.TriggerServerCallback('esx_service:isInService', function(isInService)
if isInService then
playerInService = false
local notification = {
title = _U('service_anonunce'),
subject = '',
msg = _U('service_out_announce', GetPlayerName(PlayerId())),
iconType = 1
}
TriggerServerEvent('esx_service:notifyAllInService', notification, 'police')
TriggerServerEvent('esx_service:disableService', 'police')
TriggerEvent('esx_policejob:updateBlip')
ESX.ShowNotification(_U('service_out'))
end
end, 'police')
end
end
if Config.MaxInService ~= -1 and data.current.value ~= 'citizen_wear' then
local serviceOk = 'waiting'
ESX.TriggerServerCallback('esx_service:isInService', function(isInService)
if not isInService then
ESX.TriggerServerCallback('esx_service:enableService', function(canTakeService, maxInService, inServiceCount)
if not canTakeService then
ESX.ShowNotification(_U('service_max', inServiceCount, maxInService))
else
serviceOk = true
playerInService = true
local notification = {
title = _U('service_anonunce'),
subject = '',
msg = _U('service_in_announce', GetPlayerName(PlayerId())),
iconType = 1
}
TriggerServerEvent('esx_service:notifyAllInService', notification, 'police')
TriggerEvent('esx_policejob:updateBlip')
ESX.ShowNotification(_U('service_in'))
end
end, 'police')
else
serviceOk = true
end
end, 'police')
while type(serviceOk) == 'string' do
Citizen.Wait(5)
end
-- if we couldn't enter service don't let the player get changed
if not serviceOk then
return
end
end
if
data.current.value == 'recruit_wear' or
data.current.value == 'officer_wear' or
data.current.value == 'sergeant_wear' or
data.current.value == 'intendent_wear' or
data.current.value == 'lieutenant_wear' or
data.current.value == 'chef_wear' or
data.current.value == 'boss_wear' or
data.current.value == 'bullet_wear' or
data.current.value == 'gilet_wear'
then
setUniform(data.current.value, playerPed)
end
if data.current.value == 'freemode_ped' then
local modelHash = ''
ESX.TriggerServerCallback('esx_skin:getPlayerSkin', function(skin, jobSkin)
if skin.sex == 0 then
modelHash = GetHashKey(data.current.maleModel)
else
modelHash = GetHashKey(data.current.femaleModel)
end
ESX.Streaming.RequestModel(modelHash, function()
SetPlayerModel(PlayerId(), modelHash)
SetModelAsNoLongerNeeded(modelHash)
TriggerEvent('esx:restoreLoadout')
end)
end)
end
end, function(data, menu)
menu.close()
CurrentAction = 'menu_cloakroom'
CurrentActionMsg = _U('open_cloackroom')
CurrentActionData = {}
end)
end
function OpenArmoryMenu(station)
local elements = {
{label = _U('buy_weapons'), value = 'buy_weapons'}
}
if Config.EnableArmoryManagement then
table.insert(elements, {label = _U('get_weapon'), value = 'get_weapon'})
table.insert(elements, {label = _U('put_weapon'), value = 'put_weapon'})
table.insert(elements, {label = _U('remove_object'), value = 'get_stock'})
table.insert(elements, {label = _U('deposit_object'), value = 'put_stock'})
end
ESX.UI.Menu.CloseAll()
ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'armory', {
title = _U('armory'),
align = 'top-left',
elements = elements
}, function(data, menu)
if data.current.value == 'get_weapon' then
OpenGetWeaponMenu()
elseif data.current.value == 'put_weapon' then
OpenPutWeaponMenu()
elseif data.current.value == 'buy_weapons' then
OpenBuyWeaponsMenu()
elseif data.current.value == 'put_stock' then
OpenPutStocksMenu()
elseif data.current.value == 'get_stock' then
OpenGetStocksMenu()
end
end, function(data, menu)
menu.close()
CurrentAction = 'menu_armory'
CurrentActionMsg = _U('open_armory')
CurrentActionData = {station = station}
end)
end
function OpenVehicleSpawnerMenu(type, station, part, partNum)
local playerCoords = GetEntityCoords(PlayerPedId())
PlayerData = ESX.GetPlayerData()
local elements = {
{label = _U('garage_storeditem'), action = 'garage'},
{label = _U('garage_storeitem'), action = 'store_garage'},
{label = _U('garage_buyitem'), action = 'buy_vehicle'}
}
ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'vehicle', {
title = _U('garage_title'),
align = 'top-left',
elements = elements
}, function(data, menu)
if data.current.action == 'buy_vehicle' then
local shopElements, shopCoords = {}
if type == 'car' then
shopCoords = Config.PoliceStations[station].Vehicles[partNum].InsideShop
local authorizedVehicles = Config.AuthorizedVehicles[PlayerData.job.grade_name]
if #Config.AuthorizedVehicles.Shared > 0 then
for k,vehicle in ipairs(Config.AuthorizedVehicles.Shared) do
table.insert(shopElements, {
label = ('%s - %s'):format(vehicle.label, _U('shop_item', ESX.Math.GroupDigits(vehicle.price))),
name = vehicle.label,
model = vehicle.model,
price = vehicle.price,
type = 'car'
})
end
end
if #authorizedVehicles > 0 then
for k,vehicle in ipairs(authorizedVehicles) do
table.insert(shopElements, {
label = ('%s - %s'):format(vehicle.label, _U('shop_item', ESX.Math.GroupDigits(vehicle.price))),
name = vehicle.label,
model = vehicle.model,
price = vehicle.price,
type = 'car'
})
end
else
if #Config.AuthorizedVehicles.Shared == 0 then
return
end
end
elseif type == 'helicopter' then
shopCoords = Config.PoliceStations[station].Helicopters[partNum].InsideShop
local authorizedHelicopters = Config.AuthorizedHelicopters[PlayerData.job.grade_name]
if #authorizedHelicopters > 0 then
for k,vehicle in ipairs(authorizedHelicopters) do
table.insert(shopElements, {
label = ('%s - %s'):format(vehicle.label, _U('shop_item', ESX.Math.GroupDigits(vehicle.price))),
name = vehicle.label,
model = vehicle.model,
price = vehicle.price,
livery = vehicle.livery or nil,
type = 'helicopter'
})
end
else
ESX.ShowNotification(_U('helicopter_notauthorized'))
return
end
end
OpenShopMenu(shopElements, playerCoords, shopCoords)
elseif data.current.action == 'garage' then
local garage = {}
ESX.TriggerServerCallback('esx_vehicleshop:retrieveJobVehicles', function(jobVehicles)
if #jobVehicles > 0 then
for k,v in ipairs(jobVehicles) do
local props = json.decode(v.vehicle)
local vehicleName = GetLabelText(GetDisplayNameFromVehicleModel(props.model))
local label = ('%s - %s: '):format(vehicleName, props.plate)
if v.stored then
label = label .. ('%s'):format(_U('garage_stored'))
else
label = label .. ('%s'):format(_U('garage_notstored'))
end
table.insert(garage, {
label = label,
stored = v.stored,
model = props.model,
vehicleProps = props
})
end
ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'vehicle_garage', {
title = _U('garage_title'),
align = 'top-left',
elements = garage
}, function(data2, menu2)
if data2.current.stored then
local foundSpawn, spawnPoint = GetAvailableVehicleSpawnPoint(station, part, partNum)
if foundSpawn then
menu2.close()
ESX.Game.SpawnVehicle(data2.current.model, spawnPoint.coords, spawnPoint.heading, function(vehicle)
ESX.Game.SetVehicleProperties(vehicle, data2.current.vehicleProps)
TriggerServerEvent('esx_vehicleshop:setJobVehicleState', data2.current.vehicleProps.plate, false)
ESX.ShowNotification(_U('garage_released'))
end)
end
else
ESX.ShowNotification(_U('garage_notavailable'))
end
end, function(data2, menu2)
menu2.close()
end)
else
ESX.ShowNotification(_U('garage_empty'))
end
end, type)
elseif data.current.action == 'store_garage' then
StoreNearbyVehicle(playerCoords)
end
end, function(data, menu)
menu.close()
end)
end
function StoreNearbyVehicle(playerCoords)
local vehicles, vehiclePlates = ESX.Game.GetVehiclesInArea(playerCoords, 30.0), {}
if #vehicles > 0 then
for k,v in ipairs(vehicles) do
-- Make sure the vehicle we're saving is empty, or else it wont be deleted
if GetVehicleNumberOfPassengers(v) == 0 and IsVehicleSeatFree(v, -1) then
table.insert(vehiclePlates, {
vehicle = v,
plate = ESX.Math.Trim(GetVehicleNumberPlateText(v))
})
end
end
else
ESX.ShowNotification(_U('garage_store_nearby'))
return
end
ESX.TriggerServerCallback('esx_policejob:storeNearbyVehicle', function(storeSuccess, foundNum)
if storeSuccess then
local vehicleId = vehiclePlates[foundNum]
local attempts = 0
ESX.Game.DeleteVehicle(vehicleId.vehicle)
IsBusy = true
Citizen.CreateThread(function()
BeginTextCommandBusyString('STRING')
AddTextComponentSubstringPlayerName(_U('garage_storing'))
EndTextCommandBusyString(4)
while IsBusy do
Citizen.Wait(100)
end
RemoveLoadingPrompt()
end)
-- Workaround for vehicle not deleting when other players are near it.
while DoesEntityExist(vehicleId.vehicle) do
Citizen.Wait(500)
attempts = attempts + 1
-- Give up
if attempts > 30 then
break
end
vehicles = ESX.Game.GetVehiclesInArea(playerCoords, 30.0)
if #vehicles > 0 then
for k,v in ipairs(vehicles) do
if ESX.Math.Trim(GetVehicleNumberPlateText(v)) == vehicleId.plate then
ESX.Game.DeleteVehicle(v)
break
end
end
end
end
IsBusy = false
ESX.ShowNotification(_U('garage_has_stored'))
else
ESX.ShowNotification(_U('garage_has_notstored'))
end
end, vehiclePlates)
end
function GetAvailableVehicleSpawnPoint(station, part, partNum)
local spawnPoints = Config.PoliceStations[station][part][partNum].SpawnPoints
local found, foundSpawnPoint = false, nil
for i=1, #spawnPoints, 1 do
if ESX.Game.IsSpawnPointClear(spawnPoints[i].coords, spawnPoints[i].radius) then
found, foundSpawnPoint = true, spawnPoints[i]
break
end
end
if found then
return true, foundSpawnPoint
else
ESX.ShowNotification(_U('vehicle_blocked'))
return false
end
end
function OpenShopMenu(elements, restoreCoords, shopCoords)
local playerPed = PlayerPedId()
isInShopMenu = true
ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'vehicle_shop', {
title = _U('vehicleshop_title'),
align = 'top-left',
elements = elements
}, function(data, menu)
ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'vehicle_shop_confirm', {
title = _U('vehicleshop_confirm', data.current.name, data.current.price),
align = 'top-left',
elements = {
{label = _U('confirm_no'), value = 'no'},
{label = _U('confirm_yes'), value = 'yes'}
}}, function(data2, menu2)
if data2.current.value == 'yes' then
local newPlate = exports['esx_vehicleshop']:GeneratePlate()
local vehicle = GetVehiclePedIsIn(playerPed, false)
local props = ESX.Game.GetVehicleProperties(vehicle)
props.plate = newPlate
ESX.TriggerServerCallback('esx_policejob:buyJobVehicle', function (bought)
if bought then
ESX.ShowNotification(_U('vehicleshop_bought', data.current.name, ESX.Math.GroupDigits(data.current.price)))
isInShopMenu = false
ESX.UI.Menu.CloseAll()
DeleteSpawnedVehicles()
FreezeEntityPosition(playerPed, false)
SetEntityVisible(playerPed, true)
ESX.Game.Teleport(playerPed, restoreCoords)
else
ESX.ShowNotification(_U('vehicleshop_money'))
menu2.close()
end
end, props, data.current.type)
else
menu2.close()
end
end, function(data2, menu2)
menu2.close()
end)
end, function(data, menu)
isInShopMenu = false
ESX.UI.Menu.CloseAll()
DeleteSpawnedVehicles()
FreezeEntityPosition(playerPed, false)
SetEntityVisible(playerPed, true)
ESX.Game.Teleport(playerPed, restoreCoords)
end, function(data, menu)
DeleteSpawnedVehicles()
WaitForVehicleToLoad(data.current.model)
ESX.Game.SpawnLocalVehicle(data.current.model, shopCoords, 0.0, function(vehicle)
table.insert(spawnedVehicles, vehicle)
TaskWarpPedIntoVehicle(playerPed, vehicle, -1)
FreezeEntityPosition(vehicle, true)
SetModelAsNoLongerNeeded(data.current.model)
if data.current.livery then
SetVehicleModKit(vehicle, 0)
SetVehicleLivery(vehicle, data.current.livery)
end
end)
end)
WaitForVehicleToLoad(elements[1].model)
ESX.Game.SpawnLocalVehicle(elements[1].model, shopCoords, 0.0, function(vehicle)
table.insert(spawnedVehicles, vehicle)
TaskWarpPedIntoVehicle(playerPed, vehicle, -1)
FreezeEntityPosition(vehicle, true)
SetModelAsNoLongerNeeded(elements[1].model)
if elements[1].livery then
SetVehicleModKit(vehicle, 0)
SetVehicleLivery(vehicle, elements[1].livery)
end
end)
end
Citizen.CreateThread(function()
while true do
Citizen.Wait(0)
if isInShopMenu then
DisableControlAction(0, 75, true) -- Disable exit vehicle
DisableControlAction(27, 75, true) -- Disable exit vehicle
else
Citizen.Wait(500)
end
end
end)
function DeleteSpawnedVehicles()
while #spawnedVehicles > 0 do
local vehicle = spawnedVehicles[1]
ESX.Game.DeleteVehicle(vehicle)
table.remove(spawnedVehicles, 1)
end
end
function WaitForVehicleToLoad(modelHash)
modelHash = (type(modelHash) == 'number' and modelHash or GetHashKey(modelHash))
if not HasModelLoaded(modelHash) then
RequestModel(modelHash)
BeginTextCommandBusyString('STRING')
AddTextComponentSubstringPlayerName(_U('vehicleshop_awaiting_model'))
EndTextCommandBusyString(4)
while not HasModelLoaded(modelHash) do
Citizen.Wait(0)
DisableAllControlActions(0)
end
RemoveLoadingPrompt()
end
end
function OpenPoliceActionsMenu()
ESX.UI.Menu.CloseAll()
ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'police_actions', {
title = 'Police',
align = 'top-left',
elements = {
{label = _U('citizen_interaction'), value = 'citizen_interaction'},
{label = _U('vehicle_interaction'), value = 'vehicle_interaction'},
{label = _U('object_spawner'), value = 'object_spawner'}
}}, function(data, menu)
if data.current.value == 'citizen_interaction' then
local elements = {
{label = _U('id_card'), value = 'identity_card'},
{label = _U('search'), value = 'search'},
{label = _U('handcuff'), value = 'handcuff'},
{label = _U('drag'), value = 'drag'},
{label = _U('put_in_vehicle'), value = 'put_in_vehicle'},
{label = _U('out_the_vehicle'), value = 'out_the_vehicle'},
{label = _U('fine'), value = 'fine'},
{label = _U('unpaid_bills'), value = 'unpaid_bills'}
}
if Config.EnableLicenses then
table.insert(elements, { label = _U('license_check'), value = 'license' })
end
ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'citizen_interaction', {
title = _U('citizen_interaction'),
align = 'top-left',
elements = elements
}, function(data2, menu2)
local closestPlayer, closestDistance = ESX.Game.GetClosestPlayer()
if closestPlayer ~= -1 and closestDistance <= 3.0 then
local action = data2.current.value
if action == 'identity_card' then
OpenIdentityCardMenu(closestPlayer)
elseif action == 'search' then
OpenBodySearchMenu(closestPlayer)
elseif action == 'handcuff' then
TriggerServerEvent('esx_policejob:handcuff', GetPlayerServerId(closestPlayer))
elseif action == 'drag' then
TriggerServerEvent('esx_policejob:drag', GetPlayerServerId(closestPlayer))
elseif action == 'put_in_vehicle' then
TriggerServerEvent('esx_policejob:putInVehicle', GetPlayerServerId(closestPlayer))
elseif action == 'out_the_vehicle' then
TriggerServerEvent('esx_policejob:OutVehicle', GetPlayerServerId(closestPlayer))
elseif action == 'fine' then
OpenFineMenu(closestPlayer)
elseif action == 'license' then
ShowPlayerLicense(closestPlayer)
elseif action == 'unpaid_bills' then
OpenUnpaidBillsMenu(closestPlayer)
end
else
ESX.ShowNotification(_U('no_players_nearby'))
end
end, function(data2, menu2)
menu2.close()
end)
elseif data.current.value == 'vehicle_interaction' then
local elements = {}
local playerPed = PlayerPedId()
local vehicle = ESX.Game.GetVehicleInDirection()
if DoesEntityExist(vehicle) then
table.insert(elements, {label = _U('vehicle_info'), value = 'vehicle_infos'})
table.insert(elements, {label = _U('pick_lock'), value = 'hijack_vehicle'})
table.insert(elements, {label = _U('impound'), value = 'impound'})
end
table.insert(elements, {label = _U('search_database'), value = 'search_database'})
ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'vehicle_interaction', {
title = _U('vehicle_interaction'),
align = 'top-left',
elements = elements
}, function(data2, menu2)
local coords = GetEntityCoords(playerPed)
vehicle = ESX.Game.GetVehicleInDirection()
action = data2.current.value
if action == 'search_database' then
LookupVehicle()
elseif DoesEntityExist(vehicle) then
if action == 'vehicle_infos' then
local vehicleData = ESX.Game.GetVehicleProperties(vehicle)
OpenVehicleInfosMenu(vehicleData)
elseif action == 'hijack_vehicle' then
if IsAnyVehicleNearPoint(coords.x, coords.y, coords.z, 3.0) then
TaskStartScenarioInPlace(playerPed, 'WORLD_HUMAN_WELDING', 0, true)
Citizen.Wait(20000)
ClearPedTasksImmediately(playerPed)
SetVehicleDoorsLocked(vehicle, 1)
SetVehicleDoorsLockedForAllPlayers(vehicle, false)
ESX.ShowNotification(_U('vehicle_unlocked'))
end
elseif action == 'impound' then
-- is the script busy?
if currentTask.busy then
return
end
ESX.ShowHelpNotification(_U('impound_prompt'))
TaskStartScenarioInPlace(playerPed, 'CODE_HUMAN_MEDIC_TEND_TO_DEAD', 0, true)
currentTask.busy = true
currentTask.task = ESX.SetTimeout(10000, function()
ClearPedTasks(playerPed)
ImpoundVehicle(vehicle)
Citizen.Wait(100) -- sleep the entire script to let stuff sink back to reality
end)
-- keep track of that vehicle!
Citizen.CreateThread(function()
while currentTask.busy do
Citizen.Wait(1000)
vehicle = GetClosestVehicle(coords.x, coords.y, coords.z, 3.0, 0, 71)
if not DoesEntityExist(vehicle) and currentTask.busy then
ESX.ShowNotification(_U('impound_canceled_moved'))
ESX.ClearTimeout(currentTask.task)
ClearPedTasks(playerPed)
currentTask.busy = false
break
end
end
end)
end
else
ESX.ShowNotification(_U('no_vehicles_nearby'))
end
end, function(data2, menu2)
menu2.close()
end)
elseif data.current.value == 'object_spawner' then
ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'citizen_interaction', {
title = _U('traffic_interaction'),
align = 'top-left',
elements = {
{label = _U('cone'), model = 'prop_roadcone02a'},
{label = _U('barrier'), model = 'prop_barrier_work05'},
{label = _U('spikestrips'), model = 'p_ld_stinger_s'},
{label = _U('box'), model = 'prop_boxpile_07d'},
{label = _U('cash'), model = 'hei_prop_cash_crate_half_full'}
}}, function(data2, menu2)
local playerPed = PlayerPedId()
local coords, forward = GetEntityCoords(playerPed), GetEntityForwardVector(playerPed)
local objectCoords = (coords + forward * 1.0)
ESX.Game.SpawnObject(data2.current.model, objectCoords, function(obj)
SetEntityHeading(obj, GetEntityHeading(playerPed))
PlaceObjectOnGroundProperly(obj)
end)
end, function(data2, menu2)
menu2.close()
end)
end
end, function(data, menu)
menu.close()
end)
end
function OpenIdentityCardMenu(player)
ESX.TriggerServerCallback('esx_policejob:getOtherPlayerData', function(data)
local elements = {
{label = _U('name', data.name)},
{label = _U('job', ('%s - %s'):format(data.job.label, data.job.grade_label))}
}
if Config.EnableESXIdentity then
table.insert(elements, {label = _U('sex', _U(data.sex))})
table.insert(elements, {label = _U('dob', data.dob)})
table.insert(elements, {label = _U('height', data.height)})
end
if data.drunk then
table.insert(elements, {label = _U('bac', data.drunk)})
end
if data.licenses then
table.insert(elements, {label = _U('license_label')})
for i=1, #data.licenses, 1 do
table.insert(elements, {label = data.licenses[i].label})
end
end
ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'citizen_interaction', {
title = _U('citizen_interaction'),
align = 'top-left',
elements = elements
}, nil, function(data, menu)
menu.close()
end)
end, GetPlayerServerId(player))
end
function OpenBodySearchMenu(player)
ESX.TriggerServerCallback('esx_policejob:getOtherPlayerData', function(data)
local elements = {}
for i=1, #data.accounts, 1 do
if data.accounts[i].name == 'black_money' and data.accounts[i].money > 0 then
table.insert(elements, {
label = _U('confiscate_dirty', ESX.Math.Round(data.accounts[i].money)),
value = 'black_money',
itemType = 'item_account',
amount = data.accounts[i].money
})
break
end
end
table.insert(elements, {label = _U('guns_label')})
for i=1, #data.weapons, 1 do
table.insert(elements, {
label = _U('confiscate_weapon', ESX.GetWeaponLabel(data.weapons[i].name), data.weapons[i].ammo),
value = data.weapons[i].name,
itemType = 'item_weapon',
amount = data.weapons[i].ammo
})
end
table.insert(elements, {label = _U('inventory_label')})
for i=1, #data.inventory, 1 do
if data.inventory[i].count > 0 then
table.insert(elements, {
label = _U('confiscate_inv', data.inventory[i].count, data.inventory[i].label),
value = data.inventory[i].name,
itemType = 'item_standard',
amount = data.inventory[i].count
})
end
end
ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'body_search', {
title = _U('search'),
align = 'top-left',
elements = elements
}, function(data, menu)
if data.current.value then
TriggerServerEvent('esx_policejob:confiscatePlayerItem', GetPlayerServerId(player), data.current.itemType, data.current.value, data.current.amount)
OpenBodySearchMenu(player)
end
end, function(data, menu)
menu.close()
end)
end, GetPlayerServerId(player))
end
function OpenFineMenu(player)
ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'fine', {
title = _U('fine'),
align = 'top-left',
elements = {
{label = _U('traffic_offense'), value = 0},
{label = _U('minor_offense'), value = 1},
{label = _U('average_offense'), value = 2},
{label = _U('major_offense'), value = 3}
}}, function(data, menu)
OpenFineCategoryMenu(player, data.current.value)
end, function(data, menu)
menu.close()
end)
end
function OpenFineCategoryMenu(player, category)
ESX.TriggerServerCallback('esx_policejob:getFineList', function(fines)
local elements = {}
for k,fine in ipairs(fines) do
table.insert(elements, {
label = ('%s %s'):format(fine.label, _U('armory_item', ESX.Math.GroupDigits(fine.amount))),
value = fine.id,
amount = fine.amount,
fineLabel = fine.label
})
end
ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'fine_category', {
title = _U('fine'),
align = 'top-left',
elements = elements
}, function(data, menu)
menu.close()
if Config.EnablePlayerManagement then
TriggerServerEvent('esx_billing:sendBill', GetPlayerServerId(player), 'society_police', _U('fine_total', data.current.fineLabel), data.current.amount)
else
TriggerServerEvent('esx_billing:sendBill', GetPlayerServerId(player), '', _U('fine_total', data.current.fineLabel), data.current.amount)
end
ESX.SetTimeout(300, function()
OpenFineCategoryMenu(player, category)
end)
end, function(data, menu)
menu.close()
end)
end, category)
end
function LookupVehicle()
ESX.UI.Menu.Open('dialog', GetCurrentResourceName(), 'lookup_vehicle', {
title = _U('search_database_title'),
}, function(data, menu)
local length = string.len(data.value)
if data.value == nil or length < 2 or length > 13 then
ESX.ShowNotification(_U('search_database_error_invalid'))
else
ESX.TriggerServerCallback('esx_policejob:getVehicleFromPlate', function(owner, found)
if found then
ESX.ShowNotification(_U('search_database_found', owner))
else
ESX.ShowNotification(_U('search_database_error_not_found'))
end
end, data.value)
menu.close()
end
end, function(data, menu)
menu.close()
end)
end
function ShowPlayerLicense(player)
local elements = {}
ESX.TriggerServerCallback('esx_policejob:getOtherPlayerData', function(playerData)
if playerData.licenses then
for i=1, #playerData.licenses, 1 do
if playerData.licenses[i].label and playerData.licenses[i].type then
table.insert(elements, {
label = playerData.licenses[i].label,
type = playerData.licenses[i].type
})
end
end
end
ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'manage_license', {
title = _U('license_revoke'),
align = 'top-left',
elements = elements,
}, function(data, menu)
ESX.ShowNotification(_U('licence_you_revoked', data.current.label, playerData.name))
TriggerServerEvent('esx_policejob:message', GetPlayerServerId(player), _U('license_revoked', data.current.label))
TriggerServerEvent('esx_license:removeLicense', GetPlayerServerId(player), data.current.type)
ESX.SetTimeout(300, function()
ShowPlayerLicense(player)
end)
end, function(data, menu)
menu.close()
end)
end, GetPlayerServerId(player))
end
function OpenUnpaidBillsMenu(player)
local elements = {}
ESX.TriggerServerCallback('esx_billing:getTargetBills', function(bills)
for k,bill in ipairs(bills) do
table.insert(elements, {
label = ('%s - %s'):format(bill.label, _U('armory_item', ESX.Math.GroupDigits(bill.amount))),
billId = bill.id
})
end
ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'billing', {
title = _U('unpaid_bills'),
align = 'top-left',
elements = elements
}, nil, function(data, menu)
menu.close()
end)
end, GetPlayerServerId(player))
end
function OpenVehicleInfosMenu(vehicleData)
ESX.TriggerServerCallback('esx_policejob:getVehicleInfos', function(retrivedInfo)
local elements = {{label = _U('plate', retrivedInfo.plate)}}
if retrivedInfo.owner == nil then
table.insert(elements, {label = _U('owner_unknown')})
else
table.insert(elements, {label = _U('owner', retrivedInfo.owner)})
end
ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'vehicle_infos', {
title = _U('vehicle_info'),
align = 'top-left',
elements = elements
}, nil, function(data, menu)
menu.close()
end)
end, vehicleData.plate)
end
function OpenGetWeaponMenu()
ESX.TriggerServerCallback('esx_policejob:getArmoryWeapons', function(weapons)
local elements = {}
for i=1, #weapons, 1 do
if weapons[i].count > 0 then
table.insert(elements, {
label = 'x' .. weapons[i].count .. ' ' .. ESX.GetWeaponLabel(weapons[i].name),
value = weapons[i].name
})
end
end
ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'armory_get_weapon', {
title = _U('get_weapon_menu'),
align = 'top-left',
elements = elements
}, function(data, menu)
menu.close()
ESX.TriggerServerCallback('esx_policejob:removeArmoryWeapon', function()
OpenGetWeaponMenu()
end, data.current.value)
end, function(data, menu)
menu.close()
end)
end)
end
function OpenPutWeaponMenu()
local elements = {}
local playerPed = PlayerPedId()
local weaponList = ESX.GetWeaponList()
for i=1, #weaponList, 1 do
local weaponHash = GetHashKey(weaponList[i].name)
if HasPedGotWeapon(playerPed, weaponHash, false) and weaponList[i].name ~= 'WEAPON_UNARMED' then
table.insert(elements, {
label = weaponList[i].label,
value = weaponList[i].name
})
end
end
ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'armory_put_weapon', {
title = _U('put_weapon_menu'),
align = 'top-left',
elements = elements
}, function(data, menu)
menu.close()
ESX.TriggerServerCallback('esx_policejob:addArmoryWeapon', function()
OpenPutWeaponMenu()
end, data.current.value, true)
end, function(data, menu)
menu.close()
end)
end
function OpenBuyWeaponsMenu()
local elements = {}
local playerPed = PlayerPedId()
PlayerData = ESX.GetPlayerData()
for k,v in ipairs(Config.AuthorizedWeapons[PlayerData.job.grade_name]) do
local weaponNum, weapon = ESX.GetWeapon(v.weapon)
local components, label = {}
local hasWeapon = HasPedGotWeapon(playerPed, GetHashKey(v.weapon), false)
if v.components then
for i=1, #v.components do
if v.components[i] then
local component = weapon.components[i]
local hasComponent = HasPedGotWeaponComponent(playerPed, GetHashKey(v.weapon), component.hash)
if hasComponent then
label = ('%s: %s'):format(component.label, _U('armory_owned'))
else
if v.components[i] > 0 then
label = ('%s: %s'):format(component.label, _U('armory_item', ESX.Math.GroupDigits(v.components[i])))
else
label = ('%s: %s'):format(component.label, _U('armory_free'))
end
end
table.insert(components, {
label = label,
componentLabel = component.label,
hash = component.hash,
name = component.name,
price = v.components[i],
hasComponent = hasComponent,
componentNum = i
})
end
end
end
if hasWeapon and v.components then
label = ('%s: >'):format(weapon.label)
elseif hasWeapon and not v.components then
label = ('%s: %s'):format(weapon.label, _U('armory_owned'))
else
if v.price > 0 then
label = ('%s: %s'):format(weapon.label, _U('armory_item', ESX.Math.GroupDigits(v.price)))
else
label = ('%s: %s'):format(weapon.label, _U('armory_free'))
end
end
table.insert(elements, {
label = label,
weaponLabel = weapon.label,
name = weapon.name,
components = components,
price = v.price,
hasWeapon = hasWeapon
})
end
ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'armory_buy_weapons', {
title = _U('armory_weapontitle'),
align = 'top-left',
elements = elements
}, function(data, menu)
if data.current.hasWeapon then
if #data.current.components > 0 then
OpenWeaponComponentShop(data.current.components, data.current.name, menu)
end
else
ESX.TriggerServerCallback('esx_policejob:buyWeapon', function(bought)
if bought then
if data.current.price > 0 then
ESX.ShowNotification(_U('armory_bought', data.current.weaponLabel, ESX.Math.GroupDigits(data.current.price)))
end
menu.close()
OpenBuyWeaponsMenu()
else
ESX.ShowNotification(_U('armory_money'))
end
end, data.current.name, 1)
end
end, function(data, menu)
menu.close()
end)
end
function OpenWeaponComponentShop(components, weaponName, parentShop)
ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'armory_buy_weapons_components', {
title = _U('armory_componenttitle'),
align = 'top-left',
elements = components
}, function(data, menu)
if data.current.hasComponent then
ESX.ShowNotification(_U('armory_hascomponent'))
else
ESX.TriggerServerCallback('esx_policejob:buyWeapon', function(bought)
if bought then
if data.current.price > 0 then
ESX.ShowNotification(_U('armory_bought', data.current.componentLabel, ESX.Math.GroupDigits(data.current.price)))
end
menu.close()
parentShop.close()
OpenBuyWeaponsMenu()
else
ESX.ShowNotification(_U('armory_money'))
end
end, weaponName, 2, data.current.componentNum)
end
end, function(data, menu)
menu.close()
end)
end
function OpenGetStocksMenu()
ESX.TriggerServerCallback('esx_policejob:getStockItems', function(items)
local elements = {}
for i=1, #items, 1 do
table.insert(elements, {
label = 'x' .. items[i].count .. ' ' .. items[i].label,
value = items[i].name
})
end
ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'stocks_menu', {
title = _U('police_stock'),
align = 'top-left',
elements = elements
}, function(data, menu)
local itemName = data.current.value
ESX.UI.Menu.Open('dialog', GetCurrentResourceName(), 'stocks_menu_get_item_count', {
title = _U('quantity')
}, function(data2, menu2)
local count = tonumber(data2.value)
if count == nil then
ESX.ShowNotification(_U('quantity_invalid'))
else
menu2.close()
menu.close()
TriggerServerEvent('esx_policejob:getStockItem', itemName, count)
Citizen.Wait(300)
OpenGetStocksMenu()
end
end, function(data2, menu2)
menu2.close()
end)
end, function(data, menu)
menu.close()
end)
end)
end
function OpenPutStocksMenu()
ESX.TriggerServerCallback('esx_policejob:getPlayerInventory', function(inventory)
local elements = {}
for i=1, #inventory.items, 1 do
local item = inventory.items[i]
if item.count > 0 then
table.insert(elements, {
label = item.label .. ' x' .. item.count,
type = 'item_standard',
value = item.name
})
end
end
ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'stocks_menu', {
title = _U('inventory'),
align = 'top-left',
elements = elements
}, function(data, menu)
local itemName = data.current.value
ESX.UI.Menu.Open('dialog', GetCurrentResourceName(), 'stocks_menu_put_item_count', {
title = _U('quantity')
}, function(data2, menu2)
local count = tonumber(data2.value)
if count == nil then
ESX.ShowNotification(_U('quantity_invalid'))
else
menu2.close()
menu.close()
TriggerServerEvent('esx_policejob:putStockItems', itemName, count)
Citizen.Wait(300)
OpenPutStocksMenu()
end
end, function(data2, menu2)
menu2.close()
end)
end, function(data, menu)
menu.close()
end)
end)
end
RegisterNetEvent('esx:setJob')
AddEventHandler('esx:setJob', function(job)
PlayerData.job = job
Citizen.Wait(5000)
TriggerServerEvent('esx_policejob:forceBlip')
end)
RegisterNetEvent('esx_phone:loaded')
AddEventHandler('esx_phone:loaded', function(phoneNumber, contacts)
local specialContact = {
name = _U('phone_police'),
number = 'police',
base64Icon = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NDFGQTJDRkI0QUJCMTFFN0JBNkQ5OENBMUI4QUEzM0YiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NDFGQTJDRkM0QUJCMTFFN0JBNkQ5OENBMUI4QUEzM0YiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo0MUZBMkNGOTRBQkIxMUU3QkE2RDk4Q0ExQjhBQTMzRiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo0MUZBMkNGQTRBQkIxMUU3QkE2RDk4Q0ExQjhBQTMzRiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PoW66EYAAAjGSURBVHjapJcLcFTV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'
}
TriggerEvent('esx_phone:addSpecialContact', specialContact.name, specialContact.number, specialContact.base64Icon)
end)
-- don't show dispatches if the player isn't in service
AddEventHandler('esx_phone:cancelMessage', function(dispatchNumber)
if PlayerData.job and PlayerData.job.name == 'police' and PlayerData.job.name == dispatchNumber then
-- if esx_service is enabled
if Config.MaxInService ~= -1 and not playerInService then
CancelEvent()
end
end
end)
AddEventHandler('esx_policejob:hasEnteredMarker', function(station, part, partNum)
if part == 'Cloakroom' then
CurrentAction = 'menu_cloakroom'
CurrentActionMsg = _U('open_cloackroom')
CurrentActionData = {}
elseif part == 'Armory' then
CurrentAction = 'menu_armory'
CurrentActionMsg = _U('open_armory')
CurrentActionData = {station = station}
elseif part == 'Vehicles' then
CurrentAction = 'menu_vehicle_spawner'
CurrentActionMsg = _U('garage_prompt')
CurrentActionData = {station = station, part = part, partNum = partNum}
elseif part == 'Helicopters' then
CurrentAction = 'Helicopters'
CurrentActionMsg = _U('helicopter_prompt')
CurrentActionData = {station = station, part = part, partNum = partNum}
elseif part == 'BossActions' then
CurrentAction = 'menu_boss_actions'
CurrentActionMsg = _U('open_bossmenu')
CurrentActionData = {}
end
end)
AddEventHandler('esx_policejob:hasExitedMarker', function(station, part, partNum)
if not isInShopMenu then
ESX.UI.Menu.CloseAll()
end
CurrentAction = nil
end)
AddEventHandler('esx_policejob:hasEnteredEntityZone', function(entity)
local playerPed = PlayerPedId()
if PlayerData.job and PlayerData.job.name == 'police' and IsPedOnFoot(playerPed) then
CurrentAction = 'remove_entity'
CurrentActionMsg = _U('remove_prop')
CurrentActionData = {entity = entity}
end
if GetEntityModel(entity) == GetHashKey('p_ld_stinger_s') then
local playerPed = PlayerPedId()
local coords = GetEntityCoords(playerPed)
if IsPedInAnyVehicle(playerPed, false) then
local vehicle = GetVehiclePedIsIn(playerPed)
for i=0, 7, 1 do
SetVehicleTyreBurst(vehicle, i, true, 1000)
end
end
end
end)
AddEventHandler('esx_policejob:hasExitedEntityZone', function(entity)
if CurrentAction == 'remove_entity' then
CurrentAction = nil
end
end)
RegisterNetEvent('esx_policejob:handcuff')
AddEventHandler('esx_policejob:handcuff', function()
isHandcuffed = not isHandcuffed
local playerPed = PlayerPedId()
Citizen.CreateThread(function()
if isHandcuffed then
RequestAnimDict('mp_arresting')
while not HasAnimDictLoaded('mp_arresting') do
Citizen.Wait(100)
end
TaskPlayAnim(playerPed, 'mp_arresting', 'idle', 8.0, -8, -1, 49, 0, 0, 0, 0)
SetEnableHandcuffs(playerPed, true)
DisablePlayerFiring(playerPed, true)
SetCurrentPedWeapon(playerPed, GetHashKey('WEAPON_UNARMED'), true) -- unarm player
SetPedCanPlayGestureAnims(playerPed, false)
FreezeEntityPosition(playerPed, true)
DisplayRadar(false)
if Config.EnableHandcuffTimer then
if handcuffTimer.active then
ESX.ClearTimeout(handcuffTimer.task)
end
StartHandcuffTimer()
end
else
if Config.EnableHandcuffTimer and handcuffTimer.active then
ESX.ClearTimeout(handcuffTimer.task)
end
ClearPedSecondaryTask(playerPed)
SetEnableHandcuffs(playerPed, false)
DisablePlayerFiring(playerPed, false)
SetPedCanPlayGestureAnims(playerPed, true)
FreezeEntityPosition(playerPed, false)
DisplayRadar(true)
end
end)
end)
RegisterNetEvent('esx_policejob:unrestrain')
AddEventHandler('esx_policejob:unrestrain', function()
if isHandcuffed then
local playerPed = PlayerPedId()
isHandcuffed = false
ClearPedSecondaryTask(playerPed)
SetEnableHandcuffs(playerPed, false)
DisablePlayerFiring(playerPed, false)
SetPedCanPlayGestureAnims(playerPed, true)
FreezeEntityPosition(playerPed, false)
DisplayRadar(true)
-- end timer
if Config.EnableHandcuffTimer and handcuffTimer.active then
ESX.ClearTimeout(handcuffTimer.task)
end
end
end)
RegisterNetEvent('esx_policejob:drag')
AddEventHandler('esx_policejob:drag', function(copId)
if not isHandcuffed then
return
end
dragStatus.isDragged = not dragStatus.isDragged
dragStatus.CopId = copId
end)
Citizen.CreateThread(function()
local playerPed
local targetPed
while true do
Citizen.Wait(1)
if isHandcuffed then
playerPed = PlayerPedId()
if dragStatus.isDragged then
targetPed = GetPlayerPed(GetPlayerFromServerId(dragStatus.CopId))
-- undrag if target is in an vehicle
if not IsPedSittingInAnyVehicle(targetPed) then
AttachEntityToEntity(playerPed, targetPed, 11816, 0.54, 0.54, 0.0, 0.0, 0.0, 0.0, false, false, false, false, 2, true)
else
dragStatus.isDragged = false
DetachEntity(playerPed, true, false)
end
if IsPedDeadOrDying(targetPed, true) then
dragStatus.isDragged = false
DetachEntity(playerPed, true, false)
end
else
DetachEntity(playerPed, true, false)
end
else
Citizen.Wait(500)
end
end
end)
RegisterNetEvent('esx_policejob:putInVehicle')
AddEventHandler('esx_policejob:putInVehicle', function()
local playerPed = PlayerPedId()
local coords = GetEntityCoords(playerPed)
if not isHandcuffed then
return
end
if IsAnyVehicleNearPoint(coords, 5.0) then
local vehicle = GetClosestVehicle(coords, 5.0, 0, 71)
if DoesEntityExist(vehicle) then
local maxSeats, freeSeat = GetVehicleMaxNumberOfPassengers(vehicle)
for i=maxSeats - 1, 0, -1 do
if IsVehicleSeatFree(vehicle, i) then
freeSeat = i
break
end
end
if freeSeat then
TaskWarpPedIntoVehicle(playerPed, vehicle, freeSeat)
dragStatus.isDragged = false
end
end
end
end)
RegisterNetEvent('esx_policejob:OutVehicle')
AddEventHandler('esx_policejob:OutVehicle', function()
local playerPed = PlayerPedId()
if not IsPedSittingInAnyVehicle(playerPed) then
return
end
local vehicle = GetVehiclePedIsIn(playerPed, false)
TaskLeaveVehicle(playerPed, vehicle, 16)
end)
-- Handcuff
Citizen.CreateThread(function()
while true do
Citizen.Wait(0)
local playerPed = PlayerPedId()
if isHandcuffed then
DisableControlAction(0, 1, true) -- Disable pan
DisableControlAction(0, 2, true) -- Disable tilt
DisableControlAction(0, 24, true) -- Attack
DisableControlAction(0, 257, true) -- Attack 2
DisableControlAction(0, 25, true) -- Aim
DisableControlAction(0, 263, true) -- Melee Attack 1
DisableControlAction(0, 32, true) -- W
DisableControlAction(0, 34, true) -- A
DisableControlAction(0, 31, true) -- S
DisableControlAction(0, 30, true) -- D
DisableControlAction(0, 45, true) -- Reload
DisableControlAction(0, 22, true) -- Jump
DisableControlAction(0, 44, true) -- Cover
DisableControlAction(0, 37, true) -- Select Weapon
DisableControlAction(0, 23, true) -- Also 'enter'?
DisableControlAction(0, 288, true) -- Disable phone
DisableControlAction(0, 289, true) -- Inventory
DisableControlAction(0, 170, true) -- Animations
DisableControlAction(0, 167, true) -- Job
DisableControlAction(0, 0, true) -- Disable changing view
DisableControlAction(0, 26, true) -- Disable looking behind
DisableControlAction(0, 73, true) -- Disable clearing animation
DisableControlAction(2, 199, true) -- Disable pause screen
DisableControlAction(0, 59, true) -- Disable steering in vehicle
DisableControlAction(0, 71, true) -- Disable driving forward in vehicle
DisableControlAction(0, 72, true) -- Disable reversing in vehicle
DisableControlAction(2, 36, true) -- Disable going stealth
DisableControlAction(0, 47, true) -- Disable weapon
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
DisableControlAction(0, 75, true) -- Disable exit vehicle
DisableControlAction(27, 75, true) -- Disable exit vehicle
if IsEntityPlayingAnim(playerPed, 'mp_arresting', 'idle', 3) ~= 1 then
ESX.Streaming.RequestAnimDict('mp_arresting', function()
TaskPlayAnim(playerPed, 'mp_arresting', 'idle', 8.0, -8, -1, 49, 0.0, false, false, false)
end)
end
else
Citizen.Wait(500)
end
end
end)
-- Create blips
Citizen.CreateThread(function()
for k,v in pairs(Config.PoliceStations) do
local blip = AddBlipForCoord(v.Blip.Coords)
SetBlipSprite (blip, v.Blip.Sprite)
SetBlipDisplay(blip, v.Blip.Display)
SetBlipScale (blip, v.Blip.Scale)
SetBlipColour (blip, v.Blip.Colour)
SetBlipAsShortRange(blip, true)
BeginTextCommandSetBlipName('STRING')
AddTextComponentString(_U('map_blip'))
EndTextCommandSetBlipName(blip)
end
end)
-- Display markers
Citizen.CreateThread(function()
while true do
Citizen.Wait(0)
if PlayerData.job and PlayerData.job.name == 'police' then
local playerPed = PlayerPedId()
local coords = GetEntityCoords(playerPed)
local isInMarker, hasExited, letSleep = false, false, true
local currentStation, currentPart, currentPartNum
for k,v in pairs(Config.PoliceStations) do
for i=1, #v.Cloakrooms, 1 do
local distance = GetDistanceBetweenCoords(coords, v.Cloakrooms[i], true)
if distance < Config.DrawDistance then
DrawMarker(20, v.Cloakrooms[i], 0.0, 0.0, 0.0, 0, 0.0, 0.0, 1.0, 1.0, 1.0, Config.MarkerColor.r, Config.MarkerColor.g, Config.MarkerColor.b, 100, false, true, 2, true, false, false, false)
letSleep = false
end
if distance < Config.MarkerSize.x then
isInMarker, currentStation, currentPart, currentPartNum = true, k, 'Cloakroom', i
end
end
for i=1, #v.Armories, 1 do
local distance = GetDistanceBetweenCoords(coords, v.Armories[i], true)
if distance < Config.DrawDistance then
DrawMarker(21, v.Armories[i], 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.5, 0.5, 0.5, Config.MarkerColor.r, Config.MarkerColor.g, Config.MarkerColor.b, 100, false, true, 2, true, false, false, false)
letSleep = false
end
if distance < Config.MarkerSize.x then
isInMarker, currentStation, currentPart, currentPartNum = true, k, 'Armory', i
end
end
for i=1, #v.Vehicles, 1 do
local distance = GetDistanceBetweenCoords(coords, v.Vehicles[i].Spawner, true)
if distance < Config.DrawDistance then
DrawMarker(36, v.Vehicles[i].Spawner, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, Config.MarkerColor.r, Config.MarkerColor.g, Config.MarkerColor.b, 100, false, true, 2, true, false, false, false)
letSleep = false
end
if distance < Config.MarkerSize.x then
isInMarker, currentStation, currentPart, currentPartNum = true, k, 'Vehicles', i
end
end
for i=1, #v.Helicopters, 1 do
local distance = GetDistanceBetweenCoords(coords, v.Helicopters[i].Spawner, true)
if distance < Config.DrawDistance then
DrawMarker(34, v.Helicopters[i].Spawner, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, Config.MarkerColor.r, Config.MarkerColor.g, Config.MarkerColor.b, 100, false, true, 2, true, false, false, false)
letSleep = false
end
if distance < Config.MarkerSize.x then
isInMarker, currentStation, currentPart, currentPartNum = true, k, 'Helicopters', i
end
end
if Config.EnablePlayerManagement and PlayerData.job.grade_name == 'boss' then
for i=1, #v.BossActions, 1 do
local distance = GetDistanceBetweenCoords(coords, v.BossActions[i], true)
if distance < Config.DrawDistance then
DrawMarker(22, v.BossActions[i], 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, Config.MarkerColor.r, Config.MarkerColor.g, Config.MarkerColor.b, 100, false, true, 2, true, false, false, false)
letSleep = false
end
if distance < Config.MarkerSize.x then
isInMarker, currentStation, currentPart, currentPartNum = true, k, 'BossActions', i
end
end
end
end
if isInMarker and not HasAlreadyEnteredMarker or (isInMarker and (LastStation ~= currentStation or LastPart ~= currentPart or LastPartNum ~= currentPartNum)) then
if
(LastStation and LastPart and LastPartNum) and
(LastStation ~= currentStation or LastPart ~= currentPart or LastPartNum ~= currentPartNum)
then
TriggerEvent('esx_policejob:hasExitedMarker', LastStation, LastPart, LastPartNum)
hasExited = true
end
HasAlreadyEnteredMarker = true
LastStation = currentStation
LastPart = currentPart
LastPartNum = currentPartNum
TriggerEvent('esx_policejob:hasEnteredMarker', currentStation, currentPart, currentPartNum)
end
if not hasExited and not isInMarker and HasAlreadyEnteredMarker then
HasAlreadyEnteredMarker = false
TriggerEvent('esx_policejob:hasExitedMarker', LastStation, LastPart, LastPartNum)
end
if letSleep then
Citizen.Wait(500)
end
else
Citizen.Wait(500)
end
end
end)
-- Enter / Exit entity zone events
Citizen.CreateThread(function()
local trackedEntities = {
'prop_roadcone02a',
'prop_barrier_work05',
'p_ld_stinger_s',
'prop_boxpile_07d',
'hei_prop_cash_crate_half_full'
}
while true do
Citizen.Wait(500)
local playerPed = PlayerPedId()
local coords = GetEntityCoords(playerPed)
local closestDistance = -1
local closestEntity = nil
for i=1, #trackedEntities, 1 do
local object = GetClosestObjectOfType(coords, 3.0, GetHashKey(trackedEntities[i]), false, false, false)
if DoesEntityExist(object) then
local objCoords = GetEntityCoords(object)
local distance = GetDistanceBetweenCoords(coords, objCoords, true)
if closestDistance == -1 or closestDistance > distance then
closestDistance = distance
closestEntity = object
end
end
end
if closestDistance ~= -1 and closestDistance <= 3.0 then
if LastEntity ~= closestEntity then
TriggerEvent('esx_policejob:hasEnteredEntityZone', closestEntity)
LastEntity = closestEntity
end
else
if LastEntity then
TriggerEvent('esx_policejob:hasExitedEntityZone', LastEntity)
LastEntity = nil
end
end
end
end)
-- Key Controls
Citizen.CreateThread(function()
while true do
Citizen.Wait(0)
if CurrentAction then
ESX.ShowHelpNotification(CurrentActionMsg)
if IsControlJustReleased(0, 38) and PlayerData.job and PlayerData.job.name == 'police' then
if CurrentAction == 'menu_cloakroom' then
OpenCloakroomMenu()
elseif CurrentAction == 'menu_armory' then
if Config.MaxInService == -1 then
OpenArmoryMenu(CurrentActionData.station)
elseif playerInService then
OpenArmoryMenu(CurrentActionData.station)
else
ESX.ShowNotification(_U('service_not'))
end
elseif CurrentAction == 'menu_vehicle_spawner' then
if Config.MaxInService == -1 then
OpenVehicleSpawnerMenu('car', CurrentActionData.station, CurrentActionData.part, CurrentActionData.partNum)
elseif playerInService then
OpenVehicleSpawnerMenu('car', CurrentActionData.station, CurrentActionData.part, CurrentActionData.partNum)
else
ESX.ShowNotification(_U('service_not'))
end
elseif CurrentAction == 'Helicopters' then
if Config.MaxInService == -1 then
OpenVehicleSpawnerMenu('helicopter', CurrentActionData.station, CurrentActionData.part, CurrentActionData.partNum)
elseif playerInService then
OpenVehicleSpawnerMenu('helicopter', CurrentActionData.station, CurrentActionData.part, CurrentActionData.partNum)
else
ESX.ShowNotification(_U('service_not'))
end
elseif CurrentAction == 'delete_vehicle' then
ESX.Game.DeleteVehicle(CurrentActionData.vehicle)
elseif CurrentAction == 'menu_boss_actions' then
ESX.UI.Menu.CloseAll()
TriggerEvent('esx_society:openBossMenu', 'police', function(data, menu)
menu.close()
CurrentAction = 'menu_boss_actions'
CurrentActionMsg = _U('open_bossmenu')
CurrentActionData = {}
end, { wash = false }) -- disable washing money
elseif CurrentAction == 'remove_entity' then
DeleteEntity(CurrentActionData.entity)
end
CurrentAction = nil
end
end -- CurrentAction end
if IsControlJustReleased(0, 167) and not isDead and PlayerData.job and PlayerData.job.name == 'police' and not ESX.UI.Menu.IsOpen('default', GetCurrentResourceName(), 'police_actions') then
if Config.MaxInService == -1 then
OpenPoliceActionsMenu()
elseif playerInService then
OpenPoliceActionsMenu()
else
ESX.ShowNotification(_U('service_not'))
end
end
if IsControlJustReleased(0, 38) and currentTask.busy then
ESX.ShowNotification(_U('impound_canceled'))
ESX.ClearTimeout(currentTask.task)
ClearPedTasks(PlayerPedId())
currentTask.busy = false
end
end
end)
-- Create blip for colleagues
function createBlip(id)
local ped = GetPlayerPed(id)
local blip = GetBlipFromEntity(ped)
if not DoesBlipExist(blip) then -- Add blip and create head display on player
blip = AddBlipForEntity(ped)
SetBlipSprite(blip, 1)
ShowHeadingIndicatorOnBlip(blip, true) -- Player Blip indicator
SetBlipRotation(blip, math.ceil(GetEntityHeading(ped))) -- update rotation
SetBlipNameToPlayerName(blip, id) -- update blip name
SetBlipScale(blip, 0.85) -- set scale
SetBlipAsShortRange(blip, true)
table.insert(blipsCops, blip) -- add blip to array so we can remove it later
end
end
RegisterNetEvent('esx_policejob:updateBlip')
AddEventHandler('esx_policejob:updateBlip', function()
-- Refresh all blips
for k, existingBlip in pairs(blipsCops) do
RemoveBlip(existingBlip)
end
-- Clean the blip table
blipsCops = {}
-- Enable blip?
if Config.MaxInService ~= -1 and not playerInService then
return
end
if not Config.EnableJobBlip then
return
end
-- Is the player a cop? In that case show all the blips for other cops
if PlayerData.job and PlayerData.job.name == 'police' then
ESX.TriggerServerCallback('esx_society:getOnlinePlayers', function(players)
for i=1, #players, 1 do
if players[i].job.name == 'police' then
local id = GetPlayerFromServerId(players[i].source)
if NetworkIsPlayerActive(id) and GetPlayerPed(id) ~= PlayerPedId() then
createBlip(id)
end
end
end
end)
end
end)
AddEventHandler('playerSpawned', function(spawn)
isDead = false
TriggerEvent('esx_policejob:unrestrain')
if not hasAlreadyJoined then
TriggerServerEvent('esx_policejob:spawned')
end
hasAlreadyJoined = true
end)
AddEventHandler('esx:onPlayerDeath', function(data)
isDead = true
end)
AddEventHandler('onResourceStop', function(resource)
if resource == GetCurrentResourceName() then
TriggerEvent('esx_policejob:unrestrain')
TriggerEvent('esx_phone:removeSpecialContact', 'police')
if Config.MaxInService ~= -1 then
TriggerServerEvent('esx_service:disableService', 'police')
end
if Config.EnableHandcuffTimer and handcuffTimer.active then
ESX.ClearTimeout(handcuffTimer.task)
end
end
end)
-- handcuff timer, unrestrain the player after an certain amount of time
function StartHandcuffTimer()
if Config.EnableHandcuffTimer and handcuffTimer.active then
ESX.ClearTimeout(handcuffTimer.task)
end
handcuffTimer.active = true
handcuffTimer.task = ESX.SetTimeout(Config.HandcuffTimer, function()
ESX.ShowNotification(_U('unrestrained_timer'))
TriggerEvent('esx_policejob:unrestrain')
handcuffTimer.active = false
end)
end
-- TODO
-- - return to garage if owned
-- - message owner that his vehicle has been impounded
function ImpoundVehicle(vehicle)
--local vehicleName = GetLabelText(GetDisplayNameFromVehicleModel(GetEntityModel(vehicle)))
ESX.Game.DeleteVehicle(vehicle)
ESX.ShowNotification(_U('impound_successful'))
currentTask.busy = false
end