📝Configuration

Client config

local tabletEntity = nil -- DO NOT CHANGE
local tabletModel = "pp_tablet"
local tabletDict = "amb@world_human_seat_wall_tablet@female@base"
local tabletAnim = "base"
local imagePromise = nil
local items = nil

return {
    locale = 'en', -- EN | PL
    keybind = true,

    startTabletAnimation = function()
        lib.requestAnimDict(tabletDict)
        if tabletEntity then
            stopTabletAnimation()
        end
        lib.requestModel(tabletModel)
        tabletEntity = CreateObject(GetHashKey(tabletModel), 1.0, 1.0, 1.0, 1, 1, 0)
        AttachEntityToEntity(tabletEntity, cache.ped, GetPedBoneIndex(cache.ped, 57005), 0.12, 0.10, -0.13, 25.0, 170.0, 160.0, true, true, false, true, 1, true)
        TaskPlayAnim(cache.ped, tabletDict, tabletAnim, 8.0, -8.0, -1, 50, 0, false, false, false)
    end,

    stopTabletAnimation = function()
        if tabletEntity then
            StopAnimTask(cache.ped, tabletDict, tabletAnim ,8.0, -8.0, -1, 50, 0, false, false, false)
            DeleteEntity(tabletEntity)
            tabletEntity = nil
        end
    end,

    getWeaponData = function(weapon)
        if not items then
            items = exports.ox_inventory:Items()
        end
        return {
            model = items[weapon['weapon']].label,
            img = ("https://cfx-nui-ox_inventory/web/images/%s.png"):format(weapon['weapon'])
        }
    end,

    cameraTextUI = '[BACKSPACE] - Cancel   \n[ENTER] - Confirm',

    camerasOffsets = {
        prop_cctv_cam_01a = {
            initialCamCoord = vector3(0.14, -0.62, 0.21),
            initialCamRot = vector3(-30.0, 0.0, 209.4)
        },
        prop_cctv_cam_01b = {
            initialCamCoord = vector3(-0.04, -1.29, 0.22),
            initialCamRot = vector3(-30.0, 0.0, 139.50)
        },
        prop_cctv_cam_03a = {
            initialCamCoord = vector3(-0.47, -0.45, 0.28),
            initialCamRot = vector3(0.0, 0.0, 118.0)
        },
        prop_cctv_cam_05a = {
            initialCamCoord = vector3(0.05, -0.19, 0.1),
            initialCamRot = vector3(-20.0, 0.0, 175.5)
        },
        prop_cctv_cam_06a = {
            initialCamCoord = vector3(0.01, -0.07, 0.14),
            initialCamRot = vector3(0.0, 0.0, 178.0)
        }
    }
}

UI config

return {
    homepage = {
        dispatchlimit = 10,
        maxSearchResults = 20
    },

    announcements = {
        minContentLength = 30
    },

    citizen = {
        licensePrefix = {
            ["Boat License"] = "BOAT"
        }
    },

    patrols = {
        statusTypes = {"Patrol", "Break", "Own Intervention", "Responding", "Other", "Transporting a detainee"},
        patrolTypes = {
            { value = "heli", label = "Helicopter" },
            { value = "car", label = "Car" },
            { value = "walk", label = "Walk" },
            { value = "boat", label = "Boat" },
            { value = "bike", label = "Bike" },
            { value = "motorbike", label = "Motorbike" },
        },
        statusColorMap = {
            ['Patrol'] = "blue",
            ['Break'] = "orange",
            ['Own Intervention'] = "purple",
            ['Responding'] = "green",
            ['Other'] = "gray",
            ['Transporting a detainee'] = "cyan"
        }
    },
    dispatch = {
        distanceCalculate = {
            unit = "miles",
            useRoadDistance = true
        },
        weaponColors = {
            ['handgun'] = "blue",
            ['smg'] = "red",
            ['rifle'] = "gray",
            ['sniper_rifle'] = "orange",
            ['shotgun'] = "purple",
            ['heavy'] = "black",
            ['thrown'] = "green"
        },
        timeLabels = {
            seconds = {
                { min = 0, max = 1, label = "a second" },
                { min = 2, max = 59, label = "x seconds" }
            },
            minutes = {
                { min = 1, max = 1, label = "a minute" },
                { min = 2, max = 59, label = "x minutes" }
            },
            hours = {
                { min = 1, max = 1, label = "an hour" },
                { min = 2, max = 23, label = "x hours" }
            },
            days = {
                { min = 1, max = 1, label = "a day" },
                { min = 2, max = 6, label = "x days" }
            },
            weeks = {
                { min = 1, max = 1, label = "a week" },
                { min = 2, max = 4, label = "x weeks" }
            },
            months = {
                { min = 1, max = 1, label = "a month" },
                { min = 2, max = 11, label = "x months" }
            },
            years = {
                { min = 1, max = 1, label = "a year" },
                { min = 2, max = 100, label = "x years" }
            }
        }
    }
}

Server config

exports.ox_inventory:registerHook('buyItem', function(payload)
    if payload.metadata and payload.metadata.serial then
        local xPlayer = Bridge.getPlayerFromId(payload.source)
        local coords = GetEntityCoords(GetPlayerPed(payload.source))
        MySQL.Async.execute('INSERT INTO `mdt_weapons` (weapon, serialnumber, identifier, coords) VALUES (?, ?, ?, ?)', {payload.itemName, payload.metadata.serial, Bridge.getIdentifier(xPlayer), json.encode({x = coords.x, y = coords.y})})
    end
    return true
end, {
    print = false,
})

return {
    locales = 'en', -- EN | PL

    imageUpload = {
        type = 'fivemanage', -- fivemanage | fmsdk | discord | custom
        token = '', -- fivemanage token | discord webhook
        custom = function(source)
            return nil --return url
        end
    },

    jobsWithAccess = {
        'police'
    },

    cameras = {
        enable = true,
        limit = 10
    },

    homePage = {
        getOfficerData = function(player)
            local radiochannel = Player(player.PlayerData.source).state.radioChannel
            local image = player.PlayerData.metadata.mdt_image
            local badge = player.PlayerData.metadata.callsign or 0

            return {
                radio = radiochannel,
                img = image,
                badge = badge
            }
        end,
        getPhoto = function(identifier)
            local player = exports.qbx_core:GetPlayerByCitizenId(identifier) or exports.qbx_core:GetOfflinePlayer(identifier)
            if not player then return false end

            return player.PlayerData.metadata.mdt_image
        end
    },

    citizen = {
        updatePhoto = function(identifier, url)
            local player = exports.qbx_core:GetPlayerByCitizenId(identifier) or exports.qbx_core:GetOfflinePlayer(identifier)
            if not player then return false end

            player.Functions.SetMetaData('mdt_image', url)
            return true
        end,
        getCitizenDetails = function(identifier)
            local player = exports.qbx_core:GetPlayerByCitizenId(identifier) or exports.qbx_core:GetOfflinePlayer(identifier)
            if not player or not player.PlayerData then return {} end
            local data = player.PlayerData
            local licenses = {}

            for name, value in pairs(data.metadata.licences) do
                table.insert(licenses, {
                    label = name,
                    owns = value
                })
            end

            return {
                name = data.charinfo.firstname .. ' ' .. data.charinfo.lastname,
                dob = data.charinfo.birthdate,
                img = data.metadata.mdt_image,
                ssn = identifier,
                nationality = data.charinfo.nationality,
                licenses = licenses
            }
        end
    },

    vehicle = {
        getVehicleDetails = function(plate)
            local dbdata = MySQL.query.await([[
                SELECT
                    pv.citizenid AS identifier,
                    pv.hash,
                    pv.mdt_image AS img,
                    JSON_UNQUOTE(JSON_EXTRACT(p.charinfo, '$.firstname')) AS firstname,
                    JSON_UNQUOTE(JSON_EXTRACT(p.charinfo, '$.lastname')) AS lastname
                FROM
                    `player_vehicles` pv
                LEFT JOIN
                    `players` p ON pv.citizenid = p.citizenid
                WHERE
                    pv.plate = ?
            ]], {
                plate
            })

            if dbdata and #dbdata > 0 then
                local vehicleData = dbdata[1]
                vehicleData.name = vehicleData.firstname .. " " .. vehicleData.lastname
                return vehicleData
            else
                return {}
            end
        end,
        updatePhoto = function(plate, url)
            local affectedRows = MySQL.update.await('UPDATE `player_vehicles` SET `mdt_image` = ? WHERE `plate` = ?', {
                url, plate
            })

            return affectedRows > 0 and true or false
        end
    },

    case = {
        mugshot = {
            enable = true,
            title = "Los Santos Police Department",
            subtitle = "Case #%s",
            updatePhoto = function(identifier, url)
                local player = exports.qbx_core:GetPlayerByCitizenId(identifier) or exports.qbx_core:GetOfflinePlayer(identifier)
                if not player then return false end

                player.Functions.SetMetaData('mdt_image', url)
                return true
            end,
        },
        sendToJail = function(identifier, months, fine, data)
            -- fill with your own jail system
        end,
        giveTicket = function(identifier, fine, data)
            -- fill with your own ticket system
        end,
        charges = {
            {
                id = 1,
                label = 'Speeding (Minor)',
                description = 'Exceeding the speed limit by up to 10 mph.',
                fine = 100,
                months = 0,
                level = 'low',
            },
            {
                id = 2,
                label = 'Speeding (Moderate)',
                description = 'Exceeding the speed limit by 11-20 mph.',
                fine = 500,
                months = 0,
                level = 'medium',
            },
            {
                id = 3,
                label = 'Speeding (Severe)',
                description = 'Exceeding the speed limit by over 20 mph.',
                fine = 1500,
                months = 1,
                level = 'high',
            },
            {
                id = 4,
                label = 'Reckless Driving',
                description = 'Operating a vehicle in a manner that endangers others.',
                fine = 3000,
                months = 3,
                level = 'high',
            },
            {
                id = 5,
                label = 'DUI (First Offense)',
                description = 'Driving under the influence of alcohol or drugs.',
                fine = 2000,
                months = 6,
                level = 'medium',
            },
            {
                id = 6,
                label = 'DUI (Repeat Offense)',
                description = 'Repeated offense of driving under the influence.',
                fine = 5000,
                months = 12,
                level = 'critical',
            },
            {
                id = 7,
                label = 'Assault (Minor)',
                description = 'Physical attack causing minor injuries.',
                fine = 1000,
                months = 6,
                level = 'low',
            },
            {
                id = 8,
                label = 'Assault (Severe)',
                description = 'Physical attack causing severe injuries.',
                fine = 5000,
                months = 24,
                level = 'high',
            },
            {
                id = 9,
                label = 'Robbery',
                description = 'Taking property from another person by force or threat.',
                fine = 10000,
                months = 36,
                level = 'critical',
            },
            {
                id = 10,
                label = 'Murder',
                description = 'Unlawful killing of another person.',
                fine = 25000,
                months = 60,
                level = 'critical',
            },
        }
    },

    patrols = {
        inviteExpiration = 60000, -- 1 minute
    },

    dispatch = {
        getGender = function(frPlayer)
            return frPlayer.PlayerData.charinfo.gender and "Male" or "Female"
        end,
        ignoreJobsWithAccess = true,
        gunShots = {
            enable = true,
            delay = 5000,
            locales = {
                title = 'Shots fired',
                description = 'Gun shots reported',
                code = '10-71',
                blip = '# 10-71 - Shots Fired'
            },
            monitoredWeapons = {
                ['Handgun'] = {
                    ['WEAPON_PISTOL'] = true,
                    ['WEAPON_COMBATPISTOL'] = true,
                    ['WEAPON_HEAVYPISTOL'] = true,
                    ['WEAPON_VINTAGEPISTOL'] = true,
                    ['WEAPON_SNSPISTOL'] = true,
                    ['WEAPON_PISTOL50'] = true,
                    ['WEAPON_REVOLVER'] = true,
                    ['WEAPON_REVOLVER_MK2'] = true,
                    ['WEAPON_DOUBLEACTION'] = true,
                    ['WEAPON_APPISTOL'] = true,
                    ['WEAPON_STUNGUN'] = true,
                    ['WEAPON_FLAREGUN'] = true,
                    ['WEAPON_MARKSMANPISTOL'] = true,
                    ['WEAPON_RAYPISTOL'] = true,
                    ['WEAPON_CERAMICPISTOL'] = true,
                    ['WEAPON_NAVYREVOLVER'] = true
                },
                ['SMG'] = {
                    ['WEAPON_MICROSMG'] = true,
                    ['WEAPON_SMG'] = true,
                    ['WEAPON_SMG_MK2'] = true,
                    ['WEAPON_ASSAULTSMG'] = true,
                    ['WEAPON_MINISMG'] = true,
                    ['WEAPON_MACHINEPISTOL'] = true,
                    ['WEAPON_COMBATPDW'] = true
                },
                ['Rifle'] = {
                    ['WEAPON_ASSAULTRIFLE'] = true,
                    ['WEAPON_ASSAULTRIFLE_MK2'] = true,
                    ['WEAPON_CARBINERIFLE'] = true,
                    ['WEAPON_CARBINERIFLE_MK2'] = true,
                    ['WEAPON_ADVANCEDRIFLE'] = true,
                    ['WEAPON_SPECIALCARBINE'] = true,
                    ['WEAPON_SPECIALCARBINE_MK2'] = true,
                    ['WEAPON_BULLPUPRIFLE'] = true,
                    ['WEAPON_BULLPUPRIFLE_MK2'] = true,
                    ['WEAPON_COMPACTRIFLE'] = true,
                    ['WEAPON_MILITARYRIFLE'] = true,
                    ['WEAPON_HEAVYRIFLE'] = true,
                    ['WEAPON_TACTICALRIFLE'] = true
                },
                ['Sniper rifle'] = {
                    ['WEAPON_SNIPERRIFLE'] = true,
                    ['WEAPON_HEAVYSNIPER'] = true,
                    ['WEAPON_HEAVYSNIPER_MK2'] = true,
                    ['WEAPON_MARKSMANRIFLE'] = true,
                    ['WEAPON_MARKSMANRIFLE_MK2'] = true
                },
                ['Shotgun'] = {
                    ['WEAPON_PUMPSHOTGUN'] = true,
                    ['WEAPON_PUMPSHOTGUN_MK2'] = true,
                    ['WEAPON_SAWNOFFSHOTGUN'] = true,
                    ['WEAPON_BULLPUPSHOTGUN'] = true,
                    ['WEAPON_ASSAULTSHOTGUN'] = true,
                    ['WEAPON_MUSKET'] = true,
                    ['WEAPON_HEAVYSHOTGUN'] = true,
                    ['WEAPON_DBSHOTGUN'] = true,
                    ['WEAPON_AUTOSHOTGUN'] = true,
                    ['WEAPON_COMBATSHOTGUN'] = true
                },
                ['Heavy rifle'] = {
                    ['WEAPON_GRENADELAUNCHER'] = true,
                    ['WEAPON_RPG'] = true,
                    ['WEAPON_MINIGUN'] = true,
                    ['WEAPON_FIREWORK'] = true,
                    ['WEAPON_RAILGUN'] = true,
                    ['WEAPON_HOMINGLAUNCHER'] = true,
                    ['WEAPON_COMPACTLAUNCHER'] = true,
                    ['WEAPON_RAYMINIGUN'] = true,
                    ['WEAPON_EMPLAUNCHER'] = true
                },
                ['Thrown'] = {
                    ['WEAPON_GRENADE'] = true,
                    ['WEAPON_STICKYBOMB'] = true,
                    ['WEAPON_PROXMINE'] = true,
                    ['WEAPON_BZGAS'] = true,
                    ['WEAPON_MOLOTOV'] = true,
                    ['WEAPON_FIREEXTINGUISHER'] = true,
                    ['WEAPON_PETROLCAN'] = true,
                    ['WEAPON_BALL'] = true,
                    ['WEAPON_SNOWBALL'] = true,
                    ['WEAPON_FLARE'] = true,
                    ['WEAPON_PIPEBOMB'] = true
                }
            }
        } 
    },

    permissions = {
        [1] = { -- [grade] = { permissions }
            announcements = {
                'view',
            },
            patrols = {
                'view',
            },
            citizens = {
                'view'
            },
            citizen = {
                'view',
            },
            vehicles = {
                'view'
            },
            vehicle = {
                'view'
            },
            weapons = {
                'view'
            },
            weapon = {
                'view'
            },
            evidences = {
                'view',
            },
            cases = {
                'view',
            },
            case = {
                'view',
            },
            cameras = {
                'view',
            },
            notes = {
                'view',
            },
            note = {
                'view',
            },
            settings = {
                'view'
            }
        },
        [2] = {
            homepage = {
                'viewchat',
                'chatmessage',
                'search'
            },
            announcements = {
                'create',
            },
            announcement = {
                'edit',
                'remove'
            },
            patrols = {
                'create'
            },
            citizen = {
                'takephoto',
                'removephoto',
                'viewcases',
                'viewnotes',
                'viewvehicles'
            },
            vehicle = {
                'takephoto',
                'removephoto',
                'viewcases',
                'viewnotes'
            },
            weapon = {
                'viewcases',
                'viewnotes'
            },
            evidences = {
                'listview',
                'create'
            },
            cases = {
                'listview',
                'create'
            },
            case = {
                'edit',
                'delete'
            },
            cameras = {
                'create'
            },
            notes = {
                'listview',
                'create'
            },
            note = {
                'edit',
                'remove'
            }
        }
    },

    queries = {
        ['searchCitizens'] = [[
            SELECT
                COUNT(*) as count
            FROM
                players
            WHERE
                JSON_UNQUOTE(JSON_EXTRACT(charinfo, '$.firstname')) LIKE @search
                OR JSON_UNQUOTE(JSON_EXTRACT(charinfo, '$.lastname')) LIKE @search
        ]],
        ['getCitizens'] = [[
            SELECT
                citizenid AS identifier,
                citizenid AS ssn,
                JSON_UNQUOTE(JSON_EXTRACT(charinfo, '$.firstname')) AS firstname,
                JSON_UNQUOTE(JSON_EXTRACT(charinfo, '$.lastname')) AS lastname,
                JSON_UNQUOTE(JSON_EXTRACT(metadata, '$.mdt_image')) AS image
            FROM
                players
            WHERE
                JSON_UNQUOTE(JSON_EXTRACT(charinfo, '$.firstname')) LIKE @search
                OR JSON_UNQUOTE(JSON_EXTRACT(charinfo, '$.lastname')) LIKE @search
            LIMIT @limit OFFSET @offset
        ]],
        ['countVehicles'] = [[
            SELECT COUNT(*) as count
            FROM `player_vehicles`
            WHERE `plate` LIKE @search
        ]],
        ['getVehicles'] = [[
            SELECT
                pv.plate,
                pv.citizenid,
                pv.vehicle,
                pv.hash,
                pv.mdt_image AS image,
                JSON_UNQUOTE(JSON_EXTRACT(p.charinfo, '$.firstname')) AS firstname,
                JSON_UNQUOTE(JSON_EXTRACT(p.charinfo, '$.lastname')) AS lastname
            FROM
                `player_vehicles` pv
            LEFT JOIN
                `players` p ON pv.citizenid = p.citizenid
            WHERE
                pv.plate LIKE @search
            LIMIT
                @limit OFFSET @offset
        ]],
        ['getCitizenVehicles'] = 'SELECT `hash`, `plate` FROM `player_vehicles` WHERE `citizenid` = ?',
        ['getAuthor'] = [[
            SELECT
                JSON_UNQUOTE(JSON_EXTRACT(charinfo, '$.firstname')) AS firstname,
                JSON_UNQUOTE(JSON_EXTRACT(charinfo, '$.lastname')) AS lastname
            FROM
                players
            WHERE
                citizenid = ?
        ]],
        ['getCitizensByIdentifiers'] = [[
            SELECT
                citizenid AS identifier,
                JSON_UNQUOTE(JSON_EXTRACT(charinfo, '$.firstname')) AS firstname,
                JSON_UNQUOTE(JSON_EXTRACT(charinfo, '$.lastname')) AS lastname
            FROM
                players
            WHERE
                citizenid IN (?)
        ]],
        weapons = {
            ['usersSearch'] = 'SELECT citizenid FROM players WHERE JSON_EXTRACT(charinfo, "$.firstname") LIKE @search OR JSON_EXTRACT(charinfo, "$.lastname") LIKE @search',
            ['usersFullName'] = 'CONCAT(JSON_UNQUOTE(JSON_EXTRACT(p.charinfo, "$.firstname")), " ", JSON_UNQUOTE(JSON_EXTRACT(p.charinfo, "$.lastname")))',
            ['usersJoin'] = 'LEFT JOIN players p ON w.identifier = p.citizenid'
        },
        search = {
            ['citizens'] = [[
                SELECT
                    citizenid AS identifier,
                    JSON_UNQUOTE(JSON_EXTRACT(charinfo, '$.firstname')) AS firstname,
                    JSON_UNQUOTE(JSON_EXTRACT(charinfo, '$.lastname')) AS lastname
                FROM
                    players
                WHERE
                    JSON_UNQUOTE(JSON_EXTRACT(charinfo, '$.firstname')) LIKE @query
                    OR JSON_UNQUOTE(JSON_EXTRACT(charinfo, '$.lastname')) LIKE @query
                LIMIT 20
            ]],
            ['vehicles'] = [[
                SELECT
                    plate, hash
                FROM
                    player_vehicles
                WHERE
                    plate LIKE @query
                LIMIT 20
            ]],
            ['officers'] = [[
                SELECT
                    p.citizenid AS identifier,
                    JSON_UNQUOTE(JSON_EXTRACT(p.charinfo, '$.firstname')) AS firstname,
                    JSON_UNQUOTE(JSON_EXTRACT(p.charinfo, '$.lastname')) AS lastname
                FROM
                    players p
                WHERE
                    JSON_UNQUOTE(JSON_EXTRACT(p.job, '$.name')) = @job
                    AND (
                        JSON_UNQUOTE(JSON_EXTRACT(p.charinfo, '$.firstname')) LIKE @query
                        OR JSON_UNQUOTE(JSON_EXTRACT(p.charinfo, '$.lastname')) LIKE @query
                    )
                LIMIT 20
            ]],
            ['weapons'] = [[
                SELECT
                    mw.serialnumber,
                    JSON_UNQUOTE(JSON_EXTRACT(p.charinfo, '$.firstname')) AS firstname, 
                    JSON_UNQUOTE(JSON_EXTRACT(p.charinfo, '$.lastname')) AS lastname
                FROM
                    mdt_weapons mw
                INNER JOIN
                    players p ON mw.identifier = p.citizenid
                WHERE
                    mw.serialnumber LIKE @query
                    OR (
                        JSON_UNQUOTE(JSON_EXTRACT(p.charinfo, '$.firstname')) LIKE @query 
                        OR JSON_UNQUOTE(JSON_EXTRACT(p.charinfo, '$.lastname')) LIKE @query
                    )
                LIMIT 20
            ]]
        }
    },
}

Last updated