> For the complete documentation index, see [llms.txt](https://piotreq-scripts.gitbook.io/piotreq-scripts/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://piotreq-scripts.gitbook.io/piotreq-scripts/assets-and-guides/police-job/config-files.md).

# Config Files

<details>

<summary>Main Config</summary>

```lua
Config = {}

Config.Framework = 'ESX' -- ESX / QB / QBOX
Config.Language = 'en' -- pl / en
Config.Inventory = 'ox_inventory' -- ox_inventory / qb-inventory / ps-inventory / qs-inventory / tgiann-inventory / codem-inventory
Config.Target = 'ox_target' -- ox_target / qb-target
Config.Logs = false -- true / false
Config.Debug = false
Config.Commands = true -- set to false if you want dont want to use commands
Config.OxRadial = true -- enable ox radial menu? (you can edit this in bridge/client)
Config.PoliceMenu = false -- set to true if you want to use F6 OX LIB MENU
Config.PoliceMenuKey = 'F6' -- key to open police menu
Config.PoliceMDT = GetResourceState('piotreq_gpt') ~= 'missing' -- you using our police mdt?

lib.locale(Config.Language or 'en')

Config.SSN = 'id' -- database column for character unique id

Config.Jobs = {
    ['police'] = 0,
    ['sheriff'] = 0
}

Config.OutfitsAccess = { -- permissions for /police_outfit
    ['police'] = 0,
    ['sheriff'] = 0
}

Config.Stations = {
    ['MissionRow'] = {
        blips = {
            {
                sprite = 60, color = 29, scale = 0.95, display = 2,
                label = 'Mission Row LSPD', coords = vector3(437.6986, -982.1099, 30.6904)
            },
            {
                sprite = 72, color = 29, scale = 0.8, display = 2,
                label = 'Police Extras', coords = vector3(426.9231, -1023.2134, 28.8635),
                restricted = {['police'] = 0, ['sheriff'] = 0}
            },
        },
        bells = {
            {
                coords = vector3(445.73, -990.36, 30.75), radius = 0.75,
                jobs = {['police'] = true, ['sheriff'] = true}, -- which jobs will get alert
            }
        },
        trashes = {
            {
                coords = vector3(445.83, -1004.18, 30.5), radius = 0.75,
                allowedJobs = {['police'] = 0, ['sheriff'] = 0}, -- which jobs can access trashes
            }
        },
        bodycams = {
            {
                coords = vector3(460.18, -1005.04, 34.0), radius = 0.75,
                allowedJobs = {['police'] = 0, ['sheriff'] = 0}, -- which jobs can access bodycams
            }
        },
        toggleDuty = { -- coords for duty toggle [ONLY QB AND QBOX!!!!!!]
            {
                coords = vector3(446.19, -991.22, 30.5), radius = 0.75,
                allowedJobs = {['police'] = 0, ['sheriff'] = 0},
            }
        }
    }
}

Config.Shops = {
    ['Armory'] = {
        label = 'Police Armory',
        locations = {
            vector3(449.45, -1006.15, 31.0)
        },
        requiredDuty = false,
        radius = 0.75,
        allowedJobs = {['police'] = 0, ['sheriff'] = 0}, -- which jobs can access shop
        inventory = {
            {name = 'spike_strip', price = 0},
            {name = 'police_diving_suit', price = 0},
            {name = 'tracking_band', price = 0},
            {name = 'fingerprinter', price = 0},
            {name = 'stick_bag', price = 0},
            {name = 'stick', price = 0},
            {name = 'body_cam', price = 0},
            {name = 'gps', price = 0},
            {name = 'camera', price = 0},
            {name = 'radio', price = 0},
            {name = 'handcuffs', price = 0},
            {name = 'vest_normal', price = 10},
            {name = 'vest_strong', price = 100},
            {name = 'ammo-9', price = 5},
            {name = 'ammo-rifle', price = 5},
            {name = 'ammo-shotgun', price = 5},
            {name = 'WEAPON_FLASHLIGHT', price = 100},
            {name = 'WEAPON_NIGHTSTICK', price = 100, metadata = {registered = true, serial = 'POL'}},
            {name = 'WEAPON_COMBATPISTOL', price = 1000, license = 'weapon', grade = 1, metadata = {registered = true, serial = 'POL'}},
            {name = 'WEAPON_STUNGUN', price = 1000, metadata = {registered = true, serial = 'POL'}},
            {name = 'WEAPON_PUMPSHOTGUN', price = 10000, license = 'weapon', grade = 5, metadata = {registered = true, serial = 'POL'}},
            {name = 'WEAPON_CARBINERIFLE', price = 15000, license = 'weapon', grade = 10, metadata = {registered = true, serial = 'POL'}},
        },
    }
}

Config.Wardrobes = {
    ['MissionRow'] = {
        coords = vector3(464.6, -1008.23, 31.0),
        radius = 0.75,
        drawSprite = false,
    }
}

Config.Lockers = {
    ['MissionRow'] = {
        coords = vector3(468.25, -1009.97, 31.0),
        radius = 0.75,
        drawSprite = false,
        options = {
            {
                name = 'MissionRow_Locker', -- stash name and target name ;)
                label = locale('private_locker'),
                icon = 'fa-solid fa-box-open',
                distance = 2,
                groups = Config.Jobs,
                isLocker = true, -- set to false if not locker target
                lockerOwner = false, -- false = shared / true = private
                lockerLabel = locale('private_locker'), -- set only if isLocker
                lockerSlots = 50, lockerWeight = 500000,
                onSelect = function()
                    Inventory.openInventory('stash', 'MissionRow_Locker')
                end,
                canInteract = function()
                    local dutyData = Core.CheckDuty()
                    return dutyData.status == 1
                end
            }
        }
    }
}

Config.Radio = {
    [1] = {
        jobs = {
            ['police'] = true,
            ['sheriff'] = true,
        },
        label = "LSPD"
    },
    [2] = {
        jobs = {
            ['police'] = true,
            ['sheriff'] = true,
        },
        label = "LSPD"
    },
    [3] = {
        jobs = {
            ['police'] = true,
            ['sheriff'] = true,
        },
        label = "LSPD"
    },
    [4] = {
        jobs = {
            ['police'] = true,
            ['sheriff'] = true,
        },
        label = "SHERIFF"
    },
    [5] = {
        jobs = {
            ['police'] = true,
            ['sheriff'] = true,
        },
        label = "SHERIFF"
    },
    [6] = {
        jobs = {
            ['police'] = true,
            ['sheriff'] = true,
        },
        label = "SHERIFF"
    },
}

Config.SetUniform = function(job, grade)
    local animDict = lib.requestAnimDict('clothingtie')
    TaskPlayAnim(cache.ped, animDict, 'try_tie_negative_a', 2.0, 2.0, 2000, 49, 0, false, false, false)
    RemoveAnimDict(animDict)
    Citizen.Wait(1500)
    if Config.Framework == 'ESX' then
        TriggerEvent('skinchanger:getSkin', function(skin)
            local uniformObject
            
            sex = (skin.sex == 0) and "male" or "female"
    
            uniformObject = Config.Outfits[job][grade][sex]
    
            if uniformObject then
                ClearPedBloodDamage(cache.ped)
                ResetPedVisibleDamage(cache.ped)
                ClearPedLastWeaponDamage(cache.ped)
    
                TriggerEvent('skinchanger:loadClothes', skin, uniformObject)
            else
                Core.ShowNotification(locale('no_outfit'), 'error')
            end
        end)
    else
        local uniformObject
            
        local playerSex = Core.GetPlayerSex()
        sex = (playerSex == 0) and "male" or "female"

        uniformObject = Config.Outfits[job][grade][sex]

        if uniformObject then
            ClearPedBloodDamage(cache.ped)
            ResetPedVisibleDamage(cache.ped)
            ClearPedLastWeaponDamage(cache.ped)

            TriggerEvent('qb-clothing:client:loadOutfit', {outfitData = uniformObject})
        else
            Core.ShowNotification(locale('no_outfit'), 'error')
        end
    end
end

Config.CameraShowHelpNotify = function()
    if GetResourceState('p_helper') == 'started' then
        exports['p_helper']:showHelper({
            {
                keys = {'X'},
                label = 'Cancel'
            },
            {
                keys = {'ENTER'},
                label = 'Make Photo'
            },
        })
    else
        lib.showTextUI(locale('camera_helper'))
    end
end

Config.CameraHideHelpNotify = function()
    if GetResourceState('p_helper') == 'started' then
        exports['p_helper']:hideHelper()
    else
        lib.hideTextUI()
    end
end

Config.CameraAccess = false

-- YOU CAN SET CAMERA ITEM ACCESS FOR EACH JOB
-- Config.CameraAccess = {
--     ['police'] = 0,
--     ['sheriff'] = 0
-- 
```

</details>

<details>

<summary>Bodycam Config</summary>

```lua
Config.Bodycam = {}

Config.Bodycam.Prop = {
    isEnabled = true, -- is prop enabled?
    ['male'] = {
        boneIndex = 24818,
        offsetCoords = vector3(0.16683, 0.11320, 0.11986),
        offsetRot = vector3(-14.5023, 82.1910, -164.2206),
    },
    ['female'] = {
        boneIndex = 24818,
        offsetCoords = vector3(0.16683, 0.11320, 0.11986),
        offsetRot = vector3(-14.50232, 82.19109, -164.22066),
    },
}

Config.Bodycam.JobRestricted = true -- if true player can only check bodycams from he's job, if false he can check bodycams from all jobs

Config.Bodycam.OnStartWatching = function()
    -- DO SOMETHING
end

Config.Bodycam.OnStopWatching = function()
    -- DO SOMETHING
end
```

</details>

<details>

<summary>Interactions Config</summary>

```lua
Config.Interactions = {
    ['PutMouthTape'] = {
        label = locale('put_mouth_tape'),
        icon = 'fa-solid fa-tape',
        distance = 2,
        items = 'mouthtape',
        onSelect = function(data)
            local entity = type(data) == 'number' and data or data.entity
            local targetId = GetPlayerServerId(NetworkGetPlayerIndexFromPed(entity))
            if lib.progressBar({
                duration = 5000,
                label = locale('putting_mouth_tape'),
                useWhileDead = false,
                canCancel = true,
                disable = {car = true, move = true, combat = true},
                anim = {dict = 'random@train_tracks', clip = 'idle_e',flag = 1},
            }) then
                TriggerServerEvent('p_policejob/server_interactions/toggleMouthTape', {
                    player = targetId,
                    state = true
                })
            end
        end,
        canInteract = function(entity)
            if exports['p_policejob']:inTrunk() then return false end
            local localState = LocalPlayer.state
            if localState.draggingPlayer or localState.carryingPlayer then return false end
            local targetId = GetPlayerServerId(NetworkGetPlayerIndexFromPed(entity))
            local targetState = Player(targetId).state
            if targetState.draggedBy or targetState.carriedBy then return false end
            if targetState.isCuffed and not targetState.mouthTaped then return true end
            return false
        end
    },
    ['RemoveMouthTape'] = {
        label = locale('remove_mouth_tape'),
        icon = 'fa-solid fa-tape',
        distance = 2,
        onSelect = function(data)
            local entity = type(data) == 'number' and data or data.entity
            local targetId = GetPlayerServerId(NetworkGetPlayerIndexFromPed(entity))
            if lib.progressBar({
                duration = 5000,
                label = locale('removing_mouth_tape'),
                useWhileDead = false,
                canCancel = true,
                disable = {car = true, move = true, combat = true},
                anim = {dict = 'random@train_tracks', clip = 'idle_e',flag = 1},
            }) then
                TriggerServerEvent('p_policejob/server_interactions/toggleMouthTape', {
                    player = targetId,
                    state = false
                })
            end
        end,
        canInteract = function(entity)
            if exports['p_policejob']:inTrunk() then return false end
            local localState = LocalPlayer.state
            if localState.draggingPlayer or localState.carryingPlayer then return false end
            local targetId = GetPlayerServerId(NetworkGetPlayerIndexFromPed(entity))
            local targetState = Player(targetId).state
            if targetState.draggedBy or targetState.carriedBy then return false end
            if targetState.mouthTaped then return true end
            return false
        end
    },
    ['HardCuffPlayer'] = {
        label = locale('hard_cuff_player'),
        icon = 'fa-solid fa-handcuffs',
        distance = 2,
        items = 'handcuffs',
        onSelect = function(data)
            local entity = type(data) == 'number' and data or data.entity
            local targetId = GetPlayerServerId(NetworkGetPlayerIndexFromPed(entity))
            local isInFront = utils.isInFront(entity)
            TriggerServerEvent('p_policejob:HandCuffs', {
                type = 'cuffs', state = true, player = targetId, front = isInFront,
                isHard = true
            })
        end,
        canInteract = function(entity)
            if exports['p_policejob']:inTrunk() then return false end
            local localState = LocalPlayer.state
            if localState.draggingPlayer or localState.carryingPlayer then
                return false
            end

            local targetId = GetPlayerServerId(NetworkGetPlayerIndexFromPed(entity))
            local targetState = Player(targetId).state
            if targetState.draggedBy or targetState.carriedBy then
                return false
            end

            local playerJob = Core.GetPlayerJob()
            if not targetState.isCuffed and (Player(targetId).state.isDead or Config.Jobs[playerJob.name] or IsEntityPlayingAnim(entity, "random@mugging3", "handsup_standing_base", 3)) then
                return true
            end

            return false
        end
    },
    ['CuffPlayer'] = {
        label = locale('cuff_player'),
        icon = 'fa-solid fa-handcuffs',
        distance = 2,
        items = 'handcuffs',
        onSelect = function(data)
            local entity = type(data) == 'number' and data or data.entity
            local targetId = GetPlayerServerId(NetworkGetPlayerIndexFromPed(entity))
            local isInFront = utils.isInFront(entity)
            TriggerServerEvent('p_policejob:HandCuffs', {
                type = 'cuffs', state = true, player = targetId, front = isInFront
            })
        end,
        canInteract = function(entity)
            if exports['p_policejob']:inTrunk() then return false end
            local localState = LocalPlayer.state
            if localState.draggingPlayer or localState.carryingPlayer then
                return false
            end

            local targetId = GetPlayerServerId(NetworkGetPlayerIndexFromPed(entity))
            local targetState = Player(targetId).state
            if targetState.draggedBy or targetState.carriedBy then
                return false
            end

            local playerJob = Core.GetPlayerJob()
            if not targetState.isCuffed and (Player(targetId).state.isDead or Config.Jobs[playerJob.name] or IsEntityPlayingAnim(entity, "random@mugging3", "handsup_standing_base", 3)) then
                return true
            end

            return false
        end
    },
    ['UnCuffPlayer'] = {
        label = locale('uncuff_player'),
        icon = 'fa-solid fa-handcuffs',
        distance = 2,
        items = 'handcuffs',
        onSelect = function(data)
            local entity = type(data) == 'number' and data or data.entity
            local targetId = GetPlayerServerId(NetworkGetPlayerIndexFromPed(entity))
            TriggerServerEvent('p_policejob:HandCuffs', {
                type = 'cuffs', state = false, player = targetId
            })
        end,
        canInteract = function(entity)
            if exports['p_policejob']:inTrunk() then return false end
            local localState = LocalPlayer.state
            if localState.draggingPlayer or localState.carryingPlayer then
                return false
            end

            local targetId = GetPlayerServerId(NetworkGetPlayerIndexFromPed(entity))
            if Player(targetId).state.draggedBy then
                return false
            end

            if Player(targetId).state.isCuffed and Player(targetId).state.cuffType ~= 'rope' then
                return true
            end

            return false
        end
    },
    ['LockpickHandcuffs'] = {
        label = locale('open_cuffs'),
        icon = 'fa-solid fa-lock-open',
        distance = 2,
        items = 'lockpick',
        onSelect = function(data)
            local entity = type(data) == 'number' and data or data.entity
            local targetId = GetPlayerServerId(NetworkGetPlayerIndexFromPed(entity))
            TriggerServerEvent('p_policejob:interactions:OpenCuffs', {
                player = targetId
            })
        end,
        canInteract = function(entity)
            if exports['p_policejob']:inTrunk() then return false end
            local localState = LocalPlayer.state
            if localState.draggingPlayer or localState.carryingPlayer then
                return false
            end

            local targetId = GetPlayerServerId(NetworkGetPlayerIndexFromPed(entity))
            if Player(targetId).state.draggedBy then
                return false
            end

            if Player(targetId).state.isCuffed and Player(targetId).state.cuffType ~= 'rope' then
                return true
            end

            return false
        end
    },
    ['PutPlayerHeadBag'] = {
        label = locale('put_player_headbag'),
        icon = 'fa-solid fa-eye-slash',
        distance = 2,
        items = 'headbag',
        onSelect = function(data)
            local entity = type(data) == 'number' and data or data.entity
            local targetId = GetPlayerServerId(NetworkGetPlayerIndexFromPed(entity))
            TriggerServerEvent('p_policejob/server_interactions/ToggleHeadBag', {
                state = true, player = targetId
            })
        end,
        canInteract = function(entity)
            if exports['p_policejob']:inTrunk() then return false end
            local localState = LocalPlayer.state
            if localState.draggingPlayer or localState.carryingPlayer then
                return false
            end

            local targetId = GetPlayerServerId(NetworkGetPlayerIndexFromPed(entity))
            local targetState = Player(targetId).state
            if targetState.draggedBy or targetState.hasHeadBag then
                return false
            end

            if targetState.isCuffed or IsEntityPlayingAnim(entity, "random@mugging3", "handsup_standing_base", 3) then
                return true
            end

            return false
        end
    },
    ['TakeOffPlayerHeadBag'] = {
        label = locale('take_off_player_headbag'),
        icon = 'fa-solid fa-eye',
        distance = 2,
        onSelect = function(data)
            local entity = type(data) == 'number' and data or data.entity
            local targetId = GetPlayerServerId(NetworkGetPlayerIndexFromPed(entity))
            TriggerServerEvent('p_policejob/server_interactions/ToggleHeadBag', {
                state = false, player = targetId
            })
        end,
        canInteract = function(entity)
            if exports['p_policejob']:inTrunk() then return false end
            local localState = LocalPlayer.state
            if localState.draggingPlayer or localState.carryingPlayer then
                return false
            end

            local targetId = GetPlayerServerId(NetworkGetPlayerIndexFromPed(entity))
            local targetState = Player(targetId).state
            if targetState.draggedBy or not targetState.hasHeadBag then
                return false
            end

            return true
        end
    },
    ['ZipPlayer'] = {
        label = locale('zip_player'),
        icon = 'fa-solid fa-handcuffs',
        distance = 2,
        items = 'rope',
        onSelect = function(data)
            local entity = type(data) == 'number' and data or data.entity
            local targetId = GetPlayerServerId(NetworkGetPlayerIndexFromPed(entity))
            local isInFront = utils.isInFront(entity)
            TriggerServerEvent('p_policejob:HandCuffs', {
                type = 'rope', state = true, player = targetId,
                timer = true, time = 60 * 1000, front = isInFront
            })
            -- if you dont want to auto remove rope after 5 minutes, set timer to false, time is in minutes, 5 minutes default
        end,
        canInteract = function(entity)
            if exports['p_policejob']:inTrunk() then return false end
            local localState = LocalPlayer.state
            if localState.draggingPlayer or localState.carryingPlayer then
                return false
            end

            local targetId = GetPlayerServerId(NetworkGetPlayerIndexFromPed(entity))
            if Player(targetId).state.draggedBy then
                return false
            end

            local playerJob = Core.GetPlayerJob()
            if not Player(targetId).state.isCuffed and (
                IsEntityPlayingAnim(entity, "random@mugging3", "handsup_standing_base", 3) or
                playerJob.name == 'police'
            ) then
                return true
            end

            return false
        end
    },
    ['UnZipPlayer'] = {
        label = locale('unzip_player'),
        icon = 'fa-solid fa-handcuffs',
        distance = 2,
        onSelect = function(data)
            local entity = type(data) == 'number' and data or data.entity
            local targetId = GetPlayerServerId(NetworkGetPlayerIndexFromPed(entity))
            TriggerServerEvent('p_policejob:HandCuffs', {
                type = 'rope', state = false, player = targetId
            })
        end,
        canInteract = function(entity)
            if exports['p_policejob']:inTrunk() then return false end
            local localState = LocalPlayer.state
            if localState.draggingPlayer or localState.carryingPlayer then
                return false
            end

            local targetId = GetPlayerServerId(NetworkGetPlayerIndexFromPed(entity))
            if Player(targetId).state.draggedBy then
                return false
            end

            if Player(targetId).state.isCuffed and Player(targetId).state.cuffType == 'rope' then
                return true
            end

            return false
        end
    },
    ['SearchPlayer'] = {
        label = locale('search_player'),
        icon = 'fa-solid fa-wallet',
        distance = 2,
        onSelect = function(data)
            if lib.progressBar({
                duration = 5500,
                label = locale('searching_player'),
                useWhileDead = false,
                canCancel = true,
                disable = {
                    car = true,
                    move = true,
                    combat = true,
                },
                anim = {
                    dict = 'anim@gangops@facility@servers@bodysearch@',
                    clip = 'player_search' 
                },
            }) then
                local entity = type(data) == 'number' and data or data.entity
                local targetId = GetPlayerServerId(NetworkGetPlayerIndexFromPed(entity))
                if 
                Player(targetId).state.isCuffed or
                IsEntityPlayingAnim(entity, "random@mugging3", "handsup_standing_base", 3) or
                Core.isPlayerDead(targetId) then
                    Inventory.openInventory('player', targetId)
                end
            end
        end,
        canInteract = function(entity)
            if exports['p_policejob']:inTrunk() then return false end
            local localState = LocalPlayer.state
            if localState.draggingPlayer or localState.carryingPlayer then
                return false
            end

            local targetId = GetPlayerServerId(NetworkGetPlayerIndexFromPed(entity))
            if Player(targetId).state.draggedBy then
                return false
            end

            if 
            Player(targetId).state.isCuffed or
            IsEntityPlayingAnim(entity, "random@mugging3", "handsup_standing_base", 3) or
            Core.isPlayerDead(targetId) then
                return true
            end

            return false
        end
    },
    ['StartDragPlayer'] = {
        label = locale('start_drag'),
        icon = 'fa-solid fa-people-pulling',
        distance = 2,
        onSelect = function(data)
            local entity = type(data) == 'number' and data or data.entity
            local targetId = GetPlayerServerId(NetworkGetPlayerIndexFromPed(entity))
            TriggerServerEvent('p_policejob:DragPlayer', {state = true, player = targetId})
        end,
        canInteract = function(entity)
            if exports['p_policejob']:inTrunk() then return false end
            local localState = LocalPlayer.state
            if localState.draggingPlayer or localState.carryingPlayer then
                return false
            end

            local targetId = GetPlayerServerId(NetworkGetPlayerIndexFromPed(entity))
            if Player(targetId).state.isCuffed or Core.isPlayerDead(targetId) and not Player(targetId).state.draggedBy then
                return true
            end

            return false
        end
    },
    ['StopDragPlayer'] = {
        label = locale('stop_drag'),
        icon = 'fa-solid fa-people-pulling',
        distance = 2,
        onSelect = function(data)
            local entity = type(data) == 'number' and data or data.entity
            local targetId = GetPlayerServerId(NetworkGetPlayerIndexFromPed(entity))
            TriggerServerEvent('p_policejob:DragPlayer', {state = false, player = targetId})
        end,
        canInteract = function(entity)
            if exports['p_policejob']:inTrunk() then return false end
            local targetId = GetPlayerServerId(NetworkGetPlayerIndexFromPed(entity))
            if Player(targetId).state.draggedBy and Player(targetId).state.draggedBy == cache.serverId then
                return true
            end

            return false
        end
    },
    ['OutFromVehicle'] = { -- dont touch this
        label = locale('out_player'),
        icon = 'fa-solid fa-car',
        distance = 2,
        onSelect = function(data, seat)
            local entity = type(data) == 'number' and data or data.entity
            local targetId = GetPlayerServerId(NetworkGetPlayerIndexFromPed(GetPedInVehicleSeat(entity, seat)))
            TriggerServerEvent('p_policejob:OutVehicle', {seat = seat, player = targetId})
        end,
        canInteract = function(entity, seat)
            if exports['p_policejob']:inTrunk() then return false end
            if not NetworkGetEntityIsNetworked(entity) then return false end

            local targetId = GetPlayerServerId(NetworkGetPlayerIndexFromPed(GetPedInVehicleSeat(entity, seat)))
            
            if Player(targetId).state.isCuffed or Core.isPlayerDead(targetId) then
                return true
            end

            return false
        end
    },
    ['PutInVehicle'] = { -- dont touch this
        label = locale('put_player'),
        icon = 'fa-solid fa-car',
        distance = 2,
        onSelect = function(data, seat)
            local entity = type(data) == 'number' and data or data.entity
            local targetId = GetPlayerServerId(NetworkGetPlayerIndexFromPed(entity))
            TriggerServerEvent('p_policejob:PutInVehicle', {seat = seat, player = targetId})
        end,
        canInteract = function(entity, seat)
            if exports['p_policejob']:inTrunk() then return false end
            local localState = LocalPlayer.state
            if localState.carryingPlayer then
                return false
            end

            local vehicle, coords = lib.getClosestVehicle(GetEntityCoords(cache.ped), 4.0, false)

            if not vehicle or vehicle == 0 or not IsVehicleSeatFree(vehicle, seat) or not NetworkGetEntityIsNetworked(vehicle) then
                return false
            end
            
            local targetId = GetPlayerServerId(NetworkGetPlayerIndexFromPed(entity))

            local targetState = Player(targetId).state
            if targetState.isCuffed or (targetState.draggedBy and targetState.draggedBy == cache.serverId) or Core.isPlayerDead(targetId) then
                return true
            end

            return false
        end
    },
    ['CheckGunPowder'] = {
        label = locale('check_gun_powder'),
        icon = 'fa-solid fa-gun',
        distance = 2,
        onSelect = function(data)
            local entity = type(data) == 'number' and data or data.entity
            local targetId = GetPlayerServerId(NetworkGetPlayerIndexFromPed(entity))
            if lib.progressBar({
                duration = 10000,
                label = locale('checking_gun_powder'),
                useWhileDead = false,
                canCancel = true,
                disable = {
                    car = true,
                    move = true,
                    combat = true
                },
                anim = {
                    dict = 'random@train_tracks',
                    clip = 'idle_e',
                    flag = 1
                },
            }) then
                TriggerServerEvent('p_policejob:CheckGunPowder', targetId)
            end
        end,
        canInteract = function(entity, seat)
            if exports['p_policejob']:inTrunk() then return false end
            local localState = LocalPlayer.state
            if localState.draggingPlayer or localState.carryingPlayer then
                return false
            end
            
            local targetId = GetPlayerServerId(NetworkGetPlayerIndexFromPed(entity))
            if Player(targetId).state.draggedBy then
                return false
            end

            local playerJob = Core.GetPlayerJob()
            if not Config.Jobs[playerJob.name] then
                return false
            end

            if Player(targetId).state.isCuffed or Core.isPlayerDead(targetId) or 
            IsEntityPlayingAnim(entity, "random@mugging3", "handsup_standing_base", 3) then
                return true
            end

            return false
        end
    },
    ['GetPlayerBlood'] = {
        label = locale('fetch_blood'),
        icon = 'fa-solid fa-eye-dropper',
        groups = Config.Jobs,
        items = {['stick'] = 1, ['stick_bag'] = 1},
        anyItem = true,
        distance = 2,
        onSelect = function(data)
            if Inventory.getItemCount('stick') < 1 or Inventory.getItemCount('stick_bag') < 1 then
                return Core.ShowNotification(locale('you_need_stick_and_bag'), 'error')
            end

            local entity = type(data) == 'number' and data or data.entity
            local targetId = GetPlayerServerId(NetworkGetPlayerIndexFromPed(entity))
            if lib.progressBar({
                duration = 10000,
                label = locale('fetching_blood'),
                useWhileDead = false,
                canCancel = true,
                disable = {
                    car = true,
                    move = true,
                    combat = true
                },
                anim = {
                    dict = 'random@train_tracks',
                    clip = 'idle_e',
                    flag = 1
                },
            }) then
                TriggerServerEvent('p_policejob:GetPlayerBlood', targetId)
            end
        end,
        canInteract = function(entity, seat)
            if exports['p_policejob']:inTrunk() then return false end
            local localState = LocalPlayer.state
            if localState.draggingPlayer or localState.carryingPlayer then
                return false
            end
            
            local targetId = GetPlayerServerId(NetworkGetPlayerIndexFromPed(entity))
            if Player(targetId).state.draggedBy then
                return false
            end

            local playerJob = Core.GetPlayerJob()
            if not Config.Jobs[playerJob.name] then
                return false
            end

            if Player(targetId).state.isCuffed or Core.isPlayerDead(targetId) or 
            IsEntityPlayingAnim(entity, "random@mugging3", "handsup_standing_base", 3) then
                return true
            end

            return false
        end
    },
    ['GetPlayerFinger'] = {
        label = locale('fetch_finger_print'),
        icon = 'fa-solid fa-fingerprint',
        groups = Config.Jobs,
        items = 'fingerprinter',
        distance = 2,
        onSelect = function(data)
            if Inventory.getItemCount('fingerprinter') < 1 then
                return Core.ShowNotification(locale('you_need_finger_printer'), 'error')
            end

            local entity = type(data) == 'number' and data or data.entity
            local targetId = GetPlayerServerId(NetworkGetPlayerIndexFromPed(entity))
            if lib.progressBar({
                duration = 10000,
                label = locale('fetching_finger_print'),
                useWhileDead = false,
                canCancel = true,
                disable = {
                    car = true,
                    move = true,
                    combat = true
                },
                anim = {
                    dict = 'random@train_tracks',
                    clip = 'idle_e',
                    flag = 1
                },
            }) then
                TriggerServerEvent('p_policejob:GetPlayerFingerPrint', targetId)
            end
        end,
        canInteract = function(entity, seat)
            if exports['p_policejob']:inTrunk() then return false end
            local localState = LocalPlayer.state
            if localState.draggingPlayer or localState.carryingPlayer then
                return false
            end
            
            local targetId = GetPlayerServerId(NetworkGetPlayerIndexFromPed(entity))
            if Player(targetId).state.draggedBy then
                return false
            end

            local playerJob = Core.GetPlayerJob()
            if not Config.Jobs[playerJob.name] then
                return false
            end

            if Player(targetId).state.isCuffed or Core.isPlayerDead(targetId) or 
            IsEntityPlayingAnim(entity, "random@mugging3", "handsup_standing_base", 3) then
                return true
            end

            return false
        end
    },
    ['SetPlayerBand'] = {
        label = locale('set_gps_band'),
        icon = 'fa-solid fa-hands-bound',
        groups = Config.Band.Jobs,
        items = 'tracking_band',
        distance = 2,
        onSelect = function(data)
            local entity = type(data) == 'number' and data or data.entity
            local targetId = GetPlayerServerId(NetworkGetPlayerIndexFromPed(entity))
            if lib.progressBar({
                duration = 10000,
                label = locale('setting_gps_band'),
                useWhileDead = false,
                canCancel = true,
                disable = {
                    car = true,
                    move = true,
                    combat = true
                },
                anim = {
                    dict = 'random@train_tracks',
                    clip = 'idle_e',
                    flag = 1
                },
            }) then
                TriggerServerEvent('p_policejob:SetPlayerBand', {
                    player = targetId,
                    state = true
                })
            end
        end,
        canInteract = function(entity, seat)
            if exports['p_policejob']:inTrunk() then return false end
            local localState = LocalPlayer.state
            if localState.draggingPlayer or localState.carryingPlayer then
                return false
            end
            
            local targetId = GetPlayerServerId(NetworkGetPlayerIndexFromPed(entity))
            local targetState = Player(targetId).state
            if targetState.draggedBy then
                return false
            end

            local playerJob = Core.GetPlayerJob()
            if not Config.Jobs[playerJob.name] then
                return false
            end

            local hasBand = targetState.hasTrackingBand
            if hasBand then
                return false
            end

            if targetState.isCuffed or IsEntityPlayingAnim(entity, "random@mugging3", "handsup_standing_base", 3) then
                return true
            end

            return false
        end
    },
    ['RemovePlayerBand'] = {
        label = locale('remove_gps_band'),
        icon = 'fa-solid fa-hands-bound',
        distance = 2,
        onSelect = function(data)
            local entity = type(data) == 'number' and data or data.entity
            local targetId = GetPlayerServerId(NetworkGetPlayerIndexFromPed(entity))
            local playerJob = Core.GetPlayerJob()
            local bandJob = Config.Band.Jobs[playerJob.name]
            if bandJob and tonumber(playerJob.grade) >= bandJob then
                if lib.progressBar({
                    duration = 10000,
                    label = locale('removing_gps_band'),
                    useWhileDead = false,
                    canCancel = true,
                    disable = {
                        car = true,
                        move = true,
                        combat = true
                    },
                    anim = {
                        dict = 'random@train_tracks',
                        clip = 'idle_e',
                        flag = 1
                    },
                }) then
                    TriggerServerEvent('p_policejob:SetPlayerBand', {
                        player = targetId,
                        state = false
                    })
                end
            else
                TriggerServerEvent('p_policejob:BandAlert', targetId)
                local game = lib.skillCheck(
                    {
                        {areaSize = 30, speedMultiplier = 1.5},
                    },
                    {'1', '2', '3', '4'}
                )

                if game then
                    if lib.progressBar({
                        duration = 10000,
                        label = locale('removing_gps_band'),
                        useWhileDead = false,
                        canCancel = true,
                        disable = {
                            car = true,
                            move = true,
                            combat = true
                        },
                        anim = {
                            dict = 'random@train_tracks',
                            clip = 'idle_e',
                            flag = 1
                        },
                    }) then
                        TriggerServerEvent('p_policejob:SetPlayerBand', {
                            player = targetId,
                            state = false
                        })
                    end
                end
            end
        end,
        canInteract = function(entity, seat)
            if exports['p_policejob']:inTrunk() then return false end
            local localState = LocalPlayer.state
            if localState.draggingPlayer or localState.carryingPlayer then
                return false
            end
            
            local targetId = GetPlayerServerId(NetworkGetPlayerIndexFromPed(entity))
            local targetState = Player(targetId).state
            if targetState.draggedBy then
                return false
            end

            local hasBand = targetState.hasTrackingBand
            if hasBand then
                return true
            end

            return false
        end
    },
    ['PutPlayerInTrunk'] = {
        label = locale('put_player_in_trunk'),
        icon = 'fa-solid fa-car',
        distance = 2,
        onSelect = function(data)
            local entity = type(data) == 'number' and data or data.entity
            local targetId = GetPlayerServerId(NetworkGetPlayerIndexFromPed(entity))
            TriggerServerEvent('p_policejob/server_trunks/PutPlayerInTrunk', targetId)
        end,
        canInteract = function(entity)
            if exports['p_policejob']:inTrunk() then return false end
            local localState = LocalPlayer.state
            if localState.draggingPlayer or localState.carryingPlayer then
                return false
            end
            
            local targetId = GetPlayerServerId(NetworkGetPlayerIndexFromPed(entity))
            local stateBag = Player(targetId).state
            if stateBag.isCuffed or Core.isPlayerDead(targetId) then
                local vehicle, _ = lib.getClosestVehicle(GetEntityCoords(cache.ped), 3.5, true)
                if vehicle and vehicle ~= 0 then
                    return true
                end
            end

            return false
        end
    },
    ['StartCarryPlayer'] = {
        label = locale('start_carry_player'),
        icon = 'fa-solid fa-hands-holding',
        distance = 2,
        onSelect = function(data)
            local entity = type(data) == 'number' and data or data.entity
            local targetId = GetPlayerServerId(NetworkGetPlayerIndexFromPed(entity))
            TriggerServerEvent('p_policejob/server_interactions/StartCarryPlayer', targetId)
        end,
        canInteract = function(entity)
            if exports['p_policejob']:inTrunk() then return false end
            local targetId = GetPlayerServerId(NetworkGetPlayerIndexFromPed(entity))
            local localState = LocalPlayer.state
            if localState.draggingPlayer or localState.carryingPlayer then
                return false
            end

            local stateBag = Player(targetId).state
            if stateBag.draggedBy then
                return false
            end

            return true
        end
    },
    ['StopCarryPlayer'] = {
        label = locale('stop_carry_player'),
        icon = 'fa-solid fa-hands-holding',
        distance = 2,
        onSelect = function(data)
            local entity = type(data) == 'number' and data or data.entity
            local targetId = GetPlayerServerId(NetworkGetPlayerIndexFromPed(entity))
            TriggerServerEvent('p_policejob/server_interactions/StopCarryPlayer', targetId)
        end,
        canInteract = function(entity)
            if exports['p_policejob']:inTrunk() then return false end
            local targetId = GetPlayerServerId(NetworkGetPlayerIndexFromPed(entity))
            local stateBag = Player(targetId).state
            if stateBag.carriedBy and stateBag.carriedBy == cache.serverId then
                return true
            end

            return false
        end
    },
    ['SendToJail'] = {
        label = locale('send_to_jail'),
        icon = 'fa-solid fa-hashtag',
        distance = 2,
        groups = Config.Jobs,
        onSelect = function(data)
            local input = lib.inputDialog(locale('send_to_jail'), {
                {type = 'number', label = locale('jail_time'), icon = 'clock', default = 0, min = 0, max = 500, required = false},
                {type = 'number', label = locale('jail_fine'), icon = 'dollar-sign', default = 1, min = 1, required = true},
                {type = 'textarea', label = locale('jail_reason'), icon = 'receipt', required = true}
            })
            if not input then return end
            local entity = type(data) == 'number' and data or data.entity
            local targetId = GetPlayerServerId(NetworkGetPlayerIndexFromPed(entity))
            TriggerServerEvent('p_policejob:JailPlayer', {
                player = targetId,
                jail = input[1],
                fine = input[2],
                reason = input[3]
            })
        end,
        canInteract = function(entity)
            if not Config.Jail.EnableJail then return false end
            if Config.PoliceMDT or exports['p_policejob']:inTrunk() then return false end
            local targetId = GetPlayerServerId(NetworkGetPlayerIndexFromPed(entity))
            local stateBag = Player(targetId).state
            if stateBag.isCuffed or IsEntityPlayingAnim(entity, "random@mugging3", "handsup_standing_base", 3) then
                return true
            end

            return false
        end
    }
}

Config.CuffsAsItem = true -- set to true if you want to use handcuffs as item (target will be available too)
Config.CuffItemCheck = function(entity, playerId)
    local localState = LocalPlayer.state
    if localState.draggingPlayer or localState.carryingPlayer then
        return false
    end

    local targetState = Player(playerId).state
    if targetState.draggedBy or targetState.carriedBy then
        return false
    end

    if Player(playerId).state.isCuffed then
        return 'uncuff'
    else
        local playerJob = Core.GetPlayerJob()
        if Player(playerId).state.isDead or Config.Jobs[playerJob.name] or IsEntityPlayingAnim(entity, "random@mugging3", "handsup_standing_base", 3) then
            return 'cuff'
        end
    end

    return false
end

Config.Carry = {
    useRequest = true, -- if true other player need to accept carry request
    stopCarryKey = 'E', -- set key to stop carry [FOR EXAMPLE 'E']
    onStartCarrying = function(playerId, role)
        if role == 'carrying' then
            lib.showTextUI('[E] - Stop carry')
        end
    end,
    onStopCarrying = function(playerId, role)
        if role == 'carrying' then
            lib.hideTextUI()
        end
    end,
    onRequest = function(playerId)
        local useAlert = false -- SET TO TRUE IF YOU WANT TO USE ALERT DIALOG
        if not useAlert then
            local result = false
            local timer = 0
            Core.ShowNotification(locale('player_request_carry', playerId))
            while timer < 500 do
                Citizen.Wait(1)
                timer += 1
                if IsControlJustReleased(0, 38) then
                    result = true
                    break
                end
            end
        
            return result
        else
            local alert = lib.alertDialog({
                header = locale('carry_person_request'),
                content = locale('carry_person_request_info', playerId),
                centered = true,
                cancel = true
            })
            return alert == 'confirm'
        end
    end,
    animation = {
        carried = {
            dict = 'nm',
            clip = 'firemans_carry',
            flag = 33,
            offset = {
                coords = vector3(0.25, -0.05, 0.63),
                rotation = vector3(0.25, 0.0, 180.0)
            }
        },
        carrying = {
            dict = 'missfinale_c2mcs_1',
            clip = 'fin_c2_mcs_1_camman',
            flag = 49
        }
    }
}

Config.LockpickCuffs = {
    miniGame = function()
        local game = lib.skillCheck(
            {
                {areaSize = 30, speedMultiplier = 1.5},
                {areaSize = 30, speedMultiplier = 1.5},
                {areaSize = 30, speedMultiplier = 1.5},
                {areaSize = 30, speedMultiplier = 1.5},
                {areaSize = 30, speedMultiplier = 1.5},
            },
            {'1', '2', '3', '4'}
        )
        return game
    end,
    animation = {
        enabled = true,
        dict = 'anim@amb@clubhouse@tutorial@bkr_tut_ig3@',
        clip = 'machinic_loop_mechandplayer',
        flag = 49
    }
}

Config.DisableKeys = {
    ['hardcuff'] = { -- THIS IS ENABLED KEYS WHILE HARD CUFF !!!!!!!!!!!!!!!!!!!!!!!!!
        0, 1, 2, 249
    },
    ['cuff'] = {
        24, 257, 25, 263, 45, 22, 44, 37, 23, 21, 288, 289, 170, 75,
        167, 73, 199, 59, 71, 72, 47, 264, 257, 140, 141, 142, 143
    },
    ['drag'] = {
        24, 257, 25, 263, 45, 22, 44, 37, 23, 21, 288, 289, 170, 75,
        167, 73, 199, 59, 71, 72, 47, 264, 257, 140, 141, 142, 143
    }
}

Config.OnPlayerCuff = function()
    local playerPed = cache.ped
    SetEnableHandcuffs(playerPed, true)
    DisablePlayerFiring(playerPed, true)
    SetCurrentPedWeapon(playerPed, `WEAPON_UNARMED`, true)
    SetPedCanPlayGestureAnims(playerPed, false)
    LocalPlayer.state.invBusy = true
    LocalPlayer.state.invHotkeys = false
    LocalPlayer.state.canUseWeapons = false
    lib.disableRadial(true)
    if GetResourceState('ox_target') == 'started' then
        exports['ox_target']:disableTargeting(true)
    elseif GetResourceState('qb-target') == 'started' then
        exports['qb-target']:AllowTargeting(false)
    end
    if GetResourceState('lb-phone') == 'started' then
        exports["lb-phone"]:ToggleDisabled(true)
    end
end

Config.OnPlayerUnCuff = function()
    local playerPed = cache.ped
    SetEnableHandcuffs(playerPed, false)
    DisablePlayerFiring(playerPed, false)
    SetPedCanPlayGestureAnims(playerPed, true)
    LocalPlayer.state.invBusy = false
    LocalPlayer.state.invHotkeys = true
    LocalPlayer.state.canUseWeapons = true
    lib.disableRadial(false)
    if GetResourceState('ox_target') == 'started' then
        exports['ox_target']:disableTargeting(false)
    elseif GetResourceState('qb-target') == 'started' then
        exports['qb-target']:AllowTargeting(true)
    end
    if GetResourceState('lb-phone') == 'started' then
        exports["lb-phone"]:ToggleDisabled(false)
    end
end

Config.OnStartPlayerDrag = function()
    LocalPlayer.state.invBusy = true
    LocalPlayer.state.invHotkeys = false
    LocalPlayer.state.canUseWeapons = false
    lib.disableRadial(true)
    if GetResourceState('ox_target') == 'started' then
        exports['ox_target']:disableTargeting(true)
    elseif GetResourceState('qb-target') == 'started' then
        exports['qb-target']:AllowTargeting(false)
    end
    if GetResourceState('lb-phone') == 'started' then
        exports["lb-phone"]:ToggleDisabled(true)
    end
end

Config.OnStopPlayerDrag = function()
    LocalPlayer.state.invBusy = false
    LocalPlayer.state.invHotkeys = true
    LocalPlayer.state.canUseWeapons = true
    lib.disableRadial(false)
    if GetResourceState('ox_target') == 'started' then
        exports['ox_target']:disableTargeting(false)
    elseif GetResourceState('qb-target') == 'started' then
        exports['qb-target']:AllowTargeting(true)
    end
    if GetResourceState('lb-phone') == 'started' then
        exports["lb-phone"]:ToggleDisabled(false)
    end
e
```

</details>

<details>

<summary>GPS Config</summary>

```lua
Config.GPS = {}

Config.GPS.NeedDuty = true -- true | false (need to be on duty to turn on/off gps?)
Config.GPS.ShortRange = true -- only visible closests blips on minimap
Config.GPS.RefreshRate = 2500 -- 2.5s
Config.GPS.UseCallSign = false -- true (use job call sign setted by /callsign ?) | false

Config.GPS.Jobs = {
    ['police'] = { -- YOU CAN USE GPS FOR DIFFERENT JOBS ALSO (MECHANIC, EMS, ETC)
        color = 63,
        lights = 1,
        display = 'LSPD',
        types = {
            onFoot = {
                color = 63,
                lights = 1,
                sprite = 1,
                scale = 1.1,
                heading = true
            },
            inVeh = {
                color = 63,
                lights = 1,
                sprite = 56,
                scale = 1.1,
                heading = true
            },
            boat = {
                color = 63,
                lights = 1,
                sprite = 427,
                scale = 1.1,
                heading = true
            },
            plane = {
                color = 63,
                lights = 1,
                sprite = 43,
                scale = 1.1,
                heading = true
            },
            heli = {
                color = 63,
                lights = 1,
                sprite = 43,
                scale = 1.1,
                heading = true
            },
            bike = {
                color = 63,
                lights = 1,
                sprite = 1,
                scale = 1.1,
                heading = true
            },
        }
    },
}
```

</details>

<details>

<summary>Garage Config </summary>

```lua
Config.Garage = {}

Config.Garage.CreateVehicleKeys = function(plate, model, netId)
    if GetResourceState('p_carkeys') == 'started' then
        TriggerServerEvent('p_carkeys:CreateKeys', plate)
    elseif GetResourceState('wasabi_carlock') == 'started' then
        exports['wasabi_carlock']:GiveKey(plate)
    elseif GetResourceState('qs-vehiclekeys') == 'started' then
        exports['qs-vehiclekeys']:GiveKeys(plate, model, true)
    elseif GetResourceState('tgiann-hotwire') == 'started' then
        exports["tgiann-hotwire"]:GiveKeyPlate(plate, true)
    elseif GetResourceState('qbx_vehiclekeys') == 'started' then
        TriggerEvent('qb-vehiclekeys:client:AddKeys', plate)
    elseif GetResourceState('qb-vehiclekeys') == 'started' then
        TriggerEvent('qb-vehiclekeys:client:AddKeys', plate)
    end
end

Config.Garage.RemoveVehicleKeys = function(plate, model, netId)
    if GetResourceState('p_carkeys') == 'started' then
        TriggerServerEvent('p_carkeys:RemoveKeys', plate)
    elseif GetResourceState('wasabi_carlock') == 'started' then
        exports['wasabi_carlock']:RemoveKey(plate)
    elseif GetResourceState('qs-vehiclekeys') == 'started' then
        exports['qs-vehiclekeys']:RemoveKeys(plate, model)
    elseif GetResourceState('tgiann-hotwire') == 'started' then
        exports["tgiann-hotwire"]:GiveKeyPlate(plate, true)
    elseif GetResourceState('qb-vehiclekeys') == 'started' then
        TriggerEvent('qb-vehiclekeys:client:RemoveKeys', plate)
    elseif GetResourceState('qbx_vehiclekeys') == 'started' then
        TriggerEvent('qb-vehiclekeys:client:RemoveKeys', plate)
    end
end

Config.Garage.CustomLabels = { -- FOR OWNED VEHICLES ONLY
    ['police'] = 'Police Vehicle',
    ['police2'] = 'Police Vehicle 2'
}

Config.Garage.CustomImages = {
    -- ['police'] = 'LINK TO IMAGE', -- set here link to image, it can be fivemanage :)
    -- ['police2'] = 'LINK TO IMAGE',
    -- ['police3'] = 'LINK TO IMAGE',
}

Config.Garage.Garages = {
    ['Mission_Row'] = {
        -- vehicles = { -- UNCOMMENT THIS IF YOU WANT VEHICLE SPAWNER
        --     ['police'] = {
        --         [0] = { -- FROM GRADE 0 CAN TAKE THIS VEHICLES
        --             ['police'] = 'Police Vehicle' -- spawn name and display name
        --         },
        --         [1] = { -- FROM GRADE 1 CAN TAKE THIS VEHICLES
        --             ['police'] = 'Police Vehicle', -- spawn name and display name
        --             ['police2'] = 'Police Vehicle 2' -- spawn name and display name
        --         }
        --     }
        -- },
        ped = {
            model = 's_m_y_cop_01',
            anim = {dict = 'amb@world_human_cop_idles@male@idle_b', clip = 'idle_e'}
        },
        coords = vector4(434.6770, -1029.1232, 28.9886, 0.0),
        allowedJobs = {
            ['police'] = 0,
            ['sheriff'] = 0
        },
        blip = { -- only visible for allowed jobs
            sprite = 357,
            scale = 0.75,
            color = 3,
            label = 'Mission Row Garage'
        },
        spawnPoints = {
            vector4(431.7113, -1027.2172, 28.9471, 179.8748),
            vector4(427.6960, -1027.6909, 28.9821, 182.6840),
            vector4(424.0269, -1028.0519, 29.0469, 184.6641),
            vector4(420.0333, -1028.3597, 29.1166, 186.3764),
            vector4(416.5734, -1028.6340, 29.1769, 185.2027)
        }
    }
}
```

</details>

<details>

<summary>Extras Config</summary>

```lua
Config.Extras = {}

Config.Extras.Points = {
    ['Mission_Row'] = {
        coords = vector3(426.8506, -1023.1243, 28.8620),
        allowedJobs = {
            ['police'] = 0, -- job name and grade
            ['sheriff'] = 0
        }
    }
}

Config.Extras.Callsigns = { -- THIS IS READY FOR SEB5A POLICE VEHICLE PACK
    ['cvpi'] = {
        [1] = 10, -- FIRST NUMBER = 10TH VEHICLE MOD IN cvpi VEHICLE MODEL
        [2] = 9, -- SECOND NUMBER = 9TH VEHICLE MOD IN cvpi VEHICLE MODEL
        [3] = 8 -- THIRD NUMBER = 8TH VEHICLE MOD IN cvpi VEHICLE MODEL
    },
    ['emstahoe'] = {
        [1] = 10,
        [2] = 9,
        [3] = 8
    },
    ['polbuffalo4'] = {
        [1] = 8,
        [2] = 9,
        [3] = 10
    },
    ['polgranger2'] = {
        [1] = 8,
        [2] = 9,
        [3] = 10
    },
    ['policeexp'] = {
        [1] = 10,
        [2] = 9,
        [3] = 8
    },
    ['polscout'] = {
        [1] = 8,
        [2] = 9,
        [3] = 10
    },
    ['poltorrence'] = {
        [1] = 8,
        [2] = 9,
        [3] = 10
    },
    ['polvigero'] = {
        [1] = 8,
        [2] = 9,
        [3] = 10
    },
}
```

</details>

<details>

<summary>Evidences Config</summary>

```lua
Config.EnableEvidences = true -- true or false

Config.BloodTypes = {
    'A Rh+', 'A Rh-', 'B Rh+', 'B Rh-', '0 Rh+', '0 Rh-'
}

Config.EvidencesRemovers = {
    ['bullet'] = {
        ['towel'] = 1, -- item name and count, set Config.EvidencesRemovers = false if you dont want other players to remove
    },
    ['blood'] = {
        ['towel'] = 1, -- item name and count
    },
    ['finger'] = {
        ['towel'] = 1, -- item name and count
    },
}

Config.EvidencesExpire = {
    ['bullet'] = 60, -- time in minutes
    ['blood'] = 60, -- time in minutes
    ['finger'] = 60, -- time in minutes
    ['powder'] = 10 -- time in minutes
}

Config.Flashlights = {
    [`WEAPON_FLASHLIGHT`] = true
}

Config.WhitelistedWeapons = { -- which weapons will not leave gun powder
    [`WEAPON_STUNGUN`] = 'Stun Gun' -- label
}

Config.HasGloves = function()
    local hasGloves = false
    if Config.Framework == 'ESX' then
        TriggerEvent('skinchanger:getSkin', function(skin)
            if skin.arms >= 16 and skin.arms < 51 then
                hasGloves = true
            end
        end)
    end

    return hasGloves
end

Config.Laboratories = {
    ['MissionRow'] = {
        job = {['police'] = 0},
        coords = vector3(466.94, -1001.67, 34.2),
        stashCoords = vector3(466.94, -1001.67, 34.2),
        radius = 1.0,
        drawSprite = false,
        canInteract = function()
            local dutyData = Core.CheckDuty()
            return dutyData.status ~= 0
        end,
        process = 1 -- time in minutes, how long process will take
    }
}

Config.EvidenceStorages = {
    ['MissionRow'] = {
        job = {['police'] = 0},
        coords = vector3(471.63, -997.26, 34.25),
        radius = 1.0,
        drawSprite = false,
        canInteract = function()
            local dutyData = Core.CheckDuty()
            return dutyData.status ~= 0
        end,
    }
}
```

</details>

<details>

<summary>Cameras Config</summary>

```lua
Config.Cameras = {}

Config.Cameras.WatchPoints = {
    ['MissionRow'] = {
        jobs = {['police'] = 0},
        coords = vector3(441.0, -982.0, 30.69),
        requiredDuty = true
    }
}

Config.Cameras.Models = {
    ['prop_cctv_cam_06a'] = 'CCTV Camera 1',
    ['ch_prop_ch_cctv_cam_02a'] = 'CCTV Camera 2',
    ['tr_prop_tr_camhedz_cctv_01a'] = 'CCTV Camera 3',
    ['prop_cctv_cam_02a'] = 'CCTV Camera 4',
    ['prop_cctv_pole_04'] = 'CCTV Camera Pole'
}

Config.Cameras.AllowedGroups = { -- which groups can create cameras
    ['owner'] = true,
    ['admin'] = true
}

Config.Cameras.AllowedJobs = { -- which jobs can create cameras
    ['police'] = 0,
    ['sheriff'] = 0
}

Config.Cameras.ShowHelpNotify = function()
    if GetResourceState('p_helper') == 'started' then
        exports['p_helper']:showHelper({
            {
                keys = {'X'},
                label = locale('cancel')
            },
            {
                keys = {'<', '>'},
                label = locale('rotate_x')
            },
            {
                keys = {'N', 'M'},
                label = locale('rotate_y')
            },
            {
                keys = {'↑', '↓'},
                label = locale('rotate_z')
            },
            {
                keys = {'E'},
                label = locale('confirm')
            },
        })
    else
        lib.showTextUI('[X] - '..locale('cancel')..' | [< >] - '..locale('rotate_x')..' | [N/M] -'..locale('rotate_y')..' | [↑ ↓] - '..locale('rotate_z')..' | [E] - '..locale('confirm'))
    end
end

Config.Cameras.HideHelpNotify = function()
    if GetResourceState('p_helper') == 'started' then
        exports['p_helper']:hideHelper()
    else
        lib.hideTextUI()
    end
end

Config.Cameras.OnStartWatching = function()
    lib.showTextUI('[X] - '..locale('stop_watching')..' | [⇆] - '..locale('rotate_left_right')..' | [↓↑] - '..locale('move_up_down'), {
        position = 'bottom-center'
    })
    SetTimecycleModifier('Island_CCTV_ChannelFuzz')
    SetTimecycleModifierStrength(0.25)
end

Config.Cameras.OnStopWatching = function()
    lib.hideTextUI()
    SetTimecycleModifier('default')
    SetTimecycleModifierStrength(1.0)
end
```

</details>

<details>

<summary>Jail Config</summary>

```lua
Config.Jail = {}

Config.Jail.EnableJail = true -- enable jail system
Config.Jail.NeedDuty = true -- officer need to be on duty?
Config.Jail.RemoveItems = false -- locker / wipe / false [locker = all items will go to locker, wipe = all items will be removed, false = nothing will happen]
Config.Jail.WhitelistedItems = { -- items that will not be removed [set to false if none]
    ['money'] = true,
}

Config.Jail.Access = {
    ['jail'] = {
        ['owner'] = true,
        ['admin'] = true,
    },
    ['unjail'] = {
        ['owner'] = true,
        ['admin'] = true,
    },
    ['shortjail'] = {
        ['owner'] = true,
        ['admin'] = true,
    }
}

Config.Jail.Outfit = {
    ["male"] = {
        tshirt_1 = 15,  tshirt_2 = 0,
        torso_1 = 345,   torso_2 = 0,
        decals_1 = 0,   decals_2 = 0,
        arms = 0,
        pants_1 = 138,   pants_2 = 0,
        shoes_1 = 132,   shoes_2 = 0,
        helmet_1 = -1,  helmet_2 = 0,
        mask_1 = 0,     mask_2 = 0,
        chain_1 = 0,    chain_2 = 0,
        ears_1 = 2,     ears_2 = 0
    },
    ["female"] = {
        tshirt_1 = 15,  tshirt_2 = 0,
        torso_1 = 338,   torso_2 = 0,
        decals_1 = 0,   decals_2 = 0,
        arms = 44,
        pants_1 = 145,   pants_2 = 0,
        shoes_1 = 137,   shoes_2 = 0,
        helmet_1 = -1,  helmet_2 = 0,
        mask_1 = 0,     mask_2 = 0,
        chain_1 = 0,    chain_2 = 0,
        ears_1 = 2,     ears_2 = 0
    }
}

Config.Jail.ConvertMonths = function(months)
    return math.floor(months * 60) -- month = 1 minute
end

Config.Jail.ConvertMonths_2 = function(time)
    return math.floor(time / 60) -- seconds to month (1 minute)
end

Config.Jail.SetUniform = function()
    if Config.Framework == 'ESX' then
        local uniformObject
            
        local playerSex = Core.GetPlayerSex()
        local sex = nil
        if playerSex == 'm' or playerSex == 0 then
            sex = 'male'
        else
            sex = 'female'
        end

        uniformObject = Config.Jail.Outfit[sex]

        if GetResourceState('illenium-appearance') == 'started' then
            exports['illenium-appearance']:setPedComponents(cache.ped, uniformObject.components)
            exports['illenium-appearance']:setPedProps(cache.ped, uniformObject.props)
        else
            TriggerEvent('skinchanger:getSkin', function(skin)
                if uniformObject then
                    ClearPedBloodDamage(cache.ped)
                    ResetPedVisibleDamage(cache.ped)
                    ClearPedLastWeaponDamage(cache.ped)
                    TriggerEvent('skinchanger:loadClothes', skin, uniformObject)
                end
            end)
        end
    else
        local uniformObject
            
        local playerSex = Core.GetPlayerSex()
        sex = (playerSex == 0) and "male" or "female"

        uniformObject = Config.Jail.Outfit[sex]

        if uniformObject then
            ClearPedBloodDamage(cache.ped)
            ResetPedVisibleDamage(cache.ped)
            ClearPedLastWeaponDamage(cache.ped)

            if GetResourceState('illenium-appearance') == 'started' then
                exports['illenium-appearance']:setPedComponents(cache.ped, uniformObject.components)
                exports['illenium-appearance']:setPedProps(cache.ped, uniformObject.props)
            else
                TriggerEvent('qb-clothing:client:loadOutfit', {outfitData = uniformObject})
            end
        else
            Core.ShowNotification(locale('no_outfit'), 'error')
        end
    end
end

Config.Jail.Zone = {
    jailCoords = vector4(1755.2000, 2492.9490, 45.6513, 212.2371), -- tp here on jail
    unJailCoords = vector4(1846.5839, 2585.7852, 45.6720, 273.4318), -- tp here on ujail
    points = {
        vector3(1851.6860, 2612.5491, 40.6460),
        vector3(1852.1394, 2701.5581, 40.6460),
        vector3(1773.6439, 2767.1697, 40.6460),
        vector3(1648.2583, 2762.4854, 40.6460),
        vector3(1566.2778, 2682.9824, 40.6460),
        vector3(1530.6156, 2586.8628, 40.6460),
        vector3(1537.3165, 2467.2065, 40.6460),
        vector3(1657.2385, 2390.4211, 40.6460),
        vector3(1763.3314, 2406.4651, 40.6460),
        vector3(1827.3147, 2472.8708, 40.6460),
        vector3(1817.7594, 2533.5786, 40.6460),
        vector3(1820.1619, 2567.2734, 40.6460),
        vector3(1852.0808, 2567.8420, 40.6460),
        vector3(1852.4672, 2625.8269, 40.6460)
    },
    thickness = 50
}

Config.Jail.Cutscene = {
    playerPos = vector4(402.915, -996.759, -99.0002, 185.2249),
    cameraPos = { 
        x = 402.9453, y = -998.3599, z = -98.7041, 
        rotationX = -5.4330, rotationY = 0.0, rotationZ = 0.31496
    },
}

Config.Jail.OnPlayerFine = function(playerId, fine, officerName, officerId) -- SERVER SIDE
    -- do something
end

Config.Jail.OnPlayerJailed = function(player, months, fine, officerName, officerId) -- SERVER SIDE
    -- do something
end

Config.Jail.OnPlayerUnJailed = function(player) -- SERVER SIDE
    TriggerClientEvent('p_policejob/jail/clearJob', player)
    if GetResourceState('illenium-appearance') == 'started' then
        TriggerClientEvent('illenium-appearance:client:reloadSkin', player, true)
    else
        if Config.Framework == 'ESX' then
            local xPlayer = ESX.GetPlayerFromId(player)
            local row = MySQL.single.await('SELECT skin FROM users WHERE identifier = ?', {xPlayer.identifier})
            if row and row.skin then
                local plySkin = json.decode(row.skin)
                TriggerClientEvent('skinchanger:loadClothes', player, plySkin, plySkin)
            end
        else
            local QBCore = exports['qb-core']:GetCoreObject()
            local Player = QBCore.Functions.GetPlayer(player)
            local result = MySQL.query.await('SELECT * FROM playerskins WHERE citizenid = ? AND active = ?', { Player.PlayerData.citizenid, 1 })
            if result[1] ~= nil then
                TriggerClientEvent("qb-clothes:loadSkin", player, false, result[1].model, result[1].skin)
            else
                TriggerClientEvent("qb-clothes:loadSkin", player, true)
            end
        end
    end
    -- do something
end

Config.Jail.Lockers = {
    ['MissionRow'] = {
        coords = vector3(465.61, -990.98, 27.2),
        radius = 0.75,
        drawSprite = true,
        options = {
            {
                name = 'MissionRow_Jail_Locker',
                label = locale('jail_locker'),
                icon = 'fa-solid fa-id-card',
                distance = 2,
                drawSprite = true,
                groups = {['police'] = 1},
                onSelect = function()
                    OpenPlayerLocker()
                end,
                canInteract = function()
                    local dutyData = Core.CheckDuty()
                    return dutyData.status == 1
                end
            },
            {
                name = 'MissionRow_Evidence_Locker',
                label = locale('evidence_locker'),
                icon = 'fa-solid fa-id-card',
                distance = 2,
                drawSprite = true,
                groups = {['police'] = 1},
                onSelect = function()
                    OpenPlayerEvidence()
                end,
                canInteract = function()
                    local dutyData = Core.CheckDuty()
                    return dutyData.status == 1
                end
            }
        }
    }
}

Config.Jail.PersonalPrisonLocker = {
    coords = vector3(1838.72, 2581.64, 45.89),
    radius = 0.75,
    label = locale('jail_locker'),
    icon = 'fa-solid fa-id-card',
    distance = 2,
    drawSprite = true,
}

Config.Jail.Ped = {
    model = 's_m_y_cop_01',
    anim = {},
    coords = vector4(1755.2795, 2497.3257, 45.6559, 300.7351) -- coords of ped and target
}

Config.Jail.HelpNotify = function(title, text)
    if GetResourceState('p_hints') == 'started' then
        exports['p_hints']:showHintUI({
            title = title,
            text = text,
        })
    else
        lib.showTextUI(text)
    end
end

Config.Jail.HideHelpNotify = function()
    if GetResourceState('p_hints') == 'started' then
        exports['p_hints']:hideHintUI()
    else
        lib.hideTextUI()
    end
end

Config.Jail.Jobs = {
    [locale('laundry')] = {
        [1] = { -- 1ST STEP
            target = {label = locale('take_laundry'), icon = 'fa-solid fa-tshirt'},
            locations = { -- script will select random location from table
                vector3(1591.77, 2549.59, 45.7),
            },
            blipData = {
                sprite = 514, color = 5, label = locale('laundry'), scale = 0.8
            },
            onStart = function()
                Config.Jail.HelpNotify(locale('laundry'), locale('laundry_start_help'))
            end,
            progress = {
                duration = 7500, label = locale('taking_laundry'),
                anim = {scenario = 'PROP_HUMAN_BUM_BIN'},
                disable = {move = true, combat = true, car = true},
            },
            onEnd = function()
                jailJobs.playAnim({
                    animDict = 'anim@heists@box_carry@', animClip = 'idle', flag = 49,
                    propModel = 'v_ind_rc_overallfld', propBone = 28422,
                    propCoords = vector3(0.0, -0.08, -0.17), propRot = vector3(0.0, 0.0, 0.0),
                    disableSprint = true
                })
            end,
        },
        [2] = {
            target = {label = locale('put_laundry'), icon = 'fa-solid fa-tshirt'},
            locations = {
                vector3(1596.92, 2541.54, 45.6), vector3(1596.92, 2540.85, 45.5),
                vector3(1596.96, 2539.45, 45.6), vector3(1588.68, 2538.05, 45.65),
                vector3(1588.68, 2539.41, 45.6), vector3(1588.67, 2540.86, 45.6),
            },
            blipData = {
                sprite = 514, color = 5, label = locale('laundry'), scale = 0.8
            },
            onStart = function()
                Config.Jail.HelpNotify(locale('laundry'), locale('laundry_second_help'))
            end,
            onSelect = function()
                local success = lib.skillCheck({'easy', 'easy', {areaSize = 60, speedMultiplier = 2}, 'easy'}, {'w', 'a', 's', 'd'})
                if success then
                    jailJobs.stopAnim()
                end
                return success
            end,
            progress = {
                duration = 7500, label = locale('making_laundry'),
                anim = {scenario = 'PROP_HUMAN_BUM_BIN'},
                disable = {move = true, combat = true, car = true},
            },
            onEnd = function()
                jailJobs.playAnim({
                    animDict = 'anim@heists@box_carry@', animClip = 'idle', flag = 49,
                    propModel = 'p_overalls_02_s', propBone = 28422,
                    propCoords = vector3(0.0, -0.08, -0.17), propRot = vector3(0.0, 0.0, 0.0),
                    disableSprint = true
                })
            end
        },
        [3] = {
            target = {label = locale('fold_laundry'), icon = 'fa-solid fa-tshirt'},
            locations = {
                vector3(1591.7, 2540.97, 45.6), vector3(1591.78, 2538.66, 45.5),
                vector3(1593.54, 2540.93, 45.6), vector3(1593.91, 2538.61, 45.5),
            },
            blipData = {
                sprite = 514, color = 5, label = locale('laundry'), scale = 0.8
            },
            onStart = function()
                Config.Jail.HelpNotify(locale('laundry'), locale('laundry_finish_help'))
            end,
            months = {min = 10, max = 15}, -- how much months will be removed [random select between min and max]
            onSelect = function()
                local success = lib.skillCheck({'easy', 'easy', {areaSize = 60, speedMultiplier = 2}, 'easy'}, {'w', 'a', 's', 'd'})
                if success then
                    jailJobs.stopAnim()
                end
                return success
            end,
            progress = {
                duration = 7500, label = locale('folding_laundry'),
                anim = {scenario = 'PROP_HUMAN_BUM_BIN'},
                disable = {move = true, combat = true, car = true},
            },
            onEnd = function()
                Config.Jail.HideHelpNotify()
            end
        }
    },
    [locale('woodwork')] = {
        [1] = { -- 1ST STEP
            target = {label = locale('take_wood'), icon = 'fa-solid fa-tree'},
            locations = { -- script will select random location from table
                vector3(1566.62, 2548.06, 46.0), vector3(1567.13, 2550.08, 46.0),
            },
            blipData = {
                sprite = 514, color = 5, label = locale('woodwork'), scale = 0.8
            },
            onStart = function()
                Config.Jail.HelpNotify(locale('woodwork'), locale('woodwork_start_help'))
            end,
            progress = {
                duration = 7500, label = locale('taking_wood'),
                anim = {scenario = 'PROP_HUMAN_BUM_BIN'},
                disable = {move = true, combat = true, car = true},
            },
            onEnd = function()
                jailJobs.playAnim({
                    animDict = 'missfinale_c2mcs_1', animClip = 'fin_c2_mcs_1_camman', flag = 49,
                    propModel = 'bzzz_lumberjack_wood_pack_3a_static', propBone = 6286,
                    -- PROPS CREDITS - https://forum.cfx.re/t/props-woods-for-lumberjack/5119893
                    propCoords = vector3(0.09, 0.1, -0.06), propRot = vector3(6.28, 0.0, 10.64),
                    disableSprint = true
                })
            end,
        },
        [2] = {
            target = {label = locale('process_wood'), icon = 'fa-solid fa-tree'},
            locations = {
                vector3(1570.9, 2550.35, 45.5), vector3(1574.61, 2550.47, 45.5),
                vector3(1570.87, 2545.74, 45.5), vector3(1578.4, 2550.41, 45.6),
                vector3(1574.65, 2545.84, 45.4), vector3(1578.35, 2545.74, 45.5),
                vector3(1581.95, 2550.44, 45.6), vector3(1581.95, 2545.75, 45.6),
            },
            blipData = {
                sprite = 514, color = 5, label = locale('woodwork'), scale = 0.8
            },
            onStart = function()
                Config.Jail.HelpNotify(locale('woodwork'), locale('woodwork_second_help'))
            end,
            onSelect = function()
                local success = lib.skillCheck({'easy', 'easy', {areaSize = 60, speedMultiplier = 2}, 'easy'}, {'w', 'a', 's', 'd'})
                if success then
                    jailJobs.stopAnim()
                end
                return success
            end,
            progress = {
                duration = 7500, label = locale('processing_wood'),
                anim = {dict = 'anim@heists@fleeca_bank@drilling', clip = 'drill_right_end', flag = 1},
                disable = {move = true, combat = true, car = true},
                prop = {model = `prop_tool_consaw`, pos = vec3(0.1, 0.04, 0.35), rot = vec3(5.78, -9.1, -79.23)}
            },
            onEnd = function()
                ClearPedTasks(cache.ped)
                SetTimeout(200, function()
                    jailJobs.playAnim({
                        animDict = 'anim@heists@box_carry@', animClip = 'idle', flag = 49,
                        propModel = 'bzzz_lumberjack_wood_pack_2d', propBone = 28422,
                        propCoords = vector3(0.02, -0.15, -0.17), propRot = vector3(1.3, 0.0, 90.74),
                        disableSprint = true
                    })
                end)
            end
        },
        [3] = {
            target = {label = locale('woodwork_finish'), icon = 'fa-solid fa-tree'},
            locations = { -- script will select random location from table
                vector3(1566.62, 2548.06, 46.0), vector3(1567.13, 2550.08, 46.0),
            },
            blipData = {
                sprite = 514, color = 5, label = locale('woodwork'), scale = 0.8
            },
            onStart = function()
                Config.Jail.HelpNotify(locale('woodwork'), locale('woodwork_finish_help'))
            end,
            months = {min = 2, max = 5}, -- how much months will be removed [random select between min and max]
            onSelect = function()
                local success = lib.skillCheck({'easy', 'easy', {areaSize = 60, speedMultiplier = 2}, 'easy'}, {'w', 'a', 's', 'd'})
                if success then
                    jailJobs.stopAnim()
                end
                return success
            end,
            progress = {
                duration = 7500, label = locale('putting_desks'),
                anim = {scenario = 'PROP_HUMAN_BUM_BIN'},
                disable = {move = true, combat = true, car = true},
            },
            onEnd = function()
                Config.Jail.HideHelpNotify()
            end
        }
    },
}

-- JAIL UTILITIES

Config.Jail.Utils = {}

Config.Jail.Utils.Showers = {
    {coords = vec3(1697.4, 2578.94, 45.4), radius = 0.9, duration = 10000},
    {coords = vec3(1697.26, 2577.38, 45.4), radius = 0.9, duration = 10000},
    {coords = vec3(1697.36, 2575.73, 45.5), radius = 0.9, duration = 10000},
}

Config.Jail.Utils.Undress = function()
    local p = promise.new()
    local firstDict = lib.requestAnimDict('missmic4')
    local secondDict = lib.requestAnimDict('re@construction')
    TaskPlayAnim(cache.ped, firstDict, 'michael_tux_fidget', -8.0, 8.0, 2000, 51)
    if Config.Framework == 'ESX' then
        TriggerEvent('skinchanger:getSkin', function(mySkin)
            Citizen.Wait(500)
            TriggerEvent('skinchanger:loadClothes', mySkin, {
                ['arms'] = 15,
                ['tshirt_1'] = 15, ['tshirt_2'] = 0,
                ['torso_1'] = 15, ['torso_2'] = 0,
                ['bproof_1'] = 0, ['bproof_2'] = 0
            })
            Citizen.Wait(2000)
            TaskPlayAnim(cache.ped, secondDict, 'out_of_breath', -8.0, 8.0, 2000, 51)
            Citizen.Wait(1000)
            TriggerEvent('skinchanger:loadClothes', mySkin, {
                ['arms'] = 15,
                ['pants_1'] = 14, ['pants_2'] = 0,
                ['shoes_1'] = 34, ['shoes_2'] = 0,
                ['tshirt_1'] = 15, ['tshirt_2'] = 0,
                ['torso_1'] = 15, ['torso_2'] = 0,
                ['bproof_1'] = 0, ['bproof_2'] = 0
            })
            ClearPedTasks(cache.ped)
            Citizen.Wait(250)
            p:resolve(mySkin)
        end)
    else
        
    end

    local await = Citizen.Await(p)
    RemoveAnimDict(firstDict)
    RemoveAnimDict(secondDict)
    return await
end

Config.Jail.Utils.Dress = function(playerSkin)
    if Config.Framework == 'ESX' then
        TriggerEvent('skinchanger:loadSkin', playerSkin)
    else
        TriggerServerEvent('qb-clothes:loadPlayerSkin')
    end
end
```

</details>

<details>

<summary>Mugshot Config</summary>

```lua
Config.Mugshot = {}

-- REQUIRED TO SCRIPT WORK PROPERLY!
-- https://docs.fivemanage.com/sdk/fivem/install
-- https://docs.fivemanage.com/sdk/fivem/install
-- https://docs.fivemanage.com/sdk/fivem/install
-- https://docs.fivemanage.com/sdk/fivem/install

Config.Mugshot.Points = {
    ['Mission_Row'] = {
        coords = vector3(454.47, -980.56, 27.5),
        photoCoords = vector3(451.0381, -980.3453, 27.8340),
        cameraCoords = vector3(452.9016, -980.3027, 28.3120),
        cameraFov = 40.0,
        jobs = {
            ['police'] = 0
        }
    }
}

Config.Mugshot.SendPhoto = function(data)
    if not data.webhook or data.webhook == '' then
        print('^8[ERROR] SET WEBHOOK IN CONFIG.WEBHOOKS^7')
        print('^8[ERROR] SET WEBHOOK IN CONFIG.WEBHOOKS^7')
        print('^8[ERROR] SET WEBHOOK IN CONFIG.WEBHOOKS^7')
        print('^8[ERROR] SET WEBHOOK IN CONFIG.WEBHOOKS^7')
        print('^8[ERROR] SET WEBHOOK IN CONFIG.WEBHOOKS^7')
        print('^8[ERROR] SET WEBHOOK IN CONFIG.WEBHOOKS^7')
        print('^8[ERROR] SET WEBHOOK IN CONFIG.WEBHOOKS^7')
        return
    end

    local embeds = {
        {
            ["avatar_url"] = "https://r2.fivemanage.com/xlufCGKYLtGfU8IBmjOL9/360.png",
            ["username"] = "MUGSHOT - LSPD",
            ["author"] = {
                ["name"] = "MUGSHOT",
                ["icon_url"] = "https://r2.fivemanage.com/xlufCGKYLtGfU8IBmjOL9/360.png",
            },
            ["description"] = ('Mugshot ID: **%s**\nSuspect: **%s**\nDOB: **%s**\nOfficer: **%s**\nDescription: **%s**'):format(data.id, data.suspect, data.dob, data.officer, data.description),
            ["type"]="rich",
            ["color"] =5793266,
            ["image"]= {
                ["url"] = data.url
            },
            ["footer"] = {
                ["text"] = os.date(),
                ["icon_url"] = "https://r2.fivemanage.com/xlufCGKYLtGfU8IBmjOL9/360.png",
            },
        }
    }
    PerformHttpRequest(data.webhook, function(err, text, headers) 
    end, 'POST', json.encode({ 
        username = 'MUGSHOT', avatar_url = 'https://r2.fivemanage.com/xlufCGKYLtGfU8IBmjOL9/360.png', embeds = embeds
    }), { ['Content-Type'] = 'application/json' })
end
```

</details>

<details>

<summary>Objects Config</summary>

```lua
Config.Objects = {}

Config.Objects.Jobs = {
    ['police'] = {
        ['p_ld_stinger_s'] = locale('stinger'),
        ['prop_consign_01a'] = locale('consign'),
        ['prop_roadcone02a'] = locale('roadcone'),
        ['prop_barrier_work05'] = locale('barrier'),
        ['prop_air_conelight'] = locale('roadcone_light'),
        ['reh_prop_reh_outline_01a'] = locale('tape')
    }
}

Config.Objects.SpikeStripItem = {
    enabled = true, -- IF YOU WANT SPIKE TRIPS AS ITEM, REMOVE MODEL 'p_ld_stinger_s' FROM CONFIG ABOVE
    jobRestricted = true, -- IS ONLY ALLOWED FOR JOBS?
    allowedJobs = Config.Jobs,
    
}

Config.Objects.ShowHelpNotify = function()
    if GetResourceState('p_helper') == 'started' then
        exports['p_helper']:showHelper({
            {
                keys = {'X'},
                label = locale('cancel')
            },
            {
                keys = {'<', '>'},
                label = locale('rotate_left_right')
            },
            {
                keys = {'E'},
                label = locale('confirm')
            },
        })
    else
        lib.showTextUI('[X] - Cancel | [<] [>] - Rotate | [E] - Confirm')
    end
end

Config.Objects.HideHelpNotify = function()
    if GetResourceState('p_helper') == 'started' then
        exports['p_helper']:hideHelper()
    else
        lib.hideTextUI()
    end
end

Config.Objects.NeedDuty = true -- need to be on duty to remove props?
```

</details>

<details>

<summary>Radar Config</summary>

```lua
Config.Radar = {}

Config.Radar.KeyMapper = 'G' -- Press "G" to toggle Police Radar (SET to "" if you dont want key mapper)

Config.Radar.Unit = 'MPH' -- MPH / KMH

Config.Radar.LockKeys = {
    ['front'] = 'J',
    ['rear'] = 'M'
}

Config.Radar.RestrictedJobs = {
    ['police'] = true,
    ['sheriff'] = true
}

Config.Radar.RestrictedVehicles = {
    [`police`] = true,
    [`police2`] = true,
    [`police3`] = true,
    [`cvpi`] = true
}

Config.Radar.RestrictedDuty = true -- must be on duty to use

Config.HandRadar = {}

Config.HandRadar.RestrictedJobs = { -- which jobs can use
    ['police'] = 0,
    ['sheriff'] = 0
}

Config.HandRadar.RestrictedDuty = true -- must be on duty to use
```

</details>

<details>

<summary>Radio Config</summary>

```lua
Config.RadioList = {}

Config.RadioList.Enabled = true -- set to false to disable

Config.RadioList.ToggleKey = 'G' -- KEY TO TOGGLE RADIO LIST [TO DISABLE SET TO FALSE]

Config.RadioList.RestrictedJobs = { -- set to false if you want for everyone
    ['police'] = 0,
    ['sheriff'] = 0,
}

Config.RadioList.ChangePageKeys = {
    ['left'] = 'LEFT', -- left arrow
    ['right'] = 'RIGHT', -- right arrow
}

Config.RadioList.ChannelNames = {
    ['1'] = 'LSPD',
    ['2'] = 'LSPD',
    ['3'] = 'LSPD',
    ['4'] = 'SHERIFF',
    ['5'] = 'SHERIFF'
}

Config.RadioList.TalkingDelay = 50 -- ms [anti spam for radio]

Config.RadioAnimations = {
    {
        label = 'Holding radio',
        animDict = 'anim@male@holding_radio',
        animClip = 'holding_radio_clip',
        animFlag = 50,
        prop = {
            model = 'prop_cs_hand_radio',
            bone = 6286,
            coords = vector3(0.08, 0.03, -0.01),
            rotation = vector3(-59.99, 15.54, -52.55),
        }
    },
    {
        label = 'Fast talk',
        animDict = 'random@arrests',
        animClip = 'generic_radio_chatter',
        animFlag = 50,
        isDefault = true -- default animation [you can set other]
    },
    {
        label = 'Slow talk',
        animDict = 'amb@code_human_police_investigate@idle_a',
        animClip = 'idle_b',
        animFlag = 50,
    }
}

-- https://docs.fivem.net/docs/game-references/input-mapper-parameter-ids/keyboard/ [KEYS HERE
```

</details>

<details>

<summary>Speedcam Config</summary>

```lua
Config.Speedcam = {}

Config.Speedcam.AllowedJobs = { -- ALLOWED JOBS TO CREATE SPEED CAMS
    ['police'] = 0,
    ['sheriff'] = 0
}

Config.Speedcam.AllowedGroups = { -- ALLOWED GROUPS TO CREATE SPEED CAMS
    ['owner'] = true,
    ['admin'] = true
}

Config.Speedcam.IgnoredJobs = { -- WHICH JOBS WILL BE IGNORED BY SPEED CAMS
    ['police'] = true,
    ['ambulance'] = true,
    ['sheriff'] = true
}

Config.Speedcam.Models = {
    ['prop_cctv_pole_03'] = 'CCTV Pole 1'
}

Config.Speedcam.Unit = 'KMH' -- KMH / MPH

Config.Speedcam.Blip = {
    sprite = 604,
    color = 0,
    scale = 0.85,
    label = locale('speed_camera')
}

Config.Speedcam.Sound = {
    enabled = true,
    volume = 0.3, -- 0.1 - 1.0
}


Config.Speedcam.ShowHelpNotify = function(title, text)
    if GetResourceState('p_helper') == 'started' then
        exports['p_helper']:showHelper({
            {
                keys = {'X'},
                label = locale('cancel')
            },
            {
                keys = {'<', '>'},
                label = locale('rotate_left_right')
            },
            {
                keys = {'E'},
                label = locale('confirm')
            },
        })
    else
        lib.showTextUI('[X] - '..locale('cancel')..' | [< >] - '..locale('rotate_left_right')..' | [E] - '..locale('confirm'))
    end
end

Config.Speedcam.HideHelpNotify = function()
    if GetResourceState('p_helper') == 'started' then
        exports['p_helper']:hideHelper()
    else
        lib.hideTextUI()
    end
end

Config.Speedcam.PayFine = function(playerId, totalFine, vehicleSpeed, speedLimit)
    local Player = Core.GetPlayerFromId(playerId)
    if Config.Framework == 'ESX' then
        Player.removeAccountMoney('bank', totalFine)
    else
        Player.Functions.RemoveMoney('bank', totalFine)
    end
    local totalSpeed = math.floor(vehicleSpeed - speedLimit)
    Core.ShowNotification(playerId, locale('you_got_speeding_fine', totalFine, totalSpeed..' '..Config.Speedcam.Unit))

    if Config.Framework == 'ESX' then
        TriggerEvent('esx_addonaccount:getSharedAccount', 'society_police', function(account)
            if account then
                account.addMoney(totalFine)
            end
        end)
    end
end
```

</details>

<details>

<summary>Tackle Config</summary>

```lua
Config.Tackle = {}

Config.Tackle.Keys = { -- WHICH KEYS TO PRESS TO TACKLE [ALL AT THE SAME TIME]
    21, -- LEFT SHIT
    38 -- E
}

Config.Tackle.Distance = 3.0 -- distance to tackle someone

Config.Tackle.Timeout = 10000 -- 10 seconds cooldown

Config.Tackle.RestrictedJobs = { -- set to false if you dont want restrict
    ['police'] = 0
}

Config.Tackle.CanUseTackle = function()
    if cache.vehicle and cache.vehicle ~= 0 then
        return false
    end

    if exports['p_policejob']:isTackling() then
        return false
    end

    if IsPedRagdoll(cache.ped) then
        return false
    end
    
    if not IsPedSprinting(cache.ped) then
        return false
    end

    return true
end
```

</details>

<details>

<summary>Trunks Config</summary>

```lua
Config.Trunks = {}

Config.Trunks.CameraType = 'dynamic' -- static / dynamic / game

Config.Trunks.CheckVehicleLocks = true -- true = if vehicle is locked player will not be able to get out of trunk

Config.Trunks.CheckTrunkState = true -- true = script will check if trunk is open

Config.Trunks.DefaultOffset = {
    coords = vector3(0.0, 0.85, -0.87),
    rotation = vector3(0.0, 0.0, 40.0)
}

Config.Trunks.Offsets = { -- you can also add manually trunks or use /trunk_editor
    -- ['elegy'] = {
    --     coords = vector3(0.0, -1.70, 0.25),
    --     rotation = vector3(0.0, 0.0, 0.0)
    -- }
}

Config.Trunks.AllowedGroups = {
    ['owner'] = true,
    ['admin'] = true
}

Config.Trunks.ShowHelpNotify = function()
    exports['p_helper']:showHelper({
        {
            keys = {'X'},
            label = 'Cancel'
        },
        {
            keys = {'A', 'D'},
            label = 'Offset X'
        },
        {
            keys = {'N', 'M'},
            label = 'Offset Y'
        },
        {
            keys = {'W', 'S'},
            label = 'Offset Z'
        },
        {
            keys = {'Q', 'R'},
            label = 'Rotation X'
        },
        {
            keys = {'F', 'G'},
            label = 'Rotation Y'
        },
        {
            keys = {'C', 'V'},
            label = 'Rotation Z'
        },
        {
            keys = {'E'},
            label = 'Confirm'
        },
    })
end

Config.Trunks.HideHelpNotify = function()
    exports['p_helper']:hideHelper()
end

Config.Trunks.OnPlayerEnterTrunk = function()
    -- do something
end

Config.Trunks.OnPlayerExitTrunk = function()
    -- do something
en
```

</details>

<details>

<summary>Vehicleshop Config</summary>

```lua
Config.VehicleShop = {}

Config.VehicleShop.Enabled = true

Config.VehicleShop.Shops = {
    ['Mission_Row'] = {
        coords = {
            camCoords = vector3(452.4502, -1008.3307, 26.1293),
            vehicleCoords = vector4(446.7827, -1008.3640, 25.9293, 230.3472),
        },
        ped = {
            coords = vector4(459.1993, -998.6849, 25.9292, 178.8984),
            model = 's_f_y_cop_01',
            anim = {dict = 'amb@world_human_cop_idles@male@idle_b', clip = 'idle_e'}
        },
        allowedJobs = {
            ['police'] = { -- vehicles list for specific job
                grade = 0, -- from which grade player can open vehicle shop
                vehicles = {
                    [0] = { -- GRADE 0 CAN BUY THESE VEHICLES
                        ['police'] = 25000,
                    },
                    [1] = { -- GRADE 1 CAN BUY THESE VEHICLES
                        ['police'] = 25000,
                        ['police2'] = 25000,
                    },
                    [2] = { -- GRADE 2 CAN BUY THESE VEHICLES
                        ['police'] = 25000,
                        ['police2'] = 25000,
                        ['police3'] = 25000,
                    },
                    [3] = { -- GRADE 3 CAN BUY THESE VEHICLES
                        ['police'] = 25000,
                        ['police2'] = 25000,
                        ['police3'] = 25000,
                        ['police4'] = 25000,
                    },
                }
            },
            ['sheriff'] = {
                grade = 0,
                vehicles = {
                    [0] = {
                        ['police'] = 25000,
                        ['police2'] = 30000,
                        ['police3'] = 35000
                    },
                    [1] = {
                        ['police'] = 25000,
                        ['police2'] = 30000,
                        ['police3'] = 35000
                    },
                }
            },
        },
        blip = { -- only visible for allowed jobs
            sprite = 357,
            scale = 0.75,
            color = 3,
            label = 'Police Vehicle Shop'
        },
    }
}
```

</details>

<details>

<summary>Vests Config</summary>

```lua
Config.Vests = {}

Config.Vests.Items = {
    ['vest_normal'] = {
        armourAmount = 10, -- this item will add 10% to player armout
        maxAmount = 50, -- you can add max 50% from this item
        useable = true, -- if true progress bar will show up
        usingTime = 5000, -- 5 seconds
        usingAnim = {dict = 'clothingshirt', clip = 'try_shirt_positive_d', flag = 49},
        disableControls = {move = false, car = true, combat = true} -- while using item
    },
    ['vest_strong'] = {
        armourAmount = 25, -- this item will add 10% to player armout
        maxAmount = 100, -- you can add max 50% from this item
        useable = true, -- if true progress bar will show up
        usingTime = 5000, -- 5 seconds
        usingAnim = {dict = 'clothingshirt', clip = 'try_shirt_positive_d', flag = 49},
        disableControls = {move = false, car = true, combat = true} -- while using item
    },
}

-- WHEN YOU ADDING NEW ITEM HERE YOU NEED TO CREATE NEW ITEM IN OX_INVENTORY/DATA/ITEMS.LUA LIKE BELOW
-- ['change_item_name'] = {
--     label = 'CHANGE LABEL',
--     weight = 3000,
--     stack = false,
--     consume = 1,
--     client = {
--         export = 'p_policejob.item_name_here' -- CHANGE item_name_here to item name!
--     }
-- },
```

</details>

<details>

<summary>Webhooks Config</summary>

```lua
Webhooks = {
    ['band'] = 'WEBHOOK HERE',
    ['bodycam'] = 'WEBHOOK HERE',
    ['divingsuit'] = 'WEBHOOK HERE',
    ['evidence'] = 'WEBHOOK HERE',
    ['gps'] = 'WEBHOOK HERE',
    ['interactions'] = 'WEBHOOK HERE',
    ['jail'] = 'WEBHOOK HERE',
    ['mugshot'] = 'WEBHOOK HERE',
    ['objects'] = 'WEBHOOK HERE',
    ['sounds'] = 'WEBHOOK HERE',
    ['speedcam'] = 'WEBHOOK HERE',
    ['trunks'] = 'WEBHOOK HERE',
}
```

</details>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://piotreq-scripts.gitbook.io/piotreq-scripts/assets-and-guides/police-job/config-files.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
